clone

a deno framework for local-first web apps that open instantly, work offline and sync when users choose

feat/141-demo-review-fixes
lofi / package / testing / readiness_test.ts
readiness_test.ts 3.0K
1import type { Page } from "playwright";2import { ReadinessError, waitForReady } from "./readiness.ts";34function assert(condition: unknown, message: string): asserts condition {5 if (!condition) throw new Error(message);6}78Deno.test("waitForReady delegates polling and timeout to Playwright", async () => {9 let call: unknown[] | undefined;10 const page = {11 waitForFunction(...args: unknown[]) {12 call = args;13 return Promise.resolve({});14 },15 } as unknown as Page;16 const predicate = (expected: string) => document.body.dataset.ready === expected;1718 await waitForReady(page, predicate, "yes", {19 description: "reference app boot",20 timeoutMs: 321,21 polling: 17,22 });2324 assert(call?.[0] === predicate, "predicate was replaced");25 assert(call?.[1] === "yes", "predicate argument was replaced");26 assert(27 JSON.stringify(call?.[2]) === JSON.stringify({ polling: 17, timeout: 321 }),28 `unexpected Playwright options: ${JSON.stringify(call?.[2])}`,29 );30});3132Deno.test("waitForReady accepts options in third position for argument-free predicates", async () => {33 let call: unknown[] | undefined;34 const page = {35 waitForFunction(...args: unknown[]) {36 call = args;37 return Promise.resolve({});38 },39 } as unknown as Page;40 const predicate = () => document.body.dataset.ready === "yes";4142 await waitForReady(page, predicate, { timeoutMs: 42, polling: "raf" });4344 assert(call?.[0] === predicate, "predicate was replaced");45 assert(call?.[1] === undefined, "an argument was invented for an argument-free predicate");46 assert(47 JSON.stringify(call?.[2]) === JSON.stringify({ polling: "raf", timeout: 42 }),48 `unexpected Playwright options: ${JSON.stringify(call?.[2])}`,49 );5051 await waitForReady(page, predicate);52 assert(53 JSON.stringify(call?.[2]) === JSON.stringify({ polling: "raf", timeout: 10_000 }),54 `defaults were not applied without options: ${JSON.stringify(call?.[2])}`,55 );56});5758Deno.test("waitForReady adds the app condition to timeout failures", async () => {59 const cause = new Error("playwright timeout");60 const page = {61 waitForFunction() {62 return Promise.reject(cause);63 },64 } as unknown as Page;6566 try {67 await waitForReady(page, () => false, { description: "sync indicator" });68 throw new Error("expected readiness to fail");69 } catch (error) {70 assert(error instanceof ReadinessError, `unexpected error: ${error}`);71 assert(error.message.includes("sync indicator"), "condition was missing from the error");72 assert(error.cause === cause, "Playwright failure was not retained as the cause");73 }7475 // The four-argument shape with an explicit undefined argument stays valid.76 try {77 await waitForReady(page, () => false, undefined, { description: "sync indicator" });78 throw new Error("expected readiness to fail");79 } catch (error) {80 assert(error instanceof ReadinessError, `unexpected error: ${error}`);81 assert(error.message.includes("sync indicator"), "condition was missing from the error");82 }83});