1import { assert, describe, it } from "@effect/vitest"
2import { Effect } from "effect"
3import * as esbuild from "esbuild"
4import { Miniflare } from "miniflare"
5import { fileURLToPath } from "node:url"
6
7const workerPath = fileURLToPath(new URL("./fixtures/transaction.ts", import.meta.url))
8
9describe("storage transaction scheduling", () => {
10 it.live.each([
11 { mode: "commit", success: true, count: 64 },
12 { mode: "nested", success: true, count: 64 },
13 { mode: "rollback", success: false, count: 0 }
14 ])(
15 "$mode completes after automatic yields with an outside fiber queued",
16 ({ count, mode, success }) =>
17 Effect.gen(function*() {
18 const bundle = yield* Effect.promise(() =>
19 esbuild.build({
20 entryPoints: [workerPath],
21 bundle: true,
22 format: "esm",
23 platform: "browser",
24 target: "es2022",
25 conditions: ["workerd", "worker", "browser"],
26 write: false
27 })
28 )
29 const miniflare = yield* Effect.acquireRelease(
30 Effect.sync(() =>
31 new Miniflare({
32 workers: [{
33 config: {
34 name: "test",
35 compatibilityDate: "2026-09-11",
36 compatibilityFlags: ["nodejs_compat"],
37 manifest: {
38 mainModule: "index.mjs",
39 modules: {
40 "index.mjs": { type: "esm", contents: bundle.outputFiles[0].text }
41 }
42 },
43 exports: {
44 TransactionObject: { type: "durable-object", storage: "sqlite" }
45 },
46 env: {
47 TEST: { type: "durable-object", worker: "test", exportName: "TransactionObject" }
48 }
49 }
50 }]
51 })
52 ),
53 (miniflare) => Effect.promise(() => miniflare.dispose())
54 )
55 const response = yield* Effect.promise(() => miniflare.dispatchFetch(`http://localhost/${mode}`))
56 assert.strictEqual(response.status, 200, yield* Effect.promise(() => response.clone().text()))
57 assert.deepStrictEqual(yield* Effect.promise(() => response.json()), {
58 success,
59 outsideRows: [{ n: count }],
60 rows: [{ n: count }]
61 })
62 }),
63 { timeout: 40_000 }
64 )
65})