Skip to content

Commit 0e8a058

Browse files
danieljcafonsotimdeschryverMatanBobi
authored
docs(solid-testing-library): add solid testing library docs (#1370)
* docs(solid-testing-library): add solid testing library * Update docs/solid-testing-library/api.mdx Co-authored-by: Tim Deschryver <[email protected]> * Update docs/solid-testing-library/api.mdx Co-authored-by: Matan Borenkraout <[email protected]> * Update docs/solid-testing-library/api.mdx Co-authored-by: Matan Borenkraout <[email protected]> * docs: add info to netlify.toml and address pr comments --------- Co-authored-by: Tim Deschryver <[email protected]> Co-authored-by: Matan Borenkraout <[email protected]>
1 parent 334201d commit 0e8a058

File tree

5 files changed

+244
-0
lines changed

5 files changed

+244
-0
lines changed

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/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

netlify.toml

+3
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,6 @@
121121
[[redirects]]
122122
from = "/user-event/"
123123
to = "/docs/user-event/intro"
124+
[[redirects]]
125+
from = "/solid/"
126+
to = "/docs/solid-testing-library/intro"

sidebars.js

+6
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,12 @@ module.exports = {
165165
'react-native-testing-library/setup',
166166
],
167167
},
168+
{
169+
'Solid Testing Library': [
170+
'solid-testing-library/intro',
171+
'solid-testing-library/api',
172+
],
173+
},
168174
'cypress-testing-library/intro',
169175
'pptr-testing-library/intro',
170176
'testcafe-testing-library/intro',

0 commit comments

Comments
 (0)