86 lines
2.8 KiB
JavaScript
86 lines
2.8 KiB
JavaScript
/**
|
|
* Smoke-test the same API routes the Vite client uses.
|
|
* Usage: node scripts/test-api.mjs
|
|
* $env:API_BASE="http://127.0.0.1:5173"; node scripts/test-api.mjs # via Vite proxy
|
|
*/
|
|
const base = (process.env.API_BASE ?? 'http://127.0.0.1:8080').replace(/\/$/, '')
|
|
|
|
const tests = [
|
|
['GET', '/up', null],
|
|
['GET', '/api/v1/health', null],
|
|
['GET', '/api/v1/auth/register/captcha', null],
|
|
['GET', '/api/v1/policies/school', null],
|
|
['GET', '/api/docs/public', null],
|
|
[
|
|
'POST',
|
|
'/api/v1/auth/login',
|
|
JSON.stringify({ email: 'nosuch@example.org', password: 'wrong-password' }),
|
|
],
|
|
]
|
|
|
|
async function main() {
|
|
console.log(`API_BASE=${base}\n`)
|
|
|
|
for (const [method, path, body] of tests) {
|
|
const url = `${base}${path}`
|
|
try {
|
|
const init = {
|
|
method,
|
|
headers: {
|
|
Accept: 'application/json',
|
|
...(body ? { 'Content-Type': 'application/json' } : {}),
|
|
},
|
|
...(body ? { body } : {}),
|
|
}
|
|
const res = await fetch(url, init)
|
|
const text = await res.text()
|
|
let snippet = text.slice(0, 280).replace(/\s+/g, ' ')
|
|
let fatal = false
|
|
let dbError = false
|
|
try {
|
|
const j = JSON.parse(text)
|
|
const msg =
|
|
typeof j.message === 'string'
|
|
? j.message
|
|
: typeof j.exception === 'string'
|
|
? j.exception
|
|
: ''
|
|
if (j.exception?.includes?.('FatalError') || /FatalError/i.test(j.message ?? '')) {
|
|
fatal = true
|
|
snippet = `PHP FatalError: ${(j.message ?? '').slice(0, 100)}`
|
|
} else if (j.message && typeof j.message === 'string') {
|
|
snippet = j.message.slice(0, 120)
|
|
}
|
|
if (/SQLSTATE/i.test(msg) || /SQLSTATE/i.test(text)) {
|
|
dbError = true
|
|
snippet = `${snippet.slice(0, 80)}… (DB unavailable?)`
|
|
}
|
|
if (j.ok === true && path.includes('captcha')) {
|
|
snippet = `ok=true captcha=<${String(j.captcha ?? '').length} chars>`
|
|
}
|
|
if (j.status === true && path.includes('docs/public')) {
|
|
snippet = `title=${j.title ?? 'n/a'} openapi=${!!j.openapi_url}`
|
|
}
|
|
if (j.data?.policy && path.includes('policies/school')) {
|
|
snippet = `policy content len=${String(j.data.policy.content ?? '').length}`
|
|
}
|
|
} catch {
|
|
/* not JSON */
|
|
}
|
|
const ok =
|
|
!fatal &&
|
|
!dbError &&
|
|
(res.ok ||
|
|
(path.endsWith('/login') && (res.status === 401 || res.status === 400)) ||
|
|
res.status === 422)
|
|
console.log(
|
|
`${method} ${path} → ${res.status} ${ok ? '✓' : '✗'} ${snippet}`,
|
|
)
|
|
} catch (e) {
|
|
console.log(`${method} ${path} → ERROR ${e instanceof Error ? e.message : e}`)
|
|
}
|
|
}
|
|
}
|
|
|
|
main()
|