Files
overleaf-cep/libraries/validation-tools/testUtils.js
T
Jakob Ackermann 94cad14caf [chat] migrate to express with strict zod schema (#35742)
GitOrigin-RevId: edffacde0c069768def849f45364d519d9f76f1e
2026-09-17 11:36:35 +00:00

89 lines
3.3 KiB
JavaScript

const assert = require('node:assert/strict')
function asZodError(...def) {
return {
name: 'ZodError',
_zod: { def },
}
}
/**
* Parses (if needed) a validation-error response body and asserts that it
* matches the given status and names the given field.
*
* handleValidationError (see ./handleValidationError.js) responds with
* `{ error: fromError(err.zodError).toString(), statusCode }`, and
* fromError's message includes the offending field's dotted schema path
* (e.g. `at "params.projectId"`, or the failing key name for an
* unrecognized key), so asserting the field name appears in `body.error`
* pins the test to the intended failure rather than merely the status code.
*
* @param {string|{statusCode: number, error: string}} rawOrParsedBody - the
* response body, either as raw JSON text or already parsed into an object
* (some HTTP client wrappers pre-parse the body for the caller)
* @param {number} status
* @param {string} fieldSubstring
*/
function assertValidationErrorBody(rawOrParsedBody, status, fieldSubstring) {
assert.ok(rawOrParsedBody != null, 'expected a response body')
const body =
typeof rawOrParsedBody === 'string'
? JSON.parse(rawOrParsedBody)
: rawOrParsedBody
assert.equal(body.statusCode, status)
assert.equal(typeof body.error, 'string')
assert.ok(
body.error.includes(fieldSubstring),
`expected error message ${JSON.stringify(body.error)} to include ${JSON.stringify(fieldSubstring)}`
)
}
/**
* Asserts that a request was actually rejected by the zod validation layer
* because of the specific field named in `fieldSubstring` -- not just any
* error/response that happens to produce the same status code. See
* assertValidationErrorBody() above.
*
* @param {any} errorOrResult - either the object thrown/rejected by a failed
* request, e.g. a RequestFailedError from @overleaf/fetch-utils (exposes
* `.response.status` and `.body` as raw text), or a resolved
* `{ response, body }` pair from an HTTP client wrapper that never rejects
* on non-2xx responses and has already parsed `body` from JSON. Either way
* expected to expose `.response.status` and `.body`
* @param {number} status - the expected HTTP status code
* @param {string} fieldSubstring - a substring expected in the error
* message identifying the rejected field (e.g. a param/body/query key)
*/
function expectValidationError(errorOrResult, status, fieldSubstring) {
assert.equal(
errorOrResult && errorOrResult.response && errorOrResult.response.status,
status,
`expected response.status === ${status}`
)
assertValidationErrorBody(errorOrResult.body, status, fieldSubstring)
}
/**
* Same as expectValidationError, but for a response object that exposes
* `statusCode` and `body` directly rather than nested under `.response`
* (e.g. a raw node:http response).
*
* @param {any} res - expected to expose `.statusCode` and `.body` directly
* @param {number} status
* @param {string} fieldSubstring
*/
function expectValidationErrorRaw(res, status, fieldSubstring) {
assert.equal(
res && res.statusCode,
status,
`expected a response with statusCode === ${status}`
)
assertValidationErrorBody(res.body, status, fieldSubstring)
}
module.exports = {
asZodError,
expectValidationError,
expectValidationErrorRaw,
}