test(api): cover replay and batch send endpoints#19
Merged
Conversation
Adds 6 integration tests on the public message endpoints, reusing the existing TestWebApplicationFactory (InMemory database, no Testcontainers required). Batch send: - All valid items accepted (3/3) and reported per-item. - Mixed batch with one unknown event type returns 2 accepted + 1 rejected, with the failed item carrying an error code. - Empty messages array is rejected with 422 by the validator. Replay: - Source candidates inside the date range are replayed as new pending rows; out-of-range messages are skipped. - A range with no candidates returns sourceCount=replayedCount=0. - A request without an eventType / eventTypeId is rejected with 422. These flows previously had unit-level coverage on the underlying repository but no end-to-end HTTP coverage; the tests guard against regressions in the controller, validator, and queue interaction.
3 tasks
voyvodka
added a commit
that referenced
this pull request
May 8, 2026
…skeleton, no flash, awaited refetches (#68) Six findings from the dashboard-expert audit, all in one PR before F12. a11y on Modal (audit findings #9 + #10) — the dialog was an unlabelled, focus-leaky panel: no role="dialog", no aria-modal, no aria-labelledby, and Tab/Shift+Tab walked right out of the modal into the document underneath. Fixed all four: - Panel now carries role="dialog" + aria-modal="true" with useId-stable aria-labelledby (and aria-describedby when a description is passed). - Close button got an explicit aria-label="Close dialog". - New keydown handler implements a Tab/Shift+Tab focus trap that wraps focus between the first/last focusable descendants (or pins to the panel itself when nothing inside is focusable). useDeliveryFeed reconnect cleanup (audit finding #19) — onreconnected now resets lastHealthChange to null. Without this, an EndpointsPage that re-subscribed after a disconnect would re-apply the pre-disconnect snapshot from cache, masking whatever the server may have transitioned to during the gap. DeliveryLogPage skeleton (audit finding #22) — replaced the bare "Loading..." text with a layout-preserving skeleton card (header strip + two attempt blocks) plus aria-busy on the wrapper. No layout shift on completion. EndpointsPage flash (audit finding #23) — the page was checking applications.length === 0 before the apps fetch had returned, briefly flashing "Create an application first" on every cold load. New applicationsLoading state gates that branch so the spinner shows until the apps fetch completes; only then does the empty / endpoints branch render. ApplicationsPage floating promise (audit finding #26) — both handleCreate and the delete-confirm onConfirm called fetchApps() without awaiting it, so any refetch rejection became an unhandled promise. Both now await, landing failures inside the surrounding try-catch / setError flow.
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
Coverage
Batch send (`POST /api/v1/messages/batch`):
Replay (`POST /api/v1/messages/replay`):
Why
Replay and batch are in production today (since v0.1.0) but only had unit-level coverage on the underlying repository — no end-to-end HTTP coverage. These tests guard against regressions in controller logic, validator behavior, and queue interaction.
Out of scope
Labels
`enhancement` `api`
Test plan