atproto/packages/xrpc-server/tests/parameters.test.ts
Matthieu Sieben 8ef976d385
xrpc-server & lex-cli rework (#3999)
* xrpc-server & lex-cli rework

* codegen

* tidy

* tidy

* tidy

* Update .changeset/nasty-icons-peel.md

Co-authored-by: devin ivy <devinivy@gmail.com>

* excludeErrorResult util

* Restore export of `SkeletonHandler` from `pds`

* Make `calcKey` RateLimiter option required

* Process request input after auth

* fix tests

* changeset

---------

Co-authored-by: devin ivy <devinivy@gmail.com>
2025-07-08 13:04:11 +02:00

155 lines
4.0 KiB
TypeScript

import * as http from 'node:http'
import { AddressInfo } from 'node:net'
import { LexiconDoc } from '@atproto/lexicon'
import { XrpcClient } from '@atproto/xrpc'
import * as xrpcServer from '../src'
import { closeServer, createServer } from './_util'
const LEXICONS: LexiconDoc[] = [
{
lexicon: 1,
id: 'io.example.paramTest',
defs: {
main: {
type: 'query',
parameters: {
type: 'params',
required: ['str', 'int', 'bool', 'arr'],
properties: {
str: { type: 'string', minLength: 2, maxLength: 10 },
int: { type: 'integer', minimum: 2, maximum: 10 },
bool: { type: 'boolean' },
arr: { type: 'array', items: { type: 'integer' }, maxLength: 2 },
def: { type: 'integer', default: 0 },
},
},
output: {
encoding: 'application/json',
},
},
},
},
]
describe('Parameters', () => {
let s: http.Server
const server = xrpcServer.createServer(LEXICONS)
server.method('io.example.paramTest', (ctx) => ({
encoding: 'json',
body: ctx.params,
}))
let client: XrpcClient
beforeAll(async () => {
s = await createServer(server)
const { port } = s.address() as AddressInfo
client = new XrpcClient(`http://localhost:${port}`, LEXICONS)
})
afterAll(async () => {
await closeServer(s)
})
it('validates query params', async () => {
const res1 = await client.call('io.example.paramTest', {
str: 'valid',
int: 5,
bool: true,
arr: [1, 2],
def: 5,
})
expect(res1.success).toBeTruthy()
expect(res1.data.str).toBe('valid')
expect(res1.data.int).toBe(5)
expect(res1.data.bool).toBe(true)
expect(res1.data.arr).toEqual([1, 2])
expect(res1.data.def).toEqual(5)
const res2 = await client.call('io.example.paramTest', {
str: 10,
int: '5',
bool: 'foo',
arr: '3',
})
expect(res2.success).toBeTruthy()
expect(res2.data.str).toBe('10')
expect(res2.data.int).toBe(5)
expect(res2.data.bool).toBe(true)
expect(res2.data.arr).toEqual([3])
expect(res2.data.def).toEqual(0)
// @TODO test sending blatantly bad types
await expect(
client.call('io.example.paramTest', {
str: 'n',
int: 5,
bool: true,
arr: [1],
}),
).rejects.toThrow('str must not be shorter than 2 characters')
await expect(
client.call('io.example.paramTest', {
str: 'loooooooooooooong',
int: 5,
bool: true,
arr: [1],
}),
).rejects.toThrow('str must not be longer than 10 characters')
await expect(
client.call('io.example.paramTest', {
int: 5,
bool: true,
arr: [1],
}),
).rejects.toThrow(`Params must have the property "str"`)
await expect(
client.call('io.example.paramTest', {
str: 'valid',
int: -1,
bool: true,
arr: [1],
}),
).rejects.toThrow('int can not be less than 2')
await expect(
client.call('io.example.paramTest', {
str: 'valid',
int: 11,
bool: true,
arr: [1],
}),
).rejects.toThrow('int can not be greater than 10')
await expect(
client.call('io.example.paramTest', {
str: 'valid',
bool: true,
arr: [1],
}),
).rejects.toThrow(`Params must have the property "int"`)
await expect(
client.call('io.example.paramTest', {
str: 'valid',
int: 5,
arr: [1],
}),
).rejects.toThrow(`Params must have the property "bool"`)
await expect(
client.call('io.example.paramTest', {
str: 'valid',
int: 5,
bool: true,
arr: [],
}),
).rejects.toThrow('Error: Params must have the property "arr"')
await expect(
client.call('io.example.paramTest', {
str: 'valid',
int: 5,
bool: true,
arr: [1, 2, 3],
}),
).rejects.toThrow('Error: arr must not have more than 2 elements')
})
})