@ultimat3/testing 18.0.0 → 19.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CLAUDE.md CHANGED
@@ -35,7 +35,7 @@ is its own entry point and not part of the barrel.
35
35
  | The seam has an inverse, `As of 2026-08-25` | `resetE2eDriver()`. `useE2eDriver` writes MODULE scope and `bun test` is one process, so a file that installed a browser handed every later file in the run an `e2eTest` that opened a page nobody asked for — `test-types.test.ts` was itself doing it, at module scope, with nothing to undo it. Same shape and same reason as `@ultimat3/scraping`'s `resetScrapeDriver()` |
36
36
  | Built vs declared | `clock` `mail` `network` `runJobs` `statements` `subscribe` are built in-process; `page` `budget` `signIn` `deploy` are declared and wait for a driver (`X_TEST_FIXTURE_UNAVAILABLE`). The four left all need a browser or a second build — things the framework genuinely cannot bundle |
37
37
  | `page` HAS a driver now, and the other three still do not, `As of 2026-08-25` | `installE2eDriver({ page, baseUrl })` registers `page` over its declaration and leaves `budget`, `signIn` and `deploy` refusing, on purpose: byte counts come off a built `dist/`, a sign-in route is the APP's, and a new build id is a fact about the SERVER — a page port can answer for none of the three, and a fixture that silently no-opped would make the assertion after it read as proof |
38
- | `network` is THIS process's fetch, and an e2e page is not in this process | `sealed-network.ts` patches `globalThis.fetch` here; a browser's requests never pass through it. So `network.offline()` in a test that also destructures `page` is a **no-op on the browser** — the app's online page passing an offline test. `E2eFixtures.offline()` is the browser-side spelling and the CDP driver REFUSES it (`X_TEST_FIXTURE_UNAVAILABLE`), because `CdpPageLike` declares no `setOfflineMode`. Two words, two mechanisms, and only one of them can put a browser offline |
38
+ | `network` is THIS process's fetch, and an e2e page is not in this process | `sealed-network.ts` patches `globalThis.fetch` here; a browser's requests never pass through it. So `network.offline()` in a test that also destructures `page` is a **no-op on the browser** — the app's online page passing an offline test. `E2eFixtures.offline()` is the browser-side spelling, and `As of 2026-08-27` it FORWARDS — through `E2eBrowserPage.offline()` to `ScrapePage.offline()` to `CdpPageLike.setOfflineMode`, which `cdp-port.ts` has declared since #351. This row said the CDP driver refused it "because `CdpPageLike` declares no `setOfflineMode`", and that was untrue in the commit that wrote it; the refusal it describes now fires only for a hand-rolled `E2eBrowserPage` with no `offline()`, and names that. Two words, two mechanisms, and only one of them can put a browser offline |
39
39
  | `subscribe` is a whole `sync` node | `live-node.ts` assembles what `x dev --role sync` assembles minus the listener — real `LiveQueryRegistry`, real `liveQueryDefinition` bridge, real per-subscriber gate, real cursor — over a socket that is two objects handing each other the JSON a WebSocket would. `live-replicator.ts` feeds it from `@ultimat3/entity`'s `setRowObserver`, which is the change SOURCE a test process never had: PGlite has no walsender and the memory driver no log, so `InMemoryChangeFeed` had nothing upstream of it. The WAL decoder is the only thing substituted; everything downstream of it is production code |
40
40
  | What `subscribe` does NOT hold | a client store, an offline queue or a rebase log — so `feed.local()` answers `undefined` rather than the server row. A twin reported as applied whether or not a mutator ran is coverage that reads as proof, which is worse than none. That half is `useMutation` / `useMutationQueue` and an e2e |
41
41
  | Draining is a macrotask yield | the node dispatches `message` into a floating async task, so `settled()` yields with `setImmediate` until the frame count stops moving. Counting microtask turns is a number that is right until someone adds an `await` — the first version drained 32 and read `examples/dummy`'s deeper feed read as "the node answered nothing" |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultimat3/testing",
3
- "version": "18.0.0",
3
+ "version": "19.0.0",
4
4
  "description": "Test harness: cloned template DBs per worker, frozen clock, sealed network, 6 test types",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -33,16 +33,16 @@
