import { setupServer, superRequest } from '../jest.utils'; import { HOME_LOCATION, COOKIE_DOMAIN } from './utils/env'; jest.mock('./utils/env', () => { // eslint-disable-next-line @typescript-eslint/no-unsafe-return return { ...jest.requireActual('./utils/env'), // eslint-disable-next-line @typescript-eslint/naming-convention COOKIE_DOMAIN: '.freecodecamp.org' }; }); describe('server', () => { setupServer(); describe('CSRF protection', () => { it('should receive a new CSRF token with the expected properties', async () => { const response = await superRequest('/', { method: 'GET' }); const newCookies = response.get('Set-Cookie'); const csrfTokenCookie = newCookies.find(cookie => cookie.includes('csrf_token') ); expect(csrfTokenCookie).toEqual( expect.stringContaining('SameSite=Strict') ); expect(csrfTokenCookie).toEqual( expect.stringContaining(`Domain=${COOKIE_DOMAIN}`) ); expect(csrfTokenCookie).toEqual(expect.stringContaining('Path=/')); // Since we're not mocking FREECODECAMP_NODE_ENV to production, there's no // point checking if it is secure (it won't be in testing). }); }); describe('GET /', () => { test('have a 200 response', async () => { const res = await superRequest('/', { method: 'GET' }); expect(res.statusCode).toBe(200); }); test('return { "hello": "world"}', async () => { const res = await superRequest('/', { method: 'GET' }); expect(res.body).toEqual({ hello: 'world' }); }); test('should have OWASP recommended headers', async () => { const res = await superRequest('/', { method: 'GET' }); expect(res.headers).toMatchObject({ 'cache-control': 'no-store', 'content-security-policy': "frame-ancestors 'none'", 'content-type': 'application/json; charset=utf-8', 'x-content-type-options': 'nosniff', 'x-frame-options': 'DENY' // In production we also set strict-transport-security, but in order to // test this we would need to mock FREECODECAMP_NODE_ENV to production. // This is possible, but has side effects (like using the normal // database instead of the test ones). On balance it's not worth it. }); }); test.each([ 'https://www.freecodecamp.org', 'https://www.freecodecamp.dev', 'https://beta.freecodecamp.org', 'https://beta.freecodecamp.dev', 'https://chinese.freecodecamp.org', 'https://chinese.freecodecamp.dev' ])( 'should have Access-Control-Allow-Origin header for %s', async origin => { const res = await superRequest('/', { method: 'GET' }).set( 'origin', origin ); expect(res.headers).toMatchObject({ 'access-control-allow-origin': origin }); } ); test('should have HOME_LOCATION Access-Control-Allow-Origin header for other origins', async () => { const res = await superRequest('/', { method: 'GET' }).set( 'origin', 'https://www.google.com' ); expect(res.headers).toMatchObject({ 'access-control-allow-origin': HOME_LOCATION }); }); test('should have Access-Control-Allow-(Headers+Credentials) headers', async () => { const res = await superRequest('/', { method: 'GET' }); expect(res.headers).toMatchObject({ 'access-control-allow-headers': 'Origin, X-Requested-With, Content-Type, Accept', 'access-control-allow-credentials': 'true' }); }); }); describe('GET /documentation', () => { test('should have OWASP recommended headers, except content-type', async () => { const res = await superRequest('/documentation/static/index.html', { method: 'GET' }); expect(res.headers).toMatchObject({ 'cache-control': 'no-store', 'content-security-policy': "frame-ancestors 'none'", 'content-type': 'text/html; charset=utf-8', 'x-content-type-options': 'nosniff', 'x-frame-options': 'DENY' }); }); }); });