Skip to content

Commit

Permalink
feat(within): Support cy.within (#11)
Browse files Browse the repository at this point in the history
* feat(within): Support cy.within. Also support passing in a container within the options object.

* Installed wait-port and use it within test:cypress:run to avoid race-conditions

* Improvements based on feedback.

* Documented jQuery vs DOM nodes.
* Use Cypress.cy global.
* Renamed function and parameter.
* Moved utils file.

* Use the cy global.
  • Loading branch information
npeterkamps authored and Kent C. Dodds committed Jun 5, 2018
1 parent 7d14b89 commit d105706
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 12 deletions.
3 changes: 2 additions & 1 deletion .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
"contributions": [
"code",
"doc",
"ideas"
"ideas",
"test"
]
}
],
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,16 @@ cy.getAllByText('Jackie Chan').click()
cy.queryByText('Button Text').should('exist')
cy.queryByText('Non-existing Button Text').should('not.exist')
cy.queryByLabelText('Label text', { timeout: 7000 }).should('exist')
cy.get('form').within(() => {
cy.getByText('Button Text').should('exist')
})
cy.get('form').then((subject) => {
cy.getByText('Button Text', { container: subject }).should('exist')
})
```

`cypress-testing-library` supports both jQuery elements and DOM nodes. This is necessary because Cypress uses jQuery elements, while `dom-testing-library` expects DOM nodes. When you pass a jQuery element as `container`, it will get the first DOM node from the collection and use that as the `container` parameter for the `dom-testing-library` functions.

## Other Solutions

I'm not aware of any, if you are please [make a pull request][prs] and add it
Expand All @@ -87,7 +95,7 @@ Thanks goes to these people ([emoji key][emojis]):

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore -->
| [<img src="https://avatars.githubusercontent.com/u/1500684?v=3" width="100px;"/><br /><sub><b>Kent C. Dodds</b></sub>](https://kentcdodds.com)<br />[💻](https://github.com/kentcdodds/cypress-testing-library/commits?author=kentcdodds "Code") [📖](https://github.com/kentcdodds/cypress-testing-library/commits?author=kentcdodds "Documentation") [🚇](#infra-kentcdodds "Infrastructure (Hosting, Build-Tools, etc)") [⚠️](https://github.com/kentcdodds/cypress-testing-library/commits?author=kentcdodds "Tests") | [<img src="https://avatars2.githubusercontent.com/u/498274?v=4" width="100px;"/><br /><sub><b>Ivan Babak</b></sub>](https://sompylasar.github.io)<br />[💻](https://github.com/kentcdodds/cypress-testing-library/commits?author=sompylasar "Code") [🤔](#ideas-sompylasar "Ideas, Planning, & Feedback") | [<img src="https://avatars1.githubusercontent.com/u/4002543?v=4" width="100px;"/><br /><sub><b>Łukasz Gandecki</b></sub>](http://team.thebrain.pro)<br />[💻](https://github.com/kentcdodds/cypress-testing-library/commits?author=lgandecki "Code") [⚠️](https://github.com/kentcdodds/cypress-testing-library/commits?author=lgandecki "Tests") | [<img src="https://avatars1.githubusercontent.com/u/25429764?v=4" width="100px;"/><br /><sub><b>Peter Kamps</b></sub>](https://github.com/npeterkamps)<br />[💻](https://github.com/kentcdodds/cypress-testing-library/commits?author=npeterkamps "Code") [📖](https://github.com/kentcdodds/cypress-testing-library/commits?author=npeterkamps "Documentation") [🤔](#ideas-npeterkamps "Ideas, Planning, & Feedback") |
| [<img src="https://avatars.githubusercontent.com/u/1500684?v=3" width="100px;"/><br /><sub><b>Kent C. Dodds</b></sub>](https://kentcdodds.com)<br />[💻](https://github.com/kentcdodds/cypress-testing-library/commits?author=kentcdodds "Code") [📖](https://github.com/kentcdodds/cypress-testing-library/commits?author=kentcdodds "Documentation") [🚇](#infra-kentcdodds "Infrastructure (Hosting, Build-Tools, etc)") [⚠️](https://github.com/kentcdodds/cypress-testing-library/commits?author=kentcdodds "Tests") | [<img src="https://avatars2.githubusercontent.com/u/498274?v=4" width="100px;"/><br /><sub><b>Ivan Babak</b></sub>](https://sompylasar.github.io)<br />[💻](https://github.com/kentcdodds/cypress-testing-library/commits?author=sompylasar "Code") [🤔](#ideas-sompylasar "Ideas, Planning, & Feedback") | [<img src="https://avatars1.githubusercontent.com/u/4002543?v=4" width="100px;"/><br /><sub><b>Łukasz Gandecki</b></sub>](http://team.thebrain.pro)<br />[💻](https://github.com/kentcdodds/cypress-testing-library/commits?author=lgandecki "Code") [⚠️](https://github.com/kentcdodds/cypress-testing-library/commits?author=lgandecki "Tests") | [<img src="https://avatars1.githubusercontent.com/u/25429764?v=4" width="100px;"/><br /><sub><b>Peter Kamps</b></sub>](https://github.com/npeterkamps)<br />[💻](https://github.com/kentcdodds/cypress-testing-library/commits?author=npeterkamps "Code") [📖](https://github.com/kentcdodds/cypress-testing-library/commits?author=npeterkamps "Documentation") [🤔](#ideas-npeterkamps "Ideas, Planning, & Feedback") [⚠️](https://github.com/kentcdodds/cypress-testing-library/commits?author=npeterkamps "Tests") |
| :---: | :---: | :---: | :---: |
<!-- ALL-CONTRIBUTORS-LIST:END -->

Expand Down
4 changes: 4 additions & 0 deletions cypress/fixtures/test-app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ <h2>getByPlaceholderText</h2>
<section>
<h2>getByText</h2>
<button onclick="this.innerText = 'Button Clicked'">Button Text</button>
<div id="nested">
<h3>getByText within</h3>
<button onclick="this.innerText = 'Button Clicked'">Button Text</button>
</div>
</section>
<section>
<h2>getByLabelText</h2>
Expand Down
14 changes: 14 additions & 0 deletions cypress/integration/commands.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,20 @@ describe('dom-testing-library commands', () => {
cy.queryByText('Button Text').should('exist')
cy.queryByText('Non-existing Button Text').should('not.exist')
})

it('getByText within', () => {
cy.get('#nested')
.within(() => {
cy.getByText('Button Text').click()
})
})

it('getByText in container', () => {
cy.get('#nested')
.then((subject) => {
cy.getByText('Button Text', { container: subject }).click()
})
})
})

/* global cy */
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
"test": "npm-run-all --parallel test:unit test:cypress",
"test:unit": "kcd-scripts test --no-watch",
"test:unit:watch": "kcd-scripts test",
"test:cypress:serve": "serve -l 13370 ./cypress/fixtures/test-app",
"test:cypress:run": "cypress run",
"test:cypress:serve": "serve --listen 13370 ./cypress/fixtures/test-app",
"test:cypress:run": "wait-port --timeout 10000 localhost:13370 && cypress run",
"test:cypress:open": "cypress open",
"test:cypress": "npm-run-all --silent --parallel --race test:cypress:serve test:cypress:run",
"test:cypress:dev": "npm-run-all --silent --parallel --race test:cypress:serve test:cypress:open",
Expand Down Expand Up @@ -45,7 +45,8 @@
"cypress": "^3.0.1",
"kcd-scripts": "^0.37.0",
"npm-run-all": "^4.1.2",
"serve": "^7.2.0"
"serve": "^7.2.0",
"wait-port": "^0.2.2"
},
"peerDependencies": {
"cypress": "^2.1.0 || ^3.0.0"
Expand Down
4 changes: 2 additions & 2 deletions src/add-commands.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {commands} from './'

commands.forEach(({name, command}) => {
Cypress.Commands.add(name, command.bind(null, cy))
Cypress.Commands.add(name, command)
})

/* global Cypress, cy */
/* global Cypress */
13 changes: 8 additions & 5 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {queries, waitForElement} from 'dom-testing-library'
import {getContainer} from './utils'

const defaults = {
timeout: 3000,
Expand All @@ -7,17 +8,19 @@ const defaults = {
const commands = Object.keys(queries).map(queryName => {
return {
name: queryName,
command: (cy, ...args) => {
command: (...args) => {
const lastArg = args[args.length - 1]
const waitOptions = (typeof lastArg === 'object')
? Object.assign({}, defaults, lastArg)
: defaults

const queryImpl = queries[queryName]
const baseCommandImpl = doc =>
waitForElement(() => queryImpl(doc, ...args), Object.assign({}, waitOptions, {
container: doc,
const baseCommandImpl = doc => {
const container = getContainer(waitOptions.container || doc);
return waitForElement(() => queryImpl(container, ...args), Object.assign({}, waitOptions, {
container,
}))
}
let commandImpl
if (
queryName.startsWith('queryBy') ||
Expand Down Expand Up @@ -64,4 +67,4 @@ const commands = Object.keys(queries).map(queryName => {
export {commands}

/* eslint no-new-func:0 */
/* globals Cypress */
/* globals Cypress, cy */
21 changes: 21 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
function getFirstElement(jqueryOrElement) {
if (Cypress.dom.isJquery(jqueryOrElement)) {
return jqueryOrElement.get(0)
}
return jqueryOrElement
}

function getContainer(container) {
const withinContainer = cy.state('withinSubject')
if (withinContainer) {
return getFirstElement(withinContainer)
}
return getFirstElement(container)
}

export {
getFirstElement,
getContainer,
}

/* globals Cypress, cy */

0 comments on commit d105706

Please sign in to comment.