A "YouTube history" section under YouTube access: the watch history and the Watch later csv are dropped or picked (one request each, each file's outcome said on its own), and the section then says what the import did - only the counts it produced - or that it is running, failed or was cut off by a restart. While it runs it asks again until it ends; a failed re-read shows the failure, not the previous answer. The drop zone the Files upload had inline is now ui/DropZone, used by both. The e2e seed clears the account's kept Takeout videos.
60 lines
2.9 KiB
TypeScript
60 lines
2.9 KiB
TypeScript
import { test, expect } from "@playwright/test";
|
||
import { openApp, gotoPage } from "./helpers";
|
||
|
||
// Settings › Account › YouTube history: a Google Takeout watch history, uploaded through the real
|
||
// picker, is read, imported in the background, and the section says what it did — a video the
|
||
// catalog knows is marked watched, one it does not know is remembered for later. The seed clears
|
||
// the account's kept Takeout videos each run, but the projects share one account: a later one's
|
||
// feed no longer holds the video an earlier one marked, so what it adds is counted against what was
|
||
// there before it.
|
||
test("a Takeout watch history uploads, imports, and the section says what it did", async ({
|
||
page,
|
||
}) => {
|
||
await openApp(page);
|
||
// A video the catalog knows: one on the account's feed (not a Short — the feed leaves them out).
|
||
const known = await page.getByTestId("video-card").first().getAttribute("data-video-id");
|
||
expect(known).toBeTruthy();
|
||
|
||
await gotoPage(page, "settings");
|
||
await page.getByRole("tab", { name: "Account" }).click();
|
||
await expect(page.getByRole("heading", { name: "YouTube history" })).toBeVisible();
|
||
// The first project's upload is an import already made: its "New import" opens the drop zone.
|
||
const zone = page.getByRole("button", { name: "Drop the files here, or choose them" });
|
||
const again = page.getByRole("button", { name: "New import" });
|
||
await expect(zone.or(again)).toBeVisible();
|
||
if (await again.isVisible()) await again.click();
|
||
await expect(zone).toBeVisible();
|
||
const before = (await (await page.request.get("/api/takeout")).json()) as {
|
||
watched?: Record<string, number>;
|
||
};
|
||
const watchedBefore = before.watched?.watched ?? 0;
|
||
|
||
// Watched now: later than any state the seed set, which the import would otherwise leave alone.
|
||
const now = new Date().toISOString();
|
||
const history = [
|
||
{ titleUrl: `https://www.youtube.com/watch?v=${known}`, time: now },
|
||
{ titleUrl: "https://www.youtube.com/watch?v=e2eUnknown0", time: now },
|
||
{
|
||
titleUrl: "https://www.youtube.com/watch?v=e2eAdvert00",
|
||
time: now,
|
||
details: [{ name: "From Google Ads" }],
|
||
},
|
||
];
|
||
const uploaded = page.waitForResponse(
|
||
(r) => r.url().endsWith("/api/takeout") && r.request().method() === "POST",
|
||
);
|
||
await page.locator('input[type="file"][accept=".json,.csv"]').setInputFiles({
|
||
name: "watch-history.json",
|
||
mimeType: "application/json",
|
||
buffer: Buffer.from(JSON.stringify(history)),
|
||
});
|
||
expect((await uploaded).ok()).toBeTruthy();
|
||
|
||
await expect(page.getByText("watch-history.json: 2 videos read")).toBeVisible();
|
||
const line = page.getByTestId("takeout-last");
|
||
await expect(line).toContainText("Last import:");
|
||
await expect(line).toContainText(`${watchedBefore + 1} watched`);
|
||
await expect(line).toContainText("1 remembered");
|
||
await expect(page.getByRole("button", { name: "New import" })).toBeVisible();
|
||
});
|