テストする
このルーターは何もモックせず、ブラウザのNavigation APIとURLPatternをそのまま使います。このページでは、ブラウザ無しで確かめられる部分と、ブラウザの中でナビゲーションを確かめるときの注意を説明します。
このページの内容
ルート表をブラウザ無しで確かめる
defineRoutesが返すルート表は、matchでパスを照合できます。matchはただの関数です。そのため、どのパスがどのページになるかや受け取るparams、照合の順序を、ブラウザ無しで確かめられます。
src/routes.test.tsimport { expect, it } from 'vitest';
import { routes } from './routes';
it('sends /products/new to its own page', () => {
const found = routes.match('/products/new');
expect(found?.pattern).toBe('/products/new');
});
it('reads the id of a product page', () => {
const found = routes.match('/products/42');
expect(found?.params).toStrictEqual({ id: '42' });
});matchPathも同じく、ブラウザ無しで呼べる関数です。いまいる場所によってリンクの見た目を変えるコードは、パスを引数で受け取る形にしておくと、matchPathごと確かめられます。
ブラウザの中でページを移る
<Router>を描いてページを移るテストは、Navigation APIのあるブラウザの中で動かします。このパッケージ自身のテストは、VitestのブラウザモードでChromiumとFirefox、WebKitの3つを使っています。
src/app.browser.test.tsximport { navigateTo, Router } from '@k8ordo/router';
import { expect, it } from 'vitest';
import { render } from 'vitest-browser-react';
import { routes } from './routes';
it('shows the product page once finished resolves', async () => {
await render(<Router routes={routes} />);
await navigateTo('/products/:id', { id: '1' }).finished;
const heading = document.querySelector('h1');
expect(heading?.textContent).toBe('Product 1');
});finishedは新しいページが画面に出たときに解決するので、待ったあとは、繰り返し確かめる書き方をしなくても画面を確かめられます。
ただし、ページのuseEffectは、画面に出たあとで走ります。effectの結果を確かめるときは、expect.elementやvi.waitForのように、通るまで繰り返す書き方にしてください。
表の外へ移るときはテストが自分で引き受ける
<Router>が引き受けないナビゲーションは、ブラウザのふつうのページの読み込みになります。テストの中でそれが起きると、テストを動かしているページそのものが別のページに移ってしまいます。
テストの前に表に無いURLへ移る準備や、テストのあとで元のURLに戻す後片付けが、これにあたります。そうしたナビゲーションの間だけ、テストが自分でnavigateイベントをインターセプトします。
src/app.browser.test.tsxconst interceptEverything = (event: NavigateEvent) => {
if (event.canIntercept) event.intercept();
};
const navigateOutside = async (url: string) => {
navigation.addEventListener('navigate', interceptEverything);
try {
await navigation.navigate(url, { history: 'replace' }).finished;
} finally {
navigation.removeEventListener('navigate', interceptEverything);
}
};
let home: string;
beforeEach(() => {
home = location.href;
});
afterEach(async () => {
await navigateOutside(home);
});メモ
<Router>を描いたあとの、表にあるパスへのナビゲーションは、<Router>が引き受けます。テストが自分で引き受ける必要はありません。
戻ると進むはトップレベルのページで確かめる
Vitestのブラウザモードは、テストをiframeの中で動かします。iframeの中では、FirefoxとWebKitは戻ると進むでスクロールの位置を戻しません。また、Firefoxは戻ると進むのハンドラを2回走らせます。
そのためこのパッケージでは、戻ると進むのテストだけを、Playwrightでトップレベルに開いたページで行っています。戻ったときのスクロールの位置まで確かめるなら、同じようにiframeの外で確かめてください。