resume/tests/headers.test.js

85 lines
3.6 KiB
JavaScript

const { test, expect } = require('@playwright/test');
const PRODUCTION_URL = 'https://colinknapp.com';
const LOCAL_URL = 'http://localhost:8080';
async function getPageUrl(page) {
try {
// Try production first
await page.goto(PRODUCTION_URL, { timeout: 60000 });
return PRODUCTION_URL;
} catch (error) {
console.log('Production site not available, falling back to local');
await page.goto(LOCAL_URL, { timeout: 60000 });
return LOCAL_URL;
}
}
test.describe('Security Headers Tests', () => {
test('should have all required security headers', async ({ page, request }) => {
const url = await getPageUrl(page);
console.log(`Running security header tests against ${url}`);
// Get headers directly from the main page
const response = await request.get(url);
const headers = response.headers();
// Check Content Security Policy
const csp = headers['content-security-policy'];
expect(csp).toBeTruthy();
expect(csp).toContain("default-src 'none'");
expect(csp).toContain("script-src 'self'");
expect(csp).toContain("style-src 'self'");
expect(csp).toContain("img-src 'self' data:");
expect(csp).toContain("font-src 'self' data:");
expect(csp).toContain("connect-src 'self'");
expect(csp).toContain("object-src 'none'");
expect(csp).toContain("frame-ancestors 'none'");
expect(csp).toContain("base-uri 'none'");
expect(csp).toContain("form-action 'none'");
// Check other security headers
expect(headers['x-content-type-options']).toBe('nosniff');
expect(headers['x-frame-options']).toBe('DENY');
expect(headers['referrer-policy']).toBe('strict-origin-when-cross-origin');
});
test('should have correct Subresource Integrity (SRI) attributes', async ({ page }) => {
const url = await getPageUrl(page);
console.log(`Running SRI tests against ${url}`);
await page.goto(url, { timeout: 60000 });
await page.waitForLoadState('networkidle');
// Check stylesheet
const stylesheet = await page.locator('link[rel="stylesheet"]').first();
const stylesheetIntegrity = await stylesheet.getAttribute('integrity');
const stylesheetCrossorigin = await stylesheet.getAttribute('crossorigin');
expect(stylesheetIntegrity).toBeTruthy();
expect(stylesheetCrossorigin).toBe('anonymous');
// Check script
const script = await page.locator('script[src]').first();
const scriptIntegrity = await script.getAttribute('integrity');
const scriptCrossorigin = await script.getAttribute('crossorigin');
expect(scriptIntegrity).toBeTruthy();
expect(scriptCrossorigin).toBe('anonymous');
});
test('should have correct caching headers for static assets', async ({ request }) => {
const url = await getPageUrl({ goto: async () => {} });
console.log(`Running caching header tests against ${url}`);
const baseUrl = url.replace(/\/$/, '');
// Check styles.css
const stylesResponse = await request.get(`${baseUrl}/styles.css`);
const stylesCacheControl = stylesResponse.headers()['cache-control'];
expect(stylesCacheControl).toContain('public');
expect(stylesCacheControl).toContain('max-age=');
// Check theme.js
const scriptResponse = await request.get(`${baseUrl}/theme.js`);
const scriptCacheControl = scriptResponse.headers()['cache-control'];
expect(scriptCacheControl).toContain('public');
expect(scriptCacheControl).toContain('max-age=');
});
});