feat: translate system interface to English

This commit is contained in:
2026-09-28 18:42:16 +09:00
parent e870bdfcbb
commit 1cf32705a7
74 changed files with 1232 additions and 1065 deletions
+17 -15
View File
@@ -5,21 +5,21 @@ test('opens account management after hydration without inheriting real OAuth con
}) => {
await page.goto('/deck')
await expect(
page.getByRole('button', { name: '名前を変更', includeHidden: true }),
page.getByRole('button', { name: 'Rename', includeHidden: true }),
).toBeEnabled()
const manage = page.getByRole('button', { name: '接続アカウントを管理' })
const manage = page.getByRole('button', { name: 'Manage connected accounts' })
if (!(await manage.isVisible())) {
await page.getByRole('button', { name: 'サイドバーを切り替え' }).click()
await page.getByRole('button', { name: 'Toggle sidebar' }).click()
}
await expect(manage).toBeEnabled()
await manage.click()
const dialog = page.getByRole('dialog', { name: '接続アカウント' })
const dialog = page.getByRole('dialog', { name: 'Connected accounts' })
await expect(dialog).toBeVisible()
await expect(
dialog.getByText('利用するMastodonサーバーがまだ設定されていません。'),
dialog.getByText('No Mastodon servers have been configured yet.'),
).toBeVisible()
await expect(
dialog.getByRole('button', { name: 'Mastodonで認可する' }),
dialog.getByRole('button', { name: 'Authorize with Mastodon' }),
).toHaveCount(0)
await page.keyboard.press('Escape')
await expect(dialog).toHaveCount(0)
@@ -32,19 +32,21 @@ test('opens account management from the inbox footer and restores focus on close
}) => {
await page.goto('/inbox')
await page.waitForLoadState('networkidle')
const manage = page.getByRole('button', { name: '接続アカウントを管理' })
const manage = page.getByRole('button', { name: 'Manage connected accounts' })
await expect(manage).toBeVisible()
await manage.click()
const dialog = page.getByRole('dialog', { name: '接続アカウント' })
const dialog = page.getByRole('dialog', { name: 'Connected accounts' })
await expect(dialog).toBeVisible()
await expect(
dialog.getByText('利用するMastodonサーバーがまだ設定されていません。'),
dialog.getByText('No Mastodon servers have been configured yet.'),
).toBeVisible()
expect((await a11y().analyze()).violations).toEqual([])
await page.keyboard.press('Escape')
await expect(dialog).toHaveCount(0)
await expect(manage).toBeFocused()
await expect(page.getByRole('textbox', { name: '記事を検索' })).toBeVisible()
await expect(
page.getByRole('textbox', { name: 'Search articles' }),
).toBeVisible()
})
test('rejects an unbound OAuth callback without contacting an instance', async ({
@@ -53,16 +55,16 @@ test('rejects an unbound OAuth callback without contacting an instance', async (
await page.goto('/oauth/mastodon/callback?state=invalid&code=not-a-real-code')
await expect(page).toHaveURL(/\/deck\?mastodon=failed$/)
await expect(page.getByRole('alert')).toContainText(
'Mastodonの認可を完了できませんでした。',
'Could not complete Mastodon authorization.',
)
await expect(
page.getByRole('button', { name: '名前を変更', includeHidden: true }),
page.getByRole('button', { name: 'Rename', includeHidden: true }),
).toBeEnabled()
const manage = page.getByRole('button', { name: '接続アカウントを管理' })
const manage = page.getByRole('button', { name: 'Manage connected accounts' })
if (!(await manage.isVisible())) {
await page.getByRole('button', { name: 'サイドバーを切り替え' }).click()
await page.getByRole('button', { name: 'Toggle sidebar' }).click()
}
await expect(
page.getByRole('button', { name: '接続アカウントを管理' }),
page.getByRole('button', { name: 'Manage connected accounts' }),
).toBeEnabled()
})
+76 -76
View File
@@ -10,26 +10,26 @@ async function addColumn(
kind = 'search',
) {
await showDeckManagement(page)
await page.getByRole('button', { name: 'カラムを追加', exact: true }).click()
const editor = page.getByRole('form', { name: 'カラムを追加', exact: true })
await editor.getByLabel('カラム名', { exact: true }).fill(title)
await page.getByRole('button', { name: 'Add column', exact: true }).click()
const editor = page.getByRole('form', { name: 'Add column', exact: true })
await editor.getByLabel('Column name', { exact: true }).fill(title)
await editor
.getByRole('combobox', { name: '接続プロファイル', exact: true })
.getByRole('combobox', { name: 'Connection profile', exact: true })
.selectOption({ label: profile })
await editor
.getByRole('combobox', { name: 'カラムの種類', exact: true })
.getByRole('combobox', { name: 'Column type', exact: true })
.selectOption(kind)
await editor
.getByLabel(
kind === 'search'
? 'Twitterの検索条件'
? 'Twitter search query'
: kind === 'user'
? 'ユーザー'
: 'リスト',
? 'User'
: 'List',
{ exact: true },
)
.fill(query)
await editor.getByRole('button', { name: '追加して検索' }).click()
await editor.getByRole('button', { name: 'Add and search' }).click()
await closeMobileSidebar(page)
await expect(
page
@@ -42,13 +42,13 @@ async function addColumn(
test.beforeEach(async ({ page }) => {
await page.goto('/deck')
await expect(
page.getByRole('button', { name: 'デッキとして保存', exact: true }),
page.getByRole('button', { name: 'Save as deck', exact: true }),
).toBeEnabled()
await page
.getByRole('button', { name: 'デッキとして保存', exact: true })
.click()
await page.getByRole('button', { name: 'Save as deck', exact: true }).click()
await showDeckManagement(page)
await expect(page.getByText('サーバーに保存・端末間で共有')).toBeVisible()
await expect(
page.getByText('Saved to server · Shared across devices'),
).toBeVisible()
await closeMobileSidebar(page)
})
@@ -65,19 +65,19 @@ test('binds identical searches to independent profiles through paging, editing a
await expect(
second.getByText('alternate · Latest · all page 1', { exact: true }),
).toBeVisible()
await first.getByRole('button', { name: '続きを読み込む' }).click()
await first.getByRole('button', { name: 'Load more' }).click()
await expect(first.locator('article')).toHaveCount(2)
await expect(second.locator('article')).toHaveCount(1)
await second.getByRole('button', { name: '続きを読み込む' }).click()
await second.getByRole('button', { name: 'Load more' }).click()
await expect(
second.getByText('alternate · Latest · all page 2'),
).toBeVisible()
await second.getByRole('button', { name: '別の接続の操作' }).click()
await page.getByRole('menuitem', { name: '編集', exact: true }).click()
await second.getByRole('button', { name: 'Actions for 別の接続' }).click()
await page.getByRole('menuitem', { name: 'Edit', exact: true }).click()
await page
.getByRole('combobox', { name: '接続プロファイル', exact: true })
.getByRole('combobox', { name: 'Connection profile', exact: true })
.selectOption({ label: 'e2e' })
await page.getByRole('button', { name: '変更を保存' }).click()
await page.getByRole('button', { name: 'Save changes' }).click()
await expect(
second.getByText('Latest · all page 1', { exact: true }),
).toBeVisible()
@@ -94,19 +94,19 @@ test('binds identical searches to independent profiles through paging, editing a
test('creates, switches, renames and deletes persisted deck profiles', async ({
page,
}) => {
await page.getByRole('button', { name: '名前を変更' }).click()
await page.getByLabel('調査テーマ・デッキ名').fill('最初の調査')
await page.getByRole('button', { name: '名前を保存' }).click()
await page.getByRole('button', { name: 'Rename' }).click()
await page.getByLabel('Research topic / deck name').fill('最初の調査')
await page.getByRole('button', { name: 'Save name' }).click()
await addColumn(page, '最初の観点', 'first-deck')
await showDeckManagement(page)
await page.getByRole('button', { name: 'デッキを作成', exact: true }).click()
await page.getByLabel('新しいデッキ名').fill('別の調査')
await page.getByRole('button', { name: '作成', exact: true }).click()
await page.getByRole('button', { name: 'Create deck', exact: true }).click()
await page.getByLabel('New deck name').fill('別の調査')
await page.getByRole('button', { name: 'Create', exact: true }).click()
await expect(page.locator('.deck-column')).toHaveCount(0)
await addColumn(page, '別の観点', 'second-deck', 'alternate')
await showDeckManagement(page)
await page
.getByLabel('デッキプロファイル', { exact: true })
.getByLabel('Deck profile', { exact: true })
.selectOption({ label: '最初の調査' })
await closeMobileSidebar(page)
await expect(page.locator('.deck-column h2')).toHaveText(['最初の観点'])
@@ -114,18 +114,18 @@ test('creates, switches, renames and deletes persisted deck profiles', async ({
await expect(page.getByRole('heading', { level: 1 })).toHaveText('最初の調査')
await showDeckManagement(page)
await page
.getByLabel('デッキプロファイル', { exact: true })
.getByLabel('Deck profile', { exact: true })
.selectOption({ label: '別の調査' })
await closeMobileSidebar(page)
await expect(page.locator('.deck-column h2')).toHaveText(['別の観点'])
await showDeckManagement(page)
await page.getByRole('button', { name: 'デッキを削除', exact: true }).click()
await page.getByRole('button', { name: '削除する', exact: true }).click()
await page.getByRole('button', { name: 'Delete deck', exact: true }).click()
await page.getByRole('button', { name: 'Delete', exact: true }).click()
await page.reload()
await expect(page.getByRole('heading', { level: 1 })).toHaveText('最初の調査')
await showDeckManagement(page)
await expect(
page.getByLabel('デッキプロファイル', { exact: true }).locator('option'),
page.getByLabel('Deck profile', { exact: true }).locator('option'),
).toHaveCount(1)
})
@@ -138,17 +138,17 @@ test('reads user and list timelines within columns and reorders, deletes and res
const list = page.getByRole('region', { name: 'リストの投稿', exact: true })
await expect(user.getByText('alternate profile page 1')).toBeVisible()
await expect(list.getByText('list page 1')).toBeVisible()
await list.getByRole('button', { name: '続きを読み込む' }).click()
await list.getByRole('button', { name: 'Load more' }).click()
await expect(list.getByText('list page 2')).toBeVisible()
await list.getByRole('button', { name: 'リストの投稿の操作' }).click()
await page.getByRole('menuitem', { name: 'リストの投稿を左へ' }).click()
await list.getByRole('button', { name: 'Actions for リストの投稿' }).click()
await page.getByRole('menuitem', { name: 'Move リストの投稿 left' }).click()
await expect(page.locator('.deck-column h2')).toHaveText([
'リストの投稿',
'アカウント',
])
await list.getByRole('button', { name: 'リストの投稿の操作' }).click()
await page.getByRole('menuitem', { name: 'リストの投稿を削除' }).click()
await page.getByRole('button', { name: '元に戻す' }).click()
await list.getByRole('button', { name: 'Actions for リストの投稿' }).click()
await page.getByRole('menuitem', { name: 'Delete リストの投稿' }).click()
await page.getByRole('button', { name: 'Undo' }).click()
await expect(page.locator('.deck-column h2')).toHaveText([
'リストの投稿',
'アカウント',
@@ -165,12 +165,12 @@ test('keeps other columns usable when pagination fails and retries that column',
await addColumn(page, '別の検索', 'independent-deck')
const failed = page.getByRole('region', { name: '失敗する検索', exact: true })
const other = page.getByRole('region', { name: '別の検索', exact: true })
await failed.getByRole('button', { name: '続きを読み込む' }).click()
await failed.getByRole('button', { name: 'Load more' }).click()
await expect(failed.getByRole('alert')).toBeVisible()
await expect(failed.locator('article')).toHaveCount(1)
await other.getByRole('button', { name: '続きを読み込む' }).click()
await other.getByRole('button', { name: 'Load more' }).click()
await expect(other.locator('article')).toHaveCount(2)
await failed.getByRole('button', { name: '再試行' }).click()
await failed.getByRole('button', { name: 'Retry' }).click()
await expect(failed.locator('article')).toHaveCount(2)
})
@@ -201,9 +201,7 @@ test('keeps the deck and editor accessible within narrow viewports', async ({
width: testInfo.project.name === 'desktop' ? 1440 : 393,
height: 900,
})
await expect(
page.getByRole('navigation', { name: 'カラム一覧' }),
).toHaveCount(0)
await expect(page.getByRole('navigation', { name: 'Columns' })).toHaveCount(0)
await expect(
page.getByRole('heading', { name: '公式アカウント', exact: true }),
).toBeVisible()
@@ -213,7 +211,7 @@ test('keeps the deck and editor accessible within narrow viewports', async ({
fullPage: true,
})
await showDeckManagement(page)
await page.getByRole('button', { name: 'カラムを追加', exact: true }).click()
await page.getByRole('button', { name: 'Add column', exact: true }).click()
expect((await a11y().analyze()).violations).toEqual([])
await page.screenshot({
path: testInfo.outputPath('deck.png'),
@@ -225,20 +223,22 @@ test('closes the column editor with Escape and restores focus without applying e
page,
}) => {
await showDeckManagement(page)
const opener = page.getByRole('button', { name: 'カラムを追加', exact: true })
const opener = page.getByRole('button', { name: 'Add column', exact: true })
await opener.click()
await expect(
page.getByRole('dialog', { name: 'カラムを追加', exact: true }),
page.getByRole('dialog', { name: 'Add column', exact: true }),
).toBeVisible()
await page.getByLabel('カラム名', { exact: true }).fill('キャンセルする観点')
await page
.getByLabel('Column name', { exact: true })
.fill('キャンセルする観点')
await page.keyboard.press('Escape')
await expect(
page.getByRole('dialog', { name: 'カラムを追加', exact: true }),
page.getByRole('dialog', { name: 'Add column', exact: true }),
).toHaveCount(0)
await expect(opener).toBeFocused()
await expect(page.locator('.deck-column')).toHaveCount(0)
await opener.click()
await expect(page.getByLabel('カラム名', { exact: true })).toHaveValue('')
await expect(page.getByLabel('Column name', { exact: true })).toHaveValue('')
})
test('does not overwrite unreadable storage on reload', async ({ page }) => {
@@ -246,7 +246,7 @@ test('does not overwrite unreadable storage on reload', async ({ page }) => {
localStorage.setItem('twitter-lite-research-deck', '{broken'),
)
await page.reload()
await expect(page.getByRole('alert')).toContainText('読み込めませんでした')
await expect(page.getByRole('alert')).toContainText('Unable to load')
expect(
await page.evaluate(() =>
localStorage.getItem('twitter-lite-research-deck'),
@@ -258,19 +258,19 @@ test('selects a list from the column profile catalog and refreshes it on profile
page,
}) => {
await showDeckManagement(page)
await page.getByRole('button', { name: 'カラムを追加', exact: true }).click()
await page.getByLabel('カラム名', { exact: true }).fill('購読リスト')
await page.getByRole('button', { name: 'Add column', exact: true }).click()
await page.getByLabel('Column name', { exact: true }).fill('購読リスト')
await page
.getByRole('combobox', { name: '接続プロファイル', exact: true })
.getByRole('combobox', { name: 'Connection profile', exact: true })
.selectOption({ label: 'e2e' })
await page
.getByRole('combobox', { name: 'カラムの種類', exact: true })
.getByRole('combobox', { name: 'Column type', exact: true })
.selectOption('list')
await expect(
page.getByRole('button', { name: 'My E2E List', exact: true }),
).toBeVisible()
await page
.getByRole('combobox', { name: '接続プロファイル', exact: true })
.getByRole('combobox', { name: 'Connection profile', exact: true })
.selectOption({ label: 'alternate' })
await expect(
page.getByRole('button', { name: 'My E2E List', exact: true }),
@@ -278,10 +278,10 @@ test('selects a list from the column profile catalog and refreshes it on profile
await page
.getByRole('button', { name: 'Alternate List', exact: true })
.click()
await expect(page.getByLabel('リスト', { exact: true })).toHaveValue(
await expect(page.getByLabel('List', { exact: true })).toHaveValue(
'1234567890',
)
await page.getByRole('button', { name: '追加して検索' }).click()
await page.getByRole('button', { name: 'Add and search' }).click()
await closeMobileSidebar(page)
await expect(
page
@@ -302,27 +302,27 @@ test('keeps an open draft through remote edits and rejects its stale save', asyn
try {
const device = await other.newPage()
await device.goto('/deck')
await page.getByRole('button', { name: '名前を変更' }).click()
await page.getByLabel('調査テーマ・デッキ名').fill('編集中の名前')
await device.getByRole('button', { name: '名前を変更' }).click()
await device.getByLabel('調査テーマ・デッキ名').fill('別の端末の変更')
await device.getByRole('button', { name: '名前を保存' }).click()
await page.getByRole('button', { name: 'Rename' }).click()
await page.getByLabel('Research topic / deck name').fill('編集中の名前')
await device.getByRole('button', { name: 'Rename' }).click()
await device.getByLabel('Research topic / deck name').fill('別の端末の変更')
await device.getByRole('button', { name: 'Save name' }).click()
await expect(device.getByRole('heading', { level: 1 })).toHaveText(
'別の端末の変更',
)
await page.evaluate(() => window.dispatchEvent(new Event('focus')))
await expect(page.getByLabel('調査テーマ・デッキ名')).toHaveValue(
await expect(page.getByLabel('Research topic / deck name')).toHaveValue(
'編集中の名前',
)
await page.getByRole('button', { name: '名前を保存' }).click()
await page.getByRole('button', { name: 'Save name' }).click()
await expect(page.getByRole('alert')).toContainText(
'別の端末で変更されました',
'This deck changed on another device',
)
await expect(page.getByLabel('調査テーマ・デッキ名')).toHaveValue(
await expect(page.getByLabel('Research topic / deck name')).toHaveValue(
'編集中の名前',
)
await page.keyboard.press('Escape')
await page.getByRole('button', { name: '最新のデッキを再読み込み' }).click()
await page.getByRole('button', { name: 'Reload latest deck' }).click()
await expect(page.getByRole('heading', { level: 1 })).toHaveText(
'別の端末の変更',
)
@@ -368,10 +368,10 @@ test('imports old browser decks explicitly and avoids duplicate imports after re
)
await page.reload()
await showDeckManagement(page)
const selector = page.getByLabel('デッキプロファイル', { exact: true })
const selector = page.getByLabel('Deck profile', { exact: true })
await expect(selector.locator('option')).toHaveCount(1)
await closeMobileSidebar(page)
await page.getByRole('button', { name: '旧デッキを取り込む' }).click()
await page.getByRole('button', { name: 'Import legacy decks' }).click()
await showDeckManagement(page)
await expect(selector.locator('option')).toHaveCount(2)
await selector.selectOption({ label: '以前の調査' })
@@ -388,9 +388,9 @@ test('imports old browser decks explicitly and avoids duplicate imports after re
legacy,
)
await page.reload()
await page.getByRole('button', { name: '旧デッキを取り込む' }).click()
await page.getByRole('button', { name: 'Import legacy decks' }).click()
await expect(
page.getByRole('button', { name: '旧デッキを取り込む' }),
page.getByRole('button', { name: 'Import legacy decks' }),
).toHaveCount(0)
await showDeckManagement(page)
await expect(selector.locator('option')).toHaveCount(2)
@@ -400,19 +400,19 @@ test('preserves a new deck dialog and its draft across the mobile breakpoint', a
page,
}) => {
await showDeckManagement(page)
await page.getByRole('button', { name: 'デッキを作成', exact: true }).click()
const dialog = page.getByRole('dialog', { name: 'デッキを作成', exact: true })
await dialog.getByLabel('新しいデッキ名').fill('画面を回転しても残る調査')
await page.getByRole('button', { name: 'Create deck', exact: true }).click()
const dialog = page.getByRole('dialog', { name: 'Create deck', exact: true })
await dialog.getByLabel('New deck name').fill('画面を回転しても残る調査')
for (const width of [1024, 375, 1024]) {
await page.setViewportSize({ width, height: 900 })
await expect(dialog).toHaveCount(1)
await expect(dialog).toBeVisible()
await expect(dialog.getByLabel('新しいデッキ名')).toHaveValue(
await expect(dialog.getByLabel('New deck name')).toHaveValue(
'画面を回転しても残る調査',
)
await expect(page.locator('#new-deck-title')).toHaveCount(1)
}
await dialog.getByRole('button', { name: '作成', exact: true }).click()
await dialog.getByRole('button', { name: 'Create', exact: true }).click()
await expect(dialog).toHaveCount(0)
await expect(page.getByRole('heading', { level: 1 })).toHaveText(
'画面を回転しても残る調査',
+53 -48
View File
@@ -6,21 +6,17 @@ test('previews a natural-language memo and shares the executed record with journ
await page.goto('/')
await page.waitForLoadState('networkidle')
const memo = '明日のレビューは導線から確認する'
await page
.getByRole('textbox', { name: 'ホームへの入力' })
.fill(`メモ: ${memo}`)
await page.getByRole('button', { name: '候補を表示' }).click()
const execute = page.getByRole('button', { name: '実行する', exact: true })
await page.getByRole('textbox', { name: 'Home input' }).fill(`Note: ${memo}`)
await page.getByRole('button', { name: 'Preview action' }).click()
const execute = page.getByRole('button', { name: 'Apply', exact: true })
await expect(execute).toBeVisible()
await execute.click()
await page.getByRole('link', { name: '記録', exact: true }).first().click()
await expect(page.getByRole('article', { name: 'メモの記録' })).toContainText(
await page.getByRole('link', { name: 'Journal', exact: true }).first().click()
await expect(page.getByRole('article', { name: 'Note entry' })).toContainText(
memo,
)
await page.getByRole('link', { name: 'ホーム', exact: true }).first().click()
await expect(
page.getByRole('textbox', { name: 'ホームへの入力' }),
).toBeVisible()
await page.getByRole('link', { name: 'Home', exact: true }).first().click()
await expect(page.getByRole('textbox', { name: 'Home input' })).toBeVisible()
})
test('keeps the home usable on narrow screens', async ({
@@ -32,7 +28,7 @@ test('keeps the home usable on narrow screens', async ({
for (const width of [320, 375, 768]) {
await page.setViewportSize({ width, height: 850 })
await expect(
page.getByRole('textbox', { name: 'ホームへの入力' }),
page.getByRole('textbox', { name: 'Home input' }),
).toBeVisible()
expect(
await page.evaluate(() => document.documentElement.scrollWidth),
@@ -47,28 +43,30 @@ test('adds tasks only after confirmation and can defer and restore them', async
}) => {
await page.goto('/')
await page.waitForLoadState('networkidle')
const input = page.getByRole('textbox', { name: 'ホームへの入力' })
const input = page.getByRole('textbox', { name: 'Home input' })
const complete = page.getByRole('button', {
name: '買い物を完了',
name: 'Complete grocery shopping',
exact: true,
})
await input.fill('買い物を追加')
await page.getByRole('button', { name: '候補を表示' }).click()
await input.fill('Add grocery shopping')
await page.getByRole('button', { name: 'Preview action' }).click()
await expect(complete).toHaveCount(0)
await page.getByRole('button', { name: '実行する', exact: true }).click()
await page.getByRole('button', { name: 'Apply', exact: true }).click()
await expect(complete).toBeVisible()
await input.fill('買い物をあとで')
await page.getByRole('button', { name: '候補を表示' }).click()
await input.fill('Defer grocery shopping')
await page.getByRole('button', { name: 'Preview action' }).click()
await expect(complete).toBeVisible()
await page.getByRole('button', { name: '実行する', exact: true }).click()
await page.getByRole('button', { name: 'Apply', exact: true }).click()
await expect(complete).toHaveCount(0)
await page.locator('.home-rest summary').click()
await page.getByRole('button', { name: '買い物を戻す', exact: true }).click()
await page
.getByRole('button', { name: 'Restore grocery shopping', exact: true })
.click()
await complete.click()
await expect(complete).toHaveCount(0)
await page.locator('.home-rest summary').click()
await expect(
page.getByRole('button', { name: '買い物を戻す', exact: true }),
page.getByRole('button', { name: 'Restore grocery shopping', exact: true }),
).toBeVisible()
})
@@ -78,30 +76,37 @@ test('resolves communication within home and carries the status to the shared qu
}) => {
await page.goto('/')
await page.waitForLoadState('networkidle')
await page.getByRole('button', { name: '青木 遥との会話を開く' }).click()
const dialog = page.getByRole('dialog', { name: '青木 遥との連絡' })
await page
.getByRole('button', { name: 'Open conversation with Haruka Aoki' })
.click()
const dialog = page.getByRole('dialog', {
name: 'Conversation with Haruka Aoki',
})
await expect(
dialog.getByRole('textbox', { name: '返信', exact: true }),
dialog.getByRole('textbox', { name: 'Reply', exact: true }),
).toBeVisible()
expect((await a11y().analyze()).violations).toEqual([])
await dialog.getByRole('button', { name: '今は置いておく' }).click()
await dialog.getByRole('button', { name: 'Leave for later' }).click()
await expect(dialog).toHaveCount(0)
await expect(
page.getByRole('button', { name: '青木 遥との会話を開く' }),
page.getByRole('button', { name: 'Open conversation with Haruka Aoki' }),
).toHaveCount(0)
await page.getByRole('link', { name: '連絡', exact: true }).first().click()
await page
.getByRole('link', { name: 'Messages', exact: true })
.first()
.click()
const rows = page.locator('.support-row')
await expect(
rows.filter({ hasText: '来週のレビュー、日程を決める' }),
rows.filter({ hasText: 'Schedule next week’s design review' }),
).toHaveCount(0)
await page.getByRole('button', { name: 'あとで', exact: true }).click()
await rows.filter({ hasText: '来週のレビュー、日程を決める' }).click()
await page.getByRole('button', { name: '今に戻す' }).click()
const back = page.getByRole('button', { name: '連絡一覧に戻る' })
await page.getByRole('button', { name: 'Later', exact: true }).click()
await rows.filter({ hasText: 'Schedule next week’s design review' }).click()
await page.getByRole('button', { name: 'Move to Now' }).click()
const back = page.getByRole('button', { name: 'Back to messages' })
if (await back.isVisible()) await back.click()
await page.getByRole('link', { name: 'ホーム', exact: true }).first().click()
await page.getByRole('link', { name: 'Home', exact: true }).first().click()
await expect(
page.getByRole('button', { name: '青木 遥との会話を開く' }),
page.getByRole('button', { name: 'Open conversation with Haruka Aoki' }),
).toBeVisible()
})
@@ -110,25 +115,25 @@ test('updates the prose brief as priorities change and opens the referenced conv
}) => {
await page.goto('/')
await page.waitForLoadState('networkidle')
const brief = page.getByRole('region', { name: '今日のブリーフ' })
await expect(brief).toContainText('レビュー資料を確認する')
await expect(brief).toContainText('4件')
const brief = page.getByRole('region', { name: 'Daily brief' })
await expect(brief).toContainText('Review the documents')
await expect(brief).toContainText('4 conversations')
await page
.getByRole('button', { name: 'レビュー資料を確認するを完了', exact: true })
.getByRole('button', { name: 'Complete Review the documents', exact: true })
.click()
await expect(brief).not.toContainText('レビュー資料を確認する')
await brief.getByRole('button', { name: '青木 遥さんへの返信' }).click()
await expect(brief).not.toContainText('Review the documents')
await brief.getByRole('button', { name: 'Reply to Haruka Aoki' }).click()
const dialog = page.getByRole('dialog', {
name: '青木 遥との連絡',
name: 'Conversation with Haruka Aoki',
exact: true,
})
await dialog.getByRole('button', { name: '今は置いておく' }).click()
await expect(brief).toContainText('3件')
await expect(brief).not.toContainText('青木 遥')
await dialog.getByRole('button', { name: 'Leave for later' }).click()
await expect(brief).toContainText('3 conversations')
await expect(brief).not.toContainText('Haruka Aoki')
await page
.getByRole('textbox', { name: 'ホームへの入力' })
.getByRole('textbox', { name: 'Home input' })
.fill('再開地点:資料の2ページ目から')
await page.getByRole('button', { name: '候補を表示' }).click()
await page.getByRole('button', { name: '実行する', exact: true }).click()
await page.getByRole('button', { name: 'Preview action' }).click()
await page.getByRole('button', { name: 'Apply', exact: true }).click()
await expect(brief).toContainText('資料の2ページ目から')
})
+19 -19
View File
@@ -7,7 +7,7 @@ test('selects articles and keeps the reader focused on their content', async ({
await page.waitForLoadState('networkidle')
const rows = page.locator('.inbox-article-row')
await expect(rows).toHaveCount(9)
const articleTitle = 'エージェントに渡す文脈は、短くてもよい'
const articleTitle = 'Context for an agent can be brief'
await rows.filter({ hasText: articleTitle }).click()
const reader = page.getByRole('article', { name: articleTitle, exact: true })
await expect(reader).toBeVisible()
@@ -16,26 +16,26 @@ test('selects articles and keeps the reader focused on their content', async ({
).toBeVisible()
await expect(
reader.getByText(
'まず目的を一文で書き、次に変えてはいけない条件を添える。',
'Start with a one-sentence goal, then add the constraints that must hold.',
{ exact: false },
),
).toBeVisible()
await expect(page.getByText('FOR YOU', { exact: true })).toHaveCount(0)
await expect(page.getByText('モック', { exact: true })).toHaveCount(0)
await expect(page.getByText('Mock', { exact: true })).toHaveCount(0)
await expect(page.getByText('Why this article', { exact: true })).toHaveCount(
0,
)
await expect(
page.getByText('この記事が届いた理由', { exact: true }),
page.getByRole('button', { name: /For you|Read later|Unread only/ }),
).toHaveCount(0)
await expect(
page.getByRole('button', { name: /あなたへ|あとで読む|未読のみ/ }),
).toHaveCount(0)
const back = page.getByRole('button', { name: '記事一覧に戻る' })
const back = page.getByRole('button', { name: 'Back to articles' })
if (await back.isVisible()) await back.click()
await rows
.filter({ hasText: '3カラムの余白が、情報を読むリズムをつくる' })
.filter({ hasText: 'Three columns create a rhythm for reading' })
.click()
await expect(
page.getByRole('article', {
name: '3カラムの余白が、情報を読むリズムをつくる',
name: 'Three columns create a rhythm for reading',
exact: true,
}),
).toBeVisible()
@@ -49,21 +49,21 @@ test('recovers from empty search and shares navigation with Twitter Lite', async
await page.waitForLoadState('networkidle')
const rows = page.locator('.inbox-article-row')
await page
.getByRole('textbox', { name: '記事を検索' })
.fill('存在しない検索語xyz')
.getByRole('textbox', { name: 'Search articles' })
.fill('nonexistent-query-xyz')
await expect(rows).toHaveCount(0)
await expect(
page.getByText('記事がありません', { exact: true }),
page.getByText('No articles found', { exact: true }),
).toBeVisible()
await page.getByRole('button', { name: '検索をクリア' }).click()
await page.getByRole('button', { name: 'Clear search' }).click()
await expect(rows).toHaveCount(9)
expect((await a11y().analyze()).violations).toEqual([])
await expect(
page.getByRole('button', { name: '興味を編集', exact: true }),
page.getByRole('button', { name: 'Edit interests', exact: true }),
).toHaveCount(0)
await page.getByRole('link', { name: 'Twitter Lite', exact: true }).click()
await expect(page).toHaveURL(/\/deck$/)
await page.getByRole('link', { name: 'リーダー', exact: true }).click()
await page.getByRole('link', { name: 'Reader', exact: true }).click()
await expect(page).toHaveURL(/\/inbox$/)
await expect(rows).toHaveCount(9)
})
@@ -77,14 +77,14 @@ test('keeps article navigation readable without horizontal overflow', async ({
for (const width of [320, 375, 414, 768]) {
await page.setViewportSize({ width, height: 850 })
await expect(
page.getByRole('textbox', { name: '記事を検索' }),
page.getByRole('textbox', { name: 'Search articles' }),
).toBeVisible()
expect(
await page.evaluate(() => document.documentElement.scrollWidth),
).toBe(width)
await page.locator('.inbox-article-row').first().click()
const reader = page.getByRole('article', {
name: 'ブラウザを見ながら考える。AIエージェントとの新しい開発の進め方',
name: 'Thinking in the browser: a new workflow with AI agents',
exact: true,
})
await expect(reader).toBeVisible()
@@ -95,7 +95,7 @@ test('keeps article navigation readable without horizontal overflow', async ({
path: testInfo.outputPath(`inbox-reader-${width}.png`),
})
if (width === 320) expect((await a11y().analyze()).violations).toEqual([])
const back = page.getByRole('button', { name: '記事一覧に戻る' })
const back = page.getByRole('button', { name: 'Back to articles' })
if (await back.isVisible()) await back.click()
}
})
+28 -28
View File
@@ -43,9 +43,9 @@ test('restores the conversation and growing temporary deck from reconnect snapsh
}) => {
await page.goto('/deck')
await showDeckManagement(page)
await page.getByRole('button', { name: 'カラムを追加', exact: true }).click()
await page.getByRole('button', { name: 'Add column', exact: true }).click()
const accounts = page.getByRole('combobox', {
name: '接続プロファイル',
name: 'Connection profile',
exact: true,
})
await accounts.selectOption({ label: 'e2e' })
@@ -98,7 +98,7 @@ test('restores the conversation and growing temporary deck from reconnect snapsh
)
await page.reload()
await showResearch(page)
const conversation = page.getByRole('log', { name: '調査の会話' })
const conversation = page.getByRole('log', { name: 'Research conversation' })
await expect(conversation).toContainText('既存の観点を使って調査して')
await expect(conversation).toContainText('list_decks: 完了')
await expect(conversation).toContainText('既存の検索条件を再利用しています。')
@@ -135,11 +135,11 @@ test('restores the conversation and growing temporary deck from reconnect snapsh
])
await closeMobileSidebar(page)
await expect(
page.getByRole('button', { name: 'デッキとして保存', exact: true }),
page.getByRole('button', { name: 'Save as deck', exact: true }),
).toBeEnabled()
await showResearch(page)
const accountPicker = page.getByRole('button', {
name: '接続アカウント · 1件',
name: 'Connected accounts · 1',
})
await accountPicker.click()
await expect(accountPicker).toHaveAttribute('aria-expanded', 'true')
@@ -148,13 +148,11 @@ test('restores the conversation and growing temporary deck from reconnect snapsh
).toBeChecked()
await accountPicker.click()
await expect(accountPicker).toHaveAttribute('aria-expanded', 'false')
await page.getByLabel('メッセージ', { exact: true }).fill('この観点を詳しく')
await page.getByLabel('Message', { exact: true }).fill('この観点を詳しく')
await expect(
page.getByRole('button', { name: '送信', exact: true }),
page.getByRole('button', { name: 'Send', exact: true }),
).toBeEnabled()
await page
.getByRole('button', { name: 'サイドバーを閉じる', exact: true })
.click()
await page.getByRole('button', { name: 'Close sidebar', exact: true }).click()
run.deckVersion = 3
if (run.deck) run.deck.title = '閉じている間に更新された調査'
await expect(page.getByRole('heading', { level: 1 })).toHaveText(
@@ -162,7 +160,7 @@ test('restores the conversation and growing temporary deck from reconnect snapsh
{ timeout: 15000 },
)
await showResearch(page)
await expect(page.getByLabel('メッセージ', { exact: true })).toHaveValue(
await expect(page.getByLabel('Message', { exact: true })).toHaveValue(
'この観点を詳しく',
)
await page.setViewportSize({ width: 600, height: 900 })
@@ -170,20 +168,20 @@ test('restores the conversation and growing temporary deck from reconnect snapsh
page.locator('[data-sidebar="sidebar"][data-mobile="true"]'),
).toHaveCount(1)
await showResearch(page)
await expect(page.getByLabel('メッセージ', { exact: true })).toHaveValue(
await expect(page.getByLabel('Message', { exact: true })).toHaveValue(
'この観点を詳しく',
)
await page.getByRole('button', { name: '接続アカウント · 1件' }).click()
await page.getByRole('button', { name: 'Connected accounts · 1' }).click()
await page.getByRole('checkbox', { name: 'e2e · Twitter' }).uncheck()
await page.setViewportSize({ width: 1100, height: 900 })
await expect(
page.locator('[data-sidebar="sidebar"][data-mobile="true"]'),
).toHaveCount(0)
await showResearch(page)
await expect(page.getByLabel('メッセージ', { exact: true })).toHaveValue(
await expect(page.getByLabel('Message', { exact: true })).toHaveValue(
'この観点を詳しく',
)
await page.getByRole('button', { name: '接続アカウント · 0件' }).click()
await page.getByRole('button', { name: 'Connected accounts · 0' }).click()
await expect(
page.getByRole('checkbox', { name: 'e2e · Twitter' }),
).not.toBeChecked()
@@ -192,10 +190,10 @@ test('restores the conversation and growing temporary deck from reconnect snapsh
page.locator('[data-sidebar="sidebar"][data-mobile="true"]'),
).toHaveCount(1)
await showResearch(page)
await expect(page.getByLabel('メッセージ', { exact: true })).toHaveValue(
await expect(page.getByLabel('Message', { exact: true })).toHaveValue(
'この観点を詳しく',
)
await page.getByRole('button', { name: '接続アカウント · 0件' }).click()
await page.getByRole('button', { name: 'Connected accounts · 0' }).click()
await expect(
page.getByRole('checkbox', { name: 'e2e · Twitter' }),
).not.toBeChecked()
@@ -217,9 +215,9 @@ test('renders Markdown and reveals an unloaded citation in an offscreen deck col
await page.emulateMedia({ reducedMotion: 'reduce' })
await page.goto('/deck')
await showDeckManagement(page)
await page.getByRole('button', { name: 'カラムを追加', exact: true }).click()
await page.getByRole('button', { name: 'Add column', exact: true }).click()
const accounts = page.getByRole('combobox', {
name: '接続プロファイル',
name: 'Connection profile',
exact: true,
})
await accounts.selectOption({ label: 'e2e' })
@@ -288,7 +286,7 @@ test('renders Markdown and reveals an unloaded citation in an offscreen deck col
)
await page.reload()
await showResearch(page)
const chat = page.getByRole('log', { name: '調査の会話' })
const chat = page.getByRole('log', { name: 'Research conversation' })
await expect(chat.getByRole('heading', { name: '調査結果' })).toBeVisible()
await expect(chat.getByRole('heading', { name: '調査結果' })).toHaveCSS(
'font-weight',
@@ -309,7 +307,7 @@ test('renders Markdown and reveals an unloaded citation in an offscreen deck col
await expect(card).toBeVisible()
await expect(card).toHaveClass(/citation-highlight/)
await expect(card).toBeFocused()
await expect(card).toContainText('調査時に取得した投稿')
await expect(card).toContainText('Post saved during research')
await expect(card).toContainText('AIが調査時に取得した引用本文')
expect(
await page.locator('.deck-board').evaluate((element) => element.scrollLeft),
@@ -327,23 +325,25 @@ test('explains unconfigured Codex and prevents starting research without affecti
await expect(heading).toBeVisible()
const originalTitle = await heading.textContent()
await showResearch(page)
const panel = page.getByRole('complementary', { name: '調査チャット' })
const panel = page.getByRole('complementary', { name: 'Research chat' })
await expect(panel).toBeVisible()
await expect(
panel.getByText('自宅のCodexへの接続が設定されていません。'),
panel.getByText(
'The connection to Codex on your home server is not configured.',
),
).toBeVisible()
await expect(
panel.getByRole('button', { name: '送信', exact: true }),
panel.getByRole('button', { name: 'Send', exact: true }),
).toBeDisabled()
await expect(panel.getByLabel('メッセージ', { exact: true })).toBeDisabled()
await expect(panel.getByLabel('Message', { exact: true })).toBeDisabled()
const accessibility = await a11y().analyze()
expect(accessibility.violations).toEqual([])
await closeMobileSidebar(page)
await expect(heading).toHaveText(originalTitle ?? '')
await showDeckManagement(page)
await page.getByRole('button', { name: 'デッキを作成', exact: true }).click()
await page.getByLabel('新しいデッキ名').fill('手動の調査')
await page.getByRole('button', { name: '作成', exact: true }).click()
await page.getByRole('button', { name: 'Create deck', exact: true }).click()
await page.getByLabel('New deck name').fill('手動の調査')
await page.getByRole('button', { name: 'Create', exact: true }).click()
await closeMobileSidebar(page)
await expect(heading).toHaveText('手動の調査')
await showResearch(page)
+63 -52
View File
@@ -1,7 +1,7 @@
import { expect, test } from '../fixtures'
const reviewSubject = '来週のレビュー、日程を決める'
const coffeeSubject = '久しぶりに、お茶でも'
const reviewSubject = 'Schedule next week’s design review'
const coffeeSubject = 'Catch up over coffee'
test('reviews an edited reply and keeps the simulated result in history', async ({
page,
@@ -12,28 +12,31 @@ test('reviews an edited reply and keeps the simulated result in history', async
const rows = page.locator('.support-row')
await expect(rows).toHaveCount(3)
await rows.filter({ hasText: reviewSubject }).click()
await page.getByRole('button', { name: '丁寧に', exact: true }).click()
const reply = page.getByRole('textbox', { name: '返信', exact: true })
await expect(reply).toHaveValue(/資料をご共有/)
const edited = '資料を確認しました。初回の導線について当日お話しします。'
await page.getByRole('button', { name: 'Polite', exact: true }).click()
const reply = page.getByRole('textbox', { name: 'Reply', exact: true })
await expect(reply).toHaveValue(/Thank you for sharing/)
const edited =
'I reviewed the materials. Let’s discuss the first-time experience.'
await reply.fill(edited)
const slot = '10月5日(月)14:00–14:30'
await page.getByRole('combobox', { name: '日程候補' }).selectOption(slot)
await page.getByRole('button', { name: '返信に入れる' }).click()
await expect(reply).toHaveValue(`${edited}\n\n${slot}はいかがでしょうか。`)
await page.getByRole('button', { name: '送信内容を確認' }).click()
const dialog = page.getByRole('dialog', { name: '送信内容の確認' })
const slot = 'Mon, Oct 5, 14:00–14:30'
await page
.getByRole('combobox', { name: 'Suggested times' })
.selectOption(slot)
await page.getByRole('button', { name: 'Add to reply' }).click()
await expect(reply).toHaveValue(`${edited}\n\nWould ${slot} work for you?`)
await page.getByRole('button', { name: 'Review reply' }).click()
const dialog = page.getByRole('dialog', { name: 'Review reply' })
await expect(dialog).toContainText(edited)
await expect(dialog).toContainText(slot)
await expect(dialog).toContainText('外部には送信されません')
await expect(dialog).toContainText('No message will be sent')
expect((await a11y().analyze()).violations).toEqual([])
await dialog.getByRole('button', { name: '戻る', exact: true }).click()
await dialog.getByRole('button', { name: 'Back', exact: true }).click()
await expect(reply).toHaveValue(new RegExp(edited))
await page.getByRole('button', { name: '送信内容を確認' }).click()
await dialog.getByRole('button', { name: '送信を試す' }).click()
await page.getByRole('button', { name: 'Review reply' }).click()
await dialog.getByRole('button', { name: 'Try sending' }).click()
await expect(dialog).toHaveCount(0)
await expect(rows.filter({ hasText: reviewSubject })).toHaveCount(0)
await page.getByRole('button', { name: '履歴', exact: true }).click()
await page.getByRole('button', { name: 'History', exact: true }).click()
await rows.filter({ hasText: reviewSubject }).click()
await expect(page.locator('.support-outcome')).toContainText(edited)
await expect(page.locator('.support-outcome')).toContainText(slot)
@@ -47,21 +50,21 @@ test('defers a conversation and restores it to the current queue', async ({
const rows = page.locator('.support-row')
await rows.filter({ hasText: coffeeSubject }).click()
await page
.getByRole('textbox', { name: '返信', exact: true })
.getByRole('textbox', { name: 'Reply', exact: true })
.fill('土曜の予定を確認してから返事するね。')
await page.getByRole('button', { name: '今は置いておく' }).click()
await page.getByRole('button', { name: 'Leave for later' }).click()
await expect(rows.filter({ hasText: coffeeSubject })).toHaveCount(0)
await page.getByRole('button', { name: 'あとで', exact: true }).click()
await page.getByRole('button', { name: 'Later', exact: true }).click()
await rows.filter({ hasText: coffeeSubject }).click()
await expect(
page.getByRole('textbox', { name: '返信', exact: true }),
page.getByRole('textbox', { name: 'Reply', exact: true }),
).toHaveValue('土曜の予定を確認してから返事するね。')
await page.getByRole('button', { name: '今に戻す' }).click()
const back = page.getByRole('button', { name: '連絡一覧に戻る' })
await page.getByRole('button', { name: 'Move to Now' }).click()
const back = page.getByRole('button', { name: 'Back to messages' })
if (await back.isVisible()) await back.click()
await expect(rows.filter({ hasText: coffeeSubject })).toBeVisible()
await expect(
page.getByRole('button', { name: '今', exact: true }),
page.getByRole('button', { name: 'Now', exact: true }),
).toHaveAttribute('aria-pressed', 'true')
})
@@ -72,44 +75,52 @@ test('keeps corrections as new records and summarizes only selected current fact
await page.goto('/journal')
await page.waitForLoadState('networkidle')
await expect(
page.getByRole('button', { name: '記録する', exact: true }),
page.getByRole('button', { name: 'Save entry', exact: true }),
).toBeDisabled()
await page
.getByRole('textbox', { name: '記録内容' })
.getByRole('textbox', { name: 'Entry text' })
.fill('次はレビュー資料の導線を確認する')
await page.getByRole('button', { name: '記録する', exact: true }).click()
await expect(page.getByRole('article', { name: 'メモの記録' })).toContainText(
'発生日時: 不明',
await page.getByRole('button', { name: 'Save entry', exact: true }).click()
await expect(page.getByRole('article', { name: 'Note entry' })).toContainText(
'Occurred: Unknown',
)
await page.getByRole('button', { name: '体重', exact: true }).click()
await page.getByRole('spinbutton', { name: '体重', exact: true }).fill('65.2')
await page.getByRole('textbox', { name: '記録元' }).fill('自宅の体重計')
await page.getByRole('button', { name: '記録する', exact: true }).click()
await page.getByRole('button', { name: 'Weight', exact: true }).click()
await page
.getByRole('article', { name: '体重の記録' })
.getByRole('button', { name: '訂正する' })
.getByRole('spinbutton', { name: 'Weight', exact: true })
.fill('65.2')
await page.getByRole('textbox', { name: 'Source' }).fill('自宅の体重計')
await page.getByRole('button', { name: 'Save entry', exact: true }).click()
await page
.getByRole('article', { name: 'Weight entry' })
.getByRole('button', { name: 'Correct' })
.click()
const correction = page.getByRole('dialog', { name: '記録を訂正' })
const correction = page.getByRole('dialog', { name: 'Correct entry' })
await correction
.getByRole('spinbutton', { name: '体重', exact: true })
.getByRole('spinbutton', { name: 'Weight', exact: true })
.fill('65.8')
await correction.getByRole('button', { name: '訂正を追加' }).click()
const weights = page.getByRole('article', { name: '体重の記録' })
await correction.getByRole('button', { name: 'Add correction' }).click()
const weights = page.getByRole('article', { name: 'Weight entry' })
await expect(weights).toHaveCount(2)
await expect(weights.filter({ hasText: '65.2 kg' })).toContainText('訂正前')
await expect(weights.filter({ hasText: '65.8 kg' })).toContainText('訂正')
await expect(weights.filter({ hasText: '65.2 kg' })).toContainText('Original')
await expect(weights.filter({ hasText: '65.8 kg' })).toContainText(
'Correction',
)
await page
.getByRole('button', { name: '記録をまとめる', exact: true })
.getByRole('button', { name: 'Summarize entries', exact: true })
.click()
const review = page.getByRole('dialog', { name: '記録をまとめる' })
const summary = review.getByRole('textbox', { name: '記録のまとめ' })
const review = page.getByRole('dialog', { name: 'Summarize entries' })
const summary = review.getByRole('textbox', { name: 'Entry summary' })
await expect(summary).toHaveValue(/65.8 kg/)
await expect(summary).not.toHaveValue(/65.2 kg/)
await expect(summary).toHaveValue(/記録元: 自宅の体重計/)
await expect(summary).toHaveValue(/発生日時が不明の記録: 2件/)
await expect(summary).toHaveValue(/Source: 自宅の体重計/)
await expect(summary).toHaveValue(
/Entries with an unknown event time: 2 entries/,
)
await review.getByRole('checkbox', { name: /次はレビュー資料/ }).uncheck()
await expect(summary).not.toHaveValue(/次はレビュー資料/)
await expect(summary).toHaveValue(/記録のない期間の服薬・体重は不明/)
await expect(summary).toHaveValue(
/Medication and weight are unknown for periods without entries/,
)
expect((await a11y().analyze()).violations).toEqual([])
})
@@ -126,18 +137,18 @@ test('fits communication and journal interactions in narrow screens', async ({
).toBe(width)
await page.locator('.support-row').first().click()
await expect(
page.getByRole('textbox', { name: '返信', exact: true }),
page.getByRole('textbox', { name: 'Reply', exact: true }),
).toBeVisible()
expect(
await page.evaluate(() => document.documentElement.scrollWidth),
).toBe(width)
if (width === 320) expect((await a11y().analyze()).violations).toEqual([])
const back = page.getByRole('button', { name: '連絡一覧に戻る' })
const back = page.getByRole('button', { name: 'Back to messages' })
if (await back.isVisible()) await back.click()
await page.getByRole('link', { name: '記録', exact: true }).click()
await page.getByRole('button', { name: '体重', exact: true }).click()
await page.getByRole('link', { name: 'Journal', exact: true }).click()
await page.getByRole('button', { name: 'Weight', exact: true }).click()
await expect(
page.getByRole('spinbutton', { name: '体重', exact: true }),
page.getByRole('spinbutton', { name: 'Weight', exact: true }),
).toBeVisible()
expect(
await page.evaluate(() => document.documentElement.scrollWidth),
+3 -3
View File
@@ -17,7 +17,7 @@ test('filters body systems and opens lab history', async ({ page, a11y }) => {
const dialog = page.getByRole('dialog', { name: 'Cardiovascular' })
await expect(dialog).toContainText('68')
await dialog
.getByRole('button', { name: '閉じる', exact: true })
.getByRole('button', { name: 'Close', exact: true })
.last()
.click()
await page.getByRole('button', { name: 'Lab history', exact: true }).click()
@@ -38,7 +38,7 @@ test('explores environment charts and simulated climate controls', async ({
}) => {
await page.goto('/vitals')
await page.waitForLoadState('networkidle')
const menu = page.getByRole('button', { name: 'Healthメニューを開く' })
const menu = page.getByRole('button', { name: 'Open Health menu' })
if (await menu.isVisible()) await menu.click()
await page
.getByRole('complementary', { name: 'Health navigation' })
@@ -95,7 +95,7 @@ test('keeps both dashboards within the viewport', async ({
await page.evaluate(() => document.documentElement.scrollWidth),
).toBe(width)
await page.screenshot({ path: testInfo.outputPath(`body-${width}.png`) })
const menu = page.getByRole('button', { name: 'Healthメニューを開く' })
const menu = page.getByRole('button', { name: 'Open Health menu' })
if (await menu.isVisible()) await menu.click()
const navigation = page.getByRole('complementary', {
name: 'Health navigation',
+5 -3
View File
@@ -117,9 +117,9 @@ test('creates temporary research, edits it, persists explicitly and reopens it o
).toBeVisible()
await page
.getByRole('region', { name: '日本語', exact: true })
.getByRole('button', { name: '日本語の操作' })
.getByRole('button', { name: 'Actions for 日本語' })
.click()
await page.getByRole('menuitem', { name: '編集', exact: true }).click()
await page.getByRole('menuitem', { name: 'Edit', exact: true }).click()
const replaced = await executeTool(page, 'set_deck', {
deckId: deck.id,
title: '更新した調査',
@@ -234,7 +234,9 @@ test('keeps temporary views independent and loses only unsaved views on reload',
).toBe(false)
expect(savedCount()).toEqual({ count: 0 })
await page.reload()
await expect(page.getByRole('heading', { level: 1 })).toHaveText('新しい調査')
await expect(page.getByRole('heading', { level: 1 })).toHaveText(
'New research',
)
})
test('rejects invalid input without changing the active view', async ({
+6 -6
View File
@@ -9,10 +9,10 @@ test('keeps the sidebar, composer and deck reachable at compact widths', async (
for (const width of [320, 375, 414, 768]) {
await page.setViewportSize({ width, height: 850 })
await showResearch(page)
const chat = page.getByRole('complementary', { name: '調査チャット' })
const chat = page.getByRole('complementary', { name: 'Research chat' })
await expect(chat).toBeVisible()
const composer = chat.getByRole('textbox', {
name: 'メッセージ',
name: 'Message',
exact: true,
})
await expect(composer).toBeVisible()
@@ -30,12 +30,12 @@ test('keeps the sidebar, composer and deck reachable at compact widths', async (
if (width === 320) expect((await a11y().analyze()).violations).toEqual([])
await closeMobileSidebar(page)
}
await page.getByRole('button', { name: 'サイドバーを切り替え' }).click()
await page.getByRole('button', { name: 'Toggle sidebar' }).click()
await expect(
page.getByRole('complementary', { name: '調査チャット' }),
page.getByRole('complementary', { name: 'Research chat' }),
).toBeHidden()
await page.getByRole('button', { name: '調査チャット', exact: true }).click()
await page.getByRole('button', { name: 'Research chat', exact: true }).click()
await expect(
page.getByRole('complementary', { name: '調査チャット' }),
page.getByRole('complementary', { name: 'Research chat' }),
).toBeVisible()
})