Skip to content

Commit 9772faf

Browse files
authored
Merge branch 'main' into update-svelte-api
2 parents 3483124 + 93b87b8 commit 9772faf

File tree

12 files changed

+591
-110
lines changed

12 files changed

+591
-110
lines changed

.all-contributorsrc

+9
Original file line numberDiff line numberDiff line change
@@ -2628,6 +2628,15 @@
26282628
"doc",
26292629
"review"
26302630
]
2631+
},
2632+
{
2633+
"login": "kettanaito",
2634+
"name": "Artem Zakharchenko",
2635+
"avatar_url": "https://avatars.githubusercontent.com/u/14984911?v=4",
2636+
"profile": "https://kettanaito.com",
2637+
"contributions": [
2638+
"doc"
2639+
]
26312640
}
26322641
],
26332642
"contributorsPerLine": 7,

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,7 @@ Thanks goes to these wonderful people
508508
<td align="center" valign="top" width="14.28%"><a href="https://github.com/smk267"><img src="https://avatars.githubusercontent.com/u/88115182?v=4?s=100" width="100px;" alt="smk267"/><br /><sub><b>smk267</b></sub></a><br /><a href="#infra-smk267" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
509509
<td align="center" valign="top" width="14.28%"><a href="https://www.dylangordon.co.nz/"><img src="https://avatars.githubusercontent.com/u/3656794?v=4?s=100" width="100px;" alt="Dylan Gordon"/><br /><sub><b>Dylan Gordon</b></sub></a><br /><a href="https://github.com/testing-library/testing-library-docs/commits?author=agentdylan" title="Documentation">📖</a></td>
510510
<td align="center" valign="top" width="14.28%"><a href="https://michael.cousins.io"><img src="https://avatars.githubusercontent.com/u/2963448?v=4?s=100" width="100px;" alt="Michael Cousins"/><br /><sub><b>Michael Cousins</b></sub></a><br /><a href="https://github.com/testing-library/testing-library-docs/commits?author=mcous" title="Documentation">📖</a> <a href="https://github.com/testing-library/testing-library-docs/pulls?q=is%3Apr+reviewed-by%3Amcous" title="Reviewed Pull Requests">👀</a></td>
511+
<td align="center" valign="top" width="14.28%"><a href="https://kettanaito.com"><img src="https://avatars.githubusercontent.com/u/14984911?v=4?s=100" width="100px;" alt="Artem Zakharchenko"/><br /><sub><b>Artem Zakharchenko</b></sub></a><br /><a href="https://github.com/testing-library/testing-library-docs/commits?author=kettanaito" title="Documentation">📖</a></td>
511512
</tr>
512513
</tbody>
513514
</table>

docs/dom-testing-library/install.mdx

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ install the wrapper:
2828
- [Puppeteer Testing Library](pptr-testing-library/intro.mdx)
2929
- [Testcafe Testing Library](testcafe-testing-library/intro.mdx)
3030
- [Nightwatch Testing Library](nightwatch-testing-library/intro.mdx)
31+
- [Solid Testing Library](solid-testing-library/intro.mdx)
3132

3233
## Ecosystem
3334

docs/queries/about.mdx

+3-6
Original file line numberDiff line numberDiff line change
@@ -317,12 +317,9 @@ can contain options that affect the precision of string matching:
317317

