fix: restore Journal history only after matching query data
This commit is contained in:
@@ -19,8 +19,7 @@ const root = join(dirname(fromFileUrl(import.meta.url)), "../../..");
|
|||||||
const artifacts = join(root, "target/web-ux/t-737-browser-interactions");
|
const artifacts = join(root, "target/web-ux/t-737-browser-interactions");
|
||||||
const subjectPath = `/w/${fixture.workspaceId}/subjektiv/${fixture.subjectId}`;
|
const subjectPath = `/w/${fixture.workspaceId}/subjektiv/${fixture.subjectId}`;
|
||||||
const journalPath = `${subjectPath}/journal`;
|
const journalPath = `${subjectPath}/journal`;
|
||||||
const memoryPath =
|
const memoryPath = `${subjectPath}/memories/${fixture.memoryId}?change_id=change-current`;
|
||||||
`${subjectPath}/memories/${fixture.memoryId}?change_id=change-current`;
|
|
||||||
const claim = "Keep subject Memory provenance typed and visible";
|
const claim = "Keep subject Memory provenance typed and visible";
|
||||||
const entryTitle = "Release milestone 00 · release [a+b] %_";
|
const entryTitle = "Release milestone 00 · release [a+b] %_";
|
||||||
const detailPath = `${journalPath}?journal=journal-release&entry=entry-00`;
|
const detailPath = `${journalPath}?journal=journal-release&entry=entry-00`;
|
||||||
@@ -87,9 +86,7 @@ Deno.test("Journal fixture UI keeps scoped navigation, bounded links and distinc
|
|||||||
requests.push({
|
requests.push({
|
||||||
path,
|
path,
|
||||||
method: request.method(),
|
method: request.method(),
|
||||||
payload: request.method() === "POST"
|
payload: request.method() === "POST" ? request.postDataJSON() : null,
|
||||||
? request.postDataJSON()
|
|
||||||
: null,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -169,18 +166,14 @@ Deno.test("Journal fixture UI keeps scoped navigation, bounded links and distinc
|
|||||||
fixture.literalQuery,
|
fixture.literalQuery,
|
||||||
);
|
);
|
||||||
await page.getByRole("button", { name: "検索", exact: true }).click();
|
await page.getByRole("button", { name: "検索", exact: true }).click();
|
||||||
await page.waitForURL((url) =>
|
await page.waitForURL((url) => url.searchParams.get("q") === fixture.literalQuery);
|
||||||
url.searchParams.get("q") === fixture.literalQuery
|
|
||||||
);
|
|
||||||
await page.getByRole("link", {
|
await page.getByRole("link", {
|
||||||
name: new RegExp(entryTitle.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")),
|
name: new RegExp(entryTitle.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")),
|
||||||
}).waitFor();
|
}).waitFor();
|
||||||
assertEquals(await page.locator(".entry-list > li").count(), 16);
|
assertEquals(await page.locator(".entry-list > li").count(), 16);
|
||||||
await page.getByRole("link", { name: "次のページ →", exact: true })
|
await page.getByRole("link", { name: "次のページ →", exact: true })
|
||||||
.click();
|
.click();
|
||||||
await page.waitForURL((url) =>
|
await page.waitForURL((url) => url.searchParams.get("after") === "fixture-entries-2");
|
||||||
url.searchParams.get("after") === "fixture-entries-2"
|
|
||||||
);
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
new URL(page.url()).searchParams.get("q"),
|
new URL(page.url()).searchParams.get("q"),
|
||||||
fixture.literalQuery,
|
fixture.literalQuery,
|
||||||
@@ -199,9 +192,7 @@ Deno.test("Journal fixture UI keeps scoped navigation, bounded links and distinc
|
|||||||
r.payload.query === fixture.literalQuery
|
r.payload.query === fixture.literalQuery
|
||||||
);
|
);
|
||||||
assert(
|
assert(
|
||||||
searchRequests.some((r) =>
|
searchRequests.some((r) => r.payload?.after === "fixture-entries-2"),
|
||||||
r.payload?.after === "fixture-entries-2"
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -219,9 +210,7 @@ Deno.test("Journal fixture UI keeps scoped navigation, bounded links and distinc
|
|||||||
await page.setViewportSize(viewport);
|
await page.setViewportSize(viewport);
|
||||||
await page.emulateMedia({ colorScheme: viewport.theme });
|
await page.emulateMedia({ colorScheme: viewport.theme });
|
||||||
await page.goto(
|
await page.goto(
|
||||||
`${base}${journalPath}?q=${
|
`${base}${journalPath}?q=${encodeURIComponent(fixture.literalQuery)}`,
|
||||||
encodeURIComponent(fixture.literalQuery)
|
|
||||||
}`,
|
|
||||||
);
|
);
|
||||||
const target = page.locator(".entry-list a").filter({
|
const target = page.locator(".entry-list a").filter({
|
||||||
hasText: "Release milestone 12",
|
hasText: "Release milestone 12",
|
||||||
@@ -288,7 +277,45 @@ Deno.test("Journal fixture UI keeps scoped navigation, bounded links and distinc
|
|||||||
await page.locator("[data-journal-view='detail']").waitFor();
|
await page.locator("[data-journal-view='detail']").waitFor();
|
||||||
assertEquals(page.url(), detailUrl);
|
assertEquals(page.url(), detailUrl);
|
||||||
await restoreTop(page, detailTop);
|
await restoreTop(page, detailTop);
|
||||||
await page.goBack();
|
let listBlocked = false;
|
||||||
|
const releaseList = Promise.withResolvers<void>();
|
||||||
|
const continuedList = Promise.withResolvers<void>();
|
||||||
|
await page.route("**/journal-browser", async (route) => {
|
||||||
|
if (route.request().postDataJSON()?.action === "entries") {
|
||||||
|
listBlocked = true;
|
||||||
|
await releaseList.promise;
|
||||||
|
try {
|
||||||
|
await route.continue();
|
||||||
|
} finally {
|
||||||
|
continuedList.resolve();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await route.continue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
const requested = page.waitForRequest((request) =>
|
||||||
|
request.url().endsWith("/journal-browser") &&
|
||||||
|
request.postDataJSON()?.action === "entries"
|
||||||
|
);
|
||||||
|
await page.goBack();
|
||||||
|
await requested;
|
||||||
|
await page.evaluate(() =>
|
||||||
|
new Promise<void>((resolve) => {
|
||||||
|
const frame = (globalThis as any).requestAnimationFrame;
|
||||||
|
frame(() => frame(() => resolve()));
|
||||||
|
})
|
||||||
|
);
|
||||||
|
assertEquals(
|
||||||
|
await page.locator("[data-journal-view]").count(),
|
||||||
|
0,
|
||||||
|
"a query-changing history restore must wait for its own Journal data",
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
releaseList.resolve();
|
||||||
|
if (listBlocked) await continuedList.promise;
|
||||||
|
await page.unrouteAll({ behavior: "wait" });
|
||||||
|
}
|
||||||
await page.getByRole("searchbox").waitFor();
|
await page.getByRole("searchbox").waitFor();
|
||||||
assertEquals(page.url(), listUrl);
|
assertEquals(page.url(), listUrl);
|
||||||
assertEquals(
|
assertEquals(
|
||||||
@@ -391,9 +418,7 @@ Deno.test("Journal fixture UI keeps scoped navigation, bounded links and distinc
|
|||||||
.waitFor();
|
.waitFor();
|
||||||
assertEquals(await popup.locator(".related-list a").count(), 0);
|
assertEquals(await popup.locator(".related-list a").count(), 0);
|
||||||
await popup.close();
|
await popup.close();
|
||||||
const candidateRequests = requests.filter((r) =>
|
const candidateRequests = requests.filter((r) => r.payload?.action === "memory_sources");
|
||||||
r.payload?.action === "memory_sources"
|
|
||||||
);
|
|
||||||
assert(candidateRequests.length > 0);
|
assert(candidateRequests.length > 0);
|
||||||
for (const r of candidateRequests) {
|
for (const r of candidateRequests) {
|
||||||
assertEquals(r.payload?.selector.candidate_id, fixture.candidateId);
|
assertEquals(r.payload?.selector.candidate_id, fixture.candidateId);
|
||||||
@@ -538,8 +563,7 @@ Deno.test("Journal fixture UI keeps scoped navigation, bounded links and distinc
|
|||||||
for (
|
for (
|
||||||
const state of [
|
const state of [
|
||||||
{
|
{
|
||||||
path:
|
path: `/w/${fixture.workspaceId}/subjektiv/empty-subject/journal?view=sessions`,
|
||||||
`/w/${fixture.workspaceId}/subjektiv/empty-subject/journal?view=sessions`,
|
|
||||||
text: "Journalはまだありません。",
|
text: "Journalはまだありません。",
|
||||||
role: "status" as const,
|
role: "status" as const,
|
||||||
},
|
},
|
||||||
@@ -620,9 +644,7 @@ Deno.test("Journal fixture UI keeps scoped navigation, bounded links and distinc
|
|||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
for (
|
for (
|
||||||
const request of requests.filter((r) =>
|
const request of requests.filter((r) => r.path.endsWith("/journal-browser"))
|
||||||
r.path.endsWith("/journal-browser")
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
assertEquals(request.method, "POST");
|
assertEquals(request.method, "POST");
|
||||||
if (request.payload?.limit != null) {
|
if (request.payload?.limit != null) {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { page } from '$app/state';
|
||||||
import DeferredPage from '#lib/workspace/navigation/DeferredPage.svelte';
|
import DeferredPage from '#lib/workspace/navigation/DeferredPage.svelte';
|
||||||
import ReadingPosition from '#lib/workspace/memory/ReadingPosition.svelte';
|
import ReadingPosition from '#lib/workspace/memory/ReadingPosition.svelte';
|
||||||
import PageContent from './PageContent.svelte';
|
import PageContent from './PageContent.svelte';
|
||||||
@@ -10,7 +11,7 @@
|
|||||||
restore: (saved: { top: number }) => { position = saved; },
|
restore: (saved: { top: number }) => { position = saved; },
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<DeferredPage {data} title="Journal">
|
<DeferredPage {data} title="Journal" identity={`${page.url.pathname}${page.url.search}`}>
|
||||||
{#snippet children(resolved)}
|
{#snippet children(resolved)}
|
||||||
<PageContent data={resolved} />
|
<PageContent data={resolved} />
|
||||||
<ReadingPosition {position} restored={() => { position = null; }} />
|
<ReadingPosition {position} restored={() => { position = null; }} />
|
||||||
|
|||||||
Reference in New Issue
Block a user