← Files DataARCHIVED FILE

templates/data-app/base/tests/refresh-coachmark.test.mjs

13.6 KB · Oct 5, 2026 · 12:04 UTC

↓ Download file

import assert from "node:assert/strict";
import test from "node:test";

import { claimRefreshCoachmark, REFRESH_COACHMARK_COOKIE, refreshCoachmarkDomain, rememberRefreshCoachmark } from "../src/refresh-coachmark.js";
import { readVerificationReminderDismissed, rememberVerificationReminderDismissed, VERIFICATION_REMINDER_COOKIE } from "../src/verification-reminder.js";

const site = name => new URL(`https://${name}.example.chatgpt.site/`);
function browserJar({ blocked = false } = {}) {
  const entries = new Map(), writes = [];
  return {
    writes,
    document(location) {
      return {
        get cookie() {
          return [...entries].filter(([domain]) => location.hostname === domain || location.hostname.endsWith(`.${domain}`))
            .flatMap(([, cookies]) => [...cookies.values()]).join("; ");
        },
        set cookie(value) {
          writes.push(value);
          if (blocked) return;
          const domain = /; Domain=([^;]+)/u.exec(value)?.[1];
          if (domain && (location.hostname === domain || location.hostname.endsWith(`.${domain}`))) {
            const pair = value.split(";")[0], name = pair.split("=")[0];
            if (!entries.has(domain)) entries.set(domain, new Map());
            entries.get(domain).set(name, pair);
          }
        },
      };
    },
  };
}
const immediate = () => Promise.resolve();
const nonce = () => "test-claim-token";

test("refresh education uses the workspace domain, never a website or public-suffix fallback", () => {
  assert.equal(refreshCoachmarkDomain(site("first")), "example.chatgpt.site");
  assert.equal(refreshCoachmarkDomain(site("second")), "example.chatgpt.site");
  assert.equal(refreshCoachmarkDomain(new URL("https://dashboard.openai.chatgpt.site")), "openai.chatgpt.site");
  for (const href of ["http://first.example.chatgpt.site", "https://dashboard.chatgpt.site", "https://chatgpt.site",
    "https://example.com", "https://localhost", "https://a.b.c.chatgpt.site", "https://a.b.chatgpt.site.evil.test"]) {
    assert.equal(refreshCoachmarkDomain(new URL(href)), null, href);
  }
});

test("one cookie suppresses the coachmark across different dashboard origins in the same workspace", async () => {
  const jar = browserJar();
  const first = site("first"), second = site("second");
  assert.notEqual(first.origin, second.origin);
  assert.equal(await claimRefreshCoachmark({ location: first, document: jar.document(first), nonce, settle: immediate }), true);
  assert.equal(await claimRefreshCoachmark({ location: second, document: jar.document(second), nonce, settle: immediate }), false);
  assert.equal(await claimRefreshCoachmark({ location: first, document: jar.document(first), nonce, settle: immediate }), false);
  assert.ok(jar.writes.every(value => value.includes("Domain=example.chatgpt.site; Path=/; Max-Age=34560000; Secure; SameSite=Lax")));
  assert.ok(jar.writes.every(value => value.startsWith(`${REFRESH_COACHMARK_COOKIE}=`)));
  assert.doesNotMatch(jar.writes.join("\n"), /first\.|second\.|email|user_id|account/u);
});

test("workspace and browser boundaries remain explicit", async () => {
  const jar = browserJar(), otherBrowser = browserJar();
  const first = site("first"), otherWorkspace = new URL("https://first.other.chatgpt.site/");
  for (const [browser, location] of [[jar, first], [jar, otherWorkspace], [otherBrowser, first]]) {
    assert.equal(await claimRefreshCoachmark({ document: browser.document(location), location, nonce, settle: immediate }), true);
  }
});

test("blocked or throwing cookie storage keeps the coachmark hidden", async () => {
  const location = site("first"), jar = browserJar({ blocked: true });
  assert.equal(await claimRefreshCoachmark({ location, document: jar.document(location), nonce, settle: immediate }), false);
  assert.equal(rememberRefreshCoachmark({ location, document: jar.document(location) }), false);
  const denied = { get cookie() { throw new Error("Cookie access blocked"); }, set cookie(_) { throw new Error("Cookie write blocked"); } };
  assert.equal(await claimRefreshCoachmark({ location, document: denied, nonce, settle: immediate }), false);
  assert.equal(rememberRefreshCoachmark({ location, document: denied }), false);
});

test("manual refresh setup consumes the workspace-wide tip before it is offered", async () => {
  const jar = browserJar(), first = site("first"), second = site("second");
  assert.equal(rememberRefreshCoachmark({ location: first, document: jar.document(first) }), true);
  assert.equal(await claimRefreshCoachmark({ location: second, document: jar.document(second), nonce, settle: immediate }), false);
});

test("an in-progress claim suppresses another tab and loses to explicit setup", async () => {
  const jar = browserJar(), first = site("first"), second = site("second");
  let release;
  const pending = claimRefreshCoachmark({ location: first, document: jar.document(first), nonce,
    settle: () => new Promise(resolve => { release = resolve; }) });
  assert.equal(await claimRefreshCoachmark({ location: second, document: jar.document(second), nonce, settle: immediate }), false);
  rememberRefreshCoachmark({ location: second, document: jar.document(second) });
  release();
  assert.equal(await pending, false);
});

test("cancellation and a replaced claim cannot show a stale coachmark", async () => {
  const jar = browserJar(), location = site("first"), document = jar.document(location);
  assert.equal(await claimRefreshCoachmark({ location, document, nonce, settle: immediate, cancelled: () => true }), false);
  assert.equal(jar.writes.length, 0);
  assert.equal(await claimRefreshCoachmark({ location, document, nonce, settle: async () => {
    document.cookie = `${REFRESH_COACHMARK_COOKIE}=another-tab-token; Domain=example.chatgpt.site; Path=/; Secure`;
  } }), false);
  assert.equal(await claimRefreshCoachmark({ location, document, nonce, settle: immediate }), false);
});

test("unsupported hosts and unsafe claim tokens never write a cookie", async () => {
  const jar = browserJar(), location = new URL("https://custom.example.com");
  assert.equal(await claimRefreshCoachmark({ location, document: jar.document(location), nonce, settle: immediate }), false);
  assert.equal(await claimRefreshCoachmark({ location: site("first"), document: jar.document(site("first")), nonce: () => "; Domain=other.test", settle: immediate }), false);
  assert.equal(jar.writes.length, 0);
});

test("verification reminder dismissal is shared across workspace Sites without renewing on reads", () => {
  const jar = browserJar(), first = site("first"), second = site("second");
  assert.equal(readVerificationReminderDismissed({ location: first, document: jar.document(first) }), false);
  assert.equal(jar.writes.length, 0);
  assert.equal(rememberVerificationReminderDismissed({ location: first, document: jar.document(first) }), true);
  for (let read = 0; read < 20; read += 1) {
    assert.equal(readVerificationReminderDismissed({ location: second, document: jar.document(second) }), true);
  }
  assert.equal(jar.writes.length, 1, "Opening or rendering another dashboard does not renew the cookie");
  const [pair, ...attributes] = jar.writes[0].split("; ");
  assert.equal(pair, `${VERIFICATION_REMINDER_COOKIE}=1`);
  assert.ok(Buffer.byteLength(pair) < 64, "The request carries only one compact flag, not an identity or dashboard list");
  assert.deepEqual(attributes, ["Domain=example.chatgpt.site", "Path=/", "Max-Age=34560000", "Secure", "SameSite=Lax"]);
});

test("verification reminder cookies stay within their workspace and browser", () => {
  const jar = browserJar(), otherBrowser = browserJar();
  const first = site("first"), otherWorkspace = new URL("https://first.other.chatgpt.site/");
  assert.equal(rememberVerificationReminderDismissed({ location: first, document: jar.document(first) }), true);
  assert.equal(readVerificationReminderDismissed({ location: otherWorkspace, document: jar.document(otherWorkspace) }), false);
  assert.equal(readVerificationReminderDismissed({ location: first, document: otherBrowser.document(first) }), false);
  assert.equal(rememberVerificationReminderDismissed({ location: otherWorkspace, document: jar.document(otherWorkspace) }), true);
  assert.equal(readVerificationReminderDismissed({ location: first, document: jar.document(first) }), true);
  assert.equal(readVerificationReminderDismissed({ location: otherWorkspace, document: jar.document(otherWorkspace) }), true);
});

test("verification reminder storage has no unsupported-host or malformed-location fallback", () => {
  for (const location of [
    ...["http://first.example.chatgpt.site", "https://dashboard.chatgpt.site", "https://chatgpt.site",
      "https://custom.example.com", "https://localhost", "https://a.b.c.chatgpt.site", "https://a.b.chatgpt.site.evil.test"]
      .map(href => new URL(href)),
    null, {}, { protocol: "https:", hostname: 123 },
  ]) {
    let accessed = false;
    const document = { get cookie() { accessed = true; return `${VERIFICATION_REMINDER_COOKIE}=1`; },
      set cookie(_) { accessed = true; } };
    assert.equal(readVerificationReminderDismissed({ location, document }), false);
    assert.equal(rememberVerificationReminderDismissed({ location, document }), false);
    assert.equal(accessed, false, "Unsupported locations do not read or write cookies");
  }
});

test("verification reminder reads accept only one exact flag and fail closed for malformed cookies", () => {
  const location = site("first");
  for (const cookie of ["", `${VERIFICATION_REMINDER_COOKIE}=0`, `${VERIFICATION_REMINDER_COOKIE}=true`,
    `${VERIFICATION_REMINDER_COOKIE}=01`, `${VERIFICATION_REMINDER_COOKIE}=%31`, `${VERIFICATION_REMINDER_COOKIE}="1"`,
    `${VERIFICATION_REMINDER_COOKIE}=1x`, `other_${VERIFICATION_REMINDER_COOKIE}=1`,
    `${VERIFICATION_REMINDER_COOKIE}=1; ${VERIFICATION_REMINDER_COOKIE}=0`,
    `${VERIFICATION_REMINDER_COOKIE}=1; ${VERIFICATION_REMINDER_COOKIE}=1`, null, 1]) {
    assert.equal(readVerificationReminderDismissed({ location, document: { cookie } }), false, String(cookie));
  }
  assert.equal(readVerificationReminderDismissed({ location, document: {
    cookie: `unrelated=1; ${VERIFICATION_REMINDER_COOKIE}=1; another=0`,
  } }), true);
});

test("verification reminder writes require readback and leave the reminder enabled when storage fails", () => {
  const location = site("first"), blocked = browserJar({ blocked: true });
  for (const document of [null, blocked.document(location),
    { get cookie() { throw new Error("Cookie access blocked"); }, set cookie(_) {} },
    { get cookie() { return ""; }, set cookie(_) { throw new Error("Cookie write blocked"); } },
    { get cookie() { return `${VERIFICATION_REMINDER_COOKIE}=0`; }, set cookie(_) {} },
  ]) {
    assert.equal(readVerificationReminderDismissed({ location, document }), false);
    assert.equal(rememberVerificationReminderDismissed({ location, document }), false);
  }
});

test("verification and refresh cookies coexist without dismissing each other's reminders", async () => {
  const first = site("first"), second = site("second");
  const verificationFirst = browserJar();
  assert.equal(rememberVerificationReminderDismissed({ location: first, document: verificationFirst.document(first) }), true);
  assert.equal(await claimRefreshCoachmark({ location: second, document: verificationFirst.document(second), nonce, settle: immediate }), true);
  assert.equal(readVerificationReminderDismissed({ location: second, document: verificationFirst.document(second) }), true);
  assert.equal(await claimRefreshCoachmark({ location: first, document: verificationFirst.document(first), nonce, settle: immediate }), false);

  const refreshFirst = browserJar();
  assert.equal(rememberRefreshCoachmark({ location: first, document: refreshFirst.document(first) }), true);
  assert.equal(readVerificationReminderDismissed({ location: second, document: refreshFirst.document(second) }), false);
  assert.equal(rememberVerificationReminderDismissed({ location: second, document: refreshFirst.document(second) }), true);
  assert.equal(await claimRefreshCoachmark({ location: first, document: refreshFirst.document(first), nonce, settle: immediate }), false);
  assert.equal(readVerificationReminderDismissed({ location: first, document: refreshFirst.document(first) }), true);
  assert.equal(refreshFirst.document(first).cookie.split("; ").length, 2);
});

test("coachmark is owner-only, published-only, idle, non-modal, and only points to the refresh menu", async () => {
  const { readFile } = await import("node:fs/promises");
  const chrome = await readFile(new URL("../src/components/DataAppChrome.jsx", import.meta.url), "utf8");
  const source = await readFile(new URL("../src/components/RefreshSetupCoachmark.jsx", import.meta.url), "utf8");
  assert.match(chrome, /mode !== "edit" && generatedAt && canEdit && surface !== "report"[\s\S]*?<DataAppRefreshControl[^>]*published=\{published\}/u);
  assert.match(chrome, /blocked=\{open \|\| menuOpen\}[^>]*anchor=\{trigger\}/u);
  assert.match(chrome, /if \(published === true\) rememberRefreshCoachmark\(\)/u);
  assert.match(source, /published !== true \|\| blocked \|\| !refreshCoachmarkDomain\(\) \|\| window.top !== window/u);
  assert.match(source, /document.visibilityState !== "visible"/u);
  assert.match(source, /setTimeout\(offerWhenIdle, 1800\)/u);
  assert.match(source, /cancelled: \(\) => cancelled \|\| isBusy\(\)/u);
  assert.match(source, /if \(!cancelled && claimed\) setVisible\(true\)/u);
  assert.match(source, /role="status"/u);
  assert.match(source, /Set up automatic refreshes from this menu/u);
  assert.equal((source.match(/<button\b/gu) ?? []).length, 1, "The coachmark only has its dismissal control");
  assert.doesNotMatch(source, /onSetup|autoFocus|<[^>]*role="dialog"|href=|fetch\(|getActionHref|sendPrompt/u);
});

SHA-256: 48e7ada3c0dfcccb153f22dc7a8f43e4654db4e0361dc26e9776d614d6a28ebc