33
33
  "test": "bun test"
34
34
  },
35
35
  "dependencies": {
36
- "@ultimat3/cache": "18.0.0",
37
- "@ultimat3/core": "18.0.0",
38
- "@ultimat3/db": "18.0.0",
39
- "@ultimat3/entity": "18.0.0",
40
- "@ultimat3/i18n": "18.0.0",
41
- "@ultimat3/jobs": "18.0.0",
42
- "@ultimat3/mail": "18.0.0",
43
- "@ultimat3/policy": "18.0.0",
44
- "@ultimat3/query": "18.0.0",
45
- "@ultimat3/realtime": "18.0.0",
46
- "@ultimat3/time": "18.0.0"
36
+ "@ultimat3/cache": "19.0.0",
37
+ "@ultimat3/core": "19.0.0",
38
+ "@ultimat3/db": "19.0.0",
39
+ "@ultimat3/entity": "19.0.0",
40
+ "@ultimat3/i18n": "19.0.0",
41
+ "@ultimat3/jobs": "19.0.0",
42
+ "@ultimat3/mail": "19.0.0",
43
+ "@ultimat3/policy": "19.0.0",
44
+ "@ultimat3/query": "19.0.0",
45
+ "@ultimat3/realtime": "19.0.0",
46
+ "@ultimat3/time": "19.0.0"
47
47
  }
48
48
  }
@@ -22,8 +22,18 @@ export interface IslandBundleLike {
22
22
  readonly chunks: readonly IslandChunkLike[];
23
23
  }
24
24
 
25
- /** `buildIslands` from `@ultimat3/cli` satisfies this structurally — no import, no new tier edge. */
26
- export type IslandBuilder = (root: string) => Promise<IslandBundleLike>;
25
+ /**
26
+ * `buildIslands` from `@ultimat3/cli` satisfies this structurally — no import, no new tier edge.
27
+ *
28
+ * The second parameter is OPTIONAL on both sides, `As of 2026-08-27`, which is what keeps that true:
29
+ * a builder of your own written as `(root) => …` is still assignable, and `buildIslands`' own
30
+ * `options` argument is already optional. Widening it is what lets `mountIsland` name the one island
31
+ * it is about to mount — see the call site for what building all of them was costing.
32
+ */
33
+ export type IslandBuilder = (
34
+ root: string,
35
+ options?: { readonly only?: string },
36
+ ) => Promise<IslandBundleLike>;
27
37
 
28
38
  export interface MountIslandOptions {
29
39
  readonly build: IslandBuilder;
@@ -168,7 +178,20 @@ function installGlobals(values: Readonly<Record<string, unknown>>): () => void {
168
178
  * `document` to every later FILE in the run.
169
179
  */
170
180
  export async function mountIsland(options: MountIslandOptions): Promise<MountedIsland> {
171
- const bundle = await options.build(options.root);
181
+ // `only`, because this fixture has always KNOWN which island it wants and asked for all of them
182
+ // anyway — `island-bundle.ts` added the option for exactly this caller ("a test that mounts a
183
+ // single island otherwise pays every OTHER island's Babel pass and `Bun.build` on every file, and
184
+ // the reference app is the one that feels it") and nothing ever passed it.
185
+ //
186
+ // It is also the difference between green and red on Bun 1.3.14, which is how it was found:
187
+ // building the reference app's four islands in a test process that has already imported
188
+ // `@ultimat3/realtime` at module scope makes `Bun.build` throw `Unexpected reading file:
189
+ // packages/realtime/src/index.ts`. One island does not, and neither does `x build` — measured,
190
+ // `x build --target static` is green on 1.3.14 — so this is a bundler defect confined to
191
+ // `bun test`, fixed in 1.4.0, and asking for the island we actually want walks around it while
192
+ // being the faster and more honest call regardless. A builder that ignores the argument still
193
+ // works: the `find` below is unchanged.
194
+ const bundle = await options.build(options.root, { only: options.file });
172
195
  const chunk = bundle.chunks.find((each) => each.file === options.file);
173
196
  if (chunk === undefined) {
174
197
  throw islandNotBuilt(