clone

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

chore(release): v0.1.1 — document the testing API for JSR

Dami committed 5430d61
- Add JSDoc to every exported member flagged by `deno doc --lint` across the
  `@nzip/lofi/testing` surface (convergence, fixture, readiness, browser_error):
  35 missing-jsdoc → 0. Remaining `private-type-ref` findings are inherent to
  exposing Playwright's `Page`/`Browser` types and do not block publish.
- Bump version 0.1.0 → 0.1.1 across the invariant: deno.json, package/version.ts
  (LOFI_VERSION), apps/reference/deno.json jsr pins + lock, and the
  create_core_test assertions; regenerate the starter snapshot.
commit
5430d6164fb4f2cf07c5c83eaca4954598136bf0
parent
6f16b4edd640c113df88ce16fa34362000eac380
author
Dami <dami.etoile@gmail.com>
10 files changed, +66 -38
Mapps/reference/deno.json14+++++++-------
Mapps/reference/deno.lock28++++------------------------
Mdeno.json2+-
Mpackage/create_core_test.ts6+++---
Mpackage/testdata/starter.snapshot.json2+-
Mpackage/testing/browser_error.ts5+++++
Mpackage/testing/convergence.ts24+++++++++++++++++++++++-
Mpackage/testing/fixture.ts15+++++++++++++++
Mpackage/testing/readiness.ts6++++++
Mpackage/version.ts2+-
M apps/reference/deno.json +7 -7
M apps/reference/deno.lock +4 -24
@@ -5,7 +5,6 @@
55 "npm:@astrojs/preact@6.0.1": "6.0.1_preact@10.29.7__preact-render-to-string@6.7.0_@babel+core@7.29.7",66 "npm:astro@7.0.9": "7.0.9_@emnapi+core@1.11.1_@emnapi+runtime@1.11.1",77 "npm:jazz-tools@2.0.0-alpha.53": "2.0.0-alpha.53",8- "npm:playwright@1.61.1": "1.61.1",98 "npm:preact@10.29.7": "10.29.7_preact-render-to-string@6.7.0",109 "npm:typescript@6.0.3": "6.0.3",1110 "npm:vite@8.0.1": "8.0.1_@emnapi+core@1.11.1_@emnapi+runtime@1.11.1"
@@ -1935,11 +1934,6 @@
19351934 "tiny-inflate"19361935 ]19371936 },1938- "fsevents@2.3.2": {1939- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",1940- "os": ["darwin"],1941- "scripts": true1942- },19431937 "fsevents@2.3.3": {19441938 "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",19451939 "os": ["darwin"],
@@ -2396,20 +2390,6 @@
23962390 "picomatch@4.0.5": {23972391 "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A=="23982392 },2399- "playwright-core@1.61.1": {2400- "integrity": "sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg==",2401- "bin": true2402- },2403- "playwright@1.61.1": {2404- "integrity": "sha512-DWnY5o3YbLWK4GovuAVwpqL+1VwGNdUGrRr++8j8PtQQzvAVZUIMjKQ90fY689sEJZJBbZVw1rXaOKSTitkzPQ==",2405- "dependencies": [2406- "playwright-core"2407- ],2408- "optionalDependencies": [2409- "fsevents@2.3.2"2410- ],2411- "bin": true2412- },24132393 "pluralize-esm@9.0.5": {24142394 "integrity": "sha512-Kb2dcpMsIutFw2hYrN0EhsAXOUJTd6FVMIxvNAkZCMQLVt9NGZqQczvGpYDxNWCZeCWLHUPxQIBudWzt1h7VVA=="24152395 },
@@ -2872,7 +2852,7 @@
28722852 "tinyglobby"28732853 ],28742854 "optionalDependencies": [2875- "fsevents@2.3.3"2855+ "fsevents"28762856 ],28772857 "bin": true28782858 },
@@ -2887,7 +2867,7 @@
28872867 "tinyglobby"28882868 ],28892869 "optionalDependencies": [2890- "fsevents@2.3.3"2870+ "fsevents"28912871 ],28922872 "optionalPeers": [28932873 "esbuild@0.28.1"
@@ -3121,7 +3101,7 @@
31213101 },31223102 "workspace": {31233103 "dependencies": [3124- "jsr:@nzip/lofi@0.1.0",3104+ "jsr:@nzip/lofi@0.1.1",31253105 "npm:@astrojs/check@0.9.9",31263106 "npm:@astrojs/preact@6.0.1",31273107 "npm:astro@7.0.9",
@@ -3131,7 +3111,7 @@
31313111 "npm:vite@8.0.1"31323112 ],31333113 "links": {3134- "jsr:@nzip/lofi@0.1.0": {3114+ "jsr:@nzip/lofi@0.1.1": {31353115 "dependencies": [31363116 "npm:@astrojs/check@0.9.9",31373117 "npm:@astrojs/preact@6.0.1",
M deno.json +1 -1
M package/create_core_test.ts +3 -3
M package/testdata/starter.snapshot.json +1 -1
M package/testing/browser_error.ts +5 -0
M package/testing/convergence.ts +23 -1
@@ -3,18 +3,30 @@ import type { ValueFreeState } from "./safety.ts";
33 44 /** Minimal client contract the convergence runner needs: offline state and toggles. */55 export interface OfflineTestClient {6+ /** Whether the client's network is currently forced offline. */67 readonly offline: boolean;8+ /** Force this client's network offline. */79 goOffline(): Promise<void>;10+ /** Restore this client's network. */811 goOnline(): Promise<void>;912 }1013 1114 /** Minimal two-client fixture contract required to drive an offline scenario. */1215 export interface OfflineTestFixture<Client extends OfflineTestClient> {16+ /** Both clients, ordered `[first, second]`. */1317 readonly clients: readonly [Client, Client];18+ /** The first client. */1419 readonly first: Client;20+ /** The second client. */1521 readonly second: Client;22+ /** Take both clients offline. */1623 goOffline(): Promise<void>;24+ /** Bring both clients back online. */1725 goOnline(): Promise<void>;26+ /**27+ * Capture a redacted failure artifact, optionally including a value-free28+ * per-client snapshot. Returns an opaque handle describing what was written.29+ */1830 captureFailure(1931 label: string,2032 snapshot?: (client: Client) => Promise<ValueFreeState>,
@@ -30,12 +42,15 @@ export interface ConcurrentOfflineScenario<
3042 Edit,3143 Client extends OfflineTestClient = BrowserTestClient,3244 > {45+ /** The two concurrent edits, one applied on each client while offline. */3346 readonly edits: readonly [Edit, Edit];3447 /** Overall defensive deadline. Defaults to 60 seconds. */3548 readonly timeoutMs?: number;3649 /** App-owned, deterministic readiness assertion (locator/waitForFunction/etc.). */3750 readonly ready: (client: Client, signal: AbortSignal) => Promise<void>;51+ /** Apply one client's edit while it is offline. */3852 readonly apply: (client: Client, edit: Edit, signal: AbortSignal) => Promise<void>;53+ /** Assert the edit is visible locally on its own client before reconnection. */3954 readonly locallyApplied: (client: Client, edit: Edit, signal: AbortSignal) => Promise<void>;4055 /** Use this hook for page/client restart while offline work is pending. */4156 readonly whilePending?: (
@@ -47,15 +62,22 @@ export interface ConcurrentOfflineScenario<
4762 fixture: OfflineTestFixture<Client>,4863 signal: AbortSignal,4964 ) => Promise<void>;65+ /** Optional value-free snapshot taken per client when a failure is captured. */5066 readonly snapshot?: (client: Client) => Promise<ValueFreeState>;67+ /** Label for any captured failure artifact. Defaults to a generic name. */5168 readonly failureLabel?: string;5269 }5370 5471 /** Thrown when a convergence scenario fails, naming the stage that failed via {@link stage}. */5572 export class ConvergenceScenarioError extends Error {73+ /** Always `"ConvergenceScenarioError"`. */5674 override readonly name = "ConvergenceScenarioError";5775 58- /** @param stage the lifecycle stage that was in progress when the scenario failed */76+ /**77+ * Builds the error, recording which lifecycle stage was in progress.78+ * @param stage the lifecycle stage that was in progress when the scenario failed79+ * @param options standard error options, e.g. a `cause` from the failing hook80+ */5981 constructor(readonly stage: string, options?: ErrorOptions) {6082 super(`Concurrent offline convergence failed during ${stage}`, options);6183 }
M package/testing/fixture.ts +15 -0
@@ -32,10 +32,15 @@ export type ClientName = "first" | "second";
3232 3333 /** A redacted console, page-error, or failed-request record captured from a client. */3434 export interface BrowserDiagnostic {35+ /** Which of the two clients produced this diagnostic. */3536 readonly client: ClientName;37+ /** What surfaced it: a console message, an uncaught page error, or a failed request. */3638 readonly kind: "console" | "page-error" | "request-failed";39+ /** Console severity (e.g. `"error"`, `"warning"`), when applicable. */3740 readonly level?: string;41+ /** The redacted message text. */3842 readonly message: string;43+ /** The associated URL, for `request-failed` records. */3944 readonly url?: string;4045 }4146
@@ -58,6 +63,7 @@ export type IdentityOptions =
5863 5964 /** Configures where and how redacted failure artifacts are written on capture. */6065 export interface FailureArtifactOptions {66+ /** Directory the redacted artifacts are written into on capture. */6167 readonly directory: string;6268 /** Literal credential values to remove from retained diagnostics. */6369 readonly secretValues?: readonly string[];
@@ -67,10 +73,15 @@ export interface FailureArtifactOptions {
6773 6874 /** Options for constructing a {@link TwoClientFixture} via {@link createTwoClientFixture}. */6975 export interface TwoClientFixtureOptions {76+ /** The origin both clients open and enroll identity against. */7077 readonly baseURL: string;78+ /** How the two clients obtain identity (`shared` or `isolated`). */7179 readonly identity: IdentityOptions;80+ /** An existing browser to reuse; when omitted the fixture launches and owns one. */7281 readonly browser?: Browser;82+ /** Extra context options (a disk `storageState` is forbidden to keep identity in memory). */7383 readonly context?: SafeContextOptions;84+ /** Where and how to write redacted artifacts if the test fails. */7485 readonly artifacts?: FailureArtifactOptions;7586 /** Defaults to true. Tracing begins only after identity preparation. */7687 readonly traceOnFailure?: boolean;
@@ -100,6 +111,7 @@ export class BrowserTestClient {
100111 #recording = false;101112 #closed = false;102113 114+ /** Constructed by {@link createTwoClientFixture}; not intended for direct use. */103115 constructor(104116 readonly name: ClientName,105117 context: BrowserContext,
@@ -255,7 +267,9 @@ export class BrowserTestClient {
255267 256268 /** The directory and file paths produced by a failure capture. */257269 export interface FailureArtifacts {270+ /** The directory the artifacts were written into. */258271 readonly directory: string;272+ /** Absolute paths of every file written (screenshots, traces, diagnostics). */259273 readonly files: readonly string[];260274 }261275
@@ -269,6 +283,7 @@ export class TwoClientFixture {
269283 readonly clients: readonly [BrowserTestClient, BrowserTestClient];270284 #closed = false;271285 286+ /** Constructed by {@link createTwoClientFixture}; not intended for direct use. */272287 constructor(273288 readonly browser: Browser,274289 readonly ownsBrowser: boolean,
M package/testing/readiness.ts +6 -0
M package/version.ts +1 -1