Skip to content

test(engine): add a fake engine adapter behind the RPC seam - #29612

Draft
chrisnojima wants to merge 1 commit into
masterfrom
nojima/HOTPOT-arch-10-fake-engine
Draft

test(engine): add a fake engine adapter behind the RPC seam#29612
chrisnojima wants to merge 1 commit into
masterfrom
nojima/HOTPOT-arch-10-fake-engine

Conversation

@chrisnojima

@chrisnojima chrisnojima commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Problem

The RPC seam is well placed — every generated *RpcPromise routes through one chokepoint, createRpcengine()._rpcOutgoing — but it had exactly one adapter, so it was hypothetical and every data test reached past it.

~45 test files jest.spyOn generated RPC symbols; thread-context.test.tsx alone spies 20. Tests therefore encoded which RPC the implementation happens to call, not what the module promises: swapping teamsGetAnnotatedTeam for a different RPC breaks tests whose contract is unchanged.

Change

A test-only adapter at the existing chokepoint:

const engine = installFakeEngine({
  'keybase.1.teams.getAnnotatedTeam': () => annotated,
})
expect(engine.callCount('keybase.1.teams.getAnnotatedTeam')).toBe(1)

Plus calls / setHandlers / unhandledMethods / uninstall.

Handler maps are typed off the generated MessageTypes, so a misspelled wire method or a wrong return shape is a compile error — it immediately caught one that an existing as never spy had hidden.

Covers resolve, reject, streaming through the real listener, waitingKey accounting into the real waiting store, and cancel. Unhandled methods both console.error (which fail-on-console turns into a failure even if the caller swallows the rejection) and reject, so a test calling an RPC it didn't stub fails loudly rather than hanging.

The only production change: initEngine/getEngine narrow to EngineSeam = Pick<Engine, '_rpcOutgoing' | 'cancelSession' | 'createSession' | 'dispatchWaitingAction'>, plus a resetEngine().

Converted

6 test files off jest.spyOn of generated symbols: use-loaded-team, chat/inbox/refresh-participants (10 spies), chat/conversation/team-hooks, info-panel/add-to-channel, status-actions, messages/reset-user.

Not converted: thread-context.test.tsx (2097 lines, 20 spies). Its spies replace the RPC listener wholesale and drive incomingCallMap synchronously, so routing them through the real listener's macrotask deferral means rewriting all 20 tests' flush strategy. Deserves its own PR.

Validation

lint:all clean — 0 bailed out, 0 whole-props deps, tsc clean both projects.
jest --runInBand231 suites / 2247 tests (baseline 230 / 2236).

Every generated *RpcPromise and every engine listener already funnels through
getEngine()._rpcOutgoing, but the seam had exactly one adapter, so tests reached
past it and spied on whichever generated symbol the implementation happened to
call. installFakeEngine answers at that chokepoint by wire-method string,
counting calls, so a test says what the service returns rather than which
function the module calls.

The adapter resolves, rejects, drives incremental/streaming incoming callbacks
through the real listener, holds and releases waitingKeys, and fails loudly
(console.error, which test/fail-on-console turns into a failure, plus a
rejection) on a method the test never stubbed, so an unstubbed RPC can never
look like a load that simply never finished.

Handlers are typed off the generated MessageTypes, so a misspelled wire method
or a wrong return shape is a compile error.

The seam type narrows from Engine to the four members it actually uses; no
production behaviour changes.

Converted six test files off jest.spyOn of generated RPC symbols.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015rccpV5nLxxC5opF5xzrz7
@chrisnojima
chrisnojima force-pushed the nojima/HOTPOT-arch-10-fake-engine branch from 5606d8f to 7b85df2 Compare September 11, 2026 01:47
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.

1 participant