import nextConfig from "../next.config"; /** * Testes de caminhos-base de headers() em next.config.ts: o que muda entre produção e desenvolvimento. * Produção ganha o HSTS e perde o 'unsafe-eval' da política de conteúdo (só o hot reload do dev precisa dele). */ async function siteHeaders() { const rules = (await nextConfig.headers?.()) ?? []; const site = rules.find(({ source }) => source === "/(.*)"); if (!site) throw new Error("Missing site-wide header rule"); return site.headers; } const header = (headers: { key: string; value: string }[], key: string) => headers.find((item) => item.key === key)?.value; afterEach(() => { jest.restoreAllMocks(); }); describe("next.config headers()", () => { it("path: production -> HSTS is sent and the policy has no 'unsafe-eval'", async () => { jest.replaceProperty(process.env, "NODE_ENV", "production"); const headers = await siteHeaders(); expect(header(headers, "Strict-Transport-Security")).toBe( "max-age=31536000; includeSubDomains; preload", ); expect( header(headers, "Content-Security-Policy-Report-Only"), ).not.toContain("'unsafe-eval'"); }); it("path: development or test -> no HSTS, and the policy allows 'unsafe-eval' for the dev server", async () => { jest.replaceProperty(process.env, "NODE_ENV", "development"); const headers = await siteHeaders(); expect(header(headers, "Strict-Transport-Security")).toBeUndefined(); expect(header(headers, "Content-Security-Policy-Report-Only")).toContain( "'unsafe-eval'", ); }); it("path: any environment -> the policy (still Report-Only) allows the domains the Google Ads tag uses after consent, in connect-src and img-src", async () => { const headers = await siteHeaders(); const policy = header(headers, "Content-Security-Policy-Report-Only") ?? ""; const directive = (name: string) => policy.split("; ").find((part) => part.startsWith(`${name} `)) ?? ""; for (const name of ["connect-src", "img-src"]) { for (const host of [ "https://pagead2.googlesyndication.com", "https://googleads.g.doubleclick.net", "https://www.googleadservices.com", ]) { expect(directive(name)).toContain(host); } // o que já estava liberado segue liberado expect(directive(name)).toContain("https://*.google-analytics.com"); } // nada de curinga aberto e nada enforçado: a política continua só em Report-Only expect(policy).not.toMatch(/\* |https:(?!\/)/); expect(header(headers, "Content-Security-Policy")).toBeUndefined(); }); it("path: any environment -> the video rule keeps the long cache", async () => { const rules = (await nextConfig.headers?.()) ?? []; const videos = rules.find(({ source }) => source === "/videos/:path*"); expect(videos?.headers).toEqual([ { key: "Cache-Control", value: "public, max-age=86400, stale-while-revalidate=604800", }, ]); }); });