Skip to content

Conversation

@tantaman
Copy link
Contributor

@tantaman tantaman commented Jan 8, 2026

Trying to accomplish the same goal as #5225 but with our existing test harnesses.

@vercel
Copy link

vercel bot commented Jan 8, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
replicache-docs Ready Ready Preview, Comment Jan 12, 2026 5:24pm
zbugs Ready Ready Preview, Comment Jan 12, 2026 5:24pm

@tantaman tantaman changed the title publish zeroForTest as potential alternative option to #5225 publish zeroForTest as potential alternative to #5225 Jan 8, 2026
});

test('local mutate', async () => {
const zero = zeroForTest({
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

example of how you could use zeroForTest

@github-actions
Copy link

github-actions bot commented Jan 8, 2026

🐰 Bencher Report

BranchzeroForTest
TestbedLinux
Click to view all benchmark results
BenchmarkFile SizeBenchmark Result
kilobytes (KB)
(Result Δ%)
Upper Boundary
kilobytes (KB)
(Limit %)
zero-package.tgz📈 view plot
🚷 view threshold
1,786.98 KB
(+0.24%)Baseline: 1,782.74 KB
1,818.39 KB
(98.27%)
zero.js📈 view plot
🚷 view threshold
241.21 KB
(0.00%)Baseline: 241.21 KB
246.03 KB
(98.04%)
zero.js.br📈 view plot
🚷 view threshold
66.28 KB
(0.00%)Baseline: 66.28 KB
67.60 KB
(98.04%)
🐰 View full continuous benchmarking report in Bencher

});

await zero.mutate(
// @ts-ignore - wtf?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no idea what is going on here...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard to tell. What is the type error?

Without pulling this PR to my local env I would guess it is an issue with the Context?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a context type error:

Types of property '$context' are incompatible.
                Type '{ readonly sub: string; readonly role: "user" | "crew"; } | undefined' is not assignable to type 'AuthData'.
                  Type 'undefined' is not assignable to type 'AuthData'.ts(2345)

@github-actions
Copy link

github-actions bot commented Jan 8, 2026

🐰 Bencher Report

BranchzeroForTest
Testbedself-hosted
Click to view all benchmark results
BenchmarkThroughputBenchmark Result
operations / second (ops/s)
(Result Δ%)
Lower Boundary
operations / second (ops/s)
(Limit %)
1 exists: track.exists(album)📈 view plot
🚷 view threshold
14,457.95 ops/s
(-0.37%)Baseline: 14,511.89 ops/s
12,861.14 ops/s
(88.96%)
10 exists (AND)📈 view plot
🚷 view threshold
202,747.55 ops/s
(-4.99%)Baseline: 213,399.75 ops/s
189,135.01 ops/s
(93.29%)
10 exists (OR)📈 view plot
🚷 view threshold
4,012.14 ops/s
(-3.42%)Baseline: 4,154.21 ops/s
3,737.05 ops/s
(93.14%)
12 exists (AND)📈 view plot
🚷 view threshold
180,669.02 ops/s
(-4.28%)Baseline: 188,756.77 ops/s
168,632.59 ops/s
(93.34%)
12 exists (OR)📈 view plot
🚷 view threshold
3,545.57 ops/s
(+0.20%)Baseline: 3,538.64 ops/s
3,164.03 ops/s
(89.24%)
12 level nesting📈 view plot
🚷 view threshold
3,065.55 ops/s
(-0.68%)Baseline: 3,086.66 ops/s
2,771.84 ops/s
(90.42%)
2 exists (AND): track.exists(album).exists(genre)📈 view plot
🚷 view threshold
5,532.56 ops/s
(+1.29%)Baseline: 5,462.12 ops/s
4,846.31 ops/s
(87.60%)
3 exists (AND)📈 view plot
🚷 view threshold
2,143.84 ops/s
(+1.32%)Baseline: 2,115.81 ops/s
1,871.57 ops/s
(87.30%)
3 exists (OR)📈 view plot
🚷 view threshold
1,025.35 ops/s
(-3.38%)Baseline: 1,061.22 ops/s
936.34 ops/s
(91.32%)
5 exists (AND)📈 view plot
🚷 view threshold
323.91 ops/s
(-2.97%)Baseline: 333.84 ops/s
297.85 ops/s
(91.95%)
5 exists (OR)📈 view plot
🚷 view threshold
170.80 ops/s
(-3.07%)Baseline: 176.21 ops/s
157.02 ops/s
(91.93%)
Nested 2 levels: track > album > artist📈 view plot
🚷 view threshold
4,684.33 ops/s
(-1.18%)Baseline: 4,740.42 ops/s
4,250.24 ops/s
(90.73%)
Nested 4 levels: playlist > tracks > album > artist📈 view plot
🚷 view threshold
786.39 ops/s
(+0.88%)Baseline: 779.50 ops/s
699.12 ops/s
(88.90%)
Nested with filters: track > album > artist (filtered)📈 view plot
🚷 view threshold
4,004.91 ops/s
(+1.47%)Baseline: 3,946.78 ops/s
3,528.36 ops/s
(88.10%)
planned: playlist.exists(tracks)📈 view plot
🚷 view threshold
634.69 ops/s
(-1.79%)Baseline: 646.23 ops/s
596.51 ops/s
(93.98%)
planned: track.exists(album) OR exists(genre)📈 view plot
🚷 view threshold
168.95 ops/s
(-1.13%)Baseline: 170.88 ops/s
160.59 ops/s
(95.05%)
planned: track.exists(album) where title="Big Ones"📈 view plot
🚷 view threshold
7,811.32 ops/s
(-0.97%)Baseline: 7,887.97 ops/s
7,253.60 ops/s
(92.86%)
planned: track.exists(album).exists(genre)📈 view plot
🚷 view threshold
39.80 ops/s
(-3.17%)Baseline: 41.11 ops/s
37.82 ops/s
(95.01%)
planned: track.exists(album).exists(genre) with filters📈 view plot
🚷 view threshold
5,481.85 ops/s
(-1.68%)Baseline: 5,575.51 ops/s
5,153.17 ops/s
(94.00%)
planned: track.exists(playlists)📈 view plot
🚷 view threshold
4.07 ops/s
(-2.54%)Baseline: 4.17 ops/s
3.87 ops/s
(95.03%)
unplanned: playlist.exists(tracks)📈 view plot
🚷 view threshold
606.42 ops/s
(-3.53%)Baseline: 628.59 ops/s
583.08 ops/s
(96.15%)
unplanned: track.exists(album) OR exists(genre)📈 view plot
🚷 view threshold
45.52 ops/s
(-2.77%)Baseline: 46.82 ops/s
42.37 ops/s
(93.09%)
unplanned: track.exists(album) where title="Big Ones"📈 view plot
🚷 view threshold
57.98 ops/s
(-1.10%)Baseline: 58.62 ops/s
54.01 ops/s
(93.16%)
unplanned: track.exists(album).exists(genre)📈 view plot
🚷 view threshold
39.87 ops/s
(-2.53%)Baseline: 40.90 ops/s
37.58 ops/s
(94.26%)
unplanned: track.exists(album).exists(genre) with filters📈 view plot
🚷 view threshold
55.68 ops/s
(-2.74%)Baseline: 57.25 ops/s
53.39 ops/s
(95.89%)
unplanned: track.exists(playlists)📈 view plot
🚷 view threshold
3.95 ops/s
(-5.19%)Baseline: 4.17 ops/s
3.86 ops/s
(97.58%)
zpg: all playlists📈 view plot
🚷 view threshold
5.65 ops/s
(-2.27%)Baseline: 5.78 ops/s
5.56 ops/s
(98.27%)
zql: all playlists📈 view plot
🚷 view threshold
7.66 ops/s
(-4.13%)Baseline: 7.99 ops/s
7.08 ops/s
(92.41%)
zql: edit for limited query, inside the bound📈 view plot
🚷 view threshold
212,509.04 ops/s
(-2.07%)Baseline: 216,997.14 ops/s
195,126.04 ops/s
(91.82%)
zql: edit for limited query, outside the bound📈 view plot
🚷 view threshold
221,103.64 ops/s
(-2.01%)Baseline: 225,628.86 ops/s
190,066.72 ops/s
(85.96%)
zql: push into limited query, inside the bound📈 view plot
🚷 view threshold
106,810.52 ops/s
(-4.18%)Baseline: 111,472.57 ops/s
101,194.53 ops/s
(94.74%)
zql: push into limited query, outside the bound📈 view plot
🚷 view threshold
379,960.95 ops/s
(-6.42%)Baseline: 406,048.60 ops/s
335,993.89 ops/s
(88.43%)
zql: push into unlimited query📈 view plot
🚷 view threshold
321,887.95 ops/s
(-4.88%)Baseline: 338,385.10 ops/s
298,016.02 ops/s
(92.58%)
zqlite: all playlists📈 view plot
🚷 view threshold
1.83 ops/s
(-1.29%)Baseline: 1.85 ops/s
1.67 ops/s
(91.55%)
zqlite: edit for limited query, inside the bound📈 view plot
🚷 view threshold
76,438.18 ops/s
(-2.58%)Baseline: 78,464.09 ops/s
67,565.40 ops/s
(88.39%)
zqlite: edit for limited query, outside the bound📈 view plot
🚷 view threshold
77,993.49 ops/s
(-1.59%)Baseline: 79,254.60 ops/s
66,540.03 ops/s
(85.31%)
zqlite: push into limited query, inside the bound📈 view plot
🚷 view threshold
4,068.35 ops/s
(-1.25%)Baseline: 4,119.85 ops/s
3,956.13 ops/s
(97.24%)
zqlite: push into limited query, outside the bound📈 view plot
🚷 view threshold
88,599.60 ops/s
(-1.62%)Baseline: 90,055.41 ops/s
81,714.97 ops/s
(92.23%)
zqlite: push into unlimited query📈 view plot
🚷 view threshold
124,282.53 ops/s
(-2.93%)Baseline: 128,035.51 ops/s
115,254.46 ops/s
(92.74%)
🐰 View full continuous benchmarking report in Bencher

@github-actions
Copy link

github-actions bot commented Jan 8, 2026

🐰 Bencher Report

BranchzeroForTest
Testbedself-hosted
Click to view all benchmark results
BenchmarkThroughputBenchmark Result
operations / second (ops/s)
(Result Δ%)
Lower Boundary
operations / second (ops/s)
(Limit %)
src/client/custom.bench.ts > big schema📈 view plot
🚷 view threshold
143,492.00 ops/s
(-59.98%)Baseline: 358,526.97 ops/s
-452,502.85 ops/s
(-315.35%)
src/client/zero.bench.ts > basics > All 1000 rows x 10 columns (numbers)📈 view plot
🚷 view threshold
2,567.49 ops/s
(+0.96%)Baseline: 2,542.99 ops/s
2,257.72 ops/s
(87.94%)
src/client/zero.bench.ts > pk compare > pk = N📈 view plot
🚷 view threshold
65,805.05 ops/s
(+0.53%)Baseline: 65,455.93 ops/s
59,007.21 ops/s
(89.67%)
src/client/zero.bench.ts > with filter > Lower rows 500 x 10 columns (numbers)📈 view plot
🚷 view threshold
3,934.43 ops/s
(+1.60%)Baseline: 3,872.34 ops/s
3,509.97 ops/s
(89.21%)
🐰 View full continuous benchmarking report in Bencher

@tantaman
Copy link
Contributor Author

tantaman commented Jan 8, 2026

@arv / @0xcadams - @kvnkusch is trying to use this but hitting errors with properties referenced by the testing symbol being undefined.

test/zeroForTest-repro.test.ts:
23 |   get connectingStart() {
24 |     return this[exposedToTestingSymbol].connectStart;
25 |   }
26 |   constructor(options) {
27 |     super(options);
28 |     this[exposedToTestingSymbol].connectionManager().subscribe((state) => {
              ^
TypeError: undefined is not an object (evaluating 'this[exposedToTestingSymbol].connectionManager')
      at new TestZero (/Users/kkusch/Code/ccs/cc1/node_modules/@rocicorp/zero/out/zero-client/src/client/test-utils.js:28:10)
      at zeroForTest (/Users/kkusch/Code/ccs/cc1/node_modules/@rocicorp/zero/out/zero-client/src/client/test-utils.js:174:10)
      at <anonymous> (/Users/kkusch/Code/ccs/cc1/packages/core/test/zeroForTest-repro.test.ts:23:15)

iirc, you guys fixed something like this recently? and that it has to do with our build?

@tantaman tantaman requested review from 0xcadams and arv January 8, 2026 19:34
Copy link
Contributor

@arv arv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like where this is going.

How about @rocicorp/zero/test or @rocicorp/zero/testing?

"src/transform-query.ts",
"src/zero-out.ts"
"src/zero-out.ts",
"src/test-helpers.ts"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be in tsconfig.server.json?

Seems like it should be in tsconfig.client.json instead.

Comment on lines 59 to 70
resolve: {
alias: [
{
find: '@rocicorp/zero/test-helpers',
replacement: resolve(packagesDir, 'zero/src/test-helpers.ts'),
},
{
find: '@rocicorp/zero',
replacement: resolve(packagesDir, 'zero/src/zero.ts'),
},
],
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is needed. tsconfigPaths() should deal with this?

});

await zero.mutate(
// @ts-ignore - wtf?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard to tell. What is the type error?

Without pulling this PR to my local env I would guess it is an issue with the Context?

@tantaman
Copy link
Contributor Author

@kvnkusch - does this work for you now?

Comment on lines +37 to +39
// can't make this work using the proper type. Context always throws an error
// no matter what we do.
context: {sub: 'user-1', role: 'user'} as any,
Copy link
Contributor Author

@tantaman tantaman Jan 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arv - ready for re-review. I cannot, for the life of me, figure out how to make this work however.

Changing

context: {sub: 'user-1', role: 'user'} as any,

to

context: {sub: 'user-1', role: 'user'} as AuthData | undefined

causes a type error at lines 43 and 52:

Types of property '$context' are incompatible.
                Type '{ readonly sub: string; readonly role: "user" | "crew"; } | undefined' is not assignable to type 'AuthData'.
                  Type 'undefined' is not assignable to type 'AuthData'.ts(2345)

Claude is also stumped fwiw.

@kvnkusch
Copy link
Contributor

@kvnkusch - does this work for you now?

Getting the same error. For reference, here's a minimal repro:

import { createBuilder, defineMutator, defineMutators } from '@rocicorp/zero';
import { zeroForTest } from '@rocicorp/zero/testing';
import { expect, test } from 'vitest';
import { z } from 'zod';

const schema = {
    tables: {
        item: {
            name: 'item',
            columns: {
                id: { type: 'string' as const, optional: false },
                name: { type: 'string' as const, optional: false },
            },
            primaryKey: ['id'] as const,
        },
    },
    relationships: {},
};

declare module "@rocicorp/zero" {
    interface DefaultTypes {
        schema: typeof schema;
    }
}

const zql = createBuilder(schema);

const zero = zeroForTest({
    schema,
    mutators: defineMutators({
        item: {
            insert: defineMutator(z.object({ id: z.string(), name: z.string() }), async ({ args: { id, name }, tx }) => {
                await tx.mutate.item.insert({ id, name });
            }),
        },
    }),
});

test("basic insert and query", async () => {
    await zero.mutate.item.insert({
        id: "1",
        name: "test",
    });

    const result = await zero.run(zql.item);
    expect(result).toHaveLength(1);
});

Types on zero.mutate also don't seem to be working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants