Skip to content

test(rest): REST client test suite#11

Merged
0xSaiNova merged 6 commits intodevfrom
6-sdk-set-up-vitest-and-write-rest-client-tests
Mar 2, 2026
Merged

test(rest): REST client test suite#11
0xSaiNova merged 6 commits intodevfrom
6-sdk-set-up-vitest-and-write-rest-client-tests

Conversation

@0xSaiNova
Copy link
Copy Markdown
Member

Closes #6

The REST client had no real test coverage. This adds four new test files and expands the existing one to cover everything the issue asked for.

Route bucket keys

Route.test.ts is new. Verifies that major params (server ID, channel ID) produce separate rate limit buckets while minor params (message ID) get normalized so requests against different messages in the same channel share one.

Error class hierarchy

errors.test.ts is new. Every error class gets tested for the right inheritance chain and the fields specific to it. RateLimitError gets extra attention since retryAfter, global, and bucket are the whole point of that class existing.

Request basics

REST.test.ts now stubs global.fetch inside a scoped describe block to verify that REST actually sends the right method, URL, auth header, and body. The stub is cleaned up after each test so it doesn't affect the existing token guard tests.

Error status mapping

429, 401, 403, 404, 500, 502, and unknown 4xx each get a test asserting the right error type comes back. The 429 and 5xx tests use maxRetries: 0 so they throw immediately rather than sleeping through retry delays and exhausting the fetch mock queue.

Snowflake validation

The original tests only covered getServer. This expands to getChannel, createMessage, getMessage (both IDs separately), and the before/after cursors on listMessages. Also adds a positive case confirming a valid numeric snowflake passes through to the network layer.

Covers the two core bucketing rules: major params (server_id, channel_id)
get their own buckets, minor params (message_id) are normalized so requests
against different messages in the same channel share a bucket.

Also verifies that method is always part of the key and that url() produces
the correct full URL from a given base.
Tests all six error types across the full inheritance chain.
Each class gets checked for the right instanceof relationship, status code,
and any extra fields specific to it (retryAfter/global/bucket on RateLimitError,
optional code on HTTPError, etc).
Stubs global fetch within a scoped describe block so tests can verify
what REST actually sends without making real network calls.

Covers createServer (POST + JSON body), auth header format, Content-Type,
listMessages (GET with query params), deleteChannel (DELETE, no body),
and 204 No Content resolving to undefined.
Each HTTP status code now has a test verifying the right error class comes back.
The tricky part was 429 and 5xx — the REST client retries those by default,
so tests use maxRetries: 0 to make them throw on the first attempt rather than
sleeping through retry delays and exhausting the fetch mock queue.

RateLimitError gets extra coverage for the retryAfter, global flag, and bucket
fields since those are the main reason that class exists.
…s [refs #6]

The two existing tests only covered getServer. This expands coverage to
getChannel, createMessage, getMessage (both IDs), and the before/after
cursor params on listMessages.

Also adds a positive case — a valid all-digit snowflake should pass validation
and reach the network layer without throwing.
@github-actions github-actions bot added the rest label Mar 2, 2026
@0xSaiNova
Copy link
Copy Markdown
Member Author

Worth noting the approach for anyone reviewing: fetch is stubbed inside a scoped describe block with beforeEach/afterEach so it only affects the tests that need it. The existing token guard tests make real network calls (or rather, let them fail naturally) and they still work fine.

describe('request basics', () => {
  const fetchMock = vi.fn()

  beforeEach(() => {
    vi.stubGlobal('fetch', fetchMock)
    fetchMock.mockReset()
  })

  afterEach(() => {
    vi.unstubAllGlobals()
  })

  // ...
})

The maxRetries: 0 pattern on the 429 and 5xx tests is intentional. Without it, REST retries those errors with delays and the mock queue runs out, causing the retry to get undefined back from fetch instead of a proper response.

…s [refs #6]

The token guard tests were making actual HTTP requests to api.intent.chat.
Locally they'd fail fast on connection refused, but in CI there's no network
so they'd hang until Vitest's 5s test timeout fired.

Stubbed fetch with an immediate TypeError in those tests — the token guard
check throws IntentError before fetch is even reached, and once a token is
set the TypeError surfaces correctly as a non-IntentError.
@0xSaiNova 0xSaiNova merged commit 59d2714 into dev Mar 2, 2026
3 checks passed
@0xSaiNova 0xSaiNova deleted the 6-sdk-set-up-vitest-and-write-rest-client-tests branch March 2, 2026 05:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant