Files
CloakBrowser/js/tests/widevine-integration.test.ts
T
CloakHQ dcf9ba55d6 feat(widevine): auto-seed CDM hint file for persistent contexts (Linux)
Sideloaded Widevine works on the first launch of a persistent context
instead of needing a manual two-launch hint-file workaround. The wrapper
writes Chromium's CDM hint file into the profile before launch when a
WidevineCdm directory is present next to the binary.

- New cloakbrowser/widevine.py and js/src/widevine.ts: resolve a sideloaded
  CDM (CLOAKBROWSER_WIDEVINE_CDM env var, else next to the binary) and seed
  the hint file. Linux only; no-op elsewhere. CLOAKBROWSER_WIDEVINE=0 disables.
- Never bundles/downloads/copies the CDM (proprietary); seeds only when the
  user-provided CDM is already present.
- Wired into launch_persistent_context[_async] and launchPersistentContext.
- README + js/README: Widevine / DRM section, env vars, FPJS tradeoff note.
- Tests: tests/test_widevine.py, js/tests/widevine.test.ts, persistent-context
  integration assertions.
2026-05-29 22:59:59 +02:00

58 lines
2.2 KiB
TypeScript

import { describe, it, expect, vi, afterEach, beforeEach } from "vitest";
// Assert the persistent-context launchers actually invoke seedWidevineHint,
// so accidental removal of the wiring fails CI (parity with the Python
// test_persistent_context_seeds_widevine tests).
vi.mock("../src/widevine.js", () => ({
seedWidevineHint: vi.fn(),
resolveWidevineCdmDir: vi.fn(),
}));
vi.mock("../src/download.js", () => ({
ensureBinary: vi.fn().mockResolvedValue("/fake/chrome"),
}));
vi.mock("../src/geoip.js", () => ({
resolveProxyGeo: vi.fn().mockResolvedValue({ timezone: null, locale: null }),
maybeResolveGeoip: vi.fn().mockResolvedValue({}),
resolveWebrtcArgs: vi.fn().mockImplementation((opts: any) => Promise.resolve(opts.args)),
}));
vi.mock("playwright-core", () => ({ chromium: { launchPersistentContext: vi.fn() } }));
vi.mock("puppeteer-core", () => ({ default: { launch: vi.fn() } }));
describe("persistent context seeds Widevine (integration)", () => {
beforeEach(() => {
delete process.env.CLOAKBROWSER_BINARY_PATH;
});
afterEach(() => {
vi.clearAllMocks();
});
it("Playwright launchPersistentContext seeds with (userDataDir, binaryPath)", async () => {
const pw = await import("playwright-core");
vi.mocked(pw.chromium.launchPersistentContext).mockResolvedValue({
close: vi.fn(),
pages: () => [],
} as any);
const { seedWidevineHint } = await import("../src/widevine.js");
const { launchPersistentContext } = await import("../src/playwright.js");
await launchPersistentContext({ userDataDir: "/tmp/profile" });
expect(seedWidevineHint).toHaveBeenCalledWith("/tmp/profile", "/fake/chrome");
});
it("Puppeteer launchPersistentContext seeds with (userDataDir, binaryPath)", async () => {
const pptr = await import("puppeteer-core");
vi.mocked(pptr.default.launch).mockResolvedValue({
newPage: vi.fn().mockResolvedValue({ authenticate: vi.fn() }),
close: vi.fn(),
} as any);
const { seedWidevineHint } = await import("../src/widevine.js");
const { launchPersistentContext } = await import("../src/puppeteer.js");
await launchPersistentContext({ userDataDir: "/tmp/profile" });
expect(seedWidevineHint).toHaveBeenCalledWith("/tmp/profile", "/fake/chrome");
});
});