// The X session broker UI (common/social/xSessionBroker.ts) and the X login // source (common/social/xCookieSource.ts, release 16 slice XL). The headed login // is never driven here — it would open a real browser and hit x.com, which the // suite must never do. The browser source reads a FIXTURE Firefox store written // under the test corpus, never a real browser profile. import { test, expect } from "@playwright/test"; import { readJson, resetData, resolvePath, writeSettings } from "./helpers"; // By relative path: a runtime import of the package specifier does not resolve // under playwright's loader (digest.spec.ts says why). import { writeFirefoxCookieStore } from "../../common/social/__fixtures__/firefoxCookieStore"; test("settings page renders the X session section", async ({ page }) => { await resetData("empty"); await page.goto("/settings"); await expect(page.locator("[data-x-session]")).toBeVisible(); await expect(page.getByLabel("x session state")).toHaveText("not connected"); // The headed login is an explicit operator action; the button exists but we // never click it (it would open a real browser window and hit x.com). await expect(page.getByLabel("connect x account")).toBeVisible(); await expect(page.getByLabel("refresh x cookies")).toBeDisabled(); // No cookiesFromBrowser in the fixture settings and no profile: the // read-time default is the profile. await expect(page.getByLabel("x cookie source", { exact: true })).toHaveValue("auto"); await expect(page.getByLabel("x cookie source in use")).toHaveText( "In use: Connected profile (automatic)", ); }); test("the login source select persists, and Check shows a status line", async ({ page }) => { await resetData("empty"); const profileDir = resolvePath("test-transcripts/firefox-fixture/xl.default-release"); await writeFirefoxCookieStore(profileDir, [ { host: ".x.com", name: "auth_token", value: "fixture-not-a-real-token", lastAccessed: Date.UTC(2026, 9, 1, 8, 30, 0) * 1000, }, { host: ".example.com", name: "session", value: "not-x" }, ]); const spec = `firefox:${profileDir}`; await writeSettings({ cookiesFromBrowser: spec }); await page.goto("/settings"); const section = page.locator("[data-x-session]"); const select = page.getByLabel("x cookie source", { exact: true }); const inUse = page.getByLabel("x cookie source in use"); // cookiesFromBrowser set, no profile connected: the browser, by default. await expect(select).toHaveValue("auto"); await expect(inUse).toHaveText(`In use: Browser login (${spec}) (automatic)`); await page.getByLabel("check x login").click(); await expect(page.getByLabel("x login status")).toContainText( "An X login is visible in firefox, outside its containers (where gallery-dl reads); " + "its auth_token was last used 2026-10-01 08:30:00 UTC.", ); // Choose the profile: stored, shown, and still chosen after a reload. await select.selectOption("profile"); await expect(section.getByRole("status")).toHaveText("Login source saved."); await expect(inUse).toHaveText("In use: Connected profile"); expect((await readJson<{ social?: unknown }>("test-settings.json")).social).toEqual({ x: { cookieSource: "profile" }, }); await page.reload(); await expect(select).toHaveValue("profile"); await expect(inUse).toHaveText("In use: Connected profile"); await page.getByLabel("check x login").click(); await expect(page.getByLabel("x login status")).toContainText("No profile is connected."); // Back to automatic: nothing stored, the default decides again. await select.selectOption("auto"); await expect(inUse).toHaveText(`In use: Browser login (${spec}) (automatic)`); expect((await readJson<{ social?: unknown }>("test-settings.json")).social).toEqual({ x: {} }); }); // Where X posts appear — `social.x.visibility` (release 17 slice XP). The two X // choices share one settings block, and saveSettings replaces a nested block // whole, so each is written over the other: choosing one keeps the other. test("where X posts appear persists, beside the login source and without it", async ({ page }) => { await resetData("empty"); await page.goto("/settings"); const visibility = page.getByLabel("Where X posts appear"); const source = page.getByLabel("x cookie source", { exact: true }); const social = async () => (await readJson<{ social?: unknown }>("test-settings.json")).social; await expect(visibility).toHaveValue("public"); await expect(page.locator("[data-x-posts-visibility]")).toContainText( "Sites already published change on their next build and deploy.", ); await source.selectOption("profile"); await expect(page.getByLabel("x cookie source in use")).toHaveText("In use: Connected profile"); await visibility.selectOption("private"); await expect(page.getByLabel("x posts visibility saved")).toHaveText( "Saved. Published sites change on their next build and deploy.", ); expect(await social()).toEqual({ x: { cookieSource: "profile", visibility: "private" } }); await page.reload(); await expect(visibility).toHaveValue("private"); // The login source back to automatic keeps the visibility… await source.selectOption("auto"); await expect(page.getByLabel("x cookie source in use")).toHaveText( "In use: Connected profile (automatic)", ); expect(await social()).toEqual({ x: { visibility: "private" } }); // …and public is the default, written as no key. await visibility.selectOption("public"); await expect(page.getByLabel("x posts visibility saved")).toBeVisible(); expect(await social()).toEqual({ x: {} }); });