From 13356d6777e1276147662790830ddf534e53bda8 Mon Sep 17 00:00:00 2001 From: Michael Cousins Date: Sat, 17 Feb 2024 13:33:11 -0500 Subject: [PATCH 1/4] docs(svelte-testing-library): update API docs for v5 release --- docs/svelte-testing-library/api.mdx | 352 +++++++++++++++++++++------- 1 file changed, 262 insertions(+), 90 deletions(-) diff --git a/docs/svelte-testing-library/api.mdx b/docs/svelte-testing-library/api.mdx index 0c3851b2f..310c4ec89 100644 --- a/docs/svelte-testing-library/api.mdx +++ b/docs/svelte-testing-library/api.mdx @@ -4,149 +4,321 @@ title: API sidebar_label: API --- -- [`@testing-library/dom`](#testing-library-dom) -- [`render`](#render) -- [`cleanup`](#cleanup) -- [`act`](#act-async) -- [`fireEvent`](#fireevent-async) +## `@testing-library/svelte` ---- +This library re-exports everything from DOM Testing Library. Check the +[`@testing-library/dom` API documentation][@testing-library/dom] to see what +goodies you can use. -## `@testing-library/dom` +:::info -This library re-exports everything from the DOM Testing Library -(`@testing-library/dom`). See the [documentation](queries/about.mdx) to see what -goodies you can use. +Unlike other methods which are passed through unmodified, +[`fireEvent`](#fireevent-async) is an `async` method when imported from +`@testing-library/svelte` to ensure Svelte applies new changes to the DOM after +the event is fired. + +::: + +```js +import {screen, within, fireEvent /* ... */} from '@testing-library/svelte' +``` -📝 `fireEvent` is an `async` method when imported from -`@testing-library/svelte`. This is because it calls [`tick`][svelte-tick] which -tells Svelte to apply any new changes to the DOM. +[@testing-library/dom]: ../dom-testing-library/api.mdx ## `render` +Render your component to the DOM with Svelte. By default, the component will be +rendered into a `
` appended to `document.body`. + ```js import {render} from '@testing-library/svelte' +import MyComponent from './MyComponent.svelte' -const view = render(YourComponent, {ComponentOptions}, {RenderOptions}) +const result = render(MyComponent, componentOptions, renderOptions) ``` ### Component Options -These are the options you pass when instantiating your Svelte `Component`. -Please refer to the -[Client-side component API](https://svelte.dev/docs#run-time-client-side-component-api-creating-a-component). +You may customize how the component is created and mounted. These options are +passed directly to Svelte. -📝 If the only option you're passing in is `props`, then you can just pass them -in directly. +If you only need to send props to your component, you may pass props directly, +as long as those props don't share a name with a component option. ```js -// With options. -const view = render(YourComponent, { - target: MyTarget, +// pass props to component +render(YourComponent, {myProp: 'value'}) + +// pass props and other options to component +render(YourComponent, { props: {myProp: 'value'}, + context: new Map([[('theme': 'dark')]]), }) - -// Props only. -const view = render(YourComponent, {myProp: 'value'}) ``` +The most common options you will need are: + +| Option | Description | Default | +| --------- | ------------------------------------------------------- | ----------------------------------- | +| `props` | Props to pass to the component. | N/A | +| `context` | A `Map` of context values to render the component with. | N/A | +| `target` | An `HTMLElement` to render the component into. | `
` appended to `document.body` | + +If you specify the `target` option, the `target` element will _not_ be appended +to `document.body` automatically, and it will be used as the base element for +[bound queries](#queries) and [`debug`](#debug). + +Refer to the [Svelte client-side component API docs][svelte-component-api] for +all available options. + +[svelte-component-api]: https://svelte.dev/docs/client-side-component-api + ### Render Options -| Option | Description | Default | -| ----------- | ----------------------------------------------------------------------------------- | --------------- | -| `container` | The HTML element the component is mounted into. | `document.body` | -| `queries` | Queries to bind to the container. See [within](dom-testing-library/api-within.mdx). | `null` | +You may also customize how Svelte Testing Library renders your component. Most +of the time, you shouldn't need to modify these options. -### Results +:::caution -| Result | Description | -| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `container` | The HTML element the component is mounted into. | -| `component` | The newly created Svelte component. Generally, this should only be used when testing exported functions, or when you're testing developer facing API's. Outside of said cases avoid using the component directly to build tests, instead of interacting with the rendered Svelte component, work with the DOM. Have a read of [Avoid the Test User](https://kentcdodds.com/blog/avoid-the-test-user) by Kent C. Dodds to understand the difference between the **end user** and **developer user**. | -| `debug` | Logs the `container` using [prettyDom](dom-testing-library/api-debugging.mdx/#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](queries/about.mdx) that are bound to the `container`. If you pass in `query` arguments than this will be those, otherwise all. | +Prior to `@testing-library/svelte@5.0.0`, the `baseElement` option was named +`container`. -## `cleanup` +::: + +| Option | Description | Default | +| ------------- | --------------------------------------------------- | ------------------------------------------ | +| `baseElement` | The base element for queries and [`debug`](#debug). | `componentOptions.target ?? document.body` | +| `queries` | [Custom Queries][custom-queries]. | N/A | + +[custom-queries]: ../dom-testing-library/api-custom-queries.mdx + +### Render Results + +| Result | Description | +| ----------------------------- | ----------------------------------------------------- | +| [`baseElement`](#baseelement) | The base DOM element used for queries. | +| [`component`](#component) | The created Svelte component. | +| [`container`](#container) | The DOM element the component is mounted to. | +| [`debug`](#debug) | Logs the `baseElement` using [prettyDom][pretty-dom]. | +| [`rerender`](#rerender) | Update the component's props . | +| [`unmount`](#unmount) | Unmount and destroy the component. | +| [`...queries`](#queries) | [Query functions][queries] bound to `baseElement`. | + +[pretty-dom]: ../dom-testing-library/api-debugging.mdx#prettydom +[queries]: ../queries/about.mdx + +#### `baseElement` + +_Added in `@testing-library/svelte@5.0.0`_ + +The base DOM element that queries are bound to. Corresponds to +`renderOptions.baseElement`. + +#### `container` + +The DOM element the component is mounted in. Corresponds to +`componentOptions.target`. In general, avoid using `container` to query for +elements; use [testing-library queries][queries] instead. -> This is called automatically if your testing framework (such as mocha, Jest or -> Jasmine) injects a global `afterEach()` function into the testing environment. -> If not, you will need to call `cleanup()` after each test. +:::tip -Unmounts the component from the container and destroys the container. +Use `container.firstChild` to get the first rendered element of your component. -📝 When you import anything from the library, this automatically runs after each -test. If you'd like to disable this then set `process.env.STL_SKIP_AUTO_CLEANUP` -to true or import `dont-clean-up-after-each` from the library. +::: + +:::caution + +Prior to `@testing-library/svelte@5.0.0`, `container` was set to the base +element, which made the first rendered element of the component +`container.firstChild.firstChild`. + +::: + +#### `component` + +The Svelte component instance. See the [Svelte component +API][svelte-component-api] for more details. + +:::tip + +Avoid using `component` except to test developer facing API's, like exported +functions. Instead, prefer of interacting with the DOM. Read [Avoid the Test +User][test-user] by Kent C. Dodds to understand the difference between the **end +user** and **developer user**. + +::: + +[test-user]: https://kentcdodds.com/blog/avoid-the-test-user + +#### `debug` + +Log any passed element, or the `baseElement` by default, using +[prettyDOM][pretty-dom]. + +:::tip + +If your `baseElement` is the default `document.body`, we recommend using +[`screen.debug`][screen-debug] rather than the bound `debug`.. ```js -import {render, cleanup} from '@testing-library/svelte' +import {render, screen} from '@testing-library/svelte' -afterEach(() => { - cleanup() -}) // Default on import: runs it after each test. +render(MyComponent, {myProp: 'value'}) -render(YourComponent) +screen.debug() +``` + +::: + +```js +const {debug} = render(MyComponent, {myProp: 'value'}) + +const button = screen.getByRole('button') + +// log the baseElement +debug() + +// log a specific element +debug(button) +``` + +[screen-debug]: ../dom-testing-library/api-debugging.mdx#screendebug -cleanup() // Or like this for more control. +#### `rerender` + +Update one or more of the component's props. + +```js +const {rerender} = render(MyComponent, {myProp: 'value'}) + +await rerender({myProp: 'new value'})) ``` -## `act` (`async`) +:::caution + +Prior to `@testing-library/svelte@5.0.0`, `rerender` would umount the component. +To update props witohut unmounting in earlier versions of +`@testing-library/svelte`, use `component.$set` and [`act`](#act-async): + +```js +const {component} = render(MyComponent, {myProp: 'value'}) + +await act(() => component.$set({myProp: 'new value'})) +``` + +::: + +#### `unmount` + +Unmount and destroy the Svelte component. + +```js +const {unmount} = render(MyComponent, {myProp: 'value'}) + +unmount() +``` -An `async` helper method that takes in a `function` or `Promise` that is -immediately called/resolved, and then calls [`tick`][svelte-tick] so all pending -state changes are flushed, and the view now reflects any changes made to the -DOM. +#### Queries -## `fireEvent` (`async`) +[Query functions][queries] bound to the `baseElement`. If you passed [custom +queries][custom-queries] to `render`, those will be available instead of the +default queries. -Calls `@testing-library/dom` [fireEvent](dom-testing-library/api-events.mdx). It -is an `async` method due to calling [`tick`][svelte-tick] which tells Svelte to -flush all pending state changes, basically it updates the DOM to reflect the new -changes. +:::tip -**Component** +If your `baseElement` is the default `document.body`, we recommend using +[`screen`][screen] rather than bound queries. -```html - +render(MyComponent, {myProp: 'value'}) - +const button = screen.getByRole('button') ``` -**Test** +::: ```js -import '@testing-library/jest-dom' +const {getByRole} = render(MyComponent, {myProp: 'value'}) -import {render, fireEvent, screen} from '@testing-library/svelte' +const button = getByRole('button') +``` + +[screen]: ../queries/about.mdx#screen -import Comp from '..' +## `cleanup` -test('count increments when button is clicked', async () => { - render(Comp) - const button = screen.getByText('Count is 0') +Unmount all components and remove any elements added to `document.body`. - // Option 1. - await fireEvent.click(button) - expect(button).toHaveTextContent('Count is 1') +:::info + +`cleanup` is called automatically if your testing framework adds a global +`afterEach` method (e.g. Mocha, Jest, or Jasmine), or if you use +`import '@testing-library/svelte/vitest'` in your [Vitest setup +file][vitest-setup]. + +If you'd like to disable automatic cleanup in a framework that uses the +`afterEach` global method, set `process.env.STL_SKIP_AUTO_CLEANUP`. + +::: + +```js +import {render, cleanup} from '@testing-library/svelte' - // Option 2. - await fireEvent( - button, - new MouseEvent('click', { - bubbles: true, - cancelable: true, - }), - ) - expect(button).toHaveTextContent('Count is 2') +// Default: runs after each test +afterEach(async () => { + cleanup() +}) + +render(YourComponent) + +// Called manually for more control +cleanup() +``` + +[vitest-setup]: ./setup.mdx#vitest + +## `act` (async) + +Ensure all pending updates from Svelte are applied to the DOM. Optionally, you +may pass a function to be called before flushing updates. If the function +returns a `Promise`, that promise will be resolved before flushing updates. + +Uses Svelte's [`tick`][svelte-tick] method to flush updates. + +```js +import {act, render} from '@testing-library/svelte' + +const {component} = render(MyComponent) + +act(() => { + component.updateSomething() }) ``` [svelte-tick]: https://svelte.dev/docs/svelte#tick + +## `fireEvent` (async) + +Call DOM Testing Library's [`fireEvent`][fire-event], wrapped in +[`act`](#act-async) to ensure Svelte updates the DOM. + +:::tip + +Where possible, we recommend [`@testing-library/user-event`][user-event] instead +of `fireEvent`. + +::: + +```js +import {fireEvent, render, screen} from '@testing-library/svelte' + +render(MyComponent) + +const button = screen.getByRole('button') +await fireEvent.click(button) +``` + +[fire-event]: ../dom-testing-library/api-events.mdx +[user-event]: ../user-event/intro.mdx From 864b58654c22c1abbf3aafd84cd6977587700a3e Mon Sep 17 00:00:00 2001 From: Michael Cousins Date: Sun, 18 Feb 2024 12:28:51 -0500 Subject: [PATCH 2/4] fixup: polish and simplify --- docs/svelte-testing-library/api.mdx | 135 +++++++++++++--------------- 1 file changed, 60 insertions(+), 75 deletions(-) diff --git a/docs/svelte-testing-library/api.mdx b/docs/svelte-testing-library/api.mdx index 310c4ec89..4ce30605d 100644 --- a/docs/svelte-testing-library/api.mdx +++ b/docs/svelte-testing-library/api.mdx @@ -4,24 +4,13 @@ title: API sidebar_label: API --- -## `@testing-library/svelte` +`@testing-library/svelte` re-exports everything from +[`@testing-library/dom`][@testing-library/dom], as well as: -This library re-exports everything from DOM Testing Library. Check the -[`@testing-library/dom` API documentation][@testing-library/dom] to see what -goodies you can use. - -:::info - -Unlike other methods which are passed through unmodified, -[`fireEvent`](#fireevent-async) is an `async` method when imported from -`@testing-library/svelte` to ensure Svelte applies new changes to the DOM after -the event is fired. - -::: - -```js -import {screen, within, fireEvent /* ... */} from '@testing-library/svelte' -``` +- [`render`](#render) +- [`act`](#act) +- [`cleanup`](#cleanup) +- [`fireEvent` (async)](#fireevent-async) [@testing-library/dom]: ../dom-testing-library/api.mdx @@ -94,31 +83,32 @@ Prior to `@testing-library/svelte@5.0.0`, the `baseElement` option was named ### Render Results -| Result | Description | -| ----------------------------- | ----------------------------------------------------- | -| [`baseElement`](#baseelement) | The base DOM element used for queries. | -| [`component`](#component) | The created Svelte component. | -| [`container`](#container) | The DOM element the component is mounted to. | -| [`debug`](#debug) | Logs the `baseElement` using [prettyDom][pretty-dom]. | -| [`rerender`](#rerender) | Update the component's props . | -| [`unmount`](#unmount) | Unmount and destroy the component. | -| [`...queries`](#queries) | [Query functions][queries] bound to `baseElement`. | +| Result | Description | +| ----------------------------- | ---------------------------------------------------------- | +| [`baseElement`](#baseelement) | The base DOM element used for queries. | +| [`component`](#component) | The mounted Svelte component. | +| [`container`](#container) | The DOM element the component is mounted to. | +| [`debug`](#debug) | Log elements using [`prettyDOM`][pretty-dom]. | +| [`rerender`](#rerender) | Update the component's props. | +| [`unmount`](#unmount) | Unmount and destroy the component. | +| [`...queries`](#queries) | [Query functions][query-functions] bound to `baseElement`. | [pretty-dom]: ../dom-testing-library/api-debugging.mdx#prettydom -[queries]: ../queries/about.mdx +[query-functions]: ../queries/about.mdx #### `baseElement` _Added in `@testing-library/svelte@5.0.0`_ The base DOM element that queries are bound to. Corresponds to -`renderOptions.baseElement`. +`renderOptions.baseElement`. If you do not use `componentOptions.target` nor +`renderOptions.baseElement`, this will be `document.body`. #### `container` The DOM element the component is mounted in. Corresponds to -`componentOptions.target`. In general, avoid using `container` to query for -elements; use [testing-library queries][queries] instead. +`componentOptions.target`. In general, avoid using `container` directly to query +for elements; use [testing-library queries][query-functions] instead. :::tip @@ -129,8 +119,8 @@ Use `container.firstChild` to get the first rendered element of your component. :::caution Prior to `@testing-library/svelte@5.0.0`, `container` was set to the base -element, which made the first rendered element of the component -`container.firstChild.firstChild`. +elemen. Use `container.firstChild.firstChild` to get the first rendered element +of the component in earlier versions. ::: @@ -142,9 +132,9 @@ API][svelte-component-api] for more details. :::tip Avoid using `component` except to test developer facing API's, like exported -functions. Instead, prefer of interacting with the DOM. Read [Avoid the Test -User][test-user] by Kent C. Dodds to understand the difference between the **end -user** and **developer user**. +functions. Instead, interact with the DOM. Read [Avoid the Test User][test-user] +by Kent C. Dodds to understand the difference between the **end user** and +**developer user**. ::: @@ -152,33 +142,30 @@ user** and **developer user**. #### `debug` -Log any passed element, or the `baseElement` by default, using -[prettyDOM][pretty-dom]. +Log the `baseElement` or a given element using [`prettyDOM`][pretty-dom]. :::tip If your `baseElement` is the default `document.body`, we recommend using -[`screen.debug`][screen-debug] rather than the bound `debug`.. - -```js -import {render, screen} from '@testing-library/svelte' - -render(MyComponent, {myProp: 'value'}) - -screen.debug() -``` +[`screen.debug`][screen-debug]. ::: ```js +import {render, screen} from '@testing-library/svelte' + const {debug} = render(MyComponent, {myProp: 'value'}) const button = screen.getByRole('button') -// log the baseElement +// log `document.body` +screen.debug() + +// log your custom `target` or `baseElement` debug() // log a specific element +screen.debug(button) debug(button) ``` @@ -186,7 +173,7 @@ debug(button) #### `rerender` -Update one or more of the component's props. +Update one or more of the component's props and wait for Svelte to update. ```js const {rerender} = render(MyComponent, {myProp: 'value'}) @@ -196,9 +183,9 @@ await rerender({myProp: 'new value'})) :::caution -Prior to `@testing-library/svelte@5.0.0`, `rerender` would umount the component. -To update props witohut unmounting in earlier versions of -`@testing-library/svelte`, use `component.$set` and [`act`](#act-async): +Prior to `@testing-library/svelte@5.0.0`, calling `rerender` would destroy and +remount the component. Use `component.$set` and [`act`](#act) to update props in +earlier versions: ```js const {component} = render(MyComponent, {myProp: 'value'}) @@ -220,28 +207,26 @@ unmount() #### Queries -[Query functions][queries] bound to the `baseElement`. If you passed [custom -queries][custom-queries] to `render`, those will be available instead of the -default queries. +[Query functions][query-functions] bound to the [`baseElement`](#baseelement). +If you passed [custom queries][custom-queries] to `render`, those will be +available instead of the default queries. :::tip -If your `baseElement` is the default `document.body`, we recommend using -[`screen`][screen] rather than bound queries. +If your [`baseElement`](#baseelement) is the default `document.body`, we +recommend using [`screen`][screen] rather than bound queries. + +::: ```js import {render, screen} from '@testing-library/svelte' -render(MyComponent, {myProp: 'value'}) +const {getByRole} = render(MyComponent, {myProp: 'value'}) +// query `document.body` const button = screen.getByRole('button') -``` - -::: - -```js -const {getByRole} = render(MyComponent, {myProp: 'value'}) +// query using a custom `target` or `baseElement` const button = getByRole('button') ``` @@ -249,17 +234,17 @@ const button = getByRole('button') ## `cleanup` -Unmount all components and remove any elements added to `document.body`. +Destroy all components and remove any elements added to `document.body`. :::info `cleanup` is called automatically if your testing framework adds a global `afterEach` method (e.g. Mocha, Jest, or Jasmine), or if you use `import '@testing-library/svelte/vitest'` in your [Vitest setup -file][vitest-setup]. +file][vitest-setup]. Usually, you shouldn't need to call `cleanup` yourself. -If you'd like to disable automatic cleanup in a framework that uses the -`afterEach` global method, set `process.env.STL_SKIP_AUTO_CLEANUP`. +If you'd like to disable automatic cleanup in a framework that uses a global +`afterEach` method, set `process.env.STL_SKIP_AUTO_CLEANUP`. ::: @@ -267,7 +252,7 @@ If you'd like to disable automatic cleanup in a framework that uses the import {render, cleanup} from '@testing-library/svelte' // Default: runs after each test -afterEach(async () => { +afterEach(() => { cleanup() }) @@ -279,20 +264,20 @@ cleanup() [vitest-setup]: ./setup.mdx#vitest -## `act` (async) +## `act` Ensure all pending updates from Svelte are applied to the DOM. Optionally, you -may pass a function to be called before flushing updates. If the function -returns a `Promise`, that promise will be resolved before flushing updates. +may pass a function to be called before updates are applied. If the function +returns a `Promise`, it will be resolved first. -Uses Svelte's [`tick`][svelte-tick] method to flush updates. +Uses Svelte's [`tick`][svelte-tick] method to apply updates. ```js import {act, render} from '@testing-library/svelte' const {component} = render(MyComponent) -act(() => { +await act(() => { component.updateSomething() }) ``` @@ -301,8 +286,8 @@ act(() => { ## `fireEvent` (async) -Call DOM Testing Library's [`fireEvent`][fire-event], wrapped in -[`act`](#act-async) to ensure Svelte updates the DOM. +Fire an event and wait for Svelte to update the DOM. An asynchronous wrapper of +DOM Testing Library's [`fireEvent`][fire-event]. :::tip From 3483124aed03b4a66a5f1140e2ede45f906fedaa Mon Sep 17 00:00:00 2001 From: Michael Cousins Date: Sun, 18 Feb 2024 17:16:58 -0500 Subject: [PATCH 3/4] fixup: typo --- docs/svelte-testing-library/api.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/svelte-testing-library/api.mdx b/docs/svelte-testing-library/api.mdx index 4ce30605d..597a9e6db 100644 --- a/docs/svelte-testing-library/api.mdx +++ b/docs/svelte-testing-library/api.mdx @@ -119,7 +119,7 @@ Use `container.firstChild` to get the first rendered element of your component. :::caution Prior to `@testing-library/svelte@5.0.0`, `container` was set to the base -elemen. Use `container.firstChild.firstChild` to get the first rendered element +element. Use `container.firstChild.firstChild` to get the first rendered element of the component in earlier versions. ::: From 02fc3089141c40ab49fc30fae670e289f19ad013 Mon Sep 17 00:00:00 2001 From: Michael Cousins Date: Sat, 20 Apr 2024 16:19:04 -0400 Subject: [PATCH 4/4] fixup: fix typos Co-authored-by: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com> --- docs/svelte-testing-library/api.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/svelte-testing-library/api.mdx b/docs/svelte-testing-library/api.mdx index 597a9e6db..4355dc682 100644 --- a/docs/svelte-testing-library/api.mdx +++ b/docs/svelte-testing-library/api.mdx @@ -35,10 +35,10 @@ If you only need to send props to your component, you may pass props directly, as long as those props don't share a name with a component option. ```js -// pass props to component +// pass props to the component render(YourComponent, {myProp: 'value'}) -// pass props and other options to component +// pass props and other options to the component render(YourComponent, { props: {myProp: 'value'}, context: new Map([[('theme': 'dark')]]), @@ -131,7 +131,7 @@ API][svelte-component-api] for more details. :::tip -Avoid using `component` except to test developer facing API's, like exported +Avoid using `component` except to test developer-facing APIs, like exported functions. Instead, interact with the DOM. Read [Avoid the Test User][test-user] by Kent C. Dodds to understand the difference between the **end user** and **developer user**.