Repository navigation
test(events): cover SSE streamEvents success paths - #1963
Merged
Merged
Conversation
Add eventStream.success.test.ts driving GET /api/events/stream through a real HTTP server with raw client sockets (an open SSE response cannot be consumed by supertest): - borrower connect: SSE headers, init payload, replay query params, and service registration/unregistration on socket close - Last-Event-ID replay: contract_events rows mapped to camelCase loan-event frames in order, no init frame when replay rows exist - admin (subscribeAll): init payload carrying connection counts - 429 via an actual HTTP request once the per-user limit is exhausted Import authService dynamically after the cacheService mock registration; a static import instantiates it pre-mock, the auth middleware then binds the real Redis-backed cacheService, and the never-resolving connect keeps the Jest worker alive after the run. Mock the rateLimiter module with pass-through middleware to avoid MemoryStore timers at import time. Closes LabsCrypt#1854
Line-wrapping only; no behavioral change.
Line-wrapping only; no behavioral change.
The middleware builds idemp:<wallet|anon>:<key> since the LabsCrypt#1809 namespacing, so pin the get/delete/set assertions to the real namespaced format instead of the bare idemp:<key> form.
…bsCrypt#1809) A mock returning the same entry for every key cannot model per-user isolation. Back the cacheService spies with a real Map keyed by the full namespaced cache key, seed Bob's entry/lock under his namespace, and assert the replay check against the original res.json mock — on the handler path the middleware wraps res.json and delegates to the original, so the wrapper is not a jest mock.
…rypt#1808) - pageQuery() now inspects the most recent query call (getAuditLogs emits the page SELECT after the COUNT, so the first match could be a stale earlier call) - pass an actual cursor into the keyset-predicate test so the (created_at, id) < ($n, $n) comparison has real values to assert - split nextCursor on the last ':' — ISO timestamps contain colons - compare the COUNT SQL trimmed; the template-built query carries a trailing space after the table name - pin AuditLogFilters to its real field count of 7 (actor, action, from, to, cursor, limit, withTotal), not 8
| // targets the original res.json mock captured beforehand: the wrapper | ||
| // delegates to it, making it the recorder of every body the response | ||
| // actually carried. | ||
| const originalJson = res.json as jest.Mock; |
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.
Summary
Adds success-path coverage for the SSE endpoints (
GET /api/events/stream), complementing the reject-path tests ineventStream.test.ts(issue #1854).Because a never-ending SSE response cannot be consumed by a plain supertest request, the tests drive a real
http.createServer(app)on an ephemeral port and speak raw HTTP with client sockets.Coverage (all acceptance criteria)
text/event-stream,no-cache,keep-alive,X-Accel-Buffering: no), theevent: initpayload ({"type":"init","replayed":0}), the replay query params ([borrower, null, 100]), service registration, and unregistration when the client socket closescontract_eventsrows are streamed as camelCaseloan-eventframes in order (eventId/eventType/loanId/amount/ledger/txHash), with no init frame when replay rows exist, and query params[borrower, 'evt-prev', 100]borrowerreceives the subscribeAll init payload; a second admin connection's init carries the counts of the first ({"borrower":0,"admin":1,"total":1}), pinning the write-before-register behaviorMaximum of 3 SSE connections allowed per userbefore any SSE headers are writtenTest infrastructure notes
authServiceis imported dynamically after thecacheServicemock registration. A static import instantiates it pre-mock; the auth middleware then resolves that real Redis-backed instance and its never-resolvingconnect()keeps the Jest worker alive after the run (exit 124). The suite now exits cleanly without--forceExit.rateLimitermodule is mocked with pass-through middleware soexpress-rate-limitMemoryStoretimers are never created at import time.remittanceRoutes.test.ts); teardown destroys all client sockets beforeserver.close().Verification
Closes #1854