318318
- `exact`: Defaults to `true`; matches full strings, case-sensitive. When false,
319319
matches substrings and is not case-sensitive.
320-
- `exact` has no effect on `regex` or `function` arguments.
321-
- `exact` has no effect on accessible names specified with the `name` option
322-
of `*byRole` queries. You can use a regex for fuzzy matching on accessible
323-
names.
324-
- In most cases using a regex instead of a string gives you more control over
325-
fuzzy matching and should be preferred over `{ exact: false }`.
320+
- it has no effect when used together with `regex` or `function` arguments.
321+
- in most cases, using a regex instead of a string combined with `{ exact: false }`
322+
gives you more control over fuzzy matching so it should be preferred.
326323
- `normalizer`: An optional function which overrides normalization behavior. See
327324
[`Normalization`](#normalization).
328325

docs/react-testing-library/api.mdx

+7-2
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,12 @@ your components.
107107

108108
### `legacyRoot`
109109

110+
:::warning
111+
112+
This option is only available when tests run with React 18 and earlier.
113+
114+
:::
115+
110116
By default we'll render with support for concurrent features (i.e.
111117
[`ReactDOMClient.createRoot`](https://reactjs.org/docs/react-dom-client.html#createroot)).
112118
However, if you're dealing with a legacy app that requires rendering like in
@@ -340,7 +346,7 @@ function renderHook<
340346
Props,
341347
Q extends Queries = typeof queries,
342348
Container extends Element | DocumentFragment = HTMLElement,
343-
BaseElement extends Element | DocumentFragment = Container,
349+
BaseElement extends Element | DocumentFragment = Container
344350
>(
345351
render: (initialProps: Props) => Result,
346352
options?: RenderHookOptions<Props, Q, Container, BaseElement>,
@@ -473,4 +479,3 @@ configure({reactStrictMode: true})
473479
474480
When enabled, [`<StrictMode>`](https://react.dev/reference/react/StrictMode) is
475481
rendered around the inner element. Defaults to `false`.
476-

docs/react-testing-library/example-intro.mdx

+17-14
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,24 @@ test('loads and displays greeting', async () => {
6565

6666
See the following sections for a detailed breakdown of the test
6767

68+
:::note
69+
We recommend using the
70+
[Mock Service Worker (MSW)](https://github.com/mswjs/msw) library to
71+
declaratively mock API communication in your tests instead of stubbing
72+
`window.fetch`, or relying on third-party adapters.
73+
:::
74+
6875
```jsx title="__tests__/fetch.test.jsx"
6976
import React from 'react'
70-
import {rest} from 'msw'
77+
import {http, HttpResponse} from 'msw'
7178
import {setupServer} from 'msw/node'
7279
import {render, fireEvent, screen} from '@testing-library/react'
7380
import '@testing-library/jest-dom'
7481
import Fetch from '../fetch'
7582

7683
const server = setupServer(
77-
rest.get('/greeting', (req, res, ctx) => {
78-
return res(ctx.json({greeting: 'hello there'}))
84+
http.get('/greeting', () => {
85+
return HttpResponse.json({greeting: 'hello there'})
7986
}),
8087
)
8188

@@ -96,8 +103,8 @@ test('loads and displays greeting', async () => {
96103

97104
test('handles server error', async () => {
98105
server.use(
99-
rest.get('/greeting', (req, res, ctx) => {
100-
return res(ctx.status(500))
106+
http.get('/greeting', () => {
107+
return new HttpResponse(null, {status: 500})
101108
}),
102109
)
103110

@@ -112,10 +119,6 @@ test('handles server error', async () => {
112119
})
113120
```
114121

115-
> We recommend using [Mock Service Worker](https://github.com/mswjs/msw) library
116-
> to declaratively mock API communication in your tests instead of stubbing
117-
> `window.fetch`, or relying on third-party adapters.
118-
119122
---
120123

121124
## Step-By-Step
@@ -127,7 +130,7 @@ test('handles server error', async () => {
127130
import React from 'react'
128131

129132
// import API mocking utilities from Mock Service Worker
130-
import {rest} from 'msw'
133+
import {http, HttpResponse} from 'msw'
131134
import {setupServer} from 'msw/node'
132135

133136
// import react-testing methods
@@ -156,9 +159,9 @@ component makes.
156159
// declare which API requests to mock
157160
const server = setupServer(
158161
// capture "GET /greeting" requests
159-
rest.get('/greeting', (req, res, ctx) => {
162+
http.get('/greeting', (req, res, ctx) => {
160163
// respond using a mocked JSON body
161-
return res(ctx.json({greeting: 'hello there'}))
164+
return HttpResponse.json({greeting: 'hello there'})
162165
}),
163166
)
164167

@@ -176,8 +179,8 @@ test('handles server error', async () => {
176179
server.use(
177180
// override the initial "GET /greeting" request handler
178181
// to return a 500 Server Error
179-
rest.get('/greeting', (req, res, ctx) => {
180-
return res(ctx.status(500))
182+
http.get('/greeting', (req, res, ctx) => {
183+
return new HttpResponse(null, {status: 500})
181184
}),
182185
)
183186

docs/solid-testing-library/api.mdx

+181
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
---
2+
id: api
3+
title: API
4+
sidebar_label: API
5+
---
6+
7+
Due to being inspired by the [preact-testing-library][preact-docs] you can check
8+
its page for more information.
9+
10+
[preact-docs]: ../preact-testing-library/intro.mdx
11+
12+
There are several key differences, to be aware of.
13+
14+
- [`render`](#render)
15+
- [`renderHook`](#renderHook)
16+
- [`renderDirective`](#renderDirective)
17+
- [`Async methods`](#async-methods)
18+
- [`Know issues`](#known-issues)
19+
20+
## `render`
21+
22+
The `render` function takes in a function that returns a Solid Component, rather
23+
than simply the component itself.
24+
25+
```tsx
26+
const results = render(() => <YourComponent />, options)
27+
```
28+
29+
Solid.js does _not_ re-render, it merely executes side effects triggered by
30+
reactive state that change the DOM, therefore there is no `rerender` method. You
31+
can use global signals to manipulate your test component in a way that causes it
32+
to update.
33+
34+
In addition to the original API, the render function of this testing library
35+
supports a convenient `location` option that will set up an in-memory router
36+
pointing at the specified location. Since this setup is not synchronous, you
37+
need to first use asynchronous queries (`findBy`) after employing it:
38+
39+
```tsx
40+
it('uses params', async () => {
41+
const App = () => (
42+
<>
43+
<Route path="/ids/:id" component={() => <p>Id: {useParams()?.id}</p>} />
44+
<Route path="/" component={() => <p>Start</p>} />
45+
</>
46+
)
47+
const {findByText} = render(() => <App />, {location: 'ids/1234'})
48+
expect(await findByText('Id: 1234')).not.toBeFalsy()
49+
})
50+
```
51+
52+
It uses `@solidjs/router`, so if you want to use a different router, you should
53+
consider the `wrapper` option instead. If you attempt to use this without having
54+
the package installed, you will receive an error message.
55+
56+
## `renderHook`
57+
58+
Solid.js external reactive state does not require any DOM elements to run in, so
59+
our `renderHook` call to test hooks in the context of a component (if your hook
60+
does not require the context of a component, `createRoot` should suffice to test
61+
the reactive behavior; for convenience, we also have `createEffect`, which is
62+
described in the [`Async methods`](#async-methods) section) has no `container`,
63+
`baseElement` or queries in its options or return value. Instead, it has an
64+
`owner` to be used with
65+
[`runWithOwner`](https://www.solidjs.com/docs/latest/api#runwithowner) if
66+
required. It also exposes a `cleanup` function, though this is already
67+
automatically called after the test is finished.
68+
69+
```ts
70+
function renderHook<Args extends any[], Result>(
71+
hook: (...args: Args) => Result,
72+
options: {
73+
initialProps?: Args,
74+
wrapper?: Component<{ children: JSX.Element }>
75+
}
76+
) => {
77+
result: Result;
78+
owner: Owner | null;
79+
cleanup: () => void;
80+
}
81+
```
82+
83+
This can be used to easily test a hook / primitive:
84+
85+
```ts
86+
const {result} = renderHook(createResult)
87+
expect(result).toBe(true)
88+
```
89+
90+
If you are using a `wrapper` with `renderHook`, make sure it will **always**
91+
return `props.children` - especially if you are using a context with
92+
asynchronous code together with `<Show>`, because this is required to get the
93+
value from the hook and it is only obtained synchronously once and you will
94+
otherwise only get `undefined` and wonder why this is the case.
95+
96+
## `renderDirective`
97+
98+
Solid.js supports
99+
[custom directives](https://www.solidjs.com/docs/latest/api#use___), which is a
100+
convenient pattern to tie custom behavior to elements, so we also have a
101+
`renderDirective` call, which augments `renderHook` to take a directive as first
102+
argument, accept an `initialValue` for the argument and a `targetElement`
103+
(string, HTMLElement or function returning an HTMLElement) in the `options` and
104+
also returns `arg` and `setArg` to read and manipulate the argument of the
105+
directive.
106+
107+
```ts
108+
function renderDirective<
109+
Arg extends any,
110+
Elem extends HTMLElement
111+
>(
112+
directive: (ref: Elem, arg: Accessor<Arg>) => void,
113+
options?: {
114+
...renderOptions,
115+
initialValue: Arg,
116+
targetElement:
117+
| Lowercase<Elem['nodeName']>
118+
| Elem
119+
| (() => Elem)
120+
}
121+
): Result & { arg: Accessor<Arg>, setArg: Setter<Arg> };
122+
```
123+
124+
This allows for very effective and concise testing of directives:
125+
126+
```ts
127+
const {asFragment, setArg} = renderDirective(myDirective)
128+
expect(asFragment()).toBe('<div data-directive="works"></div>')
129+
setArg('perfect')
130+
expect(asFragment()).toBe('<div data-directive="perfect"></div>')
131+
```
132+
133+
## Async methods
134+
135+
Solid.js reactive changes are pretty instantaneous, so there is rarely need to
136+
use `waitFor(…)`, `await findByRole(…)` and other asynchronous queries to test
137+
the rendered result, except for transitions, suspense, resources and router
138+
navigation.
139+
140+
Solid.js manages side effects with different variants of `createEffect`. While
141+
you can use `waitFor` to test asynchronous effects, it uses polling instead of
142+
allowing Solid's reactivity to trigger the next step. In order to simplify
143+
testing those asynchronous effects, we have a `testEffect` helper that
144+
complements the hooks for directives and hooks:
145+
146+
```ts
147+
testEffect(fn: (done: (result: T) => void) => void, owner?: Owner): Promise<T>
148+
149+
// use it like this:
150+
test("testEffect allows testing an effect asynchronously", () => {
151+
const [value, setValue] = createSignal(0);
152+
return testEffect(done => createEffect((run: number = 0) => {
153+
if (run === 0) {
154+
expect(value()).toBe(0);
155+
setValue(1);
156+
} else if (run === 1) {
157+
expect(value()).toBe(1);
158+
done();
159+
}
160+
return run + 1;
161+
}));
162+
});
163+
```
164+
165+
It allows running the effect inside a defined owner that is received as an
166+
optional second argument. This can be useful in combination with `renderHook`,
167+
which gives you an owner field in its result. The return value is a Promise with
168+
the value given to the `done()` callback. You can either await the result for
169+
further assertions or return it to your test runner.
170+
171+
## Known issues
172+
173+
If you are using [`vitest`](https://vitest.dev/), then tests might fail, because
174+
the packages `solid-js`, and `@solidjs/router` (if used) need to be loaded only
175+
once, and they could be loaded both through the internal `vite` server and
176+
through node. Typical bugs that happen because of this is that dispose is
177+
supposedly undefined, or the router could not be loaded.
178+
179+
Since version 2.8.2, our vite plugin has gained the capability to configure
180+
everything for testing, so you should only need extra configuration for globals,
181+
coverage, etc.

docs/solid-testing-library/intro.mdx

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
---
2+
id: intro
3+
title: Intro
4+
sidebar_label: Introduction
5+
---
6+
7+
[Solid Testing Library on GitHub][gh]
8+
9+
> Inspired completely by [preact-testing-library][preact-docs]
10+
11+
[preact-docs]: ../preact-testing-library/intro.mdx
12+
[gh]: https://github.com/solidjs/solid-testing-library
13+
14+
```bash npm2yarn
15+
npm install --save-dev @solidjs/testing-library
16+
```
17+
18+
> This library is built on top of
19+
> [`DOM Testing Library`](dom-testing-library/intro.mdx) which is where most of
20+
> the logic behind the queries is.
21+
22+
## The Problem
23+
24+
You want to write tests for your Solid components so that they avoid including
25+
implementation details, and are maintainable in the long run.
26+
27+
## This Solution
28+
29+
The Solid Testing Library is a very lightweight solution for testing Solid
30+
components. Its primary guiding principle is:
31+
32+
> [The more your tests resemble the way your software is used, the more confidence they can give you.](https://twitter.com/kentcdodds/status/977018512689455106)
33+
34+
See the [Dom introduction][dom-solution-explainer] and [React
35+
introduction][react-solution-explainer] for a more in-depth explanation.
36+
37+
[dom-solution-explainer]: ../dom-testing-library/intro.mdx#this-solution
38+
[react-solution-explainer]: ../react-testing-library/intro.mdx#this-solution
39+
40+
**What this library is not**:
41+
42+
1. A test runner or framework.
43+
2. Specific to a testing framework.
44+
45+
If you using Jest we recommend using
46+
[solid-jest](https://github.com/solidjs/solid-jest) to properly resolve the
47+
browser version of Solid as Jest will default to the server version when run in
48+
Node.
49+
50+
💡 If you are using Jest or vitest, you may also be interested in installing
51+
`@testing-library/jest-dom` so you can use [the custom jest matchers][jest-dom].
52+
53+
[jest-dom]: ../ecosystem-jest-dom

0 commit comments

Comments
 (0)