このコミットが含まれているのは:
2026-10-25 14:14:55 +09:00
コミット 304090f717
16個のファイルの変更、745行の追加、27行の削除
+50 -1
ファイルの表示
@@ -62,6 +62,14 @@ const responseFor = url => {
return { locales: [{ code: 'ja', name: '日本語' }, { code: 'ain-Kana', name: 'アイヌ' }] }
if (path === '/users/settings') return { theme: 'system', wiki_editor_mode: 'split' }
if (path === '/users/theme_slots') return []
if (path === '/counts/posts' || path === '/counts/tags') {
const resource = path.endsWith ('posts') ? 'posts' : 'tags'
return { count: 1, page: 1, limit: 20, group_count: 1,
groups: [{ key: 'create', name: null, count: 1 }],
versions: resource === 'posts'
? [{ post_id: 1, version_no: 1, title: { current: `SSR count ${locale}` } }]
: [{ tag_id: 1, version_no: 1, name: { current: `SSR count ${locale}` } }] }
}
if (path === '/posts') return { posts: [post (locale)], count: 1 }
if (path === '/gekanator/posts') return { posts: [post (locale)] }
if (path === '/gekanator/questions') return { questions: [] }
@@ -300,6 +308,21 @@ after (async () => {
if (errors.length) throw new AggregateError (errors, 'SSR teardown failed')
})
test ('counts SSR renders history data and retains URL query state', async () => {
for (const locale of ['ja', 'ain-Kana']) {
for (const resource of ['posts', 'tags']) {
const column = resource === 'posts' ? 'title' : 'name'
const query = `mode=details&columns=${column}&user_id=4`
const result = await renderPage (`/${locale}/counts/${resource}?${query}`, origin, apiURL)
assert.equal (result.status, 200)
assert.match (result.html, new RegExp (`SSR count ${locale}`))
assert.match (result.html, new RegExp (`/${locale}/${resource}/1`))
assert.ok (requests.some (request => request.url.includes (`/counts/${resource}`)
&& request.url.includes ('user_id=4') && request.url.includes (`locale=${locale}`)))
}
}
})
test ('every canonical screen route returns page HTML without JavaScript', async t => {
const cookie = await authenticatedCookie ()
for (const route of routes) {
@@ -582,7 +605,8 @@ test ('hydrate every route with stored browser preferences', {
}` }, sessionId)
const evaluate = async expression => (await send ('Runtime.evaluate', {
expression, returnByValue: true }, sessionId)).result.value
for (const route of routes.filter (entry => !entry.handle?.redirectTo)) {
for (const route of routes.filter (entry => !entry.handle?.redirectTo
&& (process.env.SSR_COUNTS_ONLY !== '1' || entry.path.startsWith ('counts')))) {
for (const locale of ['ja', 'ain-Kana']) {
await t.test (`hydrate ${locale} ${route.path}`, async () => {
const path = route.path.replace (':identifier', 'home').replace (/:id|:title/g, '1')
@@ -608,6 +632,31 @@ test ('hydrate every route with stored browser preferences', {
})
}
}
for (const width of [375, 1240]) {
await send ('Emulation.setDeviceMetricsOverride', {
width, height: 900, deviceScaleFactor: 1, mobile: width < 768 }, sessionId)
for (const resource of ['posts', 'tags']) {
await t.test (`counts layout ${width} ${resource}`, async () => {
await send ('Page.navigate', {
url: `${httpOrigin}/ja/counts/${resource}` }, sessionId)
let ready = false
for (let attempt = 0; attempt < 100; ++attempt) {
await new Promise (resolve => setTimeout (resolve, 75))
try {
ready = await evaluate (`document.querySelector('tbody tr')!=null`)
} catch {}
if (ready) break
}
assert.ok (ready, 'history query results must render')
for (const dark of [false, true]) {
await evaluate (`document.documentElement.classList.toggle('dark',${dark})`)
assert.ok (await evaluate ('document.documentElement.scrollWidth<=innerWidth'),
'counts controls must fit the viewport in both themes')
}
})
}
}
if (process.env.SSR_COUNTS_ONLY === '1') return
probeActive = true
for (const width of [375, 1240]) {
await send ('Emulation.setDeviceMetricsOverride', {