From dfed1816f6af130a30b22329f4824d75adb9f291 Mon Sep 17 00:00:00 2001 From: Vernon Kesner Date: Tue, 17 Sep 2019 14:26:58 -0400 Subject: [PATCH 001/971] Update events doc for event.which usage on keyboard events (#262) --- docs/dom-testing-library/api-events.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/dom-testing-library/api-events.md b/docs/dom-testing-library/api-events.md index 736c94bba..a4bd70677 100644 --- a/docs/dom-testing-library/api-events.md +++ b/docs/dom-testing-library/api-events.md @@ -70,6 +70,10 @@ fireEvent.keyDown(domNode, { key: 'Enter', code: 13 }) // will Fire an KeyboardEvent with charCode = 0 fireEvent.keyDown(domNode, { key: 'Enter', code: 13 }) +// If using event.which, be sure to set the keyCode or it will be fallback to 0 +// will Fire a KeyboardEvent with expected which = 13 +fireEvent.keyDown(domNode, { key: 'Enter', keyCode: 13 }) + // will Fire an KeyboardEvent with charCode = 65 fireEvent.keyDown(domNode, { key: 'A', code: 65, charCode: 65 }) ``` From 93215840c851b9f74c7a953c459763f78a7f59c5 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 17 Sep 2019 12:27:37 -0600 Subject: [PATCH 002/971] docs: add vernonk as a contributor (#263) * docs: update README.md * docs: update .all-contributorsrc Co-authored-by: null <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 9 +++++++++ README.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index be5b5426d..abbe90765 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -314,6 +314,15 @@ "contributions": [ "doc" ] + }, + { + "login": "vernonk", + "name": "Vernon Kesner", + "avatar_url": "https://avatars1.githubusercontent.com/u/74096?v=4", + "profile": "https://github.com/vernonk", + "contributions": [ + "doc" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index 7fbc2bbaa..53c2812d9 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Steve Taggart
Steve Taggart

πŸ“– Stephen Sugden
Stephen Sugden

πŸ“– Blai Samitier
Blai Samitier

πŸ“– + Vernon Kesner
Vernon Kesner

πŸ“– From fe4219399731a87456ec81d60f9deadaf9dfa5fd Mon Sep 17 00:00:00 2001 From: Alex Krolick Date: Tue, 17 Sep 2019 12:51:00 -0700 Subject: [PATCH 003/971] docs(react-router): examples for react-router (#261) * docs(react-router): examples for react-router - extract out "renderWithRouter" helper and explain when it is needed - add some "getBy" queries instead of just container.innerHTML assertions, to show more idiomatic RTL usage * docs(react-router): md/js syntax * docs(react-router): show wrapper option to render * docs(react-router): show memoryrouter instead of browserrouter * docs(react-router): use wrapper option --- docs/example-react-router.md | 87 +++++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 16 deletions(-) diff --git a/docs/example-react-router.md b/docs/example-react-router.md index fcb9a2d2f..e3e6e3657 100644 --- a/docs/example-react-router.md +++ b/docs/example-react-router.md @@ -4,10 +4,10 @@ title: React Router --- ```jsx +// app.js import React from 'react' import { withRouter } from 'react-router' import { Link, Route, Router, Switch } from 'react-router-dom' -import { createMemoryHistory } from 'history' import { render, fireEvent } from '@testing-library/react' const About = () =>
You are on the about page
@@ -32,11 +32,72 @@ function App() { ) } +``` -// Ok, so here's what your tests might look like +```jsx +// app.test.js +import { Router } from 'react-router-dom' +import { createMemoryHistory } from 'history' -// this is a handy function that I would utilize for any component -// that relies on the router being in context +test('full app rendering/navigating', () => { + const history = createMemoryHistory() + const { container, getByText } = render( + + + + ) + // verify page content for expected route + // often you'd use a data-testid or role query, but this is also possible + expect(container.innerHTML).toMatch('You are home') + + fireEvent.click(getByText(/about/i)) + + // check that the content changed to the new page + expect(container.innerHTML).toMatch('You are on the about page') +}) + +test('landing on a bad page shows 404 page', () => { + const history = createMemoryHistory() + history.push('/some/bad/route') + const { getByRole } = render( + + + + ) + expect(getByRole('heading')).toHaveTextContent('404 Not Found') +}) + +test('rendering a component that uses withRouter', () => { + const route = '/some-route' + window.history.pushState({}, '', route) + const { getByTestId } = render( + + + + ) + expect(getByTestId('location-display').textContent).toBe(route) +}) +``` + +## Reducing boilerplate + +1. You can use the `wrapper` option to wrap a `MemoryRouter` around the component you want to render (`MemoryRouter` works when you don't need access to the history object itself in the test, but just need the components to be able to render and navigate). + +```jsx +import { MemoryRouter } from 'react-router-dom' + +test('full app rendering/navigating', () => { + const { container, getByText } = render(, {wrapper: MemoryRouter}) + // verify page content for expected route + expect(getByRole('heading')).toMatch('Home') +}) +``` + +2. If you find yourself adding Router components to your tests a lot, you may want to create +a helper function that wraps around `render`. + +```jsx +// test utils file function renderWithRouter( ui, { @@ -44,30 +105,23 @@ function renderWithRouter( history = createMemoryHistory({ initialEntries: [route] }), } = {} ) { + const Wrapper = ({children}) => {children} return { - ...render({ui}), + ...render(ui, {wrapper: Wrapper}), // adding `history` to the returned utilities to allow us // to reference it in our tests (just try to avoid using // this to test implementation details). history, } } +``` -test('full app rendering/navigating', () => { - const { container, getByText } = renderWithRouter() - // normally I'd use a data-testid, but just wanted to show this is also possible - expect(container.innerHTML).toMatch('You are home') - const leftClick = { button: 0 } - fireEvent.click(getByText(/about/i), leftClick) - // normally I'd use a data-testid, but just wanted to show this is also possible - expect(container.innerHTML).toMatch('You are on the about page') -}) - +```jsx +// app.test.js test('landing on a bad page', () => { const { container } = renderWithRouter(, { route: '/something-that-does-not-match', }) - // normally I'd use a data-testid, but just wanted to show this is also possible expect(container.innerHTML).toMatch('No match') }) @@ -77,3 +131,4 @@ test('rendering a component that uses withRouter', () => { expect(getByTestId('location-display').textContent).toBe(route) }) ``` + From 724bfb6e479e4be2b97106efac677568c1ed6895 Mon Sep 17 00:00:00 2001 From: Will Douglas Date: Thu, 19 Sep 2019 22:40:51 -0600 Subject: [PATCH 004/971] Add initial FAQ response to what level to test react (#264) --- docs/react-testing-library/faq.md | 42 +++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/docs/react-testing-library/faq.md b/docs/react-testing-library/faq.md index dafc18338..939c4e4d2 100644 --- a/docs/react-testing-library/faq.md +++ b/docs/react-testing-library/faq.md @@ -182,22 +182,50 @@ snapshotDiff(firstVersion, container.cloneNode(true)) How do I fix "an update was not wrapped in act(...)" warnings? -This warning is usually caused by an async operation causing an update after -the test has already finished. There are 2 approaches to resolve it: +This warning is usually caused by an async operation causing an update after the +test has already finished. There are 2 approaches to resolve it: 1. Wait for the result of the operation in your test by using one of [the async utilities](/docs/dom-testing-library/api-async) like [wait](/docs/dom-testing-library/api-async#wait) or a [`find*` query](/docs/dom-testing-library/api-queries#findby). For example: `const userAddress = await findByLabel(/address/i)`. -2. Mocking out the asynchronous operation so that it doesn't trigger state updates. +2. Mocking out the asynchronous operation so that it doesn't trigger state + updates. -Generally speaking, approach 1 is preferred since it better matches the expectations -of a user interacting with your app. +Generally speaking, approach 1 is preferred since it better matches the +expectations of a user interacting with your app. In addition, you may find -[this blog post](https://kentcdodds.com/blog/write-fewer-longer-tests) helpful as you -consider how best to write tests that give you confidence and avoid these warnings. +[this blog post](https://kentcdodds.com/blog/write-fewer-longer-tests) helpful +as you consider how best to write tests that give you confidence and avoid these +warnings. + + + +
+ +What level of a component tree should I test? Children, parents, or both? + +Following the guiding principle of this library, it is useful to break down how +tests are organized around how the user experiences and interacts with +application functionality rather than around specific components themselves. In +some cases, for example for reusable component libraries, it might be useful to +include developers in the list of users to test for and test each of the +reusable components individually. Other times, the specific break down of a +component tree is just an implementation detail and testing every component +within that tree individually can cause issues (see +https://kentcdodds.com/blog/avoid-the-test-user). + +In practice this means that it is often preferable to test high enough up the +component tree to simulate realistic user interactions. The question of whether +it is worth additionally testing at a higher or lower level on top of this comes +down to a question of tradeoffs and what will provide enough value for the cost +(see https://kentcdodds.com/blog/unit-vs-integration-vs-e2e-tests on more info +on different levels of testing). + +For a more in-depth discussion of this topic see +[this video](https://youtu.be/0qmPdcV-rN8).
From b2313910c8ea2f5892f0866121fa63248372ba9b Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2019 22:41:33 -0600 Subject: [PATCH 005/971] docs: add wdoug as a contributor (#265) * docs: update README.md * docs: update .all-contributorsrc --- .all-contributorsrc | 9 +++++++++ README.md | 3 +++ 2 files changed, 12 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index abbe90765..a1744bd36 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -323,6 +323,15 @@ "contributions": [ "doc" ] + }, + { + "login": "wdoug", + "name": "Will Douglas", + "avatar_url": "https://avatars3.githubusercontent.com/u/5432102?v=4", + "profile": "https://github.com/wdoug", + "contributions": [ + "doc" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index 53c2812d9..5910db756 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Blai Samitier
Blai Samitier

πŸ“– Vernon Kesner
Vernon Kesner

πŸ“– + + Will Douglas
Will Douglas

πŸ“– + From 4d2464305c5631d89b92a16dbe9351ed0cb5efbb Mon Sep 17 00:00:00 2001 From: Ben Monro Date: Sun, 22 Sep 2019 07:46:07 -0700 Subject: [PATCH 006/971] updated docs to reflect changes in testcafe 3.2.0 (#267) --- docs/testcafe-testing-library/intro.md | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/docs/testcafe-testing-library/intro.md b/docs/testcafe-testing-library/intro.md index aa0943cc8..4caa3440a 100644 --- a/docs/testcafe-testing-library/intro.md +++ b/docs/testcafe-testing-library/intro.md @@ -40,7 +40,7 @@ fixture`selectors`.beforeEach(addTestcafeTestingLibrary) ], ``` -You can now import & use `getBy`, `getAllBy`, `queryBy` and `queryAllBy` +You can now import & use get[All]By*, query[All]By*, find[All]By* selectors in your tests. [See `DOM Testing Library` API for reference](dom-testing-library/api-queries.md) @@ -72,16 +72,16 @@ test('getByLabelText', async t => { By default the selectors come pre-bound to `document.body`, so no need to provide a container. However, if you want to restrict your query using a -container, you can use `within`. Keep in mind that `within` works using a -Testcafe `ClientFunction` so you will need to await it, and you can't make -assertions on it like you can using a `Selector`. +container, you can use `within`. Note similar to using a testcafe `ClientFunction` +so you will need to await `within`, and you can't make assertions on it like you can using a `Selector`. +`within` can take either a string or a query (get[All]By*, query[All]By*, find[All]By*). ### Examples using `within` ```javascript -import { within, addTestcafeTestingLibrary } from '@testing-library/testcafe' +import { within } from '@testing-library/testcafe' -fixture`within`.beforeEach(addTestcafeTestingLibrary) +fixture`within` .page`http://localhost:13370` test('getByText within container', async t => { @@ -94,6 +94,20 @@ test("queryByPlaceholder doesn't find anything", async t => { await t.expect(queryByPlaceholderText('Placeholder Text').exists).notOk() }) + +test('works with nested selectors', async t => { + const nested = await within(getByTestId('nested')); + await t.expect(nested.getByText('Button Text').exists).ok() + +}); + +test('works with nested selector from "All" query with index', async t => { + const nestedDivs = getAllByTestId(/nested/); + await t.expect(nestedDivs.count).eql(2); + const nested = await within(nestedDivs.nth(0)); + + await t.expect(nested.getByText('Button Text').exists).ok(); +}); ``` [gh]: https://github.com/benmonro/testcafe-testing-library From 962dd2af0b350eb28dd41e3d01e428762b2df363 Mon Sep 17 00:00:00 2001 From: Ben Monro Date: Tue, 24 Sep 2019 10:34:30 -0700 Subject: [PATCH 007/971] added config section for testcafe (#268) --- docs/testcafe-testing-library/intro.md | 58 +++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/docs/testcafe-testing-library/intro.md b/docs/testcafe-testing-library/intro.md index 4caa3440a..ef60bd65c 100644 --- a/docs/testcafe-testing-library/intro.md +++ b/docs/testcafe-testing-library/intro.md @@ -32,7 +32,7 @@ fixture`selectors`.beforeEach(addTestcafeTestingLibrary) ``` ### for v3.x+ (requires testcafe 1.4.0 or greater) -`addTestcafeTestingLibrary` was removed in 3.x, instead you can now inject clientScripts as of testcafe 1.4.0. For now, the path has to be used, but this will hopefully be changed to a module soon (pending a change to testcafe to support `umd:main` in package.json. +`addTestcafeTestingLibrary` was removed in 3.x, instead you can now [inject clientScripts][inject] as of testcafe 1.4.0. For now, the path has to be used, but this will hopefully be changed to a module soon (pending a change to testcafe to support `umd:main` in package.json. ```json "clientScripts": [ @@ -68,6 +68,59 @@ test('getByLabelText', async t => { }) ``` +## Configure +You can customize the testIdAttribute using the [configure function of dom-testing-librarty][config] in a few different ways: + +### Once in a single page load: +```javascript +import { configureOnce, getByTestId } from '@testing-library/testcafe'; + +test('can be configured once in a single page load', async t => { + await configureOnce({ testIdAttribute: 'data-other-test-id' }); + await t.click(getByTestId('other-id')); +}) +``` + +### For every test & page load in a fixture: +```javascript +import { configure, getByTestId, getByText } from '@testing-library/testcafe'; + +fixture`configure`.clientScripts(configure({ testIdAttribute: 'data-automation-id' })) + .page`http://localhost:13370` + + +test('supports alternative testIdAttribute', async t => { + await t + .click(getByTestId('image-with-random-alt-tag')) +}) + +test('still works after browser page load and reload', async t => { + await t.click(getByText('Go to Page 2')); + + await t.eval(() => location.reload(true)); + + await t.click(getByTestId('page2-thing')) + .expect(getByText('second page').exists).ok() +}) + +``` + +### Globally for all fixtures, tests and page loads by [injecting clientScripts][inject] +>Note: the dom-testing-library umd must come before your configure script + +.testcaferc.json +```json + "clientScripts": [ + "./node_modules/@testing-library/dom/dist/@testing-library/dom.umd.js" + "./path/to/my-app-testcafe.config.js" + ] +``` + +./path/to/my-app-testcafe.config.js +```javascript +window.TestingLibraryDom.configure({ testIdAttribute: 'data-automation-id' }); +``` + ## Containers By default the selectors come pre-bound to `document.body`, so no need to @@ -109,5 +162,6 @@ test('works with nested selector from "All" query with index', async t => { await t.expect(nested.getByText('Button Text').exists).ok(); }); ``` - +[config]: https://testing-library.com/docs/dom-testing-library/api-configuration [gh]: https://github.com/benmonro/testcafe-testing-library +[inject]:https://devexpress.github.io/testcafe/documentation/using-testcafe/common-concepts/inject-scripts-into-tested-pages.html#add-client-scripts-to-all-tests From 96b436f26a4f69bb8614108bfc576b5fb12e11e3 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Tue, 24 Sep 2019 20:20:28 +0200 Subject: [PATCH 008/971] feat(queries): Add docs about byRole#hidden (#266) * feat(queries): Add docs about byRole#hidden * Add example for hidden --- docs/dom-testing-library/api-queries.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/dom-testing-library/api-queries.md b/docs/dom-testing-library/api-queries.md index 72a22ba30..2e2344b2b 100644 --- a/docs/dom-testing-library/api-queries.md +++ b/docs/dom-testing-library/api-queries.md @@ -533,6 +533,7 @@ getByRole( role: TextMatch, options?: { exact?: boolean = true, + hidden?: boolean = false, normalizer?: NormalizerFn, }): HTMLElement ``` @@ -544,6 +545,27 @@ attribute. The [W3C HTML recommendation](https://www.w3.org/TR/html5/index.html#contents) lists all HTML elements with their default aria roles. +If you set `hidden` to `true` elements that are normally excluded from the +accessibility tree are considered for the query as well. The default behavior +follows https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion with the exception of +`role="none"` and `role="presentation"` which are considered in the query in any +case. For example in + +```html + +
+ +
+
+ +
+ +``` + +`getByRole('button')` would only return the `Close dialog`-button. To make +assertions about the `Open dialog`-button you would need to use +`getAllByRole('button', { hidden: true })`. + ```html
...
``` From 26399e46ef97f1dcfab05b769006ac538b63df5d Mon Sep 17 00:00:00 2001 From: Head <40166539+HTMLhead@users.noreply.github.com> Date: Wed, 25 Sep 2019 12:48:06 +0900 Subject: [PATCH 009/971] docs: fix cypress-testing-library example link and example (#270) --- docs/cypress-testing-library/intro.md | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/docs/cypress-testing-library/intro.md b/docs/cypress-testing-library/intro.md index bbc7cefee..6efe883b8 100644 --- a/docs/cypress-testing-library/intro.md +++ b/docs/cypress-testing-library/intro.md @@ -43,19 +43,25 @@ and `queryAllBy` commands. You can find [all library definitions here](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/testing-library__cypress/index.d.ts). -To show some simple examples (from -[https://github.com/testing-library/cypress-testing-library/blob/master/cypress/integration/commands.spec.js](https://github.com/testing-library/cypress-testing-library/blob/master/cypress/integration/commands.spec.js)): +To show some simple examples (from [https://github.com/testing-library/cypress-testing-library/tree/master/cypress/integration](https://github.com/testing-library/cypress-testing-library/tree/master/cypress/integration)): ```javascript -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.findAllByText(/^Button Text \d$/) + .should('have.length', 2) + .click({ multiple: true }) + .should('contain', 'Button Clicked') +cy.queryByText('Button Text 1') + .click() + .should('contain', 'Button Clicked') +cy.queryByText('Non-existing Button Text', { timeout: 100 }).should('not.exist') +cy.queryByLabelText('Label 1') + .click() + .type('Hello Input Labelled By Id') +cy.get('#nested').within(() => { + cy.queryByText('Button Text 2').click() }) -cy.get('form').then(subject => { - cy.getByText('Button Text', { container: subject }).should('exist') +cy.get('#nested').then(subject => { + cy.queryByText(/^Button Text/, { container: subject }).click() }) ``` From 854814d1d46c31fe9ea36851932b2d53145bb643 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2019 21:48:39 -0600 Subject: [PATCH 010/971] docs: add HTMLhead as a contributor (#271) * docs: update README.md * docs: update .all-contributorsrc --- .all-contributorsrc | 9 +++++++++ README.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index a1744bd36..117572d44 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -332,6 +332,15 @@ "contributions": [ "doc" ] + }, + { + "login": "HTMLhead", + "name": "Head", + "avatar_url": "https://avatars0.githubusercontent.com/u/40166539?v=4", + "profile": "https://velog.io/@head", + "contributions": [ + "doc" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index 5910db756..740862df2 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Will Douglas
Will Douglas

πŸ“– + Head
Head

πŸ“– From 8100f035d9c55a4a9802d378f8bace8a648cceae Mon Sep 17 00:00:00 2001 From: Ben Monro Date: Sat, 28 Sep 2019 19:10:57 -0700 Subject: [PATCH 011/971] chore: updated testcafe examples to reflect 3.3.0 (#272) --- docs/testcafe-testing-library/intro.md | 34 ++++++++++++++++---------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/docs/testcafe-testing-library/intro.md b/docs/testcafe-testing-library/intro.md index ef60bd65c..8e826e1aa 100644 --- a/docs/testcafe-testing-library/intro.md +++ b/docs/testcafe-testing-library/intro.md @@ -137,30 +137,38 @@ import { within } from '@testing-library/testcafe' fixture`within` .page`http://localhost:13370` -test('getByText within container', async t => { +test('works with getBy* selectors', async t => { + await t + .expect( + within(getByTestId('nested')) + .getByText('Button Text').exists + ).ok(); +}); + +test('works with CSS selector strings', async t => { const { getByText } = await within('#nested') await t.click(getByText('Button Text')).ok() }) -test("queryByPlaceholder doesn't find anything", async t => { - const { queryByPlaceholderText } = await within('#nested') - - await t.expect(queryByPlaceholderText('Placeholder Text').exists).notOk() -}) - -test('works with nested selectors', async t => { - const nested = await within(getByTestId('nested')); - await t.expect(nested.getByText('Button Text').exists).ok() +test('works on any testcafe selector', async (t) => { + const nested = Selector('#nested'); + await t + .expect( + within(nested).getByText('Button Text') + .exists).ok() }); -test('works with nested selector from "All" query with index', async t => { +test('works with results from "byAll" query with index - regex', async t => { const nestedDivs = getAllByTestId(/nested/); await t.expect(nestedDivs.count).eql(2); - const nested = await within(nestedDivs.nth(0)); - await t.expect(nested.getByText('Button Text').exists).ok(); + await t + .expect(within(nestedDivs.nth(0)).getByText('Button Text').exists).ok() + .expect(within(nestedDivs.nth(1)).getByText('text only in 2nd nested').exists).ok() + }); + ``` [config]: https://testing-library.com/docs/dom-testing-library/api-configuration [gh]: https://github.com/benmonro/testcafe-testing-library From 8f7d5d0e07e4e209c65d00278afb14f1a7bca93a Mon Sep 17 00:00:00 2001 From: Rahim Alwer Date: Mon, 30 Sep 2019 14:18:10 +1000 Subject: [PATCH 012/971] docs(preact): release initial docs (#273) * docs(preact): add logo + link to homepage * docs(preact): release initial docs --- docs/preact-testing-library/api.md | 158 +++++++++++++++++++++++++ docs/preact-testing-library/example.md | 60 ++++++++++ docs/preact-testing-library/intro.md | 46 +++++++ docs/preact-testing-library/learn.md | 32 +++++ website/pages/en/index.js | 6 + website/sidebars.json | 10 ++ website/static/img/preact-128x128.png | Bin 0 -> 11231 bytes 7 files changed, 312 insertions(+) create mode 100644 docs/preact-testing-library/api.md create mode 100644 docs/preact-testing-library/example.md create mode 100644 docs/preact-testing-library/intro.md create mode 100644 docs/preact-testing-library/learn.md create mode 100644 website/static/img/preact-128x128.png diff --git a/docs/preact-testing-library/api.md b/docs/preact-testing-library/api.md new file mode 100644 index 000000000..ab119816d --- /dev/null +++ b/docs/preact-testing-library/api.md @@ -0,0 +1,158 @@ +--- +id: api +title: API +sidebar_label: API +--- + +- [`@testing-library/dom`](#testing-library-dom) +- [`render`](#render) +- [`cleanup`](#cleanup) +- [`act`](#act) +- [`fireEvent`](#fireevent) + +--- + +## `@testing-library/dom` + +This library re-exports everything from the DOM Testing Library +(`@testing-library/dom`). See the +[documentation](../dom-testing-library/api-queries.md) to see what goodies you +can use. + +## `render` + +```jsx +import { render } from '@testing-library/preact' + +const { results } = render(, { options }) +``` + +### Options + +| Option | Description | Default | +| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | +| `container` | The HTML element the component is mounted to. | baseElement | +| `baseElement` | The root HTML element to which the container is appended to. | document.body | +| `queries` | Queries to bind to the baseElement. See [getQueriesForElement](../dom-testing-library/api-helpers#within-and-getqueriesforelement-apis). | null | +| `hydrate` | Used when the component has already been mounted and requires a rerender. Not needed for most people. The rerender function passed back to you does this already. | false | +| `wrapper` | A parent component to wrap YourComponent. | null | + +### Results + +| Result | Description | +| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `container` | The HTML element the component is mounted to. | +| `baseElement` | The root HTML element to which the container is appended to. | +| `debug` | Logs the baseElement using [prettyDom](https://testing-library.com/docs/dom-testing-library/api-helpers#prettydom). | +| `unmount` | Unmounts the component from the container. | +| `rerender` | Calls render again passing in the original arguments and sets hydrate to true. | +| `asFragment` | Returns the innerHTML of the container. | +| `...queries` | Returns all [query functions](https://testing-library.com/docs/dom-testing-library/api-queries) to be used on the baseElement. If you pass in `query` arguments than this will be those, otherwise all. | + +## `cleanup` + +Unmounts the component from the container and destroys the container. + +πŸ“ When you import anything from the library, this automatically runs after each +test. If you'd like to disable this then set `process.env.PTL_SKIP_AUTO_CLEANUP` +to true when running your tests. + +```jsx +import { render, cleanup } from '@testing-library/preact' + +afterEach(() => { + cleanup() +}) // Default on import: runs it after each test. + +render() + +cleanup() // Or like this for more control. +``` + +## `act` + +Just a convenience export that points to preact/test-utils/act. All renders and +events being fired are wrapped in `act`, so you don't really need this. It's +responsible for flushing all effects and rerenders after invoking it. + +πŸ“ If you'd love to learn more, checkout +[this explanation](https://github.com/threepointone/react-act-examples/blob/master/sync.md). +Even thought it's for React, it gives you an idea of why it's needed. + +## `fireEvent` + +Passes it to the @testing-library/dom +[fireEvent](../dom-testing-library/api-events). It's also wrapped in `act` so +you don't need to worry about doing it. + +πŸ“ Keep in mind mainly when using `h / Preact.createElement` that React uses a +Synthetic event system, and Preact uses the browser's native `addEventListener` +for event handling. This means events like `onChange` and `onDoubleClick` in +React, are `onInput` and `onDblClick` in Preact. The double click example will +give you an idea of how to test using those functions. + +### Example 1 + +```jsx +const cb = jest.fn(); + +function Counter() { + useEffect(cb); + + const [count, setCount] = useState(0); + + return ; +} + +const { container: { firstChild: buttonNode }, } = render(); + +// Clear the first call to useEffect that the initial render triggers. +cb.mockClear(); + +// Fire event Option 1. +fireEvent.click(buttonNode); + +// Fire event Option 2. +fireEvent( +button, +new Event('MouseEvent', { + bubbles: true, + cancelable: true, + button: 0, +}); + +expect(buttonNode).toHaveTextContent('1'); +expect(cb).toHaveBeenCalledTimes(1); +``` + +### Example 2 + +```jsx +const handler = jest.fn() + +const { + container: { firstChild: input }, +} = render() + +fireEvent.input(input, { target: { value: 'a' } }) + +expect(handler).toHaveBeenCalledTimes(1) +``` + +### Example 3 + +```jsx +const ref = createRef() +const spy = jest.fn() + +render( + h(elementType, { + onDblClick: spy, + ref, + }) +) + +fireEvent['onDblClick'](ref.current) + +expect(spy).toHaveBeenCalledTimes(1) +``` diff --git a/docs/preact-testing-library/example.md b/docs/preact-testing-library/example.md new file mode 100644 index 000000000..78d4b79b9 --- /dev/null +++ b/docs/preact-testing-library/example.md @@ -0,0 +1,60 @@ +--- +id: example +title: Example +sidebar_label: Example +--- + +> Preact Testing Library works with both Preact Hooks and Classes. Your tests +> will be the same however you write your components. + +## Component + +```jsx +function HiddenMessage({ children }) { + const [showMessage, setShowMessage] = useState(false) + + return ( +
+ + setShowMessage(e.target.checked)} + checked={showMessage} + /> + {showMessage ? children : null} +
+ ) +} +``` + +## Test + +```jsx +// NOTE: jest-dom adds handy assertions to Jest and it is recommended, but not required. +import '@testing-library/jest-dom/extend-expect' + +import { h } from 'preact' +import { render, fireEvent } from '@testing-library/preact' + +import HiddenMessage from '../hidden-message' + +test('shows the children when the checkbox is checked', () => { + const testMessage = 'Test Message' + + const { queryByText, getByLabelText, getByText } = render( + {testMessage} + ) + + // query* functions will return the element or null if it cannot be found. + // get* functions will return the element or throw an error if it cannot be found. + expect(queryByText(testMessage)).toBeNull() + + // The queries can accept a regex to make your selectors more resilient to content tweaks and changes. + fireEvent.click(getByLabelText(/show/i)) + + // .toBeInTheDocument() is an assertion that comes from jest-dom. + // Otherwise you could use .toBeDefined(). + expect(getByText(testMessage)).toBeInTheDocument() +}) +``` diff --git a/docs/preact-testing-library/intro.md b/docs/preact-testing-library/intro.md new file mode 100644 index 000000000..655c57a17 --- /dev/null +++ b/docs/preact-testing-library/intro.md @@ -0,0 +1,46 @@ +--- +id: intro +title: Intro +sidebar_label: Introduction +--- + +[Preact Testing Library on GitHub][gh] + +[gh]: https://github.com/testing-library/preact-testing-library + +``` +npm install --save-dev @testing-library/preact +``` + +> This library is built on top of +> [`DOM Testing Library`](dom-testing-library/intro.md) which is where most of +> the logic behind the queries is. + +## The Problem + +You want to write tests for your Preact components so that they avoid including +implementation details, and are maintainable in the long run. + +## This Solution + +The Preact Testing Library is a very lightweight solution for testing Preact +components. It provides light utility functions on top of `preact/test-utils`, +in a way that encourages better testing practices. Its primary guiding principle +is: + +> [The more your tests resemble the way your software is used, the more confidence they can give you.](https://twitter.com/kentcdodds/status/977018512689455106) + +See the [Dom introduction][dom-solution-explainer] and [React +introduction][react-solution-explainer] for a more in-depth explanation. + +[dom-solution-explainer]: ../dom-testing-library/intro.md#this-solution +[react-solution-explainer]: ../react-testing-library/intro#this-solution + +**What this library is not**: + +1. A test runner or framework. +2. Specific to a testing framework. + +We recommend Jest as our preference. You can checkout +[Using Without Jest](../react-testing-library/setup#using-without-jest) if +you're looking to use another framework. diff --git a/docs/preact-testing-library/learn.md b/docs/preact-testing-library/learn.md new file mode 100644 index 000000000..5b7b31166 --- /dev/null +++ b/docs/preact-testing-library/learn.md @@ -0,0 +1,32 @@ +--- +id: learn +title: Learn +sidebar_label: Learn +--- + +Due to the similarities between React and Preact (including the testing +libraries), you should be able to comfortably use any React based examples, +docs, answers on stack overflow etc. + +Take note of the +[differences between React and Preact](https://preactjs.com/guide/v10/differences-to-react). + +If you're still hungry for more at this point than checkout: + +- The dom-testing-library: + - [Introduction](../intro.md) + - [Queries](../dom-testing-library/api-queries) + - [Firing Events](../dom-testing-library/api-events) + - [Async Utilities](../dom-testing-library/api-async.md) + - [Helpers](../dom-testing-library/api-helpers) + - [FAQ](../dom-testing-library/faq.md) +- The react-testing-library: + - [API](../react-testing-library/api.md) + - [Example](../react-testing-library/example-intro.md) + - [Sandbox](https://codesandbox.io/s/github/kentcdodds/react-testing-library-examples) + - [FAQ](../react-testing-library/faq.md) +- This YouTube video by LevelUpTuts called + [What is React Testing Library?](https://youtu.be/JKOwJUM4_RM) +- Extending Jest with + [custom matchers](https://github.com/testing-library/jest-dom) to test the + state of the DOM. diff --git a/website/pages/en/index.js b/website/pages/en/index.js index 0a55ba956..d7c461f42 100755 --- a/website/pages/en/index.js +++ b/website/pages/en/index.js @@ -235,6 +235,12 @@ class Index extends React.Component { title: '[Native Testing Library](./docs/native-testing-library/intro)', }, + { + image: `${baseUrl}img/preact-128x128.png`, + imageAlign: 'top', + title: + '[Preact Testing Library](./docs/preact-testing-library/intro)', + }, { image: `${baseUrl}img/construction-128x128.png`, imageAlign: 'top', diff --git a/website/sidebars.json b/website/sidebars.json index 89fd4576f..a8d51d29e 100755 --- a/website/sidebars.json +++ b/website/sidebars.json @@ -80,6 +80,16 @@ "angular-testing-library/api" ] }, + { + "type": "subcategory", + "label": "Preact Testing Library", + "ids": [ + "preact-testing-library/intro", + "preact-testing-library/example", + "preact-testing-library/api", + "preact-testing-library/learn" + ] + }, "cypress-testing-library/intro", "svelte-testing-library/intro", "pptr-testing-library/intro", diff --git a/website/static/img/preact-128x128.png b/website/static/img/preact-128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..25c8dde37bf5d0d27cd153d44df4445e23707275 GIT binary patch literal 11231 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 Date: Tue, 1 Oct 2019 16:40:21 +0300 Subject: [PATCH 013/971] Remove an unused var --- docs/react-testing-library/setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/react-testing-library/setup.md b/docs/react-testing-library/setup.md index 82250e48b..805a0eb56 100644 --- a/docs/react-testing-library/setup.md +++ b/docs/react-testing-library/setup.md @@ -153,7 +153,7 @@ render method: ```js // test-utils.js -import { render, queries, queryHelpers } from '@testing-library/react' +import { render, queries } from '@testing-library/react' import * as customQueries from './custom-queries' const customRender = (ui, options) => From 0f62fa6a40441468ef16ac1d3b280afe8e5aa03f Mon Sep 17 00:00:00 2001 From: Lee <32332479+mynar7@users.noreply.github.com> Date: Wed, 2 Oct 2019 11:26:43 -0400 Subject: [PATCH 014/971] add note about component instance and methods to main FAQ (#276) --- docs/dom-testing-library/faq.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/dom-testing-library/faq.md b/docs/dom-testing-library/faq.md index ae3c094bb..841ddb6d9 100644 --- a/docs/dom-testing-library/faq.md +++ b/docs/dom-testing-library/faq.md @@ -94,6 +94,23 @@ const thirdItem = getByTestId(container, `item-${items[2].id}`) +
+ + Help! I can't access component methods or the component instance! + + +This is **intentional**. + +We want you to focus on testing the output and functionality of the component as +it is observed by the user and to **avoid worrying about the implementation +details** of the component. + +We believe this leads to less brittle and more meaningful test code. + +Please refer to the [Guiding Principles](../guiding-principles) of this testing +library for more info. + +
From c10c689fd57ae591a5e27c4dff7b1dbbb7da6734 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 2 Oct 2019 09:27:28 -0600 Subject: [PATCH 015/971] docs: add mynar7 as a contributor (#277) * docs: update README.md * docs: update .all-contributorsrc --- .all-contributorsrc | 9 +++++++++ README.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 117572d44..2cb9ac534 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -341,6 +341,15 @@ "contributions": [ "doc" ] + }, + { + "login": "mynar7", + "name": "Lee", + "avatar_url": "https://avatars0.githubusercontent.com/u/32332479?v=4", + "profile": "https://github.com/mynar7", + "contributions": [ + "doc" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index 740862df2..3b7897a74 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Will Douglas
Will Douglas

πŸ“– Head
Head

πŸ“– + Lee
Lee

πŸ“– From 5504d434f26dd000ab6565104302c6c9752d43ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Beltr=C3=A1n=20Alarc=C3=B3n?= Date: Wed, 2 Oct 2019 19:38:57 +0200 Subject: [PATCH 016/971] docs: include new page for eslint plugin within ecosystem section (#275) * docs: include new page for eslint plugin within ecosystem section * docs(eslint-plugin): remove unnecessary backticks * docs(eslint-plugin): include example screenshot within the repo * docs(eslint-plugin): update bullet list elements --- ...ecosystem-eslint-plugin-testing-library.md | 23 ++++++++++++++++++ website/sidebars.json | 3 ++- .../static/img/eslint-plugin-screenshot.png | Bin 0 -> 37172 bytes 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 docs/ecosystem-eslint-plugin-testing-library.md create mode 100644 website/static/img/eslint-plugin-screenshot.png diff --git a/docs/ecosystem-eslint-plugin-testing-library.md b/docs/ecosystem-eslint-plugin-testing-library.md new file mode 100644 index 000000000..63ca6d5de --- /dev/null +++ b/docs/ecosystem-eslint-plugin-testing-library.md @@ -0,0 +1,23 @@ +--- +id: ecosystem-eslint-plugin-testing-library +title: eslint-plugin-testing-library +--- + +[`eslint-plugin-testing-library`][gh] is an ESLint plugin for Testing Library +that helps users to follow best practices and anticipate common mistakes when +writing tests. + +![eslint-plugin-testing-library example showing an error](/img/eslint-plugin-screenshot.png) + +This plugin includes: + +- Several rules for linting Testing Library specific code. +- Shareable config for recommended rules. +- Shareable configs for specific rules by framework: Angular, React, Vue. +- Some autofixable rules. + +Find more info about available rules and configs on GitHub. + +- [eslint-plugin-testing-library on GitHub][gh] + +[gh]: https://github.com/Belco90/eslint-plugin-testing-library diff --git a/website/sidebars.json b/website/sidebars.json index a8d51d29e..fea3f2c46 100755 --- a/website/sidebars.json +++ b/website/sidebars.json @@ -100,7 +100,8 @@ "ecosystem-jest-dom", "ecosystem-bs-jest-dom", "ecosystem-jest-native", - "ecosystem-react-select-event" + "ecosystem-react-select-event", + "ecosystem-eslint-plugin-testing-library" ], "Help": ["faq", "learning", "contributing"] }, diff --git a/website/static/img/eslint-plugin-screenshot.png b/website/static/img/eslint-plugin-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..27b76ede478f08e5d58c9d587397828bbd1915d5 GIT binary patch literal 37172 zcmZTvb9`mXvQ9EFCdp*tiH(VE+nLz5wPV}1ZQD*Jwr$&bnRD;E=e+yYAN#lV>aObU z>aOm!zOO1+MoJhC8Uq>#2nbG8L_iJ*2&C=vJ_8c`^LLVWNeKuDn$(1!Uq+OlA6LfK z%Fx8z00>AVI6eW2LE!~^(9<>3nGP!gua{Oj8t;cb%f2sua_WzRq`(M03G(4NIA$VI z2K8fdvK9w^%P(>m>e+ldL`t%nN?*w18}}kE${*%kH|jlJ9#lHp7cM?tEtkz(nM-F~0?k*ZBeF#z7TXb_RR&kBg>Jz#ww zp?~)nM>F~ob>!B;0_~+5G`D2pLs|xZ2Rc9;+>;~_hNEjv9kdSvZ2TLIT0%sbc@P`z z#Q!5-dUnGl;A1LwBJ$by;Ne>Edj0$q$jX!35@Di0{^#c4pkL@ykHg2o$`ei;Lgw>J zid`X3q==&iZ6iEoTsP)wH9c%s4fi83s*e{0)n>>XXjdR0$lDr0kI>J73=y5oPBLvF zcs^7wCr5r!{gi=Vu}#4HimxF#xR|kPwUM@SHr1QD6p!*clMxZdOFjTO@V%@Y3&{8v zSk&s3k)+Xgp5I7WcR9EUX-rzZ6B>{_V4_iAf-+!|lV1pEzKBB`QaODje)VnQP-o;1hr<3irs}9)&-N~MV7>i;O9q! zK%5g)gtr`oryF36;M#|LCG;AFKnNSm_bvJtAEg0c^v6B)EsB7K{*$RhHb-)&aRyj^nytiO% z!C!vB4fYi8gjxScqaTMr4GHZFwn?>qYLZh&uK2nTcG9&r0JlA0b8#iWfiy9Ixn*&M z{Rq?sl^=ltN}Dg$Q2;MxX>+`Lguvif!f&F{`XV(1Pf?F~-{r7PaE?Ha zz7;1j@VN*VM9&Qw>NDGtvPP%zQxV~iXc0cdWJVj2%6+#8f$I;%&nqkZE*l|}Le@x1 z5QkpEppa-Pd{;Oi*C;bmN*fxx&rw)$xh#N%P6X9}GGI8WH*l`VQI&nTxar zSp#|JyAv4`IhR}y1v=?ZB{3zoB6~p-H}6xB6)+#LCm1Q}rphpKOwt!JD;ch`)nbm~ zoRaMde7U7UTNMNK`26D{j8fGc7g-01@M6PClw8FeN6|A@wTLl;!P=3Mi}N91{tCqhkf47Kmth?7d`+8=A zrIC)CZowALmfHf|!m%c?rn(mB0?P@}PS{S~&i*Xm9^sMp4*X{MWwxsacR8zPGXc-k z*aS@v&{buGr;~lx)90@M^Adh2q@K%=tD1|amr&hk6Je8kH6o}Q%7=QUI$M2M8|*LI zHjEexQ9xIaQNUU-R!}(xI|^!uZ0IzKzHhmoI+i-B^^-~cNA=_8HZV*I?snsG@%w(pFjM<#gVzj73t>S9_!|* zE~S3n+NS#?&n@3c*%^U6ifpFzLyLCrVpnVT1DA&ymoe+744t)tw&bRLl(>w|r1oXb zW_UL-gy{pU8a)_2{RD2_O6!Ai=I2c- z+#{S1oQ2A}xP z9ffxzD)2{geA$E9k(}<&Y!@BMlv`M80f2|;H8`TvnAey_*ZK2i&6cLyNzLQ+*>+!p zbpy$ly8E-$hiZGqmzvBHvD znk(z&twLdtNPD-zr-}mA;+CxEnW?^9-@(_2`UT~=*&j+=n!iHl3+5xzl^t?k@+$bG|9TJD>g?dYxOq^78RMT-OW>gnQKG-LcxQjOiB;76@#TY>ycwc`9=pPyNQ^L z(DtwG<&7GaTJ629b~ooWt(@+_?qA+YpCKUpzT`e^U$nPmI(qK&-t+hLz6#4lis4Xj zS3IkH96a-mbi?pd@uy2GayZjaqIq12UsK}<+h)>bByh>QD$<)Wxp<6Pl)XItJ|LhL zpf()1dB=N;e51b8e7`K+sZ2-eMk1)}t2ER??T~e|yFJ@(w21A9jV%0DU|4XoLDs>3 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 e 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 Y+5Or3Tx+L)+AhJfw{d}1o%W9Z6PP)#Hvj+t literal 0 HcmV?d00001 From ba012c97252c1ab619a057c3cc7caec46e60c953 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 2 Oct 2019 11:39:30 -0600 Subject: [PATCH 017/971] docs: add Belco90 as a contributor (#278) * docs: update README.md * docs: update .all-contributorsrc Co-authored-by: null <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 9 +++++++++ README.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 2cb9ac534..9fb983adc 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -350,6 +350,15 @@ "contributions": [ "doc" ] + }, + { + "login": "Belco90", + "name": "Mario BeltrΓ‘n AlarcΓ³n", + "avatar_url": "https://avatars1.githubusercontent.com/u/2677072?v=4", + "profile": "https://mario.dev/", + "contributions": [ + "doc" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index 3b7897a74..3e463f1e1 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Will Douglas
Will Douglas

πŸ“– Head
Head

πŸ“– Lee
Lee

πŸ“– + Mario BeltrΓ‘n AlarcΓ³n
Mario BeltrΓ‘n AlarcΓ³n

πŸ“– From 3311645044c8c898f96d3a2793b92a5b09fbb5e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Beltr=C3=A1n=20Alarc=C3=B3n?= Date: Fri, 4 Oct 2019 17:13:41 +0200 Subject: [PATCH 018/971] docs: add aria-query doc link to ByRole query (#280) * docs: add aria-query doc link to ByRole query * docs: reference aria in uppercase --- docs/dom-testing-library/api-queries.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/dom-testing-library/api-queries.md b/docs/dom-testing-library/api-queries.md index 2e2344b2b..1be322750 100644 --- a/docs/dom-testing-library/api-queries.md +++ b/docs/dom-testing-library/api-queries.md @@ -543,7 +543,10 @@ Queries for elements with the given role (and it also accepts a ` + + +``` + +**Test** + +```js +import '@testing-library/jest-dom/extend-expect' + +import { render, fireEvent } from '@testing-library/svelte' + +import Comp from '..' + +test('count increments when button is clicked', async () => { + const { getByText } = render(Comp) + const button = getByText('Count is 0') + + // Option 1. + await fireEvent.click(button) + expect(button).toHaveTextContent('Count is 1') + + // Option 2. + await fireEvent( + button, + new MouseEvent('click', { + bubbles: true, + cancelable: true, + }) + ) + expect(button).toHaveTextContent('Count is 2') +}) +``` + +[svelte-tick]: https://svelte.dev/docs#tick diff --git a/docs/svelte-testing-library/example.md b/docs/svelte-testing-library/example.md new file mode 100644 index 000000000..6e675f148 --- /dev/null +++ b/docs/svelte-testing-library/example.md @@ -0,0 +1,52 @@ +--- +id: example +title: Example +sidebar_label: Example +--- + +## Component + +```html +

Hello {name}!

+ + + + +``` + +## Test + +```js +// NOTE: jest-dom adds handy assertions to Jest and it is recommended, but not required. +import '@testing-library/jest-dom/extend-expect' + +import { render, fireEvent } from '@testing-library/svelte' + +import Comp from '../Comp.svelte' + +test('shows proper heading when rendered', () => { + const { getByText } = render(Comp, { props: { name: 'World' } }) + + expect(getByText('Hello World!')).toBeInTheDocument() +}) + +// Note: This is as an async test as we are using `fireEvent` +test('changes button text on click', async () => { + const { getByText } = render(Comp, { props: { name: 'World' } }) + const button = getByText('Button') + + // Using await when firing events is unique to the svelte testing library because + // we have to wait for the next `tick` so that Svelte flushes all pending state changes. + await fireEvent.click(button) + + expect(button).toHaveTextContent('Button Clicked') +}) +``` diff --git a/docs/svelte-testing-library/intro.md b/docs/svelte-testing-library/intro.md index bc03a9080..2d1a0916d 100644 --- a/docs/svelte-testing-library/intro.md +++ b/docs/svelte-testing-library/intro.md @@ -1,137 +1,44 @@ --- id: intro -title: Svelte Testing Library +title: Intro +sidebar_label: Introduction --- -[`svelte-testing-library`][gh] simplifies the use of dom-testing with -[Svelte](https://svelte.dev/) components & applications. +[Svelte Testing Library on GitHub][gh] -``` -npm install --save-dev @testing-library/svelte -``` - -- [svelte-testing-library on GitHub][gh] - -## Usage - -You will first need to install and configure -[jest-transform-svelte](https://www.npmjs.com/package/jest-transform-svelte) in -order to use svelte in jest. - -You must add `cleanup` to your test fixture's `beforeEach` hook: - -```javascript -import { render, cleanup } from '@testing-library/svelte' - -beforeEach(cleanup) //this is required. -``` - -## Examples - -App.svelte - -```html - - - +[gh]: https://github.com/testing-library/svelte-testing-library -

Hello {name}!

``` - -App.spec.js - -```javascript -import App from '../src/App.svelte' -import { render, cleanup } from '@testing-library/svelte' -beforeEach(cleanup) -describe('App', () => { - test('should render greeting', () => { - const { getByText } = render(App, { props: { name: 'world' } }) - - expect(getByText('Hello world!')) - }) - - test('should change button text after click', async () => { - const { getByText } = render(App, { props: { name: 'world' } }) - - fireEvent.click(getByText('Button Text')) - - const button = await waitForElement(() => getByText('Button Clicked')) - - expect(button).toBeInTheDocument() - }) -}) +npm install --save-dev @testing-library/svelte ``` -### Containers +> This library is built on top of +> [`DOM Testing Library`](dom-testing-library/intro.md) which is where most of +> the logic behind the queries is. -Useful for snapshot tests. You can use query the container if you need more -granular tests. +## The Problem -App.svelte +You want to write tests for your Svelte components so that they avoid including +implementation details, and are maintainable in the long run. -```html - +## This Solution - +The Svelte Testing Library is a very lightweight solution for testing Svelte +components. It provides light utility functions on top of `svelte`, in a way +that encourages better testing practices. Its primary guiding principle is: -

Hello {name}!

-``` - -App.spec.js +> [The more your tests resemble the way your software is used, the more confidence they can give you.](https://twitter.com/kentcdodds/status/977018512689455106) -```javascript -import App from '../src/App.svelte' -import { render, cleanup } from '@testing-library/svelte' -beforeEach(cleanup) -describe('App', () => { - test('should render greeting', () => { - const { container } = render(App, { props: { name: 'world' } }) - - expect(container.querySelector('h1').innerHTML).toBe('Hello world!') - expect(container).toMatchInlineSnapshot(` -
-

- Hello - {name} - ! -

-
-`) - }) -}) -``` +So rather than dealing with instances of rendered Svelte components, your tests +will work with actual DOM nodes. See the [Dom +Introduction][dom-solution-explainer] for a more in-depth explanation. -### Cleanup +[dom-solution-explainer]: ../dom-testing-library/intro.md#this-solution +[react-solution-explainer]: ../react-testing-library/intro#this-solution -You can ensure [`cleanup`](./api#cleanup) is called after each test and import -additional assertions by adding it to the setup configuration in Jest. +**What this library is not**: -In Jest 24 and up, add the -[`setupFilesAfterEnv`](https://jestjs.io/docs/en/configuration.html#setupfilesafterenv-array) -option to your Jest config: +1. A test runner or framework. +2. Specific to a testing framework. -```javascript -// jest.config.js -module.exports = { - setupFilesAfterEnv: [ - '@testing-library/svelte/cleanup-after-each', - // ... other setup files ... - ], - // ... other options ... -} -``` - -[gh]: https://github.com/testing-library/svelte-testing-library +We recommend Jest as our preference. diff --git a/website/sidebars.json b/website/sidebars.json index fea3f2c46..9a6de8c57 100755 --- a/website/sidebars.json +++ b/website/sidebars.json @@ -90,8 +90,16 @@ "preact-testing-library/learn" ] }, + { + "type": "subcategory", + "label": "Svelte Testing Library", + "ids": [ + "svelte-testing-library/intro", + "svelte-testing-library/example", + "svelte-testing-library/api" + ] + }, "cypress-testing-library/intro", - "svelte-testing-library/intro", "pptr-testing-library/intro", "testcafe-testing-library/intro" ], From c7c2bd8b79380dfc151cdd0c08debcbb154b2d75 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 8 Oct 2019 15:44:59 -0600 Subject: [PATCH 027/971] docs: add mihar-22 as a contributor (#289) * docs: update README.md * docs: update .all-contributorsrc Co-authored-by: null <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 9 +++++++++ README.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 4fd18de7d..8efad43c5 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -368,6 +368,15 @@ "contributions": [ "doc" ] + }, + { + "login": "mihar-22", + "name": "Rahim Alwer", + "avatar_url": "https://avatars2.githubusercontent.com/u/14304599?v=4", + "profile": "https://github.com/mihar-22", + "contributions": [ + "doc" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index ccf030fbf..7ab45ad2b 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Lee
Lee

πŸ“– Mario BeltrΓ‘n AlarcΓ³n
Mario BeltrΓ‘n AlarcΓ³n

πŸ“– jameslevine
jameslevine

πŸ“– + Rahim Alwer
Rahim Alwer

πŸ“– From c9c765de6217766f20bce70d8c29cc9cea939199 Mon Sep 17 00:00:00 2001 From: Rahim Alwer Date: Wed, 9 Oct 2019 11:12:31 +1100 Subject: [PATCH 028/971] docs(svelte): add setup guide --- docs/svelte-testing-library/setup.md | 74 ++++++++++++++++++++++++++++ website/sidebars.json | 1 + 2 files changed, 75 insertions(+) create mode 100644 docs/svelte-testing-library/setup.md diff --git a/docs/svelte-testing-library/setup.md b/docs/svelte-testing-library/setup.md new file mode 100644 index 000000000..debd556c8 --- /dev/null +++ b/docs/svelte-testing-library/setup.md @@ -0,0 +1,74 @@ +--- +id: setup +title: Setup +sidebar_label: Setup +--- + +We recommend using [Jest](https://jestjs.io) but you're free to use the library +with any testing framework and runner you're comfortable with. + +## Jest + +1. Install Jest and Babel + + `npm install --save-dev jest babel-jest @babel/core @babel/preset-env` + +2. Add the following to your `package.json` + + ```json + { + "scripts": { + "test": "jest src", + "test:watch": "npm run test -- --watch" + } + } + ``` + +3. Add a `.babelrc` with the following + + ```json + { + "presets": [["@babel/preset-env", { "targets": { "node": "current" } }]] + } + ``` + +4. You'll need to compile the Svelte components before using them in Jest, so + we need to install the [svelte-jest](https://github.com/ktsn/svelte-jest) + transformer. + + `npm install --save-dev svelte-jest` + +5. Add the following Jest configuration to your `package.json` + + ```json + { + "jest": { + "transform": { + "^.+\\.js$": "babel-jest", + "^.+\\.svelte$": "jest-transform-svelte" + }, + "moduleFileExtensions": ["js", "json", "svelte"] + } + } + ``` + +6. This is optional but it is recommended, you can install + [jest-dom](https://github.com/testing-library/jest-dom) to add handy + assertions to Jest. + + 6.1 Install jest-dom + + `npm install --save-dev @testing-library/jest-dom` + + 6.2 Add the following to your Jest configuration in `package.json` + + ```json + { + "setupFilesAfterEnv": ["@testing-library/jest-dom/extend-expect"] + } + ``` + +7. Create your component + test file (checkout the rest of the docs to see how) + and run + + `npm run test` diff --git a/website/sidebars.json b/website/sidebars.json index 9a6de8c57..7ad2a5e2c 100755 --- a/website/sidebars.json +++ b/website/sidebars.json @@ -95,6 +95,7 @@ "label": "Svelte Testing Library", "ids": [ "svelte-testing-library/intro", + "svelte-testing-library/setup", "svelte-testing-library/example", "svelte-testing-library/api" ] From 7209b10ee921d3ba83fcbf731465609247b2a181 Mon Sep 17 00:00:00 2001 From: Rahim Alwer Date: Wed, 9 Oct 2019 11:17:05 +1100 Subject: [PATCH 029/971] docs(svelte): keep html in svelte files at the bottom --- docs/svelte-testing-library/api.md | 4 ++-- docs/svelte-testing-library/example.md | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/svelte-testing-library/api.md b/docs/svelte-testing-library/api.md index e11247f7d..c2673c8f8 100644 --- a/docs/svelte-testing-library/api.md +++ b/docs/svelte-testing-library/api.md @@ -98,8 +98,6 @@ changes. **Component** ```html - - + + ``` **Test** diff --git a/docs/svelte-testing-library/example.md b/docs/svelte-testing-library/example.md index 6e675f148..609552437 100644 --- a/docs/svelte-testing-library/example.md +++ b/docs/svelte-testing-library/example.md @@ -7,10 +7,6 @@ sidebar_label: Example ## Component ```html -

Hello {name}!

- - - + +

Hello {name}!

+ + ``` ## Test From 02280ab6444a8b629bcb82ccb42940ae7d8c9035 Mon Sep 17 00:00:00 2001 From: Rahim Alwer Date: Wed, 9 Oct 2019 12:15:22 +1100 Subject: [PATCH 030/971] docs(svelte): fix setup guide --- docs/svelte-testing-library/setup.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/docs/svelte-testing-library/setup.md b/docs/svelte-testing-library/setup.md index debd556c8..5bb77fcaf 100644 --- a/docs/svelte-testing-library/setup.md +++ b/docs/svelte-testing-library/setup.md @@ -11,7 +11,9 @@ with any testing framework and runner you're comfortable with. 1. Install Jest and Babel - `npm install --save-dev jest babel-jest @babel/core @babel/preset-env` + ``` + npm install --save-dev jest babel-jest @babel/core @babel/preset-env + ``` 2. Add the following to your `package.json` @@ -34,9 +36,11 @@ with any testing framework and runner you're comfortable with. 4. You'll need to compile the Svelte components before using them in Jest, so we need to install the [svelte-jest](https://github.com/ktsn/svelte-jest) - transformer. + transformer - `npm install --save-dev svelte-jest` + ``` + npm install --save-dev svelte-jest + ``` 5. Add the following Jest configuration to your `package.json` @@ -45,7 +49,7 @@ with any testing framework and runner you're comfortable with. "jest": { "transform": { "^.+\\.js$": "babel-jest", - "^.+\\.svelte$": "jest-transform-svelte" + "^.+\\.svelte$": "svelte-jest" }, "moduleFileExtensions": ["js", "json", "svelte"] } @@ -54,11 +58,13 @@ with any testing framework and runner you're comfortable with. 6. This is optional but it is recommended, you can install [jest-dom](https://github.com/testing-library/jest-dom) to add handy - assertions to Jest. + assertions to Jest 6.1 Install jest-dom - `npm install --save-dev @testing-library/jest-dom` + ``` + npm install --save-dev @testing-library/jest-dom + ``` 6.2 Add the following to your Jest configuration in `package.json` @@ -69,6 +75,8 @@ with any testing framework and runner you're comfortable with. ``` 7. Create your component + test file (checkout the rest of the docs to see how) - and run + and run it - `npm run test` + ``` + npm run test + ``` From 4e0a3367df5dec3c8af8ffc3334501b0d508f795 Mon Sep 17 00:00:00 2001 From: Aaron Pettengill Date: Wed, 9 Oct 2019 17:52:51 -0400 Subject: [PATCH 031/971] Move example that no longer requires a selector --- docs/dom-testing-library/api-queries.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/dom-testing-library/api-queries.md b/docs/dom-testing-library/api-queries.md index 390201edf..742db02f2 100644 --- a/docs/dom-testing-library/api-queries.md +++ b/docs/dom-testing-library/api-queries.md @@ -96,6 +96,12 @@ The example below will find the input node for the following DOM structures: // Wrapper labels +// Wrapper labels where the label text is in another child element + + // aria-label attributes // Take care because this is not a label that users can see on the page, // so the purpose of your input must be obvious to visual users. @@ -135,12 +141,6 @@ You may also need to filter down the results of the query. For that you can use the `selector` option: ```js -// Label containing multiple elements - - // Multiple elements labelled via aria-labelledby From ce95b5c0b025da090a2a74c9bef9245eed52dff1 Mon Sep 17 00:00:00 2001 From: Rahim Alwer Date: Thu, 10 Oct 2019 10:17:56 +1100 Subject: [PATCH 032/971] docs(svelte): recommend better jest svelte transformer in setup guide --- docs/svelte-testing-library/setup.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/svelte-testing-library/setup.md b/docs/svelte-testing-library/setup.md index 5bb77fcaf..6e539ff0b 100644 --- a/docs/svelte-testing-library/setup.md +++ b/docs/svelte-testing-library/setup.md @@ -35,11 +35,11 @@ with any testing framework and runner you're comfortable with. ``` 4. You'll need to compile the Svelte components before using them in Jest, so - we need to install the [svelte-jest](https://github.com/ktsn/svelte-jest) - transformer + we need to install + [jest-transform-svelte](https://github.com/rspieker/jest-transform-svelte) ``` - npm install --save-dev svelte-jest + npm install --save-dev jest-transform-svelte ``` 5. Add the following Jest configuration to your `package.json` @@ -49,7 +49,7 @@ with any testing framework and runner you're comfortable with. "jest": { "transform": { "^.+\\.js$": "babel-jest", - "^.+\\.svelte$": "svelte-jest" + "^.+\\.svelte$": "jest-transform-svelte" }, "moduleFileExtensions": ["js", "json", "svelte"] } From 835f16ae629b650f9fad925aed410a2ea23b7eda Mon Sep 17 00:00:00 2001 From: Rahim Alwer Date: Thu, 10 Oct 2019 11:58:14 +1100 Subject: [PATCH 033/971] docs(svelte): simplify setup guide by removing babel --- docs/svelte-testing-library/example.md | 2 +- docs/svelte-testing-library/setup.md | 27 +++++++++----------------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/docs/svelte-testing-library/example.md b/docs/svelte-testing-library/example.md index 609552437..c3043d828 100644 --- a/docs/svelte-testing-library/example.md +++ b/docs/svelte-testing-library/example.md @@ -30,7 +30,7 @@ import '@testing-library/jest-dom/extend-expect' import { render, fireEvent } from '@testing-library/svelte' -import Comp from '../Comp.svelte' +import Comp from '../Comp' test('shows proper heading when rendered', () => { const { getByText } = render(Comp, { props: { name: 'World' } }) diff --git a/docs/svelte-testing-library/setup.md b/docs/svelte-testing-library/setup.md index 6e539ff0b..86f24992e 100644 --- a/docs/svelte-testing-library/setup.md +++ b/docs/svelte-testing-library/setup.md @@ -9,10 +9,10 @@ with any testing framework and runner you're comfortable with. ## Jest -1. Install Jest and Babel +1. Install Jest ``` - npm install --save-dev jest babel-jest @babel/core @babel/preset-env + npm install --save-dev jest ``` 2. Add the following to your `package.json` @@ -26,15 +26,7 @@ with any testing framework and runner you're comfortable with. } ``` -3. Add a `.babelrc` with the following - - ```json - { - "presets": [["@babel/preset-env", { "targets": { "node": "current" } }]] - } - ``` - -4. You'll need to compile the Svelte components before using them in Jest, so +3. You'll need to compile the Svelte components before using them in Jest, so we need to install [jest-transform-svelte](https://github.com/rspieker/jest-transform-svelte) @@ -42,31 +34,30 @@ with any testing framework and runner you're comfortable with. npm install --save-dev jest-transform-svelte ``` -5. Add the following Jest configuration to your `package.json` +4. Add the following Jest configuration to your `package.json` ```json { "jest": { "transform": { - "^.+\\.js$": "babel-jest", "^.+\\.svelte$": "jest-transform-svelte" }, - "moduleFileExtensions": ["js", "json", "svelte"] + "moduleFileExtensions": ["js", "svelte"] } } ``` -6. This is optional but it is recommended, you can install +5. This is optional but it is recommended, you can install [jest-dom](https://github.com/testing-library/jest-dom) to add handy assertions to Jest - 6.1 Install jest-dom + 5.1 Install jest-dom ``` npm install --save-dev @testing-library/jest-dom ``` - 6.2 Add the following to your Jest configuration in `package.json` + 5.2 Add the following to your Jest configuration in `package.json` ```json { @@ -74,7 +65,7 @@ with any testing framework and runner you're comfortable with. } ``` -7. Create your component + test file (checkout the rest of the docs to see how) +6. Create your component + test file (checkout the rest of the docs to see how) and run it ``` From 0cdb0fc868c86ca1ce60757e5f11c9e2906959c1 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Sat, 12 Oct 2019 10:23:33 +0200 Subject: [PATCH 034/971] feat: Add isInaccessible (#284) --- docs/dom-testing-library/api-helpers.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/dom-testing-library/api-helpers.md b/docs/dom-testing-library/api-helpers.md index 6c8934c20..1ebdf837b 100644 --- a/docs/dom-testing-library/api-helpers.md +++ b/docs/dom-testing-library/api-helpers.md @@ -77,7 +77,8 @@ for other popular assertion libraries: - [chai-dom](https://github.com/nathanboktae/chai-dom) -If you're aware of some other alternatives, please [make a pull request](https://github.com/testing-library/testing-library-docs/pulls) +If you're aware of some other alternatives, please +[make a pull request](https://github.com/testing-library/testing-library-docs/pulls) and add it here! ## `getNodeText` @@ -185,6 +186,19 @@ console.log(getRoles(nav)) // } ``` +## `isInaccessible` + +This function will compute if the given element should be excluded from the +accessibility API by the browser. It implements every **MUST** criteria from the +[Excluding Elements from the Accessibility Tree](https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion) +section in WAI-ARIA 1.2 with the exception of checking the `role` attribute. + +It is defined as: + +```typescript +function isInaccessible(element: Element): boolean +``` + ## Debugging When you use any `get` calls in your test cases, the current state of the From 40af41302e3f797d7d63a2bea0b0b8a30e7e8886 Mon Sep 17 00:00:00 2001 From: Pob Ch <590650@gmail.com> Date: Sat, 12 Oct 2019 22:48:02 +0700 Subject: [PATCH 035/971] Fix bug in code example of example-react-router.md (#297) ## Issues - `` requires `history` prop - `` would not be updated when we call `window.history.pushState({}, '', route)`. Therefore, the test "rendering a component that uses withRouter" would fail. --- docs/example-react-router.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/example-react-router.md b/docs/example-react-router.md index e3e6e3657..1094d97f3 100644 --- a/docs/example-react-router.md +++ b/docs/example-react-router.md @@ -60,7 +60,7 @@ test('landing on a bad page shows 404 page', () => { const history = createMemoryHistory() history.push('/some/bad/route') const { getByRole } = render( - + ) @@ -68,10 +68,11 @@ test('landing on a bad page shows 404 page', () => { }) test('rendering a component that uses withRouter', () => { + const history = createMemoryHistory() const route = '/some-route' - window.history.pushState({}, '', route) + history.push(route) const { getByTestId } = render( - + ) From 4b6379d944ed7e28a8bba398abfbf9915a37b851 Mon Sep 17 00:00:00 2001 From: Chenjia Date: Sun, 13 Oct 2019 06:23:08 +0800 Subject: [PATCH 036/971] docs: add riot ecosystem plugin (#296) * docs: add riot ecosystem plugin * docs: remove unnecessary async & add auto cleanup --- docs/ecosystem-riot-testing-library.md | 32 ++++++++++++++++++++++++++ website/sidebars.json | 3 ++- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 docs/ecosystem-riot-testing-library.md diff --git a/docs/ecosystem-riot-testing-library.md b/docs/ecosystem-riot-testing-library.md new file mode 100644 index 000000000..e633a5b0e --- /dev/null +++ b/docs/ecosystem-riot-testing-library.md @@ -0,0 +1,32 @@ +--- +id: ecosystem-riot-testing-library +title: riot-testing-library +--- + +[`riot-testing-library`][gh] builds on top of [DOM Testing Library](https://github.com/testing-library/dom-testing-library) by adding APIs for working with [Riot.js](https://riot.js.org/) components. + +``` +npm install --save-dev riot-testing-library +``` + +```javascript +import render, { fireEvent } from 'riot-testing-library' +import TestTag from './test.tag' + +test('should show count text when rendered', () => { + const { queryByTestId } = render(TestTag, {count: 10}); + expect(queryByTestId('count').textContent).toBe("10"); +}) + +test('should add count when click add button text', () => { + const { queryByTestId } = render(TestTag, {count: 1}); + expect(queryByTestId('count').textContent).toBe("1"); + fireEvent.click(queryByTestId('button')) + expect(queryByTestId('count').textContent).toBe("2"); +}) +``` + + +- [riot-testing-library on GitHub][gh] + +[gh]: https://github.com/ariesjia/riot-testing-library diff --git a/website/sidebars.json b/website/sidebars.json index 7ad2a5e2c..bf0ab83e1 100755 --- a/website/sidebars.json +++ b/website/sidebars.json @@ -110,7 +110,8 @@ "ecosystem-bs-jest-dom", "ecosystem-jest-native", "ecosystem-react-select-event", - "ecosystem-eslint-plugin-testing-library" + "ecosystem-eslint-plugin-testing-library", + "ecosystem-riot-testing-library" ], "Help": ["faq", "learning", "contributing"] }, From 56bd607d463967cd9d628cd84654bbd2da8b4178 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 12 Oct 2019 16:23:44 -0600 Subject: [PATCH 037/971] docs: add ariesjia as a contributor (#298) * docs: update README.md * docs: update .all-contributorsrc --- .all-contributorsrc | 9 +++++++++ README.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 8efad43c5..35335beea 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -377,6 +377,15 @@ "contributions": [ "doc" ] + }, + { + "login": "ariesjia", + "name": "Chenjia", + "avatar_url": "https://avatars1.githubusercontent.com/u/1797160?v=4", + "profile": "http://www.btorange.com/", + "contributions": [ + "doc" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index 7ab45ad2b..b5adf6835 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Mario BeltrΓ‘n AlarcΓ³n
Mario BeltrΓ‘n AlarcΓ³n

πŸ“– jameslevine
jameslevine

πŸ“– Rahim Alwer
Rahim Alwer

πŸ“– + Chenjia
Chenjia

πŸ“– From e91fb71f28b8886799b31efa144e72fcad2e1d2c Mon Sep 17 00:00:00 2001 From: Rahim Alwer Date: Mon, 14 Oct 2019 20:47:01 +1100 Subject: [PATCH 038/971] docs(svelte): remove warning on using component from rendered results and provide use cases --- docs/svelte-testing-library/api.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/svelte-testing-library/api.md b/docs/svelte-testing-library/api.md index c2673c8f8..2d675f75e 100644 --- a/docs/svelte-testing-library/api.md +++ b/docs/svelte-testing-library/api.md @@ -50,14 +50,14 @@ Please refer to the ### Results -| Result | Description | -| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `container` | The HTML element the component is mounted into. | -| `component` | The newly created Svelte component. **Please do not use this, it will most likely be removed in a future release.** Using this method goes against the testing libraries guiding principles. | -| `debug` | Logs the baseElement using [prettyDom](https://testing-library.com/docs/dom-testing-library/api-helpers#prettydom). | -| `unmount` | Unmounts the component from the `target` by calling `component.$destroy()`. | -| `rerender` | Calls render again destroying the old component, and mounting the new component on the original `target` with any new options passed in. | -| `...queries` | Returns all [query functions](https://testing-library.com/docs/dom-testing-library/api-queries) that are binded to the `container`. If you pass in `query` arguments than this will be those, otherwise all. | +| Result | Description | +| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `container` | The HTML element the component is mounted into. | +| `component` | The newly created Svelte component. This is mostly useful for testing exported functions or cases where manipulating the DOM doesn't fit. Outside of said cases avoid using the component directly to build tests, instead of interacting with the rendered Svelte component, work with the DOM . | +| `debug` | Logs the baseElement using [prettyDom](https://testing-library.com/docs/dom-testing-library/api-helpers#prettydom). | +| `unmount` | Unmounts the component from the `target` by calling `component.$destroy()`. | +| `rerender` | Calls render again destroying the old component, and mounting the new component on the original `target` with any new options passed in. | +| `...queries` | Returns all [query functions](https://testing-library.com/docs/dom-testing-library/api-queries) that are binded to the `container`. If you pass in `query` arguments than this will be those, otherwise all. | ## `cleanup` From 01b0a5f2153d3d37f51c41eee518996d2898462c Mon Sep 17 00:00:00 2001 From: Rahim Alwer Date: Mon, 14 Oct 2019 20:48:16 +1100 Subject: [PATCH 039/971] docs(svelte): debug description mentions wrong element --- docs/svelte-testing-library/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/svelte-testing-library/api.md b/docs/svelte-testing-library/api.md index 2d675f75e..65182e627 100644 --- a/docs/svelte-testing-library/api.md +++ b/docs/svelte-testing-library/api.md @@ -54,7 +54,7 @@ Please refer to the | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `container` | The HTML element the component is mounted into. | | `component` | The newly created Svelte component. This is mostly useful for testing exported functions or cases where manipulating the DOM doesn't fit. Outside of said cases avoid using the component directly to build tests, instead of interacting with the rendered Svelte component, work with the DOM . | -| `debug` | Logs the baseElement using [prettyDom](https://testing-library.com/docs/dom-testing-library/api-helpers#prettydom). | +| `debug` | Logs the `container` using [prettyDom](https://testing-library.com/docs/dom-testing-library/api-helpers#prettydom). | | `unmount` | Unmounts the component from the `target` by calling `component.$destroy()`. | | `rerender` | Calls render again destroying the old component, and mounting the new component on the original `target` with any new options passed in. | | `...queries` | Returns all [query functions](https://testing-library.com/docs/dom-testing-library/api-queries) that are binded to the `container`. If you pass in `query` arguments than this will be those, otherwise all. | From b4f6b7d8cd14b3c7a6f31dc4c1e98626e9f58bba Mon Sep 17 00:00:00 2001 From: Ben Monro Date: Thu, 17 Oct 2019 23:25:03 -0700 Subject: [PATCH 040/971] Added Nightwatch Testing Library (#301) * added nightwatch testing library, cleaned up some bad links in Testcafe. Added Walmart Labs to users * fixed typo --- docs/nightwatch-testing-library/intro.md | 138 ++++++++++++++++++++++ docs/testcafe-testing-library/intro.md | 109 +++++++++-------- website/blog/2019-04-25-new-org.md | 8 +- website/pages/en/index.js | 6 + website/sidebars.json | 3 +- website/siteConfig.js | 6 + website/static/img/nightwatch-128x128.png | Bin 0 -> 16303 bytes website/static/img/users/walmart.png | Bin 0 -> 31646 bytes 8 files changed, 216 insertions(+), 54 deletions(-) create mode 100644 docs/nightwatch-testing-library/intro.md create mode 100644 website/static/img/nightwatch-128x128.png create mode 100644 website/static/img/users/walmart.png diff --git a/docs/nightwatch-testing-library/intro.md b/docs/nightwatch-testing-library/intro.md new file mode 100644 index 000000000..be6ec79e3 --- /dev/null +++ b/docs/nightwatch-testing-library/intro.md @@ -0,0 +1,138 @@ +--- +id: intro +title: Nightwatch Testing Library +--- + +[`nightwatch-testing-library`][gh] allows the use of dom-testing-library queries +in [Nightwatch](https://nightwatchjs.org) for end-to-end web testing. + +> Be sure to follow the +> [Nightwatch install & config instructions first](https://nightwatchjs.org/gettingstarted/installation/) + +then just + +``` +npm install -D @testing-library/nightwatch +``` + +- [nightwatch-testing-library on GitHub][gh] + +## READ THIS FIRST + +At it's core, `nightwatch-testing-library` translates between +dom-testing-library queries and css selectors. This is due to the fact that +Nightwatch adheres to the WebDriver standards for +[locator strategies](https://www.w3.org/TR/webdriver/#locator-strategies). For +now, this means that the logging will have some very detailed css paths. PRs +welcome for a +[custom reporter](https://nightwatchjs.org/guide/extending-nightwatch/#custom-reporter) +to solve this problemΒ πŸ€—. + +**So remember, the results from NWTL queries are WebDriver locators, not DOM +nodes.** + +> Note, in NWTL, all queries must be `await`ed. + +## Usage + +```javascript +const { getQueriesFrom } = require('@testing-library/nightwatch') + +module.exports = { + beforeEach(browser, done) { + browser.url('http://localhost:13370/') + done() + }, + + async getByLabelText(browser) { + const { getByLabelText } = getQueriesFrom(browser) + + const input = await getByLabelText('Label Text') + browser.setValue(input, '@TL FTW') + + browser.expect.element(input).value.to.equal('@TL FTW') + }, + + async getByAltText(browser) { + const { getByAltText } = getQueriesFrom(browser) + const image = await getByAltText('Image Alt Text') + + browser.click(image) + browser.expect + .element(image) + .to.have.css('border') + .which.equals('5px solid rgb(255, 0, 0)') + }, +} +``` + +### `AllBy` queries + +The results of `AllBy` queries have an additional function added to them: `nth` +which can be used in nightwatch functions as well as in the `within` function of +NWTL. + +```javascript + + async 'getAllByText - regex'(browser) { + const { getAllByText } = getQueriesFrom(browser); + const chans = await getAllByText(/Jackie Chan/) + + + browser.expect.elements(chans).count.to.equal(2) + + const firstChan = chans.nth(0); + const secondChan = chans.nth(1); + + + browser.click(chans.nth(0)); + browser.click(chans.nth(1)); + + browser.expect.element(secondChan).text.to.equal('Jackie Kicked'); + browser.expect.element(firstChan).text.to.equal('Jackie Kicked'); + + }, + +``` + +## Configure + +You can customize the testIdAttribute using the `configure` function just like +[dom-testing-library][config]: + +```javascript +const { configure } = require('@testing-library/nightwatch') + +configure({ testIdAttribute: 'data-automation-id' }) +``` + +## Containers + +By default the queries come pre-bound to `document.body`, so no need to provide +a container. However, if you want to restrict your query using a container, you +can use `within`. + +### Examples using `within` + +```javascript +const { getQueriesFrom, within } = require('@testing-library/nightwatch') + +module.exports = { + beforeEach(browser, done) { + browser.url('http://localhost:13370/') + done() + }, + async 'getByText within container'(browser) { + const { getByTestId } = getQueriesFrom(browser) + + const nested = await getByTestId('nested') + const button = await within(nested).getByText('Button Text') + + browser.click(button) + browser.expect.element(button).text.to.equal('Button Clicked') + }, +} +``` + +[config]: https://testing-library.com/docs/dom-testing-library/api-configuration +[gh]: https://github.com/testing-library/nightwatch-testing-library diff --git a/docs/testcafe-testing-library/intro.md b/docs/testcafe-testing-library/intro.md index 846514527..14851785c 100644 --- a/docs/testcafe-testing-library/intro.md +++ b/docs/testcafe-testing-library/intro.md @@ -19,6 +19,7 @@ npm install --save-dev testcafe @testing-library/testcafe dom. ### for v2.x: + Add `testcafe-testing-library` to your test fixture's `beforeEach` hook: ```javascript @@ -32,7 +33,11 @@ fixture`selectors`.beforeEach(addTestcafeTestingLibrary) ``` ### for v3.x+ (requires testcafe 1.4.0 or greater) -`addTestcafeTestingLibrary` was removed in 3.x, instead you can now [inject clientScripts][inject] as of testcafe 1.4.0. For now, the path has to be used, but this will hopefully be changed to a module soon (pending a change to testcafe to support `umd:main` in package.json. + +`addTestcafeTestingLibrary` was removed in 3.x, instead you can now [inject +clientScripts][inject] as of testcafe 1.4.0. For now, the path has to be used, +but this will hopefully be changed to a module soon (pending a change to +testcafe to support `umd:main` in package.json. ```json "clientScripts": [ @@ -40,14 +45,14 @@ fixture`selectors`.beforeEach(addTestcafeTestingLibrary) ], ``` -You can now import & use get[All]By*, query[All]By*, find[All]By* -selectors in your tests. +You can now import & use get[All]By*, query[All]By*, find[All]By\* selectors in +your tests. [See `DOM Testing Library` API for reference](dom-testing-library/api-queries.md) ## Examples To show some simple examples (from -[https://github.com/benmonro/testcafe-testing-library/blob/master/tests/testcafe/selectors.js](https://github.com/benmonro/testcafe-testing-library/blob/master/tests/testcafe/selectors.js)): +[https://github.com/testing-library/testcafe-testing-library/blob/master/tests/testcafe/selectors.js](https://github.com/testing-library/testcafe-testing-library/blob/master/tests/testcafe/selectors.js)): ```javascript test('getByPlaceHolderText', async t => { @@ -69,107 +74,113 @@ test('getByLabelText', async t => { ``` ## Configure -You can customize the testIdAttribute using the [configure function of DOM Testing Library][config] in a few different ways: + +You can customize the testIdAttribute using the [configure function of DOM +Testing Library][config] in a few different ways: ### Once in a single page load: + ```javascript -import { configureOnce, getByTestId } from '@testing-library/testcafe'; +import { configureOnce, getByTestId } from '@testing-library/testcafe' test('can be configured once in a single page load', async t => { - await configureOnce({ testIdAttribute: 'data-other-test-id' }); - await t.click(getByTestId('other-id')); + await configureOnce({ testIdAttribute: 'data-other-test-id' }) + await t.click(getByTestId('other-id')) }) ``` ### For every test & page load in a fixture: -```javascript -import { configure, getByTestId, getByText } from '@testing-library/testcafe'; -fixture`configure`.clientScripts(configure({ testIdAttribute: 'data-automation-id' })) - .page`http://localhost:13370` +```javascript +import { configure, getByTestId, getByText } from '@testing-library/testcafe' +fixture`configure`.clientScripts( + configure({ testIdAttribute: 'data-automation-id' }) +).page`http://localhost:13370` test('supports alternative testIdAttribute', async t => { - await t - .click(getByTestId('image-with-random-alt-tag')) + await t.click(getByTestId('image-with-random-alt-tag')) }) test('still works after browser page load and reload', async t => { - await t.click(getByText('Go to Page 2')); + await t.click(getByText('Go to Page 2')) - await t.eval(() => location.reload(true)); + await t.eval(() => location.reload(true)) - await t.click(getByTestId('page2-thing')) - .expect(getByText('second page').exists).ok() + await t + .click(getByTestId('page2-thing')) + .expect(getByText('second page').exists) + .ok() }) - ``` ### Globally for all fixtures, tests and page loads by [injecting clientScripts][inject] ->Note: the dom-testing-library umd must come before your configure script + +> Note: the dom-testing-library umd must come before your configure script .testcaferc.json + ```json "clientScripts": [ - "./node_modules/@testing-library/dom/dist/@testing-library/dom.umd.js" - "./path/to/my-app-testcafe.config.js" + "./node_modules/@testing-library/dom/dist/@testing-library/dom.umd.js" + "./path/to/my-app-testcafe.config.js" ] ``` ./path/to/my-app-testcafe.config.js + ```javascript -window.TestingLibraryDom.configure({ testIdAttribute: 'data-automation-id' }); +window.TestingLibraryDom.configure({ testIdAttribute: 'data-automation-id' }) ``` ## Containers By default the selectors come pre-bound to `document.body`, so no need to provide a container. However, if you want to restrict your query using a -container, you can use `within`. Note similar to using a testcafe `ClientFunction` -so you will need to await `within`, and you can't make assertions on it like you can using a `Selector`. -`within` can take either a string or a query (get[All]By*, query[All]By*, find[All]By*). +container, you can use `within`. Note similar to using a testcafe +`ClientFunction` so you will need to await `within`, and you can't make +assertions on it like you can using a `Selector`. `within` can take either a +string or a query (get[All]By*, query[All]By*, find[All]By\*). ### Examples using `within` ```javascript import { within } from '@testing-library/testcafe' -fixture`within` - .page`http://localhost:13370` +fixture`within`.page`http://localhost:13370` test('works with getBy* selectors', async t => { await t - .expect( - within(getByTestId('nested')) - .getByText('Button Text').exists - ).ok(); -}); + .expect(within(getByTestId('nested')).getByText('Button Text').exists) + .ok() +}) test('works with CSS selector strings', async t => { const { getByText } = await within('#nested') await t.click(getByText('Button Text')).ok() }) -test('works on any testcafe selector', async (t) => { - const nested = Selector('#nested'); +test('works on any testcafe selector', async t => { + const nested = Selector('#nested') - await t - .expect( - within(nested).getByText('Button Text') - .exists).ok() -}); + await t.expect(within(nested).getByText('Button Text').exists).ok() +}) test('works with results from "byAll" query with index - regex', async t => { - const nestedDivs = getAllByTestId(/nested/); - await t.expect(nestedDivs.count).eql(2); + const nestedDivs = getAllByTestId(/nested/) + await t.expect(nestedDivs.count).eql(2) await t - .expect(within(nestedDivs.nth(0)).getByText('Button Text').exists).ok() - .expect(within(nestedDivs.nth(1)).getByText('text only in 2nd nested').exists).ok() - -}); - + .expect(within(nestedDivs.nth(0)).getByText('Button Text').exists) + .ok() + .expect( + within(nestedDivs.nth(1)).getByText('text only in 2nd nested').exists + ) + .ok() +}) ``` + [config]: https://testing-library.com/docs/dom-testing-library/api-configuration -[gh]: https://github.com/benmonro/testcafe-testing-library -[inject]:https://devexpress.github.io/testcafe/documentation/using-testcafe/common-concepts/inject-scripts-into-tested-pages.html#add-client-scripts-to-all-tests +[gh]: https://github.com/testing-library/testcafe-testing-library +[inject]: + https://devexpress.github.io/testcafe/documentation/using-testcafe/common-concepts/inject-scripts-into-tested-pages.html#add-client-scripts-to-all-tests diff --git a/website/blog/2019-04-25-new-org.md b/website/blog/2019-04-25-new-org.md index c835f1a8b..4bb3838d0 100644 --- a/website/blog/2019-04-25-new-org.md +++ b/website/blog/2019-04-25-new-org.md @@ -71,7 +71,7 @@ Here are the current (or soon to be) members of the org: (Puppeteer) - [bs-react-testing-library](https://github.com/wyze/bs-react-testing-library) (ReasonReact) -- [testcafe-testing-library](https://github.com/benmonro/testcafe-testing-library) +- [testcafe-testing-library](https://github.com/testing-library/testcafe-testing-library) - [user-event](https://github.com/Gpx/user-event) - [jest-dom](https://github.com/testing-library/jest-dom) - [jest-native](https://github.com/testing-library/jest-native) @@ -157,9 +157,9 @@ As of a few months ago, you use react-testing-library to test your react applications. That's kinda neat :) -At the React Amsterdam [Open Source awards](https://osawards.com/react/) ceremony, -react-testing-library won the award for the Most impactful contribution to the -community! +At the React Amsterdam [Open Source awards](https://osawards.com/react/) +ceremony, react-testing-library won the award for the Most impactful +contribution to the community! ![Open Source Awards award](/img/blog/award.jpg) diff --git a/website/pages/en/index.js b/website/pages/en/index.js index d7c461f42..6604e5105 100755 --- a/website/pages/en/index.js +++ b/website/pages/en/index.js @@ -241,6 +241,12 @@ class Index extends React.Component { title: '[Preact Testing Library](./docs/preact-testing-library/intro)', }, + { + image: `${baseUrl}img/nightwatch-128x128.png`, + imageAlign: 'top', + title: + '[Nightwatch Testing Library](./docs/nightwatch-testing-library/intro)', + }, { image: `${baseUrl}img/construction-128x128.png`, imageAlign: 'top', diff --git a/website/sidebars.json b/website/sidebars.json index bf0ab83e1..89daaad16 100755 --- a/website/sidebars.json +++ b/website/sidebars.json @@ -102,7 +102,8 @@ }, "cypress-testing-library/intro", "pptr-testing-library/intro", - "testcafe-testing-library/intro" + "testcafe-testing-library/intro", + "nightwatch-testing-library/intro" ], "Ecosystem": [ "ecosystem-user-event", diff --git a/website/siteConfig.js b/website/siteConfig.js index 1cfa532ea..382417dce 100755 --- a/website/siteConfig.js +++ b/website/siteConfig.js @@ -16,6 +16,12 @@ const users = [ infoLink: 'https://www.paypal.com/', pinned: true, }, + { + caption: 'Walmart Labs', + pinned: true, + image: '/img/users/walmart.png', + infoLink: 'https://www.walmartlabs.com/', + }, { caption: 'Tiller', image: '/img/users/tiller.svg', diff --git a/website/static/img/nightwatch-128x128.png b/website/static/img/nightwatch-128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..1457a147f5145e6947a721a5be5a929a1d649976 GIT binary patch literal 16303 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 XmtJcyKNHq}ZqZAM%8Aqp83g@bx@i7> literal 0 HcmV?d00001 diff --git a/website/static/img/users/walmart.png b/website/static/img/users/walmart.png new file mode 100644 index 0000000000000000000000000000000000000000..af0a034d7f52c3d195c62bdaea4779598089897d GIT binary patch literal 31646 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 QPykYpQ Date: Thu, 17 Oct 2019 23:54:59 -0700 Subject: [PATCH 041/971] added header to install in nightwatch (#302) --- docs/nightwatch-testing-library/intro.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/nightwatch-testing-library/intro.md b/docs/nightwatch-testing-library/intro.md index be6ec79e3..19c9fdc09 100644 --- a/docs/nightwatch-testing-library/intro.md +++ b/docs/nightwatch-testing-library/intro.md @@ -3,9 +3,13 @@ id: intro title: Nightwatch Testing Library --- + [`nightwatch-testing-library`][gh] allows the use of dom-testing-library queries in [Nightwatch](https://nightwatchjs.org) for end-to-end web testing. + +## Install + > Be sure to follow the > [Nightwatch install & config instructions first](https://nightwatchjs.org/gettingstarted/installation/) From 44dc2d4985685f716ff643f9ba59360f5e5938f6 Mon Sep 17 00:00:00 2001 From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com> Date: Fri, 18 Oct 2019 19:58:29 +0200 Subject: [PATCH 042/971] docs(angular): update docs to latest API changes (#295) --- docs/angular-testing-library/api.md | 100 ++++++++++++++++++----- docs/angular-testing-library/examples.md | 4 + 2 files changed, 84 insertions(+), 20 deletions(-) diff --git a/docs/angular-testing-library/api.md b/docs/angular-testing-library/api.md index 976e959c9..4abe8852f 100644 --- a/docs/angular-testing-library/api.md +++ b/docs/angular-testing-library/api.md @@ -12,17 +12,17 @@ well as these methods: ## `render` ```typescript -function render( - component: Type, - renderOptions?: RenderOptions -): Promise -function render( - template: string, - renderOptions: RenderOptions -): Promise +async function render( + component: Type, + renderOptions?: RenderComponentOptions +): Promise> +async function render( + component: Type, + renderOptions?: RenderDirectiveOptions +): Promise> ``` -## RenderOptions +## Component RenderOptions ### `detectChanges` @@ -146,34 +146,79 @@ const component = await render(AppComponent, { }) ``` -### `wrapper` +### `excludeComponentDeclaration` -An Angular component to wrap the component in. +Exclude the component to be automatically be added as a declaration. This is +needed when the component is declared in an imported module. -**default** : `WrapperComponent`, an empty component that strips the -`ng-version` attribute. +**default** : `false` **example**: ```typescript const component = await render(AppComponent, { - wrapper: CustomWrapperComponent, + imports: [AppModule], // a module that includes AppComponent + excludeComponentDeclaration: true, }) ``` -### `excludeComponentDeclaration` +### `routes` -Exclude the component to be automatically be added as a declaration. This is -needed when the component is declared in an imported module. +The route configuration to set up the router service via +`RouterTestingModule.withRoutes`. For more info see the +[Angular Routes docs](https://angular.io/api/router/Routes). -**default** : `false` +**default** : `[]` **example**: ```typescript const component = await render(AppComponent, { - imports: [AppModule], // a module that includes AppComponent - excludeComponentDeclaration: true, + declarations: [ChildComponent], + routes: [ + { + path: '', + children: [ + { + path: 'child/:id', + component: ChildComponent, + }, + ], + }, + ], +}) +``` + +## Directive RenderOptions + +To test a directive, the render API is a bit different. The API has the same +options as the Component RenderOptions, but has more options: + +### `template` + +The template to render the directive. + +**example**: + +```typescript +const component = await render(SpoilerDirective, { + template: `
`, +}) +``` + +### `wrapper` + +An Angular component to wrap the directive in. + +**default**: `WrapperComponent` , an empty component that strips the +`ng-version` attribute. + +**example**: + +```typescript +const component = await render(SpoilerDirective, { + template: `
` + wrapper: CustomWrapperComponent }) ``` @@ -246,6 +291,21 @@ component.selectOptions(component.getByLabelText('Fruit'), 'Blueberry') component.selectOptions(component.getByLabelText('Fruit'), ['Blueberry'. 'Grape']) ``` +### `navigate` + +Accepts a DOM element or a path as parameter. If an element is passed, +`navigate` will navigate to the `href` value of the element. If a path is +passed, `navigate` will navigate to the path. + +```typescript +const component = await render(AppComponent, { + routes: [...] +}) + +await component.navigate(component.getByLabelText('To details')) +await component.navigate('details/3') +``` + ### `fixture` The Angular `ComponentFixture` of the component. diff --git a/docs/angular-testing-library/examples.md b/docs/angular-testing-library/examples.md index ad2e2cd35..c94f191a2 100644 --- a/docs/angular-testing-library/examples.md +++ b/docs/angular-testing-library/examples.md @@ -4,6 +4,10 @@ title: Examples sidebar_label: Examples --- +> Read +> [Good testing practices with πŸ¦” Angular Testing Library](https://timdeschryver.dev/posts/good-testing-practices-with-angular-testing-library) +> for a guided example + counter.component.ts ```typescript From 201c85d9b44199d2ed550bf7f4dd72738b4e3e39 Mon Sep 17 00:00:00 2001 From: "Pablo R. Dinella" Date: Fri, 18 Oct 2019 15:20:19 -0300 Subject: [PATCH 043/971] Fix user-event example (#303) --- docs/ecosystem-user-event.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/ecosystem-user-event.md b/docs/ecosystem-user-event.md index 312f4273a..186253e1f 100644 --- a/docs/ecosystem-user-event.md +++ b/docs/ecosystem-user-event.md @@ -16,12 +16,12 @@ import React from 'react' import { render } from '@testing-library/react' import userEvent from '@testing-library/user-event' -const { getByText } = test('click', () => { - render( - -``` - -```js -const inputNode = screen.getByLabelText('Username', { selector: 'input' }) -``` - -> **Note** -> -> `getByLabelText` will not work in the case where a `for` attribute on a -> `
About ℹ️ -``` - - - - -```js -import { screen } from '@testing-library/dom' - -const aboutAnchorNode = screen.getByText(/about/i) -``` - - - - -```jsx -import { render, screen } from '@testing-library/react' - -render() -const aboutAnchorNode = screen.getByText(/about/i) -``` - - - - -```js -cy.findByText(/about/i).should('exist') -``` - - - - -It also works with `input`s whose `type` attribute is either `submit` or -`button`: - -```js - -``` - -> **Note** -> -> See [`getByLabelText`](#bylabeltext) for more details on how and when to use -> the `selector` option - -The `ignore` option accepts a query selector. If the -[`node.matches`](https://developer.mozilla.org/en-US/docs/Web/API/Element/matches) -returns true for that selector, the node will be ignored. This defaults to -`'script'` because generally you don't want to select script tags, but if your -content is in an inline script file, then the script tag could be returned. - -If you'd rather disable this behavior, set `ignore` to `false`. - -### `ByAltText` - -> getByAltText, queryByAltText, getAllByAltText, queryAllByAltText, -> findByAltText, findAllByAltText - -```typescript -getByAltText( - container: HTMLElement, // if you're using `screen`, then skip this argument - text: TextMatch, - options?: { - exact?: boolean = true, - normalizer?: NormalizerFn, - }): HTMLElement -``` - -This will return the element (normally an ``) that has the given `alt` -text. Note that it only supports elements which accept an `alt` attribute: -[``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img), -[``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input), -and [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/area) -(intentionally excluding -[``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/applet) -as it's deprecated). - -```html -Incredibles 2 Poster -``` - - - - -```js -import { screen } from '@testing-library/dom' - -const incrediblesPosterImg = screen.getByAltText(/incredibles.*? poster/i) -``` - - - - -```jsx -import { render, screen } from '@testing-library/react' - -render() -const incrediblesPosterImg = screen.getByAltText(/incredibles.*? poster/i) -``` - - - - -```js -cy.findByAltText(/incredibles.*? poster/i).should('exist') -``` - - - - -### `ByTitle` - -> getByTitle, queryByTitle, getAllByTitle, queryAllByTitle, findByTitle, -> findAllByTitle - -```typescript -getByTitle( - container: HTMLElement, // if you're using `screen`, then skip this argument - title: TextMatch, - options?: { - exact?: boolean = true, - normalizer?: NormalizerFn, - }): HTMLElement -``` - -Returns the element that has the matching `title` attribute. - -Will also find a `title` element within an SVG. - -```html - - - Close - - -``` - - - - -```js -import { screen } from '@testing-library/dom' - -const deleteElement = screen.getByTitle('Delete') -const closeElement = screen.getByTitle('Close') -``` - - - - -```jsx -import { render, screen } from '@testing-library/react' - -render() -const deleteElement = screen.getByTitle('Delete') -const closeElement = screen.getByTitle('Close') -``` - - - - -```js -cy.findByTitle('Delete').should('exist') -cy.findByTitle('Close').should('exist') -``` - - - - -### `ByDisplayValue` - -> getByDisplayValue, queryByDisplayValue, getAllByDisplayValue, -> queryAllByDisplayValue, findByDisplayValue, findAllByDisplayValue - -```typescript -getByDisplayValue( - container: HTMLElement, // if you're using `screen`, then skip this argument - value: TextMatch, - options?: { - exact?: boolean = true, - normalizer?: NormalizerFn, - }): HTMLElement -``` - -Returns the `input`, `textarea`, or `select` element that has the matching -display value. - -#### `input` - -```html - -``` - -```js -document.getElementById('lastName').value = 'Norris' -``` - - - - -```js -import { screen } from '@testing-library/dom' - -const lastNameInput = screen.getByDisplayValue('Norris') -``` - - - - -```jsx -import { render, screen } from '@testing-library/react' - -render() -const lastNameInput = screen.getByDisplayValue('Norris') -``` - - - - -```js -cy.findByDisplayValue('Norris').should('exist') -``` - - - - -#### `textarea` - -```html - + +``` + +```js +const inputNode = screen.getByLabelText('Username', { selector: 'input' }) +``` + +> **Note** +> +> `getByLabelText` will not work in the case where a `for` attribute on a +> `