test: downstream wire-compat (vectors + smoke)#136
Merged
Conversation
Phase 2 of ether/etherpad#7923. Adds this repo's first test runner (node:test via tsx) plus two suites: - test:vectors — server-free, replays the canonical wire-format fixture through the repo's own Changeset/AttributePool decoders and asserts byte-for-byte text equality. All 5 vectors pass with no decoder changes. - test:smoke — live HTTP+socket.io round-trip; skips cleanly when no server/API key is available. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
Code Review by Qodo
1.
|
- Guard close() call (client?.close?.()): connect() assigns close only after its async bootstrap resolves, so the method may be undefined when the finally-block cleanup runs. - Clear the withTimeout setTimeout in a finally so a fast-resolving promise no longer leaves a dangling timer keeping the test process alive. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Member
Author
|
Thanks Qodo — both bugs were valid and are fixed in e4b4643 (test-only, no source changes):
|
JohnMcLear
added a commit
to ether/etherpad
that referenced
this pull request
Jun 9, 2026
Implements the per-kind orchestration (clone @ pinned ref, inject core's freshly-generated wire-vectors fixture via ETHERPAD_WIRE_VECTORS, run each client's vectorTest + smokeCmd against the booted server) in a testable run-clients.sh, and flips the three manifest entries to enabled, pinned to the commits that carry their Phase 2 tests: ether/pad#1, ether/etherpad-cli-client#136, ether/etherpad-desktop#78. Validated end-to-end locally against a real core: all three clients' vectors + live smoke pass. Refs should be bumped to the squash-merge commits once those client PRs land. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
JohnMcLear
added a commit
to ether/etherpad
that referenced
this pull request
Jun 9, 2026
The three client Phase-2 PRs merged; bump each manifest ref from its pre-merge PR-branch tip (now deleted / unfetchable) to its squash-merge commit on main: etherpad-pad -> 91620c6 (ether/pad#1) etherpad-cli-client -> ebc516e (ether/etherpad-cli-client#136) etherpad-desktop -> ab83da6 (ether/etherpad-desktop#78) Verified each merged main carries the test entry points (vectors.rs/smoke.rs; test:vectors/test:smoke scripts). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
JohnMcLear
added a commit
to ether/etherpad
that referenced
this pull request
Jun 9, 2026
…7927) * ci(downstream): robust per-client error handling in run-clients.sh (Qodo) - Move clone/fetch/checkout inside the per-client guarded block with explicit '|| exit 1' on every step. set -e is suspended inside a subshell used as an '||' operand, so relying on it silently swallowed clone/checkout failures (and continued from the wrong cwd); explicit guards make one client's failure a per-client fail=1 while the loop continues, and the run exits non-zero. - Stop suppressing fetch errors; fetch only when the pinned commit isn't already reachable, and surface the real error. - Run manifest commands via 'bash -c' instead of 'eval' (trusted in-repo allowlist; avoids double-parsing / leaking into this script's shell). Verified: two bogus clients -> both reported, loop continues, exit 1; happy path (cli, no server) -> vectors pass, smoke skips, exit 0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci(downstream): pin clients to their merged-commit SHAs The three client Phase-2 PRs merged; bump each manifest ref from its pre-merge PR-branch tip (now deleted / unfetchable) to its squash-merge commit on main: etherpad-pad -> 91620c6 (ether/pad#1) etherpad-cli-client -> ebc516e (ether/etherpad-cli-client#136) etherpad-desktop -> ab83da6 (ether/etherpad-desktop#78) Verified each merged main carries the test entry points (vectors.rs/smoke.rs; test:vectors/test:smoke scripts). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci(downstream): run manifest commands under bash strict mode (Qodo) bash -c spawns a fresh shell without -e/-u/-o pipefail, so a pipeline-stage failure inside a client's vectorTest/smokeCmd could be masked. Use 'bash -euo pipefail -c' so those failures surface as a non-zero exit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR Summary by Qodo
Add wire-compat vector tests and optional live smoke test (node:test via tsx)
🧪 Tests⚙️ Configuration changes🕐 20-40 MinutesWalkthroughs
User Description
Phase 2 of ether/etherpad#7923.
Core PR #7923 (Phase 1) added a canonical wire-format fixture that every Etherpad client must decode identically. This PR is the downstream half for
etherpad-cli-client: it vendors that fixture and verifies this repo's ownChangeset/AttributePooldecoders produce identical results.This repo previously had no test runner at all — this adds the first one, using the built-in
node:testdriver run throughtsx(the repo is TS, ESM,.js-extension imports).What's added
test/fixtures/wire-vectors.json— the canonical fixture, vendored verbatim. 5 vectors: plain insert/delete, formatted insert, multiline insert, attribute reuse. Each says: applyingchangesettoinitialText(withpool) yieldsresultText. Path overridable viaETHERPAD_WIRE_VECTORS.test/vectors.test.ts(pnpm run test:vectors) — server-free, must pass. Reconstructs eachAttributePoolviaAttributePool.fromJsonable, applies the changeset with the repo'sChangeset.applyToText(text equality) andChangeset.applyToAText(drives the pool decode throughmustGetAttrib), asserting byte-for-byte againstresultText.test/smoke.test.ts(pnpm run test:smoke) — live, skips cleanly with no server. ReadsETHERPAD_SMOKE_URL(defaulthttp://localhost:9003) andETHERPAD_SMOKE_APIKEY. If no API key, or/api/isn't reachable (1.5s probe), itt.skip()s instead of failing. With a server it: creates a pad via HTTP API → connects with the repo's ownconnect()socket.io client → appends via theUSER_CHANGESwrite path (pad.append) → pollsgetText(bounded 10s) to confirm round-trip → deletes the pad.Scripts
These exact names are what the core CI manifest invokes.
Env contract
ETHERPAD_WIRE_VECTORStest/fixtures/wire-vectors.jsonETHERPAD_SMOKE_URLhttp://localhost:9003ETHERPAD_SMOKE_APIKEYResults
pnpm run test:vectors→ 5 pass / 0 fail, no decoder changes needed (this repo's decoders are already wire-compatible).pnpm run test:smokewith no server → 1 skipped, 0 fail (green). Lint clean.Only test files, the fixture, the
tsxdevDep, and the three scripts are added; no source refactors.🤖 Generated with Claude Code
AI Description
Diagram
graph TD TR(["pnpm test (tsx + node:test)"]) --> TV["vectors.test.ts"] --> CL["Changeset + AttributePool"] TV --> FX["wire-vectors.json"] TR --> TS["smoke.test.ts"] --> ES{{"Etherpad server"}} TS --> CL subgraph Legend direction LR _t([Test runner/test]) ~~~ _f["File/fixture"] ~~~ _ext{{External service}} endHigh-Level Assessment
The following are alternative approaches to this PR:
1. Adopt Vitest/Jest as the test runner
node:test2. Compile tests with `tsc` and run `node --test` on emitted JS
3. Containerize Etherpad for smoke test in CI
Recommendation: Keep the current
tsx+node:testapproach: it’s minimal, matches Node 18+ ESM constraints, and cleanly separates deterministic (vectors) from opportunistic (smoke) coverage via skip logic. Consider containerizing Etherpad later if always-on smoke coverage becomes a CI requirement.File Changes
Tests (3)
Other (2)