├── .all-contributorsrc ├── .eslintrc ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── validate.yml ├── .gitignore ├── .huskyrc.js ├── .npmrc ├── .prettierignore ├── .prettierrc.js ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── add-commands.js ├── cypress.config.js ├── cypress ├── .eslintrc ├── e2e │ └── find.cy.js ├── fixtures │ └── test-app │ │ ├── index.html │ │ └── next-page.html └── support │ └── e2e.js ├── jest.config.js ├── lint-staged.config.js ├── other ├── CODE_OF_CONDUCT.md ├── MAINTAINING.md ├── USERS.md ├── manual-releases.md ├── testingjavascript.jpg └── tiger.png ├── package.json ├── src ├── __tests__ │ ├── add-commands.js │ └── commands.js ├── add-commands.js ├── index.js └── utils.js └── types ├── add-commands.d.ts ├── index.d.ts ├── test.ts └── tsconfig.json /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "cypress-testing-library", 3 | "projectOwner": "testing-library", 4 | "files": [ 5 | "README.md" 6 | ], 7 | "imageSize": 100, 8 | "commit": false, 9 | "skipCi": false, 10 | "contributors": [ 11 | { 12 | "login": "kentcdodds", 13 | "name": "Kent C. Dodds", 14 | "avatar_url": "https://avatars.githubusercontent.com/u/1500684?v=3", 15 | "profile": "https://kentcdodds.com", 16 | "contributions": [ 17 | "code", 18 | "doc", 19 | "infra", 20 | "test" 21 | ] 22 | }, 23 | { 24 | "login": "sompylasar", 25 | "name": "Ivan Babak", 26 | "avatar_url": "https://avatars2.githubusercontent.com/u/498274?v=4", 27 | "profile": "https://sompylasar.github.io", 28 | "contributions": [ 29 | "code", 30 | "ideas" 31 | ] 32 | }, 33 | { 34 | "login": "lgandecki", 35 | "name": "Łukasz Gandecki", 36 | "avatar_url": "https://avatars1.githubusercontent.com/u/4002543?v=4", 37 | "profile": "http://team.thebrain.pro", 38 | "contributions": [ 39 | "code", 40 | "test" 41 | ] 42 | }, 43 | { 44 | "login": "npeterkamps", 45 | "name": "Peter Kamps", 46 | "avatar_url": "https://avatars1.githubusercontent.com/u/25429764?v=4", 47 | "profile": "https://github.com/npeterkamps", 48 | "contributions": [ 49 | "code", 50 | "doc", 51 | "ideas", 52 | "test" 53 | ] 54 | }, 55 | { 56 | "login": "airato", 57 | "name": "Airat Aminev", 58 | "avatar_url": "https://avatars3.githubusercontent.com/u/4506749?v=4", 59 | "profile": "https://github.com/airato", 60 | "contributions": [ 61 | "code", 62 | "test", 63 | "tool" 64 | ] 65 | }, 66 | { 67 | "login": "adrian1358", 68 | "name": "Adrian Smijulj", 69 | "avatar_url": "https://avatars0.githubusercontent.com/u/5121148?v=4", 70 | "profile": "https://www.webiny.com", 71 | "contributions": [ 72 | "code" 73 | ] 74 | }, 75 | { 76 | "login": "misoguy", 77 | "name": "Soo Jae Hwang", 78 | "avatar_url": "https://avatars0.githubusercontent.com/u/12230408?v=4", 79 | "profile": "https://www.ossfinder.com", 80 | "contributions": [ 81 | "bug", 82 | "code", 83 | "test" 84 | ] 85 | }, 86 | { 87 | "login": "wKovacs64", 88 | "name": "Justin Hall", 89 | "avatar_url": "https://avatars1.githubusercontent.com/u/1288694?v=4", 90 | "profile": "https://github.com/wKovacs64", 91 | "contributions": [ 92 | "code", 93 | "test" 94 | ] 95 | }, 96 | { 97 | "login": "euZebe", 98 | "name": "euzebe", 99 | "avatar_url": "https://avatars3.githubusercontent.com/u/9463809?v=4", 100 | "profile": "https://github.com/euZebe", 101 | "contributions": [ 102 | "doc" 103 | ] 104 | }, 105 | { 106 | "login": "jkdowdle", 107 | "name": "jkdowdle", 108 | "avatar_url": "https://avatars0.githubusercontent.com/u/19804196?v=4", 109 | "profile": "https://github.com/jkdowdle", 110 | "contributions": [ 111 | "code" 112 | ] 113 | }, 114 | { 115 | "login": "existentialism", 116 | "name": "Brian Ng", 117 | "avatar_url": "https://avatars3.githubusercontent.com/u/56288?v=4", 118 | "profile": "https://brian.ng", 119 | "contributions": [ 120 | "code" 121 | ] 122 | }, 123 | { 124 | "login": "klaari", 125 | "name": "Kari Laari", 126 | "avatar_url": "https://avatars2.githubusercontent.com/u/2477131?v=4", 127 | "profile": "https://karilaari.fi", 128 | "contributions": [ 129 | "doc" 130 | ] 131 | }, 132 | { 133 | "login": "ppi-buck", 134 | "name": "Basti Buck", 135 | "avatar_url": "https://avatars2.githubusercontent.com/u/37330764?v=4", 136 | "profile": "https://github.com/ppi-buck", 137 | "contributions": [ 138 | "code" 139 | ] 140 | }, 141 | { 142 | "login": "ShimiTheFirst", 143 | "name": "ShimiTheFirst", 144 | "avatar_url": "https://avatars2.githubusercontent.com/u/25421369?v=4", 145 | "profile": "https://github.com/ShimiTheFirst", 146 | "contributions": [ 147 | "bug" 148 | ] 149 | }, 150 | { 151 | "login": "omerose", 152 | "name": "omerose", 153 | "avatar_url": "https://avatars2.githubusercontent.com/u/9358542?v=4", 154 | "profile": "https://github.com/omerose", 155 | "contributions": [ 156 | "doc" 157 | ] 158 | }, 159 | { 160 | "login": "aaronmcadam", 161 | "name": "Aaron Mc Adam", 162 | "avatar_url": "https://avatars3.githubusercontent.com/u/37928?v=4", 163 | "profile": "http://www.aaronmcadam.com", 164 | "contributions": [ 165 | "code", 166 | "test" 167 | ] 168 | }, 169 | { 170 | "login": "karlhorky", 171 | "name": "Karl Horky", 172 | "avatar_url": "https://avatars2.githubusercontent.com/u/1935696?v=4", 173 | "profile": "https://twitter.com/karlhorky", 174 | "contributions": [ 175 | "doc" 176 | ] 177 | }, 178 | { 179 | "login": "NoriSte", 180 | "name": "Stefano Magni", 181 | "avatar_url": "https://avatars0.githubusercontent.com/u/173663?v=4", 182 | "profile": "https://twitter.com/NoriSte", 183 | "contributions": [ 184 | "code", 185 | "test", 186 | "doc" 187 | ] 188 | }, 189 | { 190 | "login": "weyert", 191 | "name": "Weyert de Boer", 192 | "avatar_url": "https://avatars3.githubusercontent.com/u/7049?v=4", 193 | "profile": "https://github.com/weyert", 194 | "contributions": [ 195 | "code" 196 | ] 197 | }, 198 | { 199 | "login": "simjes", 200 | "name": "Simon Jespersen", 201 | "avatar_url": "https://avatars0.githubusercontent.com/u/6494049?v=4", 202 | "profile": "https://simjes.dev/", 203 | "contributions": [ 204 | "code", 205 | "review" 206 | ] 207 | }, 208 | { 209 | "login": "afontcu", 210 | "name": "Adrià Fontcuberta", 211 | "avatar_url": "https://avatars0.githubusercontent.com/u/9197791?v=4", 212 | "profile": "https://afontcu.dev", 213 | "contributions": [ 214 | "infra", 215 | "doc", 216 | "review" 217 | ] 218 | }, 219 | { 220 | "login": "Megoos", 221 | "name": "Mikhail Guskov", 222 | "avatar_url": "https://avatars2.githubusercontent.com/u/9866017?v=4", 223 | "profile": "https://github.com/Megoos", 224 | "contributions": [ 225 | "bug" 226 | ] 227 | }, 228 | { 229 | "login": "juliusdelta", 230 | "name": "JD Gonzales", 231 | "avatar_url": "https://avatars1.githubusercontent.com/u/10285055?v=4", 232 | "profile": "https://jds.work", 233 | "contributions": [ 234 | "doc" 235 | ] 236 | }, 237 | { 238 | "login": "frinyvonnick", 239 | "name": "Yvonnick FRIN", 240 | "avatar_url": "https://avatars0.githubusercontent.com/u/13099512?v=4", 241 | "profile": "https://yvonnickfrin.dev", 242 | "contributions": [ 243 | "doc" 244 | ] 245 | }, 246 | { 247 | "login": "kefranabg", 248 | "name": "Franck Abgrall", 249 | "avatar_url": "https://avatars3.githubusercontent.com/u/9840435?v=4", 250 | "profile": "https://www.franck-abgrall.me/", 251 | "contributions": [ 252 | "review" 253 | ] 254 | }, 255 | { 256 | "login": "tlrobinson", 257 | "name": "Tom Robinson", 258 | "avatar_url": "https://avatars0.githubusercontent.com/u/18193?v=4", 259 | "profile": "http://twitter.com/tlrobinson", 260 | "contributions": [ 261 | "code", 262 | "test" 263 | ] 264 | }, 265 | { 266 | "login": "NicholasBoll", 267 | "name": "Nicholas Boll", 268 | "avatar_url": "https://avatars2.githubusercontent.com/u/338257?v=4", 269 | "profile": "https://github.com/NicholasBoll", 270 | "contributions": [ 271 | "code", 272 | "test" 273 | ] 274 | }, 275 | { 276 | "login": "FlopieUtd", 277 | "name": "FlopieUtd", 278 | "avatar_url": "https://avatars3.githubusercontent.com/u/23555863?v=4", 279 | "profile": "https://github.com/FlopieUtd", 280 | "contributions": [ 281 | "doc" 282 | ] 283 | }, 284 | { 285 | "login": "leosuncin", 286 | "name": "Jaime Leonardo Suncin Cruz", 287 | "avatar_url": "https://avatars1.githubusercontent.com/u/4307697?v=4", 288 | "profile": "https://github.com/leosuncin", 289 | "contributions": [ 290 | "bug", 291 | "code", 292 | "test" 293 | ] 294 | }, 295 | { 296 | "login": "travi", 297 | "name": "Matt Travi", 298 | "avatar_url": "https://avatars1.githubusercontent.com/u/126441?v=4", 299 | "profile": "https://matt.travi.org", 300 | "contributions": [ 301 | "code" 302 | ] 303 | }, 304 | { 305 | "login": "MichaelDeBoey", 306 | "name": "Michaël De Boey", 307 | "avatar_url": "https://avatars3.githubusercontent.com/u/6643991?v=4", 308 | "profile": "https://michaeldeboey.be", 309 | "contributions": [ 310 | "code" 311 | ] 312 | }, 313 | { 314 | "login": "huchenme", 315 | "name": "Hu Chen", 316 | "avatar_url": "https://avatars3.githubusercontent.com/u/2078389?v=4", 317 | "profile": "https://huchen.dev", 318 | "contributions": [ 319 | "doc" 320 | ] 321 | }, 322 | { 323 | "login": "frederickfogerty", 324 | "name": "Frederick Fogerty", 325 | "avatar_url": "https://avatars0.githubusercontent.com/u/615334?v=4", 326 | "profile": "https://github.com/frederickfogerty", 327 | "contributions": [ 328 | "code" 329 | ] 330 | }, 331 | { 332 | "login": "kylemh", 333 | "name": "Kyle Holmberg", 334 | "avatar_url": "https://avatars1.githubusercontent.com/u/9523719?v=4", 335 | "profile": "https://kylemh.com", 336 | "contributions": [ 337 | "doc" 338 | ] 339 | }, 340 | { 341 | "login": "Thisen", 342 | "name": "Mathis Møller", 343 | "avatar_url": "https://avatars2.githubusercontent.com/u/10807938?v=4", 344 | "profile": "https://github.com/Thisen", 345 | "contributions": [ 346 | "code", 347 | "test" 348 | ] 349 | }, 350 | { 351 | "login": "SimenB", 352 | "name": "Simen Bekkhus", 353 | "avatar_url": "https://avatars1.githubusercontent.com/u/1404810?v=4", 354 | "profile": "https://github.com/SimenB", 355 | "contributions": [ 356 | "code" 357 | ] 358 | }, 359 | { 360 | "login": "amitmiran137", 361 | "name": "Amit Miran", 362 | "avatar_url": "https://avatars.githubusercontent.com/u/47772523?v=4", 363 | "profile": "https://github.com/amitmiran137", 364 | "contributions": [ 365 | "infra" 366 | ] 367 | }, 368 | { 369 | "login": "leschdom", 370 | "name": "Dominik Lesch", 371 | "avatar_url": "https://avatars.githubusercontent.com/u/62334278?v=4", 372 | "profile": "https://github.com/leschdom", 373 | "contributions": [ 374 | "doc" 375 | ] 376 | }, 377 | { 378 | "login": "Andarist", 379 | "name": "Mateusz Burzyński", 380 | "avatar_url": "https://avatars.githubusercontent.com/u/9800850?v=4", 381 | "profile": "https://github.com/Andarist", 382 | "contributions": [ 383 | "code" 384 | ] 385 | }, 386 | { 387 | "login": "nielsdB97", 388 | "name": "Niels de Bruin", 389 | "avatar_url": "https://avatars.githubusercontent.com/u/11021818?v=4", 390 | "profile": "https://nielsdb97.nl", 391 | "contributions": [ 392 | "code" 393 | ] 394 | }, 395 | { 396 | "login": "MatanBobi", 397 | "name": "Matan Borenkraout", 398 | "avatar_url": "https://avatars.githubusercontent.com/u/12711091?v=4", 399 | "profile": "https://matan.io", 400 | "contributions": [ 401 | "code" 402 | ] 403 | } 404 | ], 405 | "repoType": "github", 406 | "repoHost": "https://github.com", 407 | "contributorsPerLine": 7 408 | } 409 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./node_modules/kcd-scripts/eslint.js", 3 | "rules": { 4 | "max-lines-per-function": "off", 5 | "testing-library/prefer-screen-queries": "off", 6 | "testing-library/no-dom-import": "off", // We're not using React Testing Library here. We're wrapping DOM Testing Library directly 7 | "@typescript-eslint/no-explicit-any": "off" // let's do better in the future 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 18 | 19 | - `cypress-testing-library` version: 20 | - `node` version: 21 | - `npm` (or `yarn`) version: 22 | 23 | Relevant code or config 24 | 25 | ```javascript 26 | 27 | ``` 28 | 29 | What you did: 30 | 31 | What happened: 32 | 33 | 34 | 35 | Reproduction repository: 36 | 37 | 41 | 42 | Problem description: 43 | 44 | Suggested solution: 45 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | **What**: 20 | 21 | 22 | 23 | **Why**: 24 | 25 | 26 | 27 | **How**: 28 | 29 | 30 | 31 | **Checklist**: 32 | 33 | 34 | 35 | 36 | 37 | - [ ] Documentation 38 | - [ ] Tests 39 | - [ ] Ready to be merged 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /.github/workflows/validate.yml: -------------------------------------------------------------------------------- 1 | name: validate 2 | on: 3 | push: 4 | branches: 5 | - '+([0-9])?(.{+([0-9]),x}).x' 6 | - 'main' 7 | - 'next' 8 | - 'next-major' 9 | - 'beta' 10 | - 'alpha' 11 | - '!all-contributors/**' 12 | pull_request: 13 | 14 | concurrency: 15 | group: ${{ github.workflow }}-${{ github.ref }} 16 | cancel-in-progress: true 17 | 18 | jobs: 19 | main: 20 | # ignore all-contributors PRs 21 | if: ${{ !contains(github.head_ref, 'all-contributors') }} 22 | strategy: 23 | matrix: 24 | node: [18, 20] 25 | runs-on: ubuntu-latest 26 | steps: 27 | - name: ⬇️ Checkout repo 28 | uses: actions/checkout@v2 29 | 30 | - name: ⎔ Setup node 31 | uses: actions/setup-node@v2 32 | with: 33 | node-version: ${{ matrix.node }} 34 | 35 | - name: 📥 Download deps 36 | uses: bahmutov/npm-install@v1 37 | with: 38 | useLockFile: false 39 | 40 | - name: ▶️ Run validate script 41 | run: npm run validate 42 | 43 | - name: ⬆️ Upload coverage report 44 | uses: codecov/codecov-action@v1 45 | 46 | release: 47 | needs: main 48 | runs-on: ubuntu-latest 49 | if: 50 | ${{ github.repository == 'testing-library/cypress-testing-library' && 51 | contains('refs/heads/main,refs/heads/beta,refs/heads/next,refs/heads/alpha', 52 | github.ref) && github.event_name == 'push' }} 53 | steps: 54 | - name: ⬇️ Checkout repo 55 | uses: actions/checkout@v2 56 | 57 | - name: ⎔ Setup node 58 | uses: actions/setup-node@v2 59 | with: 60 | node-version: 20 61 | 62 | - name: 📥 Download deps 63 | uses: bahmutov/npm-install@v1 64 | with: 65 | useLockFile: false 66 | 67 | - name: 🏗 Run build script 68 | run: npm run build 69 | 70 | - name: 🚀 Release 71 | uses: cycjimmy/semantic-release-action@v2 72 | with: 73 | semantic_version: 17 74 | branches: | 75 | [ 76 | '+([0-9])?(.{+([0-9]),x}).x', 77 | 'main', 78 | 'next', 79 | 'next-major', 80 | {name: 'beta', prerelease: true}, 81 | {name: 'alpha', prerelease: true} 82 | ] 83 | env: 84 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 85 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 86 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | dist 4 | .DS_Store 5 | 6 | # these cause more harm than good 7 | # when working with contributors 8 | package-lock.json 9 | yarn.lock 10 | 11 | # cypress recordings during a test run are temporary files 12 | /cypress/videos/ 13 | /cypress/screenshots/ 14 | -------------------------------------------------------------------------------- /.huskyrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('kcd-scripts/husky') 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org/ 2 | package-lock=false 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | dist 4 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('kcd-scripts/prettier') 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | The changelog is automatically updated using 4 | [semantic-release](https://github.com/semantic-release/semantic-release). You 5 | can see it on the [releases page](../../releases). 6 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thanks for being willing to contribute! 4 | 5 | **Working on your first Pull Request?** You can learn how from this _free_ 6 | series [How to Contribute to an Open Source Project on GitHub][egghead] 7 | 8 | ## Project setup 9 | 10 | 1. Fork and clone the repo 11 | 2. Run `npm run setup -s` to install dependencies and run validation 12 | 3. Create a branch for your PR with `git checkout -b pr/your-branch-name` 13 | 14 | > Tip: Keep your `main` branch pointing at the original repository and make 15 | > pull requests from branches on your fork. To do this, run: 16 | > 17 | > ``` 18 | > git remote add upstream https://github.com/testing-library/cypress-testing-library.git 19 | > git fetch upstream 20 | > git branch --set-upstream-to=upstream/main main 21 | > ``` 22 | > 23 | > This will add the original repository as a "remote" called "upstream," Then 24 | > fetch the git information from that remote, then set your local `main` 25 | > branch to use the upstream main branch whenever you run `git pull`. Then you 26 | > can make all of your pull request branches based on this `main` branch. 27 | > Whenever you want to update your version of `main`, do a regular `git pull`. 28 | 29 | ## Committing and Pushing changes 30 | 31 | Please make sure to run the tests before you commit your changes. 32 | 33 | ### opt into git hooks 34 | 35 | There are git hooks set up with this project that are automatically installed 36 | when you install dependencies. They're really handy, but are turned off by 37 | default (so as to not hinder new contributors). You can opt into these by 38 | creating a file called `.opt-in` at the root of the project and putting this 39 | inside: 40 | 41 | ``` 42 | pre-commit 43 | ``` 44 | 45 | ## Help needed 46 | 47 | Please checkout the [the open issues][issues] 48 | 49 | Also, please watch the repo and respond to questions/bug reports/feature 50 | requests! Thanks! 51 | 52 | [egghead]: 53 | https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github 54 | [issues]: https://github.com/testing-library/cypress-testing-library/issues 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2017 Kent C. Dodds 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

