Skip to content

Commit 013095a

Browse files
committed
test: トップページのタイトル判定を関数に切り出して分岐を固定する
翻訳のあるロケールと固定文へのフォールバックを両方テストする。 useHead が locale を見られているかは index.head.spec で見る。
1 parent 89b1440 commit 013095a

4 files changed

Lines changed: 69 additions & 27 deletions

File tree

lib/siteMeta.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// トップページのタイトルと説明。翻訳が揃っているロケールは翻訳を使い、
2+
// それ以外は英語の固定文にフォールバックする。
3+
// "kr" は移行前からの誤りで、ロケールコードは ko である。挙動を変えないためそのまま残す。
4+
const TRANSLATED_LOCALES = ["ja", "en", "kr"];
5+
6+
export function getSiteMeta(
7+
locale: string | undefined,
8+
// eslint-disable-next-line no-unused-vars -- 型注釈の引数名を未使用変数と誤検知するため
9+
t: (key: string) => string
10+
): { siteName: string; siteDesc: string } {
11+
if (locale && TRANSLATED_LOCALES.includes(locale)) {
12+
return { siteName: t("common.site_name"), siteDesc: t("common.site_desc") };
13+
}
14+
return {
15+
siteName: "KamiMap",
16+
siteDesc: "Paper Map for printable map information",
17+
};
18+
}

pages/index.vue

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import mapList from "~/assets/config/list.json";
5252
import Modal from "~/components/Modal.vue";
5353
import { getMapConfig } from "~/lib/mapConfigs";
54+
import { getSiteMeta } from "~/lib/siteMeta";
5455
5556
const maps = mapList.map((name) => getMapConfig(name));
5657
@@ -70,21 +71,7 @@ export default defineNuxtComponent({
7071
// 移さないと this.locale が undefined になって常に default 分岐に落ち、
7172
// 日本語でもタイトルが "KamiMap" になってしまう。
7273
useHead(() => {
73-
let siteName, siteDesc;
74-
switch (locale.value) {
75-
// "kr" は移行前からの誤りで、ロケールコードは ko である。
76-
// 挙動を変えないためそのまま残す
77-
case "ja":
78-
case "en":
79-
case "kr":
80-
siteName = t("common.site_name");
81-
siteDesc = t("common.site_desc");
82-
break;
83-
default:
84-
siteName = "KamiMap";
85-
siteDesc = "Paper Map for printable map information";
86-
break;
87-
}
74+
const { siteName, siteDesc } = getSiteMeta(locale.value, t);
8875
return {
8976
title: siteName,
9077
meta: [

test-unit/lib/siteMeta.spec.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { getSiteMeta } from '~/lib/siteMeta';
2+
3+
const t = (key: string) => ({ 'common.site_name': '紙マップ', 'common.site_desc': '説明' }[key] ?? key);
4+
5+
describe('getSiteMeta', () => {
6+
test.each(['ja', 'en', 'kr'])('%s は翻訳を使う', (locale) => {
7+
expect(getSiteMeta(locale, t)).toEqual({ siteName: '紙マップ', siteDesc: '説明' });
8+
});
9+
10+
// 翻訳が揃っていないロケールで空にならないことを確認する。
11+
// ここが空になると日本語圏以外の利用者にタイトルも説明も出なくなる。
12+
test.each(['zh', 'th', 'ne', 'si'])('%s は英語の固定文にフォールバックする', (locale) => {
13+
expect(getSiteMeta(locale, t)).toEqual({
14+
siteName: 'KamiMap',
15+
siteDesc: 'Paper Map for printable map information',
16+
});
17+
});
18+
19+
// head() が setup 経由で評価されると locale が undefined になる。
20+
// その場合も落ちずに固定文を返すが、ja でこれになっては困る(回帰は index.head.spec が見る)
21+
test('locale が undefined でも落ちない', () => {
22+
expect(getSiteMeta(undefined, t).siteName).toBe('KamiMap');
23+
});
24+
25+
// ko は翻訳ファイルがあるのに "kr" と書かれているため翻訳されない(移行前からの誤り)
26+
test('ko は現状フォールバックする(移行前からの誤りを保持)', () => {
27+
expect(getSiteMeta('ko', t).siteName).toBe('KamiMap');
28+
});
29+
});

test-unit/pages/index.head.spec.ts

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,29 @@ import IndexPage from '~/pages/index.vue';
88
// undefined になり、日本語でもタイトルが "KamiMap" になっていた。
99
// 例外は出ず画面も崩れないので、実際に描画したタイトルで固定する。
1010

11-
const titleFor = async (locale: string) => {
11+
const titleFor = async (locale: string, expected: string) => {
1212
const { $i18n } = useNuxtApp() as any;
13-
$i18n.locale.value = locale;
14-
await mountSuspended(IndexPage);
15-
// useHead はクライアントでは document に反映されるので、実際のタイトルを見る
16-
await new Promise((r) => setTimeout(r, 0));
17-
return document.title;
13+
// lazy: true なので locale.value を直接書き換えても翻訳は読み込まれない。
14+
// setLocale を使って読み込みまで待つ
15+
await $i18n.setLocale(locale);
16+
const wrapper = await mountSuspended(IndexPage);
17+
// useHead が document に反映されるのは非同期なので、期待値になるまで待つ。
18+
// 壊れているときは変わらないままタイムアウトして、その値で落ちる
19+
for (let i = 0; i < 40 && document.title !== expected; i++) {
20+
await new Promise((r) => setTimeout(r, 25));
21+
}
22+
const title = document.title;
23+
// 前のマウントが残るとその useHead が document.title を握り続けるため必ず破棄する
24+
wrapper.unmount();
25+
await new Promise((r) => setTimeout(r, 25));
26+
return title;
1827
};
1928

29+
// 分岐そのものは test-unit/lib/siteMeta.spec.ts で見ている。
30+
// ここは useHead が実際に locale を見られているか(head() のままなら見られない)だけを見る。
31+
// 同じ app に2回マウントすると前の useHead が document.title を握るため、1件に絞る。
2032
describe('トップページのタイトル', () => {
21-
test('ja では翻訳された名前を使う', async () => {
22-
expect(await titleFor('ja')).toBe('紙マップ');
23-
});
24-
25-
test('翻訳のないロケールでは英語の固定名にフォールバックする', async () => {
26-
expect(await titleFor('zh')).toBe('KamiMap');
33+
test('ja では翻訳された名前が実際に描画される', async () => {
34+
expect(await titleFor('ja', '紙マップ')).toBe('紙マップ');
2735
});
2836
});

0 commit comments

Comments
 (0)