fix: bound social preview smoke response

This commit is contained in:
2026-09-05 01:06:01 +03:00
parent c958d4a05f
commit f58b079c18
2 changed files with 102 additions and 4 deletions

View File

@@ -11,6 +11,8 @@ const alternate = 'http://www.portfolio.example/';
const escapedTitle = 'Luca Pîslaru — System Administrator & Full-Stack Developer';
const description = 'Portfolio of Luca Pîslaru, a Bucharest-based System Administrator and Full-Stack Developer working across Linux infrastructure and end-to-end software delivery.';
const socialImage = `${canonical}assets/project-social-preview.webp`;
const projectStillMaxBytes = 400 * 1024;
const socialImageFixture = Buffer.alloc(15_068);
const html = `<!doctype html><html><head>
<title>${escapedTitle}</title>
<meta name="description" content="${description}" />
@@ -36,6 +38,8 @@ interface FixtureOptions {
html?: string;
imageStatus?: number;
imageType?: string;
imageContentLength?: string | null;
imageChunks?: readonly Buffer[];
}
const mutateJsonLd = (source: string, mutate: (graph: Record<string, any>) => void): string =>
@@ -78,12 +82,19 @@ async function fixtureFetch(options: FixtureOptions = {}) {
}
if (url.pathname === '/assets/project-social-preview.webp') {
const status = options.imageStatus ?? 200;
response.writeHead(status, {
const chunks = status === 200 ? options.imageChunks ?? [socialImageFixture] : [];
const contentLength = options.imageContentLength === undefined
? String(chunks.reduce((total, chunk) => total + chunk.byteLength, 0))
: options.imageContentLength;
const headers: Record<string, string> = {
...base,
'content-type': options.imageType ?? 'image/webp',
'cache-control': 'public, max-age=31536000, immutable',
});
response.end(status === 200 ? Buffer.from('social-preview-fixture') : undefined);
};
if (contentLength !== null) headers['content-length'] = contentLength;
response.writeHead(status, headers);
for (const chunk of chunks) response.write(chunk);
response.end();
return;
}
if (url.pathname === '/assets/demo.12345678.webm') {
@@ -224,4 +235,36 @@ describe('production smoke and SEO contract', () => {
fetchImpl,
})).rejects.toThrow(error);
});
it.each([
{
name: 'a zero-byte body',
options: { imageChunks: [], imageContentLength: '0' },
error: /social image.*empty|zero-byte/iu,
},
{
name: 'a declared body above the project-still limit',
options: {
imageChunks: [Buffer.alloc(projectStillMaxBytes + 1)],
imageContentLength: String(projectStillMaxBytes + 1),
},
error: /social image.*(?:limit|large|400)/iu,
},
{
name: 'an undeclared chunked body above the project-still limit',
options: {
imageChunks: [Buffer.alloc(projectStillMaxBytes), Buffer.alloc(1)],
imageContentLength: null,
},
error: /social image.*(?:limit|large|400)/iu,
},
])('rejects $name without buffering the social image', async ({ options, error }) => {
const fetchImpl = await fixtureFetch(options);
await expect(verifyProductionSmoke({
canonicalUrl: canonical,
expectedManifestDigest: digest,
fetchImpl,
})).rejects.toThrow(error);
});
});