Cypress Testing Library

3 | 4 | 5 | tiger 11 | 12 | 13 |

Simple and complete custom Cypress commands and utilities that encourage good 14 | testing practices.

15 | 16 | [**Read the docs**](https://testing-library.com/cypress) | 17 | [Edit the docs](https://github.com/alexkrolick/testing-library-docs) 18 | 19 |
20 | 21 | --- 22 | 23 | 24 | [![Build Status][build-badge]][build] 25 | [![Code Coverage][coverage-badge]][coverage] 26 | [![version][version-badge]][package] 27 | [![downloads][downloads-badge]][npmtrends] 28 | [![MIT License][license-badge]][license] 29 | [![All Contributors][all-contributors-badge]](#contributors-) 30 | [![PRs Welcome][prs-badge]][prs] 31 | [![Code of Conduct][coc-badge]][coc] 32 | 33 | 34 |
35 | 36 | TestingJavaScript.com Learn the smart, efficient way to test any JavaScript application. 41 | 42 |
43 | 44 | ## The problem 45 | 46 | You want to use [`DOM Testing Library`][dom-testing-library] methods in your 47 | [Cypress][cypress] tests. 48 | 49 | ## This solution 50 | 51 | This allows you to use all the useful 52 | [`DOM Testing Library`][dom-testing-library] methods in your tests. 53 | 54 | ## Table of Contents 55 | 56 | 57 | 58 | 59 | - [Installation](#installation) 60 | - [With TypeScript](#with-typescript) 61 | - [Intellisense for JavaScript with VS Code](#intellisense-for-javascript-with-vs-code) 62 | - [Usage](#usage) 63 | - [Differences from DOM Testing Library](#differences-from-dom-testing-library) 64 | - [Config testIdAttribute](#config-testidattribute) 65 | - [Other Solutions](#other-solutions) 66 | - [Issues](#issues) 67 | - [🐛 Bugs](#-bugs) 68 | - [💡 Feature Requests](#-feature-requests) 69 | - [Contributors ✨](#contributors-) 70 | - [LICENSE](#license) 71 | 72 | 73 | 74 | ## Installation 75 | 76 | This module is distributed via [npm][npm] which is bundled with [node][node] and 77 | should be installed as one of your project's `devDependencies`: 78 | 79 | ``` 80 | npm install --save-dev @testing-library/cypress 81 | ``` 82 | 83 | ### With TypeScript 84 | 85 | Typings should be added as follows in `tsconfig.json`: 86 | 87 | ```json 88 | { 89 | "compilerOptions": { 90 | "types": ["cypress", "@testing-library/cypress"] 91 | } 92 | } 93 | ``` 94 | 95 | ### Intellisense for JavaScript with VS Code 96 | 97 | If you're not using TypeScript, you use VS Code, and want to have 98 | code-completion with the methods from this library, simply add the following 99 | line to your project's root-level `jsconfig.json` file: 100 | 101 | ```json 102 | { 103 | "include": ["node_modules/cypress", "./cypress/**/*.js"] 104 | } 105 | ``` 106 | 107 | ## Usage 108 | 109 | `Cypress Testing Library` extends Cypress' `cy` command. 110 | 111 | Add this line to your project's `cypress/support/commands.js`: 112 | 113 | ```javascript 114 | import '@testing-library/cypress/add-commands' 115 | ``` 116 | 117 | You can now use all of `DOM Testing Library`'s `findBy` and `findAllBy` 118 | commands. 119 | [See the `DOM Testing Library` docs for reference](https://testing-library.com) 120 | 121 | You can find 122 | [all Library definitions here](https://github.com/testing-library/cypress-testing-library/tree/main/types/index.d.ts). 123 | 124 | To configure DOM Testing Library, use the following custom command: 125 | 126 | ```javascript 127 | cy.configureCypressTestingLibrary(config) 128 | ``` 129 | 130 | To show some simple examples (from 131 | [cypress/e2e/find.cy.js](cypress/e2e/find.cy.js)): 132 | 133 | ```javascript 134 | cy.findAllByText('Button Text').should('exist') 135 | cy.findAllByText('Non-existing Button Text').should('not.exist') 136 | cy.findAllByLabelText('Label text', {timeout: 7000}).should('exist') 137 | cy.findAllByText('Jackie Chan').click() 138 | 139 | // findAllByText _inside_ a form element 140 | cy.get('form').findAllByText('Button Text').should('exist') 141 | ``` 142 | 143 | ### Differences from DOM Testing Library 144 | 145 | `Cypress Testing Library` supports both jQuery elements and DOM nodes. This is 146 | necessary because Cypress uses jQuery elements, while `DOM Testing Library` 147 | expects DOM nodes. When you chain a query, it will get the first DOM node from 148 | `subject` of the collection and use that as the `container` parameter for the 149 | `DOM Testing Library` functions. 150 | 151 | `query*` queries are not supported. You should use the `should('not.exist')` 152 | assertion instead to check for the absence of an element. 153 | 154 | `get*` queries are not supported. `find*` queries do not use the Promise API of 155 | `DOM Testing Library`, but instead forward to the `get*` queries and use 156 | Cypress' built-in retryability using error messages from `get*` APIs to forward 157 | as error messages if a query fails. 158 | 159 | `findAll*` can select more than one element and is closer in functionality to 160 | how Cypress built-in commands work. `find*` commands will fail if more than one 161 | element is found that matches the criteria which is not how built-in Cypress 162 | commands work, but is provided for closer compatibility to other Testing 163 | Libraries. 164 | 165 | Cypress handles actions when there is only one element found. For example, the 166 | following will work without having to limit to only 1 returned element. The 167 | `cy.click` will automatically fail if more than 1 element is returned by the 168 | `findAllByText`: 169 | 170 | ```javascript 171 | cy.findAllByText('Some Text').click() 172 | ``` 173 | 174 | If you intend to enforce only 1 element is returned by a selector, the following 175 | examples will both fail if more than one element is found. 176 | 177 | ```javascript 178 | cy.findAllByText('Some Text').should('have.length', 1) 179 | cy.findByText('Some Text').should('exist') 180 | ``` 181 | 182 | ## Config testIdAttribute 183 | 184 | If you would like to change the default testId from `data-testId` to 185 | `data-test-id`, add to your project's `cypress/support/index.js`: 186 | 187 | ```javascript 188 | import {configure} from '@testing-library/cypress' 189 | configure({testIdAttribute: 'data-test-id'}) 190 | ``` 191 | 192 | It accepts all configurations listed in 193 | [DOM testing library](https://testing-library.com/docs/dom-testing-library/api-configuration). 194 | 195 | ## Other Solutions 196 | 197 | I'm not aware of any, if you are please [make a pull request][prs] and add it 198 | here! 199 | 200 | ## Issues 201 | 202 | _Looking to contribute? Look for the [Good First Issue][good-first-issue] 203 | label._ 204 | 205 | ### 🐛 Bugs 206 | 207 | Please file an issue for bugs, missing documentation, or unexpected behavior. 208 | 209 | [**See Bugs**][bugs] 210 | 211 | ### 💡 Feature Requests 212 | 213 | Please file an issue to suggest new features. Vote on feature requests by adding 214 | a 👍. This helps maintainers prioritize what to work on. 215 | 216 | [**See Feature Requests**][requests] 217 | 218 | ## Contributors ✨ 219 | 220 | Thanks goes to these people ([emoji key][emojis]): 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 |

Kent C. Dodds

💻 📖 🚇 ⚠️

Ivan Babak

💻 🤔

Łukasz Gandecki

💻 ⚠️

Peter Kamps

💻 📖 🤔 ⚠️

Airat Aminev

💻 ⚠️ 🔧

Adrian Smijulj

💻

Soo Jae Hwang

🐛 💻 ⚠️

Justin Hall

💻 ⚠️

euzebe

📖

jkdowdle

💻

Brian Ng

💻

Kari Laari

📖

Basti Buck

💻

ShimiTheFirst

🐛

omerose

📖

Aaron Mc Adam

💻 ⚠️

Karl Horky

📖

Stefano Magni

💻 ⚠️ 📖

Weyert de Boer

💻

Simon Jespersen

💻 👀

Adrià Fontcuberta

🚇 📖 👀

Mikhail Guskov

🐛

JD Gonzales

📖

Yvonnick FRIN

📖

Franck Abgrall

👀

Tom Robinson

💻 ⚠️

Nicholas Boll

💻 ⚠️

FlopieUtd

📖

Jaime Leonardo Suncin Cruz

🐛 💻 ⚠️

Matt Travi

💻

Michaël De Boey

💻

Hu Chen

📖

Frederick Fogerty

💻

Kyle Holmberg

📖

Mathis Møller

💻 ⚠️

Simen Bekkhus

💻

Amit Miran

🚇

Dominik Lesch

📖

Mateusz Burzyński

💻

Niels de Bruin

💻

Matan Borenkraout

💻
280 | 281 | 282 | 283 | 284 | 285 | 286 | This project follows the [all-contributors][all-contributors] specification. 287 | Contributions of any kind welcome! 288 | 289 | ## LICENSE 290 | 291 | MIT 292 | 293 | 294 | [npm]: https://npmjs.com 295 | [node]: https://nodejs.org 296 | [build-badge]: https://img.shields.io/github/workflow/status/testing-library/cypress-testing-library/validate?logo=github&style=flat-square 297 | [build]: https://github.com/testing-library/cypress-testing-library/actions?query=workflow%3Avalidate 298 | [coverage-badge]: https://img.shields.io/codecov/c/github/testing-library/cypress-testing-library.svg?style=flat-square 299 | [coverage]: https://codecov.io/github/testing-library/cypress-testing-library 300 | [version-badge]: https://img.shields.io/npm/v/@testing-library/cypress.svg?style=flat-square 301 | [package]: https://www.npmjs.com/package/@testing-library/cypress 302 | [downloads-badge]: https://img.shields.io/npm/dm/@testing-library/cypress.svg?style=flat-square 303 | [npmtrends]: http://www.npmtrends.com/@testing-library/cypress 304 | [license-badge]: https://img.shields.io/npm/l/@testing-library/cypress.svg?style=flat-square 305 | [license]: https://github.com/testing-library/cypress-testing-library/blob/main/LICENSE 306 | [prs-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square 307 | [prs]: http://makeapullrequest.com 308 | [coc-badge]: https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square 309 | [coc]: https://github.com/testing-library/cypress-testing-library/blob/main/other/CODE_OF_CONDUCT.md 310 | [emojis]: https://allcontributors.org/docs/en/emoji-key 311 | [all-contributors]: https://github.com/all-contributors/all-contributors 312 | [all-contributors-badge]: https://img.shields.io/github/all-contributors/testing-library/cypress-testing-library?color=orange&style=flat-square 313 | [bugs]: https://github.com/testing-library/cypress-testing-library/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3A%22%F0%9F%90%9B+Bug%22+sort%3Acreated-desc 314 | [requests]: https://github.com/testing-library/cypress-testing-library/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3Aenhancement 315 | [good-first-issue]: https://github.com/testing-library/cypress-testing-library/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3A%22good+first+issue%22 316 | 317 | [cypress]: https://cypress.io 318 | [dom-testing-library]: https://github.com/testing-library/dom-testing-library 319 | 320 | -------------------------------------------------------------------------------- /add-commands.js: -------------------------------------------------------------------------------- 1 | // this file is here so it's easy to register the commands 2 | // `import '@testing-library/cypress/add-commands'` 3 | // eslint-disable-next-line 4 | require('./dist/add-commands') 5 | -------------------------------------------------------------------------------- /cypress.config.js: -------------------------------------------------------------------------------- 1 | const {defineConfig} = require('cypress') 2 | 3 | module.exports = defineConfig({ 4 | e2e: {}, 5 | video: false, 6 | }) 7 | -------------------------------------------------------------------------------- /cypress/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "testing-library/await-async-query": "off", // Cypress chains don't use promises 4 | "testing-library/prefer-screen-queries": "off", // screen queries don't make sense in the context of Cypress Testing Library 5 | "testing-library/prefer-explicit-assert": "off", // we're lazy 6 | 7 | // No Jest here 8 | "jest/valid-expect": "off", 9 | "jest/valid-expect-in-promise": "off", 10 | "jest/no-conditional-expect": "off" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /cypress/e2e/find.cy.js: -------------------------------------------------------------------------------- 1 | /// 2 | describe('find* dom-testing-library commands', () => { 3 | beforeEach(() => { 4 | cy.visit('cypress/fixtures/test-app/') 5 | }) 6 | 7 | // Test each of the types of queries: LabelText, PlaceholderText, Text, DisplayValue, AltText, Title, Role, TestId 8 | 9 | it('findByLabelText', () => { 10 | cy.findByLabelText('Label 1').click().type('Hello Input Labelled By Id') 11 | }) 12 | 13 | it('findAllByLabelText', () => { 14 | cy.findAllByLabelText(/^Label \d$/).should('have.length', 2) 15 | }) 16 | 17 | it('findByPlaceholderText', () => { 18 | cy.findByPlaceholderText('Input 1').click().type('Hello Placeholder') 19 | }) 20 | 21 | it('findAllByPlaceholderText', () => { 22 | cy.findAllByPlaceholderText(/^Input \d$/).should('have.length', 2) 23 | }) 24 | 25 | it('findByText', () => { 26 | cy.findByText('Button Text 1').click().should('contain', 'Button Clicked') 27 | }) 28 | 29 | it('findAllByText', () => { 30 | cy.findAllByText(/^Button Text \d$/) 31 | .should('have.length', 2) 32 | .click({multiple: true}) 33 | .should('contain', 'Button Clicked') 34 | }) 35 | 36 | it('findByDisplayValue', () => { 37 | cy.findByDisplayValue('Display Value 1') 38 | .click() 39 | .clear() 40 | .type('Some new text') 41 | }) 42 | 43 | it('findAllByDisplayValue', () => { 44 | cy.findAllByDisplayValue(/^Display Value \d$/).should('have.length', 2) 45 | }) 46 | 47 | it('findByAltText', () => { 48 | cy.findByAltText('Image Alt Text 1').click() 49 | }) 50 | 51 | it('findAllByAltText', () => { 52 | cy.findAllByAltText(/^Image Alt Text \d$/).should('have.length', 2) 53 | }) 54 | 55 | it('findByTitle', () => { 56 | cy.findByTitle('Title 1').click() 57 | }) 58 | 59 | it('findAllByTitle', () => { 60 | cy.findAllByTitle(/^Title \d$/).should('have.length', 2) 61 | }) 62 | 63 | it('findByRole', () => { 64 | cy.findByRole('dialog').click() 65 | }) 66 | 67 | it('findAllByRole', () => { 68 | cy.findAllByRole('dialog').should('have.length', 1) 69 | }) 70 | 71 | it('findByTestId', () => { 72 | cy.findByTestId('image-with-random-alt-tag-1').click() 73 | }) 74 | 75 | it('findAllByTestId', () => { 76 | cy.findAllByTestId(/^image-with-random-alt-tag-\d$/).should( 77 | 'have.length', 78 | 2, 79 | ) 80 | }) 81 | 82 | /* Test the behaviour around these queries */ 83 | 84 | it('findByText should handle non-existence', () => { 85 | cy.findByText('Does Not Exist').should('not.exist') 86 | }) 87 | 88 | it('findByText should handle eventual existence', () => { 89 | cy.findByText('Eventually Exists').should('exist') 90 | }) 91 | 92 | it('findByText should handle eventual non-existence', () => { 93 | cy.findByText('Eventually Not exists').should('not.exist') 94 | }) 95 | 96 | it("findByText with should('not.exist')", () => { 97 | cy.findAllByText(/^Button Text \d$/).should('exist') 98 | cy.findByText('Non-existing Button Text', {timeout: 100}).should( 99 | 'not.exist', 100 | ) 101 | }) 102 | 103 | it('findByText with a previous subject', () => { 104 | cy.get('#nested').findByText('Button Text 1').should('not.exist') 105 | cy.get('#nested').findByText('Button Text 2').should('exist') 106 | }) 107 | 108 | it('findByText within', () => { 109 | cy.get('#nested').within(() => { 110 | cy.findByText('Button Text 1').should('not.exist') 111 | cy.findByText('Button Text 2').should('exist') 112 | }) 113 | }) 114 | 115 | it('findByText in container', () => { 116 | cy.get('#nested').then(subject => { 117 | cy.findByText('Button Text 1', {container: subject}).should('not.exist') 118 | cy.findByText('Button Text 2', {container: subject}).should('exist') 119 | }) 120 | }) 121 | 122 | it('findByText inside within and with a previous subject', () => { 123 | cy.get('section:nth-of-type(2)').within(() => { 124 | cy.findByText(/Button Text 1/).should('exist') 125 | }) 126 | cy.get('#nested') 127 | .findByText(/Button Text/) 128 | .should('exist') 129 | cy.get('section:nth-of-type(2)').within(() => { 130 | cy.get('#nested') 131 | .findByText(/Button Text/) 132 | .should('exist') 133 | }) 134 | }) 135 | 136 | it('findByText works when another page loads', () => { 137 | cy.findByText('Next Page').click() 138 | cy.findByText('New Page Loaded').should('exist') 139 | }) 140 | 141 | it('findByText should set the Cypress element to the found element', () => { 142 | // This test is a little strange since snapshots show what element 143 | // is selected, but snapshots themselves don't give access to those 144 | // elements. I had to make the implementation specific so that the `$el` 145 | // is the `subject` when the log is added and the `$el` is the `value` 146 | // when the log is changed. It would be better to extract the `$el` from 147 | // each snapshot 148 | 149 | cy.on('log:changed', (attrs, log) => { 150 | if (log.get('name') === 'findByText') { 151 | expect(log.get('$el')).to.have.text('Button Text 1') 152 | } 153 | }) 154 | 155 | cy.findByText('Button Text 1') 156 | }) 157 | 158 | it('findByText should error if no elements are found', () => { 159 | const regex = /Supercalifragilistic/ 160 | const errorMessage = `Unable to find an element with the text: /Supercalifragilistic/` 161 | cy.on('fail', err => { 162 | expect(err.message).to.contain(errorMessage) 163 | }) 164 | 165 | cy.findByText(regex, {timeout: 100}) 166 | }) 167 | 168 | it('findByText should default to Cypress non-existence error message', () => { 169 | const errorMessage = `Expected 46 |
47 |

ByText within

48 | 49 |
50 | 51 |
52 |

*ByDisplayValue

53 | 54 | 55 | 56 |
57 |
58 |

*ByAltText

59 | Image Alt Text 1 64 | Image Alt Text 2 69 |
70 |
71 |

*ByTitle

72 | 1 73 | 2 74 |
75 |
76 |

*ByRole

77 |
dialog 1
78 |
dialog 2
79 |
80 |
81 |

*ByTestId

82 | 87 | 92 |
93 |
94 |

*AllByText

95 | 96 | 97 |
98 |
99 |

*ByText on another page

100 | Next Page 101 |
102 |
103 |

Eventual existence

104 | 105 | 110 |
111 |
112 |

Eventual non-existence

113 | 114 | 119 |
120 |
121 |

Chain selectors

122 |
123 | 124 | 125 |
126 |
127 | 128 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /cypress/fixtures/test-app/next-page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | cypress-testing-library 8 | 19 | 20 | 21 |
22 | No auto-reload after changing this static HTML markup: 23 | click Run All Tests. 24 |
25 |
26 |

New Page Loaded

27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /cypress/support/e2e.js: -------------------------------------------------------------------------------- 1 | import '../../src/add-commands' 2 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | const jestConfig = require('kcd-scripts/jest') 2 | 3 | module.exports = Object.assign(jestConfig, { 4 | testEnvironment: 'jest-environment-jsdom', 5 | testURL: 'http://localhost/', 6 | }) 7 | -------------------------------------------------------------------------------- /lint-staged.config.js: -------------------------------------------------------------------------------- 1 | const config = require('kcd-scripts/dist/config/lintstagedrc') 2 | 3 | // we need to exclude the test and lint scripts on commit because we run it in the validate script 4 | const jsLinter = Object.keys(config).find(key => key.includes('js')) 5 | config[jsLinter] = config[jsLinter].filter( 6 | script => !script.includes('test') && !script.includes('lint'), 7 | ) 8 | 9 | module.exports = config 10 | -------------------------------------------------------------------------------- /other/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | - Demonstrating empathy and kindness toward other people 21 | - Being respectful of differing opinions, viewpoints, and experiences 22 | - Giving and gracefully accepting constructive feedback 23 | - Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | - Focusing on what is best not just for us as individuals, but for the overall 26 | community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | - The use of sexualized language or imagery, and sexual attention or advances of 31 | any kind 32 | - Trolling, insulting or derogatory comments, and personal or political attacks 33 | - Public or private harassment 34 | - Publishing others' private information, such as a physical or email address, 35 | without their explicit permission 36 | - Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | me+coc@kentcdodds.com. All complaints will be reviewed and investigated promptly 64 | and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series of 86 | actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or permanent 93 | ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within the 113 | community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by 122 | [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /other/MAINTAINING.md: -------------------------------------------------------------------------------- 1 | # Maintaining 2 | 3 | 4 | 5 | 6 | **Table of Contents** 7 | 8 | - [Code of Conduct](#code-of-conduct) 9 | - [Issues](#issues) 10 | - [Pull Requests](#pull-requests) 11 | - [Release](#release) 12 | - [Thanks!](#thanks) 13 | 14 | 15 | 16 | This is documentation for maintainers of this project. 17 | 18 | ## Code of Conduct 19 | 20 | Please review, understand, and be an example of it. Violations of the code of 21 | conduct are taken seriously, even (especially) for maintainers. 22 | 23 | ## Issues 24 | 25 | We want to support and build the community. We do that best by helping people 26 | learn to solve their own problems. We have an issue template and hopefully most 27 | folks follow it. If it's not clear what the issue is, invite them to create a 28 | minimal reproduction of what they're trying to accomplish or the bug they think 29 | they've found. 30 | 31 | Once it's determined that a code change is necessary, point people to 32 | [makeapullrequest.com](http://makeapullrequest.com) and invite them to make a 33 | pull request. If they're the one who needs the feature, they're the one who can 34 | build it. If they need some hand holding and you have time to lend a hand, 35 | please do so. It's an investment into another human being, and an investment 36 | into a potential maintainer. 37 | 38 | Remember that this is open source, so the code is not yours, it's ours. If 39 | someone needs a change in the codebase, you don't have to make it happen 40 | yourself. Commit as much time to the project as you want/need to. Nobody can ask 41 | any more of you than that. 42 | 43 | ## Pull Requests 44 | 45 | As a maintainer, you're fine to make your branches on the main repo or on your 46 | own fork. Either way is fine. 47 | 48 | When we receive a pull request, a GitHub Action is kicked off automatically (see 49 | the `.github/workflows/validate.yml` for what runs in the Action). We avoid 50 | merging anything that breaks the GitHub Action. 51 | 52 | Please review PRs and focus on the code rather than the individual. You never 53 | know when this is someone's first ever PR and we want their experience to be as 54 | positive as possible, so be uplifting and constructive. 55 | 56 | When you merge the pull request, 99% of the time you should use the 57 | [Squash and merge](https://help.github.com/articles/merging-a-pull-request) 58 | feature. This keeps our git history clean, but more importantly, this allows us 59 | to make any necessary changes to the commit message so we release what we want 60 | to release. See the next section on Releases for more about that. 61 | 62 | ## Release 63 | 64 | Our releases are automatic. They happen whenever code lands into `main`. A 65 | GitHub Action gets kicked off and if it's successful, a tool called 66 | [`semantic-release`](https://github.com/semantic-release/semantic-release) is 67 | used to automatically publish a new release to npm as well as a changelog to 68 | GitHub. It is only able to determine the version and whether a release is 69 | necessary by the git commit messages. With this in mind, **please brush up on 70 | [the commit message convention][commit] which drives our releases.** 71 | 72 | > One important note about this: Please make sure that commit messages do NOT 73 | > contain the words "BREAKING CHANGE" in them unless we want to push a major 74 | > version. I've been burned by this more than once where someone will include 75 | > "BREAKING CHANGE: None" and it will end up releasing a new major version. Not 76 | > a huge deal honestly, but kind of annoying... 77 | 78 | ## Thanks! 79 | 80 | Thank you so much for helping to maintain this project! 81 | 82 | 83 | [commit]: https://github.com/conventional-changelog-archived-repos/conventional-changelog-angular/blob/ed32559941719a130bb0327f886d6a32a8cbc2ba/convention.md 84 | 85 | -------------------------------------------------------------------------------- /other/USERS.md: -------------------------------------------------------------------------------- 1 | # Users 2 | 3 | If you or your company uses this project, add your name to this list! Eventually 4 | we may have a website to showcase these (wanna build it!?) 5 | 6 | > No users have been added yet! 7 | 8 | 13 | -------------------------------------------------------------------------------- /other/manual-releases.md: -------------------------------------------------------------------------------- 1 | # manual-releases 2 | 3 | This project has an automated release set up. So things are only released when 4 | there are useful changes in the code that justify a release. But sometimes 5 | things get messed up one way or another and we need to trigger the release 6 | ourselves. When this happens, simply bump the number below and commit that with 7 | the following commit message based on your needs: 8 | 9 | **Major** 10 | 11 | ``` 12 | fix(release): manually release a major version 13 | 14 | There was an issue with a major release, so this manual-releases.md 15 | change is to release a new major version. 16 | 17 | Reference: # 18 | 19 | BREAKING CHANGE: 20 | ``` 21 | 22 | **Minor** 23 | 24 | ``` 25 | feat(release): manually release a minor version 26 | 27 | There was an issue with a minor release, so this manual-releases.md 28 | change is to release a new minor version. 29 | 30 | Reference: # 31 | ``` 32 | 33 | **Patch** 34 | 35 | ``` 36 | fix(release): manually release a patch version 37 | 38 | There was an issue with a patch release, so this manual-releases.md 39 | change is to release a new patch version. 40 | 41 | Reference: # 42 | ``` 43 | 44 | The number of times we've had to do a manual release is: 3 45 | -------------------------------------------------------------------------------- /other/testingjavascript.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/testing-library/cypress-testing-library/d77c9df17863dc0ca1d14fb7ccd1f568c6b65580/other/testingjavascript.jpg -------------------------------------------------------------------------------- /other/tiger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/testing-library/cypress-testing-library/d77c9df17863dc0ca1d14fb7ccd1f568c6b65580/other/tiger.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@testing-library/cypress", 3 | "version": "0.0.0-semantically-released", 4 | "description": "Simple and complete custom Cypress commands and utilities that encourage good testing practices.", 5 | "main": "dist/index.js", 6 | "types": "types/index.d.ts", 7 | "engines": { 8 | "node": ">=12", 9 | "npm": ">=6" 10 | }, 11 | "scripts": { 12 | "build": "kcd-scripts build", 13 | "lint": "kcd-scripts lint", 14 | "setup": "npm install && npm run validate -s", 15 | "test": "npm-run-all --parallel test:unit test:cypress", 16 | "test:cypress": "npm run test:cypress:run", 17 | "test:cypress:dev": "npm run test:cypress:open", 18 | "test:cypress:open": "cypress open", 19 | "test:cypress:run": "cypress run", 20 | "test:unit": "kcd-scripts test --no-watch", 21 | "test:unit:watch": "kcd-scripts test", 22 | "typecheck": "kcd-scripts typecheck --build types", 23 | "validate": "kcd-scripts validate build,lint,test,typecheck" 24 | }, 25 | "files": [ 26 | "dist", 27 | "add-commands.js", 28 | "types/*.d.ts" 29 | ], 30 | "keywords": [ 31 | "testing", 32 | "cypress", 33 | "ui", 34 | "dom", 35 | "integration", 36 | "functional", 37 | "end-to-end", 38 | "e2e" 39 | ], 40 | "author": "Kent C. Dodds (https://kentcdodds.com)", 41 | "license": "MIT", 42 | "dependencies": { 43 | "@babel/runtime": "^7.14.6", 44 | "@testing-library/dom": "^10.1.0" 45 | }, 46 | "devDependencies": { 47 | "cypress": "^14.0.0", 48 | "kcd-scripts": "^11.2.0", 49 | "npm-run-all": "^4.1.5", 50 | "typescript": "^4.3.5" 51 | }, 52 | "peerDependencies": { 53 | "cypress": "^12.0.0 || ^13.0.0 || ^14.0.0" 54 | }, 55 | "eslintConfig": { 56 | "extends": "./node_modules/kcd-scripts/eslint.js", 57 | "rules": { 58 | "import/prefer-default-export": "off", 59 | "import/no-unassigned-import": "off", 60 | "jest/valid-expect": "off" 61 | } 62 | }, 63 | "eslintIgnore": [ 64 | "node_modules", 65 | "coverage", 66 | "dist" 67 | ], 68 | "repository": { 69 | "type": "git", 70 | "url": "https://github.com/testing-library/cypress-testing-library" 71 | }, 72 | "bugs": { 73 | "url": "https://github.com/testing-library/cypress-testing-library/issues" 74 | }, 75 | "homepage": "https://github.com/testing-library/cypress-testing-library#readme" 76 | } 77 | -------------------------------------------------------------------------------- /src/__tests__/add-commands.js: -------------------------------------------------------------------------------- 1 | import {commands} from '../' 2 | 3 | test('adds commands to Cypress', () => { 4 | const addMock = jest.fn().mockName('Cypress.Commands.add') 5 | const addQueryMock = jest.fn().mockName('Cypress.Commands.addQuery') 6 | global.Cypress = {Commands: {add: addMock, addQuery: addQueryMock}} 7 | global.cy = {} 8 | 9 | require('../add-commands') 10 | 11 | expect(addQueryMock).toHaveBeenCalledTimes(commands.length) 12 | expect(addMock).toHaveBeenCalledTimes(1) // we're also adding a configuration command 13 | commands.forEach(({name}, index) => { 14 | expect(addQueryMock.mock.calls[index]).toMatchObject([ 15 | name, 16 | // We get a new function that is `command.bind(null, cy)` i.e. global `cy` passed into the first argument. 17 | // The commands themselves will be tested separately in the Cypress end-to-end tests. 18 | expect.any(Function), 19 | ]) 20 | }) 21 | }) 22 | -------------------------------------------------------------------------------- /src/__tests__/commands.js: -------------------------------------------------------------------------------- 1 | import {queries} from '@testing-library/dom' 2 | import {commands} from '../' 3 | 4 | const queryNames = Object.keys(queries).filter(q => /^find/.test(q)) 5 | 6 | test('exports expected commands', () => { 7 | expect(commands).toMatchObject(expect.any(Array)) 8 | const sortedQueryNames = queryNames.sort() 9 | const sortedCommandNames = commands.map(({name}) => name).sort() 10 | expect(sortedCommandNames).toEqual(sortedQueryNames) 11 | commands.forEach(command => 12 | expect(command).toMatchObject({ 13 | name: expect.any(String), 14 | // We get a new function that wraps the respective query from `dom-testing-library`. 15 | // The commands themselves will be tested separately in the Cypress end-to-end tests. 16 | command: expect.any(Function), 17 | }), 18 | ) 19 | }) 20 | -------------------------------------------------------------------------------- /src/add-commands.js: -------------------------------------------------------------------------------- 1 | import {configure, commands} from './' 2 | 3 | commands.forEach(({name, command}) => { 4 | Cypress.Commands.addQuery(name, command) 5 | }) 6 | 7 | Cypress.Commands.add('configureCypressTestingLibrary', config => { 8 | configure(config) 9 | }) 10 | 11 | /* global Cypress */ 12 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import {configure as configureDTL, queries} from '@testing-library/dom' 2 | import {getFirstElement} from './utils' 3 | 4 | function configure({fallbackRetryWithoutPreviousSubject, ...config}) { 5 | return configureDTL(config) 6 | } 7 | 8 | const findRegex = /^find/ 9 | const queryNames = Object.keys(queries).filter(q => findRegex.test(q)) 10 | 11 | const commands = queryNames.map(queryName => { 12 | return createQuery(queryName, queryName.replace(findRegex, 'get')) 13 | }) 14 | 15 | function createQuery(queryName, implementationName) { 16 | return { 17 | name: queryName, 18 | command(...args) { 19 | const lastArg = args[args.length - 1] 20 | const options = typeof lastArg === 'object' ? {...lastArg} : {} 21 | 22 | this.set('timeout', options.timeout) 23 | 24 | const queryImpl = queries[implementationName] 25 | const inputArr = args.filter(filterInputs) 26 | 27 | const selector = `${queryName}(${queryArgument(args)})` 28 | 29 | const consoleProps = { 30 | // TODO: Would be good to completely separate out the types of input into their own properties 31 | input: inputArr, 32 | Selector: selector, 33 | } 34 | 35 | const log = 36 | options.log !== false && 37 | Cypress.log({ 38 | name: queryName, 39 | type: 40 | this.get('prev')?.get('chainerId') === this.get('chainerId') 41 | ? 'child' 42 | : 'parent', 43 | message: inputArr, 44 | timeout: options.timeout, 45 | consoleProps: () => consoleProps, 46 | }) 47 | 48 | const withinSubject = cy.state('withinSubjectChain') 49 | 50 | let error 51 | this.set('onFail', err => { 52 | if (error) { 53 | err.message = error.message 54 | } 55 | }) 56 | 57 | return subject => { 58 | const container = getFirstElement( 59 | options.container || 60 | subject || 61 | cy.getSubjectFromChain(withinSubject) || 62 | cy.state('window').document, 63 | ) 64 | consoleProps['Applied To'] = container 65 | 66 | let value 67 | 68 | try { 69 | value = queryImpl(container, ...args) 70 | } catch (e) { 71 | error = e 72 | value = Cypress.$() 73 | value.selector = selector 74 | } 75 | 76 | const result = Cypress.$(value) 77 | 78 | if (value && log) { 79 | log.set('$el', result) 80 | } 81 | 82 | // Overriding the selector of the jquery object because it's displayed in the long message of .should('exist') failure message 83 | // Hopefully it makes it clearer, because I find the normal response of "Expected to find element '', but never found it" confusing 84 | result.selector = selector 85 | 86 | consoleProps.elements = result.length 87 | if (result.length === 1) { 88 | consoleProps.yielded = result.toArray()[0] 89 | } else if (result.length > 0) { 90 | consoleProps.yielded = result.toArray() 91 | } 92 | 93 | if (result.length > 1 && !/All/.test(queryName)) { 94 | // Is this useful? 95 | throw Error( 96 | `Found multiple elements with the text: ${queryArgument(args)}`, 97 | ) 98 | } 99 | 100 | return result 101 | } 102 | }, 103 | } 104 | } 105 | 106 | function filterInputs(value) { 107 | if (Array.isArray(value) && value.length === 0) { 108 | return false 109 | } 110 | if (value instanceof RegExp) { 111 | return value.toString() 112 | } 113 | if (typeof value === 'object' && Object.keys(value).length === 0) { 114 | return false 115 | } 116 | return Boolean(value) 117 | } 118 | 119 | function queryArgument(args) { 120 | const input = args.find(value => { 121 | return value instanceof RegExp || typeof value === 'string' 122 | }) 123 | 124 | if (input && typeof input === 'string') { 125 | return `\`${input}\`` 126 | } 127 | 128 | return input 129 | } 130 | 131 | export {commands, configure} 132 | 133 | /* eslint no-new-func:0, complexity:0 */ 134 | /* globals Cypress, cy */ 135 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | function getFirstElement(jqueryOrElement) { 2 | if (Cypress.dom.isJquery(jqueryOrElement)) { 3 | return jqueryOrElement.get(0) 4 | } 5 | return jqueryOrElement 6 | } 7 | 8 | export {getFirstElement} 9 | 10 | /* globals Cypress */ 11 | -------------------------------------------------------------------------------- /types/add-commands.d.ts: -------------------------------------------------------------------------------- 1 | // Allow `import '@testing-library/cypress/add-commands'` from a `cypress/commands.ts` file 2 | import './' 3 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | // TypeScript Version: 3.8 2 | 3 | import { 4 | configure, 5 | Matcher, 6 | ByRoleMatcher, 7 | MatcherOptions as DTLMatcherOptions, 8 | ByRoleOptions as DTLByRoleOptions, 9 | SelectorMatcherOptions as DTLSelectorMatcherOptions, 10 | } from '@testing-library/dom' 11 | 12 | export interface CTLMatcherOptions 13 | extends Partial, 14 | Partial { 15 | container?: Element | JQuery 16 | } 17 | 18 | export type MatcherOptions = DTLMatcherOptions | CTLMatcherOptions 19 | export type ByRoleOptions = DTLByRoleOptions | CTLMatcherOptions 20 | export type SelectorMatcherOptions = 21 | | DTLSelectorMatcherOptions 22 | | CTLMatcherOptions 23 | 24 | declare global { 25 | namespace Cypress { 26 | // 🤔 unsure why this Subject is unused, nor what to do with it... 27 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 28 | interface Chainable { 29 | /** 30 | * dom-testing-library helpers for Cypress 31 | * 32 | * `findBy*` APIs search for an element and throw an error if nothing found 33 | * `findAllBy*` APIs search for all elements and throw an error if nothing found 34 | * 35 | * @see https://github.com/testing-library/cypress-testing-library#usage 36 | * @see https://github.com/testing-library/dom-testing-library#table-of-contents 37 | */ 38 | findByPlaceholderText( 39 | id: Matcher, 40 | options?: MatcherOptions, 41 | ): Chainable 42 | 43 | /** 44 | * dom-testing-library helpers for Cypress 45 | * 46 | * `findBy*` APIs search for an element and throw an error if nothing found 47 | * `findAllBy*` APIs search for all elements and throw an error if nothing found 48 | * 49 | * @see https://github.com/testing-library/cypress-testing-library#usage 50 | * @see https://github.com/testing-library/dom-testing-library#table-of-contents 51 | */ 52 | findAllByPlaceholderText( 53 | id: Matcher, 54 | options?: MatcherOptions, 55 | ): Chainable 56 | 57 | /** 58 | * dom-testing-library helpers for Cypress 59 | * 60 | * `findBy*` APIs search for an element and throw an error if nothing found 61 | * `findAllBy*` APIs search for all elements and throw an error if nothing found 62 | * 63 | * @see https://github.com/testing-library/cypress-testing-library#usage 64 | * @see https://github.com/testing-library/dom-testing-library#table-of-contents 65 | */ 66 | findByText( 67 | id: Matcher, 68 | options?: SelectorMatcherOptions, 69 | ): Chainable 70 | 71 | /** 72 | * dom-testing-library helpers for Cypress 73 | * 74 | * `findBy*` APIs search for an element and throw an error if nothing found 75 | * `findAllBy*` APIs search for all elements and throw an error if nothing found 76 | * 77 | * @see https://github.com/testing-library/cypress-testing-library#usage 78 | * @see https://github.com/testing-library/dom-testing-library#table-of-contents 79 | */ 80 | findAllByText( 81 | id: Matcher, 82 | options?: SelectorMatcherOptions, 83 | ): Chainable 84 | 85 | /** 86 | * dom-testing-library helpers for Cypress 87 | * 88 | * `findBy*` APIs search for an element and throw an error if nothing found 89 | * `findAllBy*` APIs search for all elements and throw an error if nothing found 90 | * 91 | * @see https://github.com/testing-library/cypress-testing-library#usage 92 | * @see https://github.com/testing-library/dom-testing-library#table-of-contents 93 | */ 94 | findByLabelText( 95 | id: Matcher, 96 | options?: SelectorMatcherOptions, 97 | ): Chainable 98 | 99 | /** 100 | * dom-testing-library helpers for Cypress 101 | * 102 | * `findBy*` APIs search for an element and throw an error if nothing found 103 | * `findAllBy*` APIs search for all elements and throw an error if nothing found 104 | * 105 | * @see https://github.com/testing-library/cypress-testing-library#usage 106 | * @see https://github.com/testing-library/dom-testing-library#table-of-contents 107 | */ 108 | findAllByLabelText( 109 | id: Matcher, 110 | options?: SelectorMatcherOptions, 111 | ): Chainable 112 | 113 | /** 114 | * dom-testing-library helpers for Cypress 115 | * 116 | * `findBy*` APIs search for an element and throw an error if nothing found 117 | * `findAllBy*` APIs search for all elements and throw an error if nothing found 118 | * 119 | * @see https://github.com/testing-library/cypress-testing-library#usage 120 | * @see https://github.com/testing-library/dom-testing-library#table-of-contents 121 | */ 122 | findByAltText(id: Matcher, options?: MatcherOptions): Chainable 123 | 124 | /** 125 | * dom-testing-library helpers for Cypress 126 | * 127 | * `findBy*` APIs search for an element and throw an error if nothing found 128 | * `findAllBy*` APIs search for all elements and throw an error if nothing found 129 | * 130 | * @see https://github.com/testing-library/cypress-testing-library#usage 131 | * @see https://github.com/testing-library/dom-testing-library#table-of-contents 132 | */ 133 | findAllByAltText(id: Matcher, options?: MatcherOptions): Chainable 134 | 135 | /** 136 | * dom-testing-library helpers for Cypress 137 | * 138 | * `findBy*` APIs search for an element and throw an error if nothing found 139 | * `findAllBy*` APIs search for all elements and throw an error if nothing found 140 | * 141 | * @see https://github.com/testing-library/cypress-testing-library#usage 142 | * @see https://github.com/testing-library/dom-testing-library#table-of-contents 143 | */ 144 | findByTestId(id: Matcher, options?: MatcherOptions): Chainable 145 | 146 | /** 147 | * dom-testing-library helpers for Cypress 148 | * 149 | * `findBy*` APIs search for an element and throw an error if nothing found 150 | * `findAllBy*` APIs search for all elements and throw an error if nothing found 151 | * 152 | * @see https://github.com/testing-library/cypress-testing-library#usage 153 | * @see https://github.com/testing-library/dom-testing-library#table-of-contents 154 | */ 155 | findAllByTestId(id: Matcher, options?: MatcherOptions): Chainable 156 | 157 | /** 158 | * dom-testing-library helpers for Cypress 159 | * 160 | * `findBy*` APIs search for an element and throw an error if nothing found 161 | * `findAllBy*` APIs search for all elements and throw an error if nothing found 162 | * 163 | * @see https://github.com/testing-library/cypress-testing-library#usage 164 | * @see https://github.com/testing-library/dom-testing-library#table-of-contents 165 | */ 166 | findByTitle(id: Matcher, options?: MatcherOptions): Chainable 167 | 168 | /** 169 | * dom-testing-library helpers for Cypress 170 | * 171 | * `findBy*` APIs search for an element and throw an error if nothing found 172 | * `findAllBy*` APIs search for all elements and throw an error if nothing found 173 | * 174 | * @see https://github.com/testing-library/cypress-testing-library#usage 175 | * @see https://github.com/testing-library/dom-testing-library#table-of-contents 176 | */ 177 | findAllByTitle(id: Matcher, options?: MatcherOptions): Chainable 178 | 179 | /** 180 | * dom-testing-library helpers for Cypress 181 | * 182 | * `findBy*` APIs search for an element and throw an error if nothing found 183 | * `findAllBy*` APIs search for all elements and throw an error if nothing found 184 | * 185 | * @see https://github.com/testing-library/cypress-testing-library#usage 186 | * @see https://github.com/testing-library/dom-testing-library#table-of-contents 187 | */ 188 | findByDisplayValue( 189 | id: Matcher, 190 | options?: MatcherOptions, 191 | ): Chainable 192 | 193 | /** 194 | * dom-testing-library helpers for Cypress 195 | * 196 | * `findBy*` APIs search for an element and throw an error if nothing found 197 | * `findAllBy*` APIs search for all elements and throw an error if nothing found 198 | * 199 | * @see https://github.com/testing-library/cypress-testing-library#usage 200 | * @see https://github.com/testing-library/dom-testing-library#table-of-contents 201 | */ 202 | findAllByDisplayValue( 203 | id: Matcher, 204 | options?: MatcherOptions, 205 | ): Chainable 206 | 207 | /** 208 | * dom-testing-library helpers for Cypress 209 | * 210 | * `findBy*` APIs search for an element and throw an error if nothing found 211 | * `findAllBy*` APIs search for all elements and throw an error if nothing found 212 | * 213 | * @see https://github.com/testing-library/cypress-testing-library#usage 214 | * @see https://github.com/testing-library/dom-testing-library#table-of-contents 215 | */ 216 | findByRole(id: ByRoleMatcher, options?: ByRoleOptions): Chainable 217 | 218 | /** 219 | * dom-testing-library helpers for Cypress 220 | * 221 | * `findBy*` APIs search for an element and throw an error if nothing found 222 | * `findAllBy*` APIs search for all elements and throw an error if nothing found 223 | * 224 | * @see https://github.com/testing-library/cypress-testing-library#usage 225 | * @see https://github.com/testing-library/dom-testing-library#table-of-contents 226 | */ 227 | findAllByRole( 228 | id: ByRoleMatcher, 229 | options?: ByRoleOptions, 230 | ): Chainable 231 | 232 | /** 233 | * dom-testing-library helpers for Cypress 234 | * 235 | * Configure dom-testing-library through Cypress object. Wraps `configure(config)` 236 | * 237 | * @see https://github.com/testing-library/cypress-testing-library#usage 238 | * @see https://github.com/testing-library/dom-testing-library#table-of-contents 239 | */ 240 | configureCypressTestingLibrary( 241 | config: Parameters[0], 242 | ): Chainable 243 | } 244 | } 245 | } 246 | 247 | export {configure} 248 | -------------------------------------------------------------------------------- /types/test.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import {configure} from '.' 3 | import './add-commands' 4 | 5 | configure({testIdAttribute: 'data-myown-testid'}) 6 | 7 | // findBy* 8 | cy.findByPlaceholderText('foo') // $ExpectType Chainable> 9 | cy.findByText('foo') // $ExpectType Chainable> 10 | cy.findByLabelText('foo') // $ExpectType Chainable> 11 | cy.findByAltText('foo') // $ExpectType Chainable> 12 | cy.findByTestId('foo') // $ExpectType Chainable> 13 | cy.findByTitle('foo') // $ExpectType Chainable> 14 | cy.findByDisplayValue('foo') // $ExpectType Chainable> 15 | cy.findByRole('foo') // $ExpectType Chainable> 16 | 17 | // findAllBy* 18 | cy.findAllByPlaceholderText('foo') // $ExpectType Chainable> 19 | cy.findAllByText('foo') // $ExpectType Chainable> 20 | cy.findAllByLabelText('foo') // $ExpectType Chainable> 21 | cy.findAllByAltText('foo') // $ExpectType Chainable> 22 | cy.findAllByTestId('foo') // $ExpectType Chainable> 23 | cy.findAllByTitle('foo') // $ExpectType Chainable> 24 | cy.findAllByDisplayValue('foo') // $ExpectType Chainable> 25 | cy.findAllByRole('foo') // $ExpectType Chainable> 26 | 27 | // configure 28 | cy.configureCypressTestingLibrary({testIdAttribute: 'data-myawesome-testid'}) // $ExpectType Chainable 29 | -------------------------------------------------------------------------------- /types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../node_modules/kcd-scripts/shared-tsconfig.json", 3 | "include": ["."] 4 | } 5 | --------------------------------------------------------------------------------