@k8ordo/router

テストする

このルーターは何もモックせず、ブラウザのNavigation APIとURLPatternをそのまま使います。このページでは、ブラウザ無しで確かめられる部分と、ブラウザの中でナビゲーションを確かめるときの注意を説明します。

このページの内容

ルート表をブラウザ無しで確かめる

defineRoutesが返すルート表は、matchでパスを照合できます。matchはただの関数です。そのため、どのパスがどのページになるかや受け取るparams、照合の順序を、ブラウザ無しで確かめられます。

src/routes.test.ts
import { 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.tsx
import { 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.tsx
const 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の外で確かめてください。

k8ordo

Baselineに入った機能を、制限なく使うReactのライブラリ群。

© 2026 k8o — MIT License

組版:Noto Sans JP / M PLUS 2