import { describe, expect, it, vi } from 'vitest'
import { verifyDeployment } from './verify-deployment-lib.mjs'
const baseUrl = 'https://nabu.example'
function response(body, init = {}) {
return new Response(body, { status: 200, ...init })
}
function deploymentFetch(overrides = {}) {
const responses = {
[`${baseUrl}/login?redirect=&error=`]: response(
'',
{ headers: { 'content-type': 'text/html' } },
),
[`${baseUrl}/assets/styles-good.css`]: response('.app-shell{}.vault-shell{}', {
headers: { 'content-type': 'text/css' },
}),
[`${baseUrl}/assets/app-good.js`]: response('export {}', {
headers: { 'content-type': 'text/javascript' },
}),
[`${baseUrl}/api/health`]: response(JSON.stringify({ status: 'ok', storage: 'ready' }), {
headers: { 'content-type': 'application/json' },
}),
...overrides,
}
return vi.fn(async (input) => responses[String(input)] ?? response('missing', { status: 404 }))
}
describe('verifyDeployment', () => {
it('verifies the deployed HTML, CSS, JavaScript, and health response', async () => {
const result = await verifyDeployment(baseUrl, deploymentFetch())
expect(result.assets).toEqual([
'/assets/styles-good.css',
'/assets/app-good.js',
])
})
it.each([
['missing stylesheet', response('missing', { status: 404 })],
['HTML fallback', response('
fallback', { headers: { 'content-type': 'text/html' } })],
])('fails when health is ready but the deployed CSS is a %s', async (_label, brokenCss) => {
const fetchImpl = deploymentFetch({ [`${baseUrl}/assets/styles-good.css`]: brokenCss })
await expect(verifyDeployment(baseUrl, fetchImpl)).rejects.toThrow(/stylesheet/i)
})
it('fails closed when a local asset redirects', async () => {
const redirected = response('', { status: 302, headers: { location: 'https://cdn.example/app.js' } })
const fetchImpl = deploymentFetch({ [`${baseUrl}/assets/app-good.js`]: redirected })
await expect(verifyDeployment(baseUrl, fetchImpl)).rejects.toThrow(/redirect/i)
})
it('fails when the page does not reference a local JavaScript asset', async () => {
const pageWithoutJavaScript = response('', {
headers: { 'content-type': 'text/html' },
})
const fetchImpl = deploymentFetch({ [`${baseUrl}/login?redirect=&error=`]: pageWithoutJavaScript })
await expect(verifyDeployment(baseUrl, fetchImpl)).rejects.toThrow(/JavaScript/i)
})
it('does not treat a module preload as an executable JavaScript asset', async () => {
const preloadOnly = response(
'',
{ headers: { 'content-type': 'text/html' } },
)
const fetchImpl = deploymentFetch({ [`${baseUrl}/login?redirect=&error=`]: preloadOnly })
await expect(verifyDeployment(baseUrl, fetchImpl)).rejects.toThrow(/JavaScript/i)
})
it('accepts a non-empty inline module bootstrap and validates local module preloads', async () => {
const inlineModule = response(
'',
{ headers: { 'content-type': 'text/html' } },
)
const fetchImpl = deploymentFetch({
[`${baseUrl}/login?redirect=&error=`]: inlineModule,
[`${baseUrl}/assets/chunk-good.js`]: response('export {}', {
headers: { 'content-type': 'text/javascript' },
}),
})
await expect(verifyDeployment(baseUrl, fetchImpl)).resolves.toMatchObject({
assets: ['/assets/styles-good.css', '/assets/chunk-good.js'],
})
})
it('rejects an inline bootstrap backed only by external scripts and module preloads', async () => {
const externalAssets = response(
'',
{ headers: { 'content-type': 'text/html' } },
)
const fetchImpl = deploymentFetch({
[`${baseUrl}/login?redirect=&error=`]: externalAssets,
})
await expect(verifyDeployment(baseUrl, fetchImpl)).rejects.toThrow(/local JavaScript/i)
})
it('validates the content type of local module preloads', async () => {
const invalidPreload = response(
'',
{ headers: { 'content-type': 'text/html' } },
)
const fetchImpl = deploymentFetch({
[`${baseUrl}/login?redirect=&error=`]: invalidPreload,
[`${baseUrl}/assets/chunk-good.js`]: response('.not-javascript{}', {
headers: { 'content-type': 'text/css' },
}),
})
await expect(verifyDeployment(baseUrl, fetchImpl)).rejects.toThrow(/JavaScript/i)
})
it('rejects a whitespace-only inline module as the only bootstrap', async () => {
const whitespaceModule = response(
'',
{ headers: { 'content-type': 'text/html' } },
)
const fetchImpl = deploymentFetch({
[`${baseUrl}/login?redirect=&error=`]: whitespaceModule,
})
await expect(verifyDeployment(baseUrl, fetchImpl)).rejects.toThrow(/JavaScript/i)
})
it('rejects a classic inline script as the only bootstrap', async () => {
const classicInline = response(
'',
{ headers: { 'content-type': 'text/html' } },
)
const fetchImpl = deploymentFetch({
[`${baseUrl}/login?redirect=&error=`]: classicInline,
})
await expect(verifyDeployment(baseUrl, fetchImpl)).rejects.toThrow(/JavaScript/i)
})
it('checks required selectors across the combined local stylesheets', async () => {
const splitStyles = response(
'',
{ headers: { 'content-type': 'text/html' } },
)
const fetchImpl = deploymentFetch({
[`${baseUrl}/login?redirect=&error=`]: splitStyles,
[`${baseUrl}/assets/vendor.css`]: response(':root{color-scheme:light}', { headers: { 'content-type': 'text/css' } }),
})
await expect(verifyDeployment(baseUrl, fetchImpl)).resolves.toMatchObject({
assets: ['/assets/vendor.css', '/assets/styles-good.css', '/assets/app-good.js'],
})
})
it('aborts a stalled deployment request', async () => {
const stalledFetch = vi.fn((_input, init) => new Promise((_resolve, reject) => {
init.signal.addEventListener('abort', () => reject(init.signal.reason), { once: true })
}))
await expect(verifyDeployment(baseUrl, stalledFetch, { timeoutMs: 5 })).rejects.toThrow(/timed out/i)
})
})