// Import Node's built-in test tools. const test = require("node:test"); const assert = require("node:assert/strict"); // Import the HTTP headers service functions. const { checkHeaders, headersToObject, analyzeSecurityHeaders, isRedirectStatus, SECURITY_HEADERS, } = require("../src/services/headersService"); // --------------------------------------------------------- // isRedirectStatus() tests // --------------------------------------------------------- test("recognizes standard redirect status codes", () => { [301, 302, 303, 307, 308].forEach((statusCode) => { assert.equal(isRedirectStatus(statusCode), true); }); }); test("rejects non-redirect status codes", () => { [200, 201, 204, 400, 404, 500].forEach((statusCode) => { assert.equal(isRedirectStatus(statusCode), false); }); }); // --------------------------------------------------------- // headersToObject() tests // --------------------------------------------------------- test("converts Fetch Headers into a plain object", () => { const headers = new Headers({ "content-type": "text/html", "x-content-type-options": "nosniff", }); const result = headersToObject(headers); assert.deepEqual(result, { "content-type": "text/html", "x-content-type-options": "nosniff", }); }); test("normalizes header names to lowercase", () => { const headers = new Headers({ "X-Frame-Options": "DENY", }); const result = headersToObject(headers); assert.equal(result["x-frame-options"], "DENY"); }); // --------------------------------------------------------- // analyzeSecurityHeaders() tests // --------------------------------------------------------- test("marks present security headers correctly", () => { const headers = { "strict-transport-security": "max-age=31536000", "x-content-type-options": "nosniff", }; const result = analyzeSecurityHeaders(headers); const hsts = result.find( (header) => header.name === "Strict-Transport-Security" ); const contentType = result.find( (header) => header.name === "X-Content-Type-Options" ); assert.equal(hsts.present, true); assert.equal( hsts.value, "max-age=31536000" ); assert.equal(contentType.present, true); assert.equal(contentType.value, "nosniff"); }); test("marks missing security headers correctly", () => { const result = analyzeSecurityHeaders({}); result.forEach((header) => { assert.equal(header.present, false); assert.equal(header.value, null); }); }); test("returns one result for every configured security header", () => { const result = analyzeSecurityHeaders({}); assert.equal( result.length, SECURITY_HEADERS.length ); }); test("returns the expected security header labels", () => { const result = analyzeSecurityHeaders({}); const names = result.map((header) => header.name); assert.deepEqual(names, [ "Strict-Transport-Security", "Content-Security-Policy", "X-Content-Type-Options", "X-Frame-Options", "Referrer-Policy", "Permissions-Policy", "Cross-Origin-Opener-Policy", "Cross-Origin-Resource-Policy", ]); }); // --------------------------------------------------------- // checkHeaders() integration tests // --------------------------------------------------------- test("checks headers for a public website", async () => { const result = await checkHeaders( "https://example.com" ); assert.equal( result.requestedUrl, "https://example.com" ); assert.equal(typeof result.finalUrl, "string"); assert.equal(typeof result.statusCode, "number"); assert.equal(typeof result.statusText, "string"); assert.equal(typeof result.redirectCount, "number"); assert.equal(typeof result.headers, "object"); assert.equal( Array.isArray(result.securityHeaders), true ); assert.equal( result.securityHeaders.length, SECURITY_HEADERS.length ); assert.equal( typeof result.presentSecurityHeaderCount, "number" ); assert.equal( result.totalSecurityHeaderCount, SECURITY_HEADERS.length ); assert.equal(typeof result.checkedAt, "string"); }); test("follows redirects safely", async () => { const result = await checkHeaders( "http://example.com" ); assert.equal(typeof result.finalUrl, "string"); assert.equal(result.redirectCount >= 0, true); }); test("blocks loopback addresses", async () => { await assert.rejects( checkHeaders("http://127.0.0.1"), /Local and private network addresses are not allowed/ ); }); test("blocks private network addresses", async () => { await assert.rejects( checkHeaders("http://192.168.1.1"), /Local and private network addresses are not allowed/ ); }); test("rejects malformed URLs", async () => { await assert.rejects( checkHeaders("not a valid URL"), /Enter a valid URL/ ); });