API
preact-testing-library にインスパイアされているため、詳細についてはそのページをご確認ください。
いくつかの重要な違いがありますので、ご注意ください。
render
render
関数は、単にコンポーネント自体ではなく、Solid コンポーネントを返す関数を受け取ります。
const results = render(() => <YourComponent />, options)
Solid.js は再レンダリングを*行いません*。DOM を変更するリアクティブな状態によってトリガーされる副作用を実行するだけです。そのため、rerender
メソッドはありません。グローバルシグナルを使用して、更新されるようにテストコンポーネントを操作できます。
元の API に加えて、このテスティングライブラリの render 関数は、指定された場所を指すインメモリルーターを設定する便利な location
オプションをサポートしています。この設定は同期ではないため、使用後は最初に非同期クエリ(findBy
)を使用する必要があります
it('uses params', async () => {
const App = () => (
<>
<Route path="/ids/:id" component={() => <p>Id: {useParams()?.id}</p>} />
<Route path="/" component={() => <p>Start</p>} />
</>
)
const {findByText} = render(() => <App />, {location: 'ids/1234'})
expect(await findByText('Id: 1234')).not.toBeFalsy()
})
@solidjs/router
を使用しているため、別のルーターを使用する場合は、代わりに wrapper
オプションを検討する必要があります。パッケージをインストールせずにこれを使用しようとすると、エラーメッセージが表示されます。
renderHook
Solid.js の外部リアクティブ状態は、実行に DOM 要素を必要としないため、コンポーネントのコンテキストでフックをテストするための renderHook
呼び出し(フックがコンポーネントのコンテキストを必要としない場合、createRoot
でリアクティブな動作をテストするだけで十分です。便宜上、非同期メソッド
セクションで説明する createEffect
もあります)には、オプションまたは戻り値に container
、baseElement
、またはクエリがありません。代わりに、必要に応じて runWithOwner
で使用する owner
があります。また、cleanup
関数も公開していますが、これはテスト終了後に自動的に呼び出されます。
function renderHook<Args extends any[], Result>(
hook: (...args: Args) => Result,
options: {
initialProps?: Args,
wrapper?: Component<{ children: JSX.Element }>
}
) => {
result: Result;
owner: Owner | null;
cleanup: () => void;
}
これは、フック/プリミティブを簡単にテストするために使用できます
const {result} = renderHook(createResult)
expect(result).toBe(true)
renderHook
で wrapper
を使用している場合は、*常に* props.children
を返すようにしてください。特に、非同期コードを含むコンテキストを <Show>
とともに使用している場合は、フックから値を取得するためにこれが必要であり、同期的に 1 回だけ取得されるため、そうでない場合は undefined
しか取得されず、その理由がわからなくなります。
renderDirective
Solid.js は カスタムディレクティブ をサポートしています。これは、カスタムの動作を要素に結び付ける便利なパターンです。そのため、renderDirective
呼び出しもあります。これは、renderHook
を拡張して、最初の引数としてディレクティブを取り、引数の initialValue
と options
内の targetElement
(文字列、HTMLElement、または HTMLElement を返す関数) を受け入れ、ディレクティブの引数を読み取って操作するための arg
と setArg
も返します。
function renderDirective<
Arg extends any,
Elem extends HTMLElement
>(
directive: (ref: Elem, arg: Accessor<Arg>) => void,
options?: {
...renderOptions,
initialValue: Arg,
targetElement:
| Lowercase<Elem['nodeName']>
| Elem
| (() => Elem)
}
): Result & { arg: Accessor<Arg>, setArg: Setter<Arg> };
これにより、ディレクティブを非常に効果的かつ簡潔にテストできます
const {asFragment, setArg} = renderDirective(myDirective)
expect(asFragment()).toBe('<div data-directive="works"></div>')
setArg('perfect')
expect(asFragment()).toBe('<div data-directive="perfect"></div>')
非同期メソッド
Solid.js のリアクティブな変更は非常に瞬間的であるため、トランジション、サスペンス、リソース、ルーターのナビゲーションを除いて、レンダリング結果をテストするために waitFor(…)
、await findByRole(…)
、およびその他の非同期クエリを使用する必要はほとんどありません。
Solid.js は、createEffect
の異なるバリアントを使用して副作用を管理します。waitFor
を使用して非同期効果をテストできますが、Solid のリアクティビティが次のステップをトリガーできるようにする代わりに、ポーリングを使用します。これらの非同期効果のテストを簡素化するために、ディレクティブとフックのフックを補完する testEffect
ヘルパーがあります
testEffect(fn: (done: (result: T) => void) => void, owner?: Owner): Promise<T>
// use it like this:
test("testEffect allows testing an effect asynchronously", () => {
const [value, setValue] = createSignal(0);
return testEffect(done => createEffect((run: number = 0) => {
if (run === 0) {
expect(value()).toBe(0);
setValue(1);
} else if (run === 1) {
expect(value()).toBe(1);
done();
}
return run + 1;
}));
});
オプションの 2 番目の引数として受信される定義済みのオーナー内で効果を実行できます。これは、結果に owner フィールドを提供する renderHook
と組み合わせて使用すると便利です。戻り値は、done()
コールバックに渡された値を持つ Promise です。さらなるアサーションのために結果を待つことも、テストランナーに返すこともできます。
既知の問題
vitest
を使用している場合、パッケージ solid-js
と @solidjs/router
(使用されている場合) は 1 回だけロードする必要があり、内部の vite
サーバーとノードの両方からロードされる可能性があるため、テストが失敗する可能性があります。これによって発生する典型的なバグは、dispose が未定義であるか、ルーターをロードできなかったことです。
バージョン 2.8.2 以降、vite プラグインはテスト用にすべてを構成できるようになったため、グローバル、カバレッジなどに対してのみ追加の構成が必要になります。