Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
384 commits
Select commit Hold shift + click to select a range
5e622fe
Fix sync
joepio Apr 16, 2026
64a1cd9
Fix sync
joepio Apr 17, 2026
6fa4442
Fix history scrub
joepio Apr 17, 2026
28ec9fc
Improve loro speed, benchmark
joepio Apr 18, 2026
4063898
desktop strategy
joepio Apr 18, 2026
2c0ff1b
begin_batch and commit_batch in redb store for performant populate
joepio Apr 18, 2026
4766c33
Fix CRDT loro bug
joepio Apr 19, 2026
53a5d65
Too many commit errs
joepio Apr 19, 2026
612e229
Improved debug tools
joepio Apr 19, 2026
36c494f
Multi-tab opfs
joepio Apr 19, 2026
0af475d
Improved sync page, local toggle
joepio Apr 19, 2026
5b85b42
Fix offline => online sync
joepio Apr 19, 2026
0ce2299
Fix various e2e tests, search
joepio Apr 20, 2026
56a0a45
Drive scoped watched queries, fix some tests, single JS web worker
joepio Apr 21, 2026
2da27e7
Content-Addressed files, offline upload #1147
joepio Apr 30, 2026
a60cef6
e2e fixes
joepio May 1, 2026
c5f7c56
More e2e fixes
joepio May 4, 2026
3724a8e
e2e fixes
joepio May 5, 2026
a7262b6
Fix delete not working
joepio May 5, 2026
bf4aa8f
More e2e fixes
joepio May 5, 2026
c4e11d6
Fix onboarding: WS auth race when switching agents
joepio May 5, 2026
508d0af
DevDrive: guard against multi-fire creating duplicate agents/drives
joepio May 6, 2026
4cc7243
e2e fixes
joepio May 6, 2026
9a3cc95
CLean up sync, e2e fixes
joepio May 7, 2026
82c9250
Collection E2E fixes
joepio May 8, 2026
41ed23c
Describe client side plugins #1193
joepio May 8, 2026
66bca67
e2e fixes
joepio May 8, 2026
fbea72e
Did import
joepio May 8, 2026
a1cf934
Fix typecheck + tighten e2e under suite-load contention
joepio May 8, 2026
20fb07a
Fix typedoc-publish CI: use `netlify link --id` before deploy
joepio May 8, 2026
47bbe7b
Trust empty local-DB collection results once a drive sync completes
joepio May 8, 2026
adbbc6c
CI: skip Netlify deploy when NETLIFY_AUTH_TOKEN is empty + replace ne…
joepio May 8, 2026
0ee4501
Bump WS request + async-resource timeouts from 5s to 10s
joepio May 8, 2026
e20d0ec
e2e: replace fixed waitForTimeouts with proper data/visibility waits
joepio May 8, 2026
c2b513c
e2e: replace tables-refresh post-Tab and post-mount sleeps with prope…
joepio May 8, 2026
4780afb
e2e: replace fixed sleeps in offline-reload with explicit OPFS / load…
joepio May 8, 2026
981884c
e2e: revert contextMenuClick visibility wait — broke dialog test
joepio May 8, 2026
bcf51e4
e2e: revert dirtyCount poll for alphabet-typing test, keep 1500ms
joepio May 8, 2026
5d38bfd
Fix upload-roundtrip integration test: separate setup file (no ws-dis…
joepio May 8, 2026
38d0778
e2e: focus the gridcell explicitly after click in tables.spec:28
joepio May 8, 2026
98325f6
e2e: drop \`{ force: true }\` from gridcell click in tables.spec:28
joepio May 8, 2026
e83fa39
Apply cargo fmt across the workspace
joepio May 8, 2026
d110524
Fix workspace clippy: gate atomic-wasm to wasm32, fix bench moved-value
joepio May 8, 2026
ac7c729
ci: cap nextest test-threads at 2
joepio May 8, 2026
bb05256
ci: mkdir before tar-extracting nextest into /usr/local/cargo/bin
joepio May 8, 2026
9f0a4f6
ci: use \`linux-musl\` nextest artifact + resolve CARGO_HOME at runtime
joepio May 8, 2026
9538b95
ci: serialize rust pipeline to avoid cargo target-lock contention
joepio May 9, 2026
3dbb230
ci: exclude desktop crate + serialize the flaky tantivy search test
joepio May 9, 2026
96a0f81
ci: drop \`--all-features\` from rustClippy (openssl-sys system dep)
joepio May 9, 2026
4d430c4
Switch tokio-tungstenite TLS from native-tls → rustls
joepio May 9, 2026
17aa0e4
e2e: bump actionTimeout to 10s + retry once on CI
joepio May 9, 2026
67a7ca0
Make search test_update_resource poll for the new tantivy generation
joepio May 9, 2026
b727a7a
e2e: bump default expect timeout to 10s (matches actionTimeout)
joepio May 9, 2026
4b2017d
Add runtime perf profiler — React renders, store events, WS frame counts
joepio May 9, 2026
052ba0d
perf: parallelise children + drop merge clone + skip echo SUB pushes
joepio May 9, 2026
2e9cdee
Add PERFORMANCE_PLAN.md — branch-level perf audit + rollout order
joepio May 9, 2026
05fcc6e
perf(B2): index collection members by subject for O(1) lookup
joepio May 9, 2026
3567f66
perf: drop OPFS putResource verification round-trip
joepio May 9, 2026
5278b60
perf: skip useResource LoadingChange listener for already-loaded reso…
joepio May 9, 2026
8336f88
Update PERFORMANCE_PLAN: B2 + 2 bonus wins shipped, B1/B3/B8 deferred…
joepio May 9, 2026
66864e8
perf: combine OPFS getResource + getLoroSnapshot into one worker roun…
joepio May 9, 2026
8bc26cf
ci: oxfmt-format lib + data-browser, add putResources batch handler
joepio May 9, 2026
a7801ce
perf: cold-load — split init/seed wait + batch the bootstrap seed loop
joepio May 9, 2026
b2c8b19
perf: cold-load — preload OPFS WASM + parallelise IDB read with Loro …
joepio May 9, 2026
5c25c19
perf-plan: log cold-load wins shipped (combined OPFS read, init/seed …
joepio May 9, 2026
bd7bd12
perf: add hot-path benchmarks for regression detection
joepio May 9, 2026
07dae7c
ci: lock cargo registry cache + add waitForInit/isInitialized to Node…
joepio May 9, 2026
b1f6276
ci: bump search::test_update_resource poll deadline 5s → 30s
joepio May 9, 2026
51a156b
e2e: bump CI retries 1 → 2 (match nextest)
joepio May 9, 2026
b56a4b3
ci: bump nextest retries to 5 for search::test_update_resource
joepio May 9, 2026
ae3a177
docs: annotate flaky tests inline with \`// FLAKY (env): ...\` markers
joepio May 9, 2026
185460d
ci: mount .config/nextest.toml into rustBuild dagger container
joepio May 9, 2026
06382e0
ci: split rustFmt/Clippy/Test off the JS-coupled rustBuild
joepio May 9, 2026
9d35dfe
fix: await getResource/getLoroSnapshot in OPFS worker batch handler
joepio May 9, 2026
1e0a0cd
ci: nextest override `retries` needs the `{ count, ... }` table form
joepio May 9, 2026
9b9fa12
perf-plan: record local-vs-dagger regression baseline (May 9, 2026)
joepio May 9, 2026
41a7d89
perf: drop the futile waitForFirstDriveSync retry in Collection.fetch…
joepio May 9, 2026
1458e45
perf: race OPFS lookup against server /query in Collection.fetchPage
joepio May 9, 2026
62ab776
ci: nextest override filter — use \`package()\` not \`binary()\`
joepio May 9, 2026
e7abbd3
perf-plan: refresh dagger baseline after override + cold-load fixes
joepio May 9, 2026
ad7d275
fix: coalesce concurrent pushCommits to stop genesis double-POST
joepio May 9, 2026
da73e51
perf-infra: always-on trace + e2e CPU throttle to repro dagger flakes
joepio May 9, 2026
6c0ae9b
perf-probe: sidebar visibility timing after reload
joepio May 9, 2026
72b6bf1
fix: collection drops members created while initial /query is in flight
joepio May 9, 2026
e13e681
fix(client-db): bump leader-election timeout 5s → 30s for dagger CI
joepio May 9, 2026
2cfe184
phase 1: OpfsPersistor — single chokepoint for OPFS writes
joepio May 9, 2026
d4ccea8
phase 2: LocalOutbox — single durable queue for unsynced writes
joepio May 9, 2026
602cdfe
phase 3a: applyIncoming chokepoint — WS UPDATE + SYNC_PUSH migrated
joepio May 9, 2026
60db06f
phase 3b: applyIncoming chokepoint completes — every ingress unified
joepio May 9, 2026
fa886dc
phase 3c: aggressive deletion — −238 LoC across the chokepoint code
joepio May 9, 2026
c59a7b1
phase 3d: delete OpfsPersistor wrapper — −182 LoC
joepio May 9, 2026
bc12831
phase 3e: trim verbose comments in resource.ts hot paths — −66 LoC
joepio May 9, 2026
41de499
phase 3f: delete ResourceSource — duplicate of ChangeSource
joepio May 9, 2026
7003b55
phase 3g: simplify WSClient.handleOpen — −15 LoC
joepio May 9, 2026
e5ee25d
docs: post-mortem of the architecture-review gripes vs what was shipped
joepio May 9, 2026
ec20a9d
phase 5a: useValue → useSyncExternalStore, no more proxy dependency
joepio May 10, 2026
6fe8596
phase 4a: drop _dirtySyncInProgress, derive from outbox.isDraining
joepio May 10, 2026
66ce3dd
phase 5b: useResource → useSyncExternalStore — −44 LoC
joepio May 10, 2026
1d532ed
phase 5c: useResources (plural) → useSyncExternalStore — −31 LoC
joepio May 10, 2026
23e0d71
phase 5d: trim useValue dead-state — −29 LoC
joepio May 10, 2026
cf6becd
phase 5e: useLoroDoc → useSyncExternalStore — −10 LoC
joepio May 10, 2026
0c022fa
phase 5f: drop deprecated APIs — −44 LoC
joepio May 10, 2026
44118a9
phase 5g: drop dead deprecated APIs — −31 LoC
joepio May 10, 2026
9b2d1be
phase 5h: dedupe Collection.fetchPageFromLocalDb empty-page stamping
joepio May 10, 2026
c92ea2b
trim: drop unused putLoroSnapshot proxy paths
joepio May 10, 2026
3a4e14e
docs: refresh post-mortem with actual final state after Phases 4a + 5
joepio May 10, 2026
b4cab80
trim: drop verifyCommit-stub dead comment
joepio May 10, 2026
4998b7b
trim: drop unused parseCommitResource export
joepio May 10, 2026
ed43aa9
trim: consolidate redundant useValue subscribe-source comments
joepio May 10, 2026
6b3829c
trim: drop unused WaitForImmediate helper in resource.ts
joepio May 10, 2026
13afec1
data-browser: clean up Resource.getSubject + Resource.source aftershocks
joepio May 10, 2026
ac16b28
phase 4b: trim StoreSyncStatus + drop dead helpers
joepio May 10, 2026
5a6d826
docs: post-mortem reflects Phase 4b sync-status surface trim
joepio May 10, 2026
4dbe83b
big-refactor 1/N: delete proxyResource — major-bump territory
joepio May 10, 2026
4d64736
big-refactor 2/N: extract getResolved + failResource helpers
joepio May 10, 2026
d716935
big-refactor 3/N: collapse Loro subscriber boilerplate
joepio May 10, 2026
0c598cb
big-refactor 4/N: collapse commit-log entry construction
joepio May 10, 2026
ea9a557
big-refactor 5/N: tidy pushCommitLog + drop stale TODOs/dead code
joepio May 10, 2026
3018767
big-refactor 6/N: clean up duplicate jsdoc + double-normalize
joepio May 10, 2026
a59593e
big-refactor 7/N: extract Resource.extractLoroSnapshot helper
joepio May 10, 2026
8ee9e0f
big-refactor 8/N: dedupe Loro snapshot decode in getLoroDoc
joepio May 10, 2026
5c1085d
big-refactor 9/N: extract resolveSubject + buildPreloadUrl helpers
joepio May 10, 2026
0e774f4
big-refactor 10/N: extract WSClient.sendText helper
joepio May 10, 2026
f161cc0
big-refactor 11/N: simplify getResourceLoading
joepio May 10, 2026
b64fd70
big-refactor 12/N: collapse Resource.getRights write/read duplication
joepio May 10, 2026
849220e
big-refactor 13/N: route Store.subscribe through addLoroSubscriber
joepio May 10, 2026
9d1f480
docs: post-mortem reflects major-bump cleanup pass
joepio May 10, 2026
a93ac88
big-refactor 14/N: extract hydrateOfflineReplay helper
joepio May 10, 2026
75d5d8e
big-refactor 15/N: drop the unsubscribeWebSocket dead chain
joepio May 10, 2026
bba1994
big-refactor 16/N: extract Resource.saveOffline helper
joepio May 10, 2026
bd1355f
big-refactor 17/N: Resource.applyToStore helper
joepio May 10, 2026
eada0f5
big-refactor 18/N: Resource.destroy uses shared getCommitEndpoint
joepio May 10, 2026
e7ae691
big-refactor 19/N: extract Collection.writePageMembers helper
joepio May 10, 2026
8e24470
big-refactor 20/N: extract commitIdOf shared helper
joepio May 10, 2026
8546568
big-refactor 21/N: extract WSClient.takePending helper
joepio May 10, 2026
85bc6e7
docs: post-mortem reflects round-3b major-bump cleanup
joepio May 10, 2026
906d84c
flake-fix: serialize outbox drain before refetch on reconnect
joepio May 10, 2026
ac2799b
flake-fix: wake WS reconnect immediately on browser 'online' event
joepio May 10, 2026
14d4446
flake-fix: single reconnect chain — handleOpen owns auth+drain+refetc…
joepio May 10, 2026
9af1307
flake-fix: reject in-flight pending GETs on WS close
joepio May 10, 2026
3be8881
flake-fix: cancel stale extractMembers runs in useChildren
joepio May 10, 2026
aab151e
fix: narrow useValue return type to JSONValue (was latent ts error)
joepio May 10, 2026
47b4f30
trim: drop unused waitForFirstDriveSync + supporting state
joepio May 10, 2026
29ef751
flake-fix: guard the 'online' listener against double-socket race
joepio May 10, 2026
e7ecb8f
flake-fix: clear getResource wait-timer on resolve
joepio May 10, 2026
03e4112
flake-fix: don't leave refetch'd resource stuck on loading=true
joepio May 10, 2026
95b821e
flake-fix: cancel stale canWrite resolves in useCanWrite
joepio May 10, 2026
3da3b25
flake-fix: await cookie installation before the request that needs it
joepio May 10, 2026
c1aa17e
flake-fix: stale-write guard on invalidateCollection
joepio May 10, 2026
f178b87
flake-fix: prune stale recentlyCreatedSubjects entries
joepio May 10, 2026
a1bcb01
flake-fix: guard handleSyncDiff send against mid-flight WS close
joepio May 10, 2026
8571648
flake-fix: reject pending GETs on WS error too, not just close
joepio May 10, 2026
00174a5
flake-fix: Resource.set falls back to no-validate on getProperty failure
joepio May 10, 2026
ad2dbc5
flake-fix: catch multi-step parent cycles in Resource.canWrite
joepio May 10, 2026
0299f36
flake-fix: time out sendToLeader rpc-req on dead leader
joepio May 10, 2026
190080f
flake-fix: off-by-one slice on LORO_EPHEMERAL_UPDATE
joepio May 10, 2026
816cd42
flake-fix: catch unawaited handleSyncDiff rejections
joepio May 10, 2026
872b83d
chore: oxfmt fixes for the flake-fix series
joepio May 10, 2026
b1043d5
ci: enable pnpm-store + cargo-install caches in dagger
joepio May 10, 2026
c9f824c
perf: kill the ClientDb safety-net reseed (-1.8s cold load)
joepio May 11, 2026
81f3b3f
perf: gate ClientDb seed on a bootstrap fingerprint
joepio May 11, 2026
329a4f2
perf: don't block first paint on Loro WASM init
joepio May 11, 2026
45d78b4
test: add first-paint, dev-drive timing + CDP-trace specs
joepio May 11, 2026
49839d6
perf: race server vs OPFS in Collection.fetchPage
joepio May 11, 2026
7d0222f
perf: defer Loro WASM download until after first paint
joepio May 11, 2026
5996935
perf: pre-compress static assets with brotli q11 at build time
joepio May 11, 2026
b9e4718
fix: cache the unknown-subject Resource in getResourceLoading
joepio May 11, 2026
be34899
fix: revert Collection.fetchPage server/OPFS race — caused stale side…
joepio May 11, 2026
c7a73e7
fix: undo Loro requestIdleCallback deferral — broke title-save in tests
joepio May 11, 2026
1d915f7
test: fix perf-sidebar-reload via setTitle + annotate two pre-existin…
joepio May 11, 2026
ae520d2
test(e2e): default to workers=1 locally — matches CI, drops flake count
joepio May 11, 2026
86587ec
fix: harden e2e under high parallelism (workers=4+)
joepio May 11, 2026
23bb62b
fix: optimistic page-0 bootstrap + notify-before-navigate
joepio May 11, 2026
e0ac579
fix: Collection preserves optimistic adds across background re-fetch
joepio May 11, 2026
69767a7
test: perf-sidebar-reload waits for URL change before setTitle
joepio May 11, 2026
dc7eb54
test: table-refresh:86 waits for stable row count, not a fixed 1500ms
joepio May 11, 2026
a7b3ff6
Various e2e fixes
joepio May 12, 2026
67bc064
Fix more tests
joepio May 12, 2026
e571742
Fix sync perf issue
joepio May 12, 2026
7be2e88
Store commits in client
joepio May 12, 2026
52faf29
Far less requests over WS
joepio May 12, 2026
fe1c465
perf(server): boot in seconds, not a minute
joepio May 13, 2026
2f58392
test(e2e): bump per-subject GET threshold to 10 for parallel load
joepio May 13, 2026
416cdf6
test(e2e): wait for /show after Save before opening context menu
joepio May 13, 2026
e81654e
test: WS GET latency benchmark for anonymous users on private resources
joepio May 13, 2026
99abf56
test: add SYNC_VV head-of-line blocker benchmark
joepio May 13, 2026
7321e95
fix(sync): skip full-store scan on SYNC_VV for non-DID "drives"
joepio May 13, 2026
d8db031
fix(ws): skip SYNC_VV when drive is not a real DID
joepio May 13, 2026
b01f232
Revert "fix(ws): skip SYNC_VV when drive is not a real DID"
joepio May 13, 2026
7ee35e2
Revert "fix(sync): skip full-store scan on SYNC_VV for non-DID "drives""
joepio May 13, 2026
0d4a5e0
OPFS fix
joepio May 13, 2026
ca7e8e6
Flutter + dart #1195 + Canvas #1172
joepio May 13, 2026
8a6e406
Add flutter CI #1195
joepio May 13, 2026
868c367
Planning / docs cleanup
joepio May 13, 2026
22ab21e
Lint fixes
joepio May 13, 2026
48c2fa8
Fix search test
joepio May 13, 2026
2c9ddfd
E2E fixes
joepio May 14, 2026
1107c7c
fix e2e
May 19, 2026
875a58d
Improve sync page
joepio May 19, 2026
26e9273
Commits over WS sync
joepio May 19, 2026
98dd749
Virtual drive plan #1154
joepio May 19, 2026
c6db6a9
Fix commit bug - loro changes not stored
joepio May 19, 2026
b2cf5ab
Update virtual-drive.md
joepio May 19, 2026
8879aa2
Fix history and ontology
joepio May 19, 2026
281d187
Fix sync canvas
joepio May 19, 2026
dd771c2
E2E fixes, loro fixes
joepio May 21, 2026
58f62b3
Loro source of truth
joepio May 21, 2026
2c44b1a
Loro 2b/2c: snapshot+projection in one tx, strip loroUpdate from blob
joepio May 21, 2026
2cbd6d4
Ignore .antigravitycli tooling dir
joepio May 21, 2026
4118aeb
Loro 2a step 1: explicit is_native() guard for loroUpdate serialization
joepio May 22, 2026
80a5033
Loro 2a step 2: add fallible doc-first set_unsafe_fallible / remove_p…
joepio May 22, 2026
38b9ab0
Loro 2a step 3: migrate Commit::into_resource to set_unsafe_fallible
joepio May 22, 2026
e961d09
Loro 2a: doc-first fallible mutation + client/server doc continuity
joepio May 22, 2026
ac47c01
e2e: robust dialog close + outbox diagnostics on sync timeout
joepio May 22, 2026
bb7b2c7
Outbox: skip already-applied commits instead of stranding the drain
joepio May 22, 2026
b8c1c21
e2e: retry typeInSearch against the re-rendering search overlay
joepio May 22, 2026
f985691
react: retry useServerSearch while results are empty
joepio May 22, 2026
caacbf5
e2e: cover offline search against the local index
joepio May 22, 2026
be9f341
lib: rehydrate local search index from ClientDb on startup
joepio May 22, 2026
abae32f
lib: per-drive local search index + offline scoping
joepio May 22, 2026
39200a8
commit: distinguish idempotent replay from silent LWW loss
joepio May 22, 2026
8e4e5e0
e2e: poll the real index in scoped-search instead of a fixed sleep
joepio May 22, 2026
cf2c3c2
collection: keep optimistic adds in totalMembers after a local-DB fetch
joepio May 22, 2026
32db134
Improve drive page, resources in sub menu
joepio May 22, 2026
15495b1
planning: commit-retention proposal + Phase 0 audit findings
joepio May 22, 2026
7435a27
history: surface document body content in version history
joepio May 22, 2026
58664e8
Canvas browser default name and move with space #1172
joepio May 23, 2026
37062d4
e2e: expand the drive page 'Resources' section before checking rename…
joepio May 23, 2026
e69a236
chore: oxfmt sweep across earlier session commits
joepio May 23, 2026
9390155
i18n: prune wuchale-obsolete .po entries (clean)
joepio May 23, 2026
9572560
Update rust deps
joepio May 23, 2026
24a866c
Fmt & clippy fixes
joepio May 23, 2026
547f6a8
chore: remove accidentally-committed binaries, scratch files, and too…
joepio May 23, 2026
1449c31
deps: bump browser packages + adapt source for the regressions surfaced
joepio May 23, 2026
da16502
canvas: scrub-history gesture on undo button + jsonArray ontology + u…
joepio May 23, 2026
64f77a7
lib: tag system commits + exclude from UndoManager so tap-undo actual…
joepio May 23, 2026
d199553
canvas: bottom pill toolbar with 9 buttons (Flutter parity, Phase D1)
joepio May 23, 2026
dfbd4fc
canvas: color + width fans with drag-to-pick gesture (Flutter parity,…
joepio May 23, 2026
5832a76
canvas: zoom-scrub on the zoom button (Flutter parity, Phase D4)
joepio May 23, 2026
77b3cac
Browser canvas #1172
joepio May 23, 2026
e36c903
Editable title in navbar
joepio May 23, 2026
ee3b11e
Fix Drag & Drop, use floats
joepio May 23, 2026
7d07743
Fix canvas sync
joepio May 24, 2026
42d4ddb
Fix ctrl-z in doc editor
joepio May 25, 2026
c9fdae4
Fix document cursor sync
joepio May 26, 2026
12befb3
DevDrive secret to clipboard
joepio May 26, 2026
fa7d657
Fix ws drops
joepio May 26, 2026
b5a9fee
Add authorization sync
joepio May 26, 2026
ad098e3
FIx e2e tests
joepio May 26, 2026
5656f31
Auto install wasm-pack
Polleps May 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
e2e: replace fixed waitForTimeouts with proper data/visibility waits
The replaced sleeps were guessing at how long async work would take
(commit-debounce-flush, dropdown mount, post-fill auto-submit, menu
unfurl). Each is now an explicit wait on the actual signal:

- After typing-edits: poll `pendingDirtyCount === 0` instead of a 1.5s/2s
  guess. The dirty queue settles to 0 once every keystroke has been ack'd
  by the server — that's the real "saved" signal.
- Before opening an invite URL in a new context: same `pendingDirtyCount`
  drain, instead of 200ms.
- After typing `@` in the RTE: wait for `rte-command-list` visibility
  instead of 500ms.
- Onboarding `verifySecret`: drop the 500ms before the URL assertion —
  `expect(page).toHaveURL` already polls for 10s, the auto-submit fires
  inside that window.
- `contextMenuClick`: wait for the menu item's visibility instead of
  guessing 100ms for unfurl.
- `tables.spec`: replace the two pre-reload "wait for save" sleeps with
  the same dirty-queue check.

These are the cases where the wait had a clear signal to bind to. Some
remaining sleeps (dblclick gap to defeat dblclick threshold, network-stack
warmup after `setOffline(false)`, debug-trace pacing) are intentional and
left in place.
  • Loading branch information
joepio committed May 8, 2026
commit e20d0ecd4e912618f36684d00616d269c3ba4c29
6 changes: 5 additions & 1 deletion browser/e2e/tests/documents.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,11 @@ test.describe('documents', async () => {
// Add a link to a folder via @ mention
await page2.keyboard.press('Space');
await page2.keyboard.type('@');
await page2.waitForTimeout(500);
// The RTE command list mounts asynchronously after `@` is typed.
// Wait for it instead of guessing a fixed delay.
await expect(page2.getByTestId('rte-command-list')).toBeVisible({
timeout: 10000,
});
await page2.keyboard.type(folderTitle, { delay: 50 });
await expect(
page2.getByTestId('rte-command-list').getByText(folderTitle),
Expand Down
22 changes: 19 additions & 3 deletions browser/e2e/tests/e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,15 @@ test.describe('data-browser', async () => {
);
expect(inviteUrl).not.toBeFalsy();

await page.waitForTimeout(200);
// The invite resource needs to be persisted server-side before the
// invitee opens its URL — otherwise the server returns 404. Wait for
// the dirty queue to drain rather than guessing a fixed 200ms.
await page.waitForFunction(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
() => (window as any).store?.getSyncStatus?.().pendingDirtyCount === 0,
undefined,
{ timeout: 10000 },
);

// Open invite
const page3 = await openNewSubjectWindow(browser, inviteUrl as string);
Expand Down Expand Up @@ -253,8 +261,16 @@ test.describe('data-browser', async () => {
await editableTitle(page).type(letter, { delay: Math.random() * 300 });
}

// Wait long enough for the final debounce (100ms) + network round-trip.
await page.waitForTimeout(1500);
// Wait for the debounced save to drain into the server before exiting
// edit mode. The dirty queue settles to 0 once every accumulated keystroke
// has been ack'd — that's the actual "typing finished saving" signal,
// and it returns immediately if we're already idle.
await page.waitForFunction(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
() => (window as any).store?.getSyncStatus?.().pendingDirtyCount === 0,
undefined,
{ timeout: 10000 },
);
await page.keyboard.press('Escape');

await expect(
Expand Down
6 changes: 2 additions & 4 deletions browser/e2e/tests/onboarding.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,8 @@ test.describe('onboarding', () => {
// Paste the secret we read earlier (clipboard may not work after signout)
await page.getByLabel('Enter your Agent Secret').fill(secret!);

// Wait for auto-verify to trigger
await page.waitForTimeout(500);

// Should auto-verify and navigate to the drive
// The form auto-submits ~150ms after fill (GettingStartedFlow useEffect).
// The URL assertion below already polls — no separate sleep needed.
await expect(page).toHaveURL(/did(?:%3A|:)ad(?:%3A|:)/, { timeout: 10000 });

// Open a NEW BROWSER CONTEXT (fresh, as if on a completely different computer)
Expand Down
22 changes: 17 additions & 5 deletions browser/e2e/tests/tables.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,16 @@ test.describe('tables', async () => {
page.getByRole('button', { name: selectColumnName }),
).toBeVisible();

// Wait for all pending commits to be flushed before reload.
// 'networkidle' is unreliable on SPAs with persistent WebSocket connections.
await page.waitForTimeout(2000);
// Wait for all pending commits to drain into the server before reload.
// 'networkidle' is unreliable on SPAs with persistent WebSocket
// connections (commit subscriptions, the open WS, etc.). The dirty
// queue is the actual saved-to-server signal.
await page.waitForFunction(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
() => (window as any).store?.getSyncStatus?.().pendingDirtyCount === 0,
undefined,
{ timeout: 10000 },
);
await page.reload();
await expect(
page.getByRole('button', { name: selectColumnName }),
Expand Down Expand Up @@ -308,8 +315,13 @@ test.describe('tables', async () => {
// Exit edit mode
await page.keyboard.press('Escape');

// Wait for all debounced saves to complete
await page.waitForTimeout(2000);
// Wait for all debounced saves to drain into the server.
await page.waitForFunction(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
() => (window as any).store?.getSyncStatus?.().pendingDirtyCount === 0,
undefined,
{ timeout: 10000 },
);

// Verify all values are displayed correctly before refresh
for (const value of values) {
Expand Down
6 changes: 4 additions & 2 deletions browser/e2e/tests/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -634,8 +634,10 @@ export async function clickSidebarItem(text: string, page: Page) {
/** Click an item from the main, visible context menu */
export async function contextMenuClick(text: string, page: Page) {
await page.click(contextMenu);
await page.waitForTimeout(100);
await page.getByTestId(`menu-item-${text}`).click();
// Wait for the menu item to mount instead of guessing 100ms.
const item = page.getByTestId(`menu-item-${text}`);
await item.waitFor({ state: 'visible', timeout: 5000 });
await item.click();
}

export const anyValue = Symbol('any');
Expand Down