From 72510dc8d92ac0e06e3f2e8d65fdaa11ccd45f73 Mon Sep 17 00:00:00 2001 From: Peter Kamps Date: Sun, 3 Jun 2018 19:53:42 +0200 Subject: [PATCH 1/3] 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 --- .all-contributorsrc | 3 ++- README.md | 8 +++++++- cypress/fixtures/test-app/index.html | 4 ++++ cypress/integration/commands.spec.js | 14 ++++++++++++++ package.json | 7 ++++--- src/index.js | 9 ++++++--- src/support/utils.js | 21 +++++++++++++++++++++ 7 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 src/support/utils.js diff --git a/.all-contributorsrc b/.all-contributorsrc index 2ff0486..74e8584 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -47,7 +47,8 @@ "contributions": [ "code", "doc", - "ideas" + "ideas", + "test" ] } ], diff --git a/README.md b/README.md index bbb59b0..2de6439 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,12 @@ 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') +}) ``` ## Other Solutions @@ -87,7 +93,7 @@ Thanks goes to these people ([emoji key][emojis]): -| [
Kent C. Dodds](https://kentcdodds.com)
[💻](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") | [
Ivan Babak](https://sompylasar.github.io)
[💻](https://github.com/kentcdodds/cypress-testing-library/commits?author=sompylasar "Code") [🤔](#ideas-sompylasar "Ideas, Planning, & Feedback") | [
Łukasz Gandecki](http://team.thebrain.pro)
[💻](https://github.com/kentcdodds/cypress-testing-library/commits?author=lgandecki "Code") [⚠️](https://github.com/kentcdodds/cypress-testing-library/commits?author=lgandecki "Tests") | [
Peter Kamps](https://github.com/npeterkamps)
[💻](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") | +| [
Kent C. Dodds](https://kentcdodds.com)
[💻](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") | [
Ivan Babak](https://sompylasar.github.io)
[💻](https://github.com/kentcdodds/cypress-testing-library/commits?author=sompylasar "Code") [🤔](#ideas-sompylasar "Ideas, Planning, & Feedback") | [
Łukasz Gandecki](http://team.thebrain.pro)
[💻](https://github.com/kentcdodds/cypress-testing-library/commits?author=lgandecki "Code") [⚠️](https://github.com/kentcdodds/cypress-testing-library/commits?author=lgandecki "Tests") | [
Peter Kamps](https://github.com/npeterkamps)
[💻](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") | | :---: | :---: | :---: | :---: | diff --git a/cypress/fixtures/test-app/index.html b/cypress/fixtures/test-app/index.html index 1719775..867a217 100644 --- a/cypress/fixtures/test-app/index.html +++ b/cypress/fixtures/test-app/index.html @@ -29,6 +29,10 @@

getByPlaceholderText

getByText

+
+

getByText within

+ +

getByLabelText

diff --git a/cypress/integration/commands.spec.js b/cypress/integration/commands.spec.js index 7fbbd0f..fe813e9 100644 --- a/cypress/integration/commands.spec.js +++ b/cypress/integration/commands.spec.js @@ -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 */ diff --git a/package.json b/package.json index 209dc12..27c349f 100644 --- a/package.json +++ b/package.json @@ -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", @@ -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" diff --git a/src/index.js b/src/index.js index b9fa208..3f83a2b 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,5 @@ import {queries, waitForElement} from 'dom-testing-library' +import {getContainer} from './support/utils' const defaults = { timeout: 3000, @@ -14,10 +15,12 @@ const commands = Object.keys(queries).map(queryName => { : defaults const queryImpl = queries[queryName] - const baseCommandImpl = doc => - waitForElement(() => queryImpl(doc, ...args), Object.assign({}, waitOptions, { - container: doc, + const baseCommandImpl = doc => { + const container = getContainer(cy, waitOptions.container || doc); + return waitForElement(() => queryImpl(container, ...args), Object.assign({}, waitOptions, { + container, })) + } let commandImpl if ( queryName.startsWith('queryBy') || diff --git a/src/support/utils.js b/src/support/utils.js new file mode 100644 index 0000000..e2319bd --- /dev/null +++ b/src/support/utils.js @@ -0,0 +1,21 @@ +function getElement(element) { + if (Cypress.dom.isJquery(element)) { + return element.get(0) + } + return element +} + +function getContainer(cy, container) { + const withinContainer = cy.state('withinSubject') + if (withinContainer) { + return getElement(withinContainer) + } + return getElement(container) +} + +export { + getElement, + getContainer, +} + +/* globals Cypress */ From 6394e7e3b24485b2dda95cef4e3e5e4e9a9cee68 Mon Sep 17 00:00:00 2001 From: Peter Kamps Date: Mon, 4 Jun 2018 18:38:57 +0200 Subject: [PATCH 2/3] Improvements based on feedback. * Documented jQuery vs DOM nodes. * Use Cypress.cy global. * Renamed function and parameter. * Moved utils file. --- README.md | 2 ++ src/index.js | 4 ++-- src/support/utils.js | 21 --------------------- src/utils.js | 21 +++++++++++++++++++++ 4 files changed, 25 insertions(+), 23 deletions(-) delete mode 100644 src/support/utils.js create mode 100644 src/utils.js diff --git a/README.md b/README.md index 2de6439..be0ddd3 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,8 @@ cy.get('form').then((subject) => { }) ``` +`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 diff --git a/src/index.js b/src/index.js index 3f83a2b..6b90bfa 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,5 @@ import {queries, waitForElement} from 'dom-testing-library' -import {getContainer} from './support/utils' +import {getContainer} from './utils' const defaults = { timeout: 3000, @@ -16,7 +16,7 @@ const commands = Object.keys(queries).map(queryName => { const queryImpl = queries[queryName] const baseCommandImpl = doc => { - const container = getContainer(cy, waitOptions.container || doc); + const container = getContainer(waitOptions.container || doc); return waitForElement(() => queryImpl(container, ...args), Object.assign({}, waitOptions, { container, })) diff --git a/src/support/utils.js b/src/support/utils.js deleted file mode 100644 index e2319bd..0000000 --- a/src/support/utils.js +++ /dev/null @@ -1,21 +0,0 @@ -function getElement(element) { - if (Cypress.dom.isJquery(element)) { - return element.get(0) - } - return element -} - -function getContainer(cy, container) { - const withinContainer = cy.state('withinSubject') - if (withinContainer) { - return getElement(withinContainer) - } - return getElement(container) -} - -export { - getElement, - getContainer, -} - -/* globals Cypress */ diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..bbb80ae --- /dev/null +++ b/src/utils.js @@ -0,0 +1,21 @@ +function getFirstElement(jqueryOrElement) { + if (Cypress.dom.isJquery(jqueryOrElement)) { + return jqueryOrElement.get(0) + } + return jqueryOrElement +} + +function getContainer(container) { + const withinContainer = Cypress.cy.state('withinSubject') + if (withinContainer) { + return getFirstElement(withinContainer) + } + return getFirstElement(container) +} + +export { + getFirstElement, + getContainer, +} + +/* globals Cypress */ From 68237c9e2ba303a951a189a4db297ce19cef368e Mon Sep 17 00:00:00 2001 From: Peter Kamps Date: Tue, 5 Jun 2018 19:32:53 +0200 Subject: [PATCH 3/3] Use the cy global. --- src/add-commands.js | 4 ++-- src/index.js | 4 ++-- src/utils.js | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/add-commands.js b/src/add-commands.js index 52d90ba..43e8f14 100644 --- a/src/add-commands.js +++ b/src/add-commands.js @@ -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 */ diff --git a/src/index.js b/src/index.js index 6b90bfa..095004c 100644 --- a/src/index.js +++ b/src/index.js @@ -8,7 +8,7 @@ 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) @@ -67,4 +67,4 @@ const commands = Object.keys(queries).map(queryName => { export {commands} /* eslint no-new-func:0 */ -/* globals Cypress */ +/* globals Cypress, cy */ diff --git a/src/utils.js b/src/utils.js index bbb80ae..abe38b9 100644 --- a/src/utils.js +++ b/src/utils.js @@ -6,7 +6,7 @@ function getFirstElement(jqueryOrElement) { } function getContainer(container) { - const withinContainer = Cypress.cy.state('withinSubject') + const withinContainer = cy.state('withinSubject') if (withinContainer) { return getFirstElement(withinContainer) } @@ -18,4 +18,4 @@ export { getContainer, } -/* globals Cypress */ +/* globals Cypress, cy */