UNPKG

@datadome/module-nextjs

Version:

DataDome module for Next.js applications

191 lines (171 loc) 6.96 kB
import test from 'ava'; import { RequestCookies } from 'next/dist/compiled/@edge-runtime/cookies'; import type { NextRequest } from 'next/server'; import { convertHeadersToMap, getAuthorizationLength, getCookieData, getHeadersList, stringify } from './utils'; // Mock NextRequest for testing function createMockNextRequest(headersObj: Record<string, string>): NextRequest { return { headers: { keys: () => Object.keys(headersObj)[Symbol.iterator](), get: (key: string) => headersObj[key.toLowerCase()] ?? null, }, } as unknown as NextRequest; } // Mock RequestCookies for testing function createMockCookies(cookiesArr: Array<{ name: string; value: string }>): RequestCookies { const cookieHeader = cookiesArr .map((c) => `${encodeURIComponent(c.name)}=${encodeURIComponent(c.value)}`) .join('; '); const headers = new Headers({ cookie: cookieHeader }); return new RequestCookies(headers); } test('getHeadersList returns comma separated header names', (t) => { const req = createMockNextRequest({ authorization: 'Bearer token', 'content-type': 'application/json', 'x-custom-header': 'value', }); const result = getHeadersList(req); t.true(result.includes('authorization')); t.true(result.includes('content-type')); t.true(result.includes('x-custom-header')); t.is(result.split(',').length, 3); }); test('getHeadersList returns empty string when no headers', (t) => { const req = createMockNextRequest({}); t.is(getHeadersList(req), ''); }); test('getAuthorizationLength returns correct length when Authorization header is present', (t) => { const req = createMockNextRequest({ authorization: 'Bearer mytoken123', }); const result = getAuthorizationLength(req); t.is(result, 'Bearer mytoken123'.length); }); test('getAuthorizationLength returns undefined when Authorization header is missing', (t) => { const req = createMockNextRequest({}); const result = getAuthorizationLength(req); t.is(result, undefined); }); test('getAuthorizationLength returns 0 for empty Authorization header', (t) => { const req = createMockNextRequest({ authorization: '', }); const result = getAuthorizationLength(req); t.is(result, 0); }); test('stringify returns URL-encoded string for all defined values', (t) => { const obj = { foo: 'bar', baz: 'qux quux', num: '123', }; const result = stringify(obj as any); t.true(result.includes('foo=bar')); t.true(result.includes('baz=qux%20quux')); t.true(result.includes('num=123')); t.is(result.split('&').length, 3); }); test('stringify skips keys with falsy values', (t) => { const obj = { foo: 'bar', empty: '', nil: null, undef: undefined, zero: 0, valid: 'yes', }; const result = stringify(obj as any); t.true(result.includes('foo=bar')); t.true(result.includes('valid=yes')); t.false(result.includes('empty=')); t.false(result.includes('nil=')); t.false(result.includes('undef=')); t.false(result.includes('zero=')); t.is(result.split('&').length, 2); }); test('stringify returns empty string for empty object', (t) => { t.is(stringify({} as any), ''); }); test('stringify returns empty string for null or undefined', (t) => { t.is(stringify(null as any), ''); t.is(stringify(undefined as any), ''); }); test('getCookieData returns value of datadome cookie if present', (t) => { const cookies = createMockCookies([ { name: 'foo', value: 'bar' }, { name: 'datadome', value: 'client-id-123' }, { name: 'baz', value: 'qux' }, ]); t.is(getCookieData(cookies), 'client-id-123'); }); test('getCookieData returns empty string if datadome cookie is not present', (t) => { const cookies = createMockCookies([ { name: 'foo', value: 'bar' }, { name: 'baz', value: 'qux' }, ]); t.is(getCookieData(cookies), ''); }); test('getCookieData returns empty string if cookies iterable is empty', (t) => { const cookies = createMockCookies([]); t.is(getCookieData(cookies), ''); }); test('convertHeadersToMap returns empty map if listKey header is missing', (t) => { const reqHeaders = new Headers({ host: 'example.com' }); const dataDomeResHeaders = new Headers(); const result = convertHeadersToMap(reqHeaders, dataDomeResHeaders, 'x-list'); t.true(result instanceof Map); t.is(result.size, 0); }); test('convertHeadersToMap returns empty map if listKey header is present but empty', (t) => { const reqHeaders = new Headers({ host: 'example.com' }); const dataDomeResHeaders = new Headers({ 'x-list': '' }); const result = convertHeadersToMap(reqHeaders, dataDomeResHeaders, 'x-list'); t.is(result.size, 0); }); test('convertHeadersToMap maps headers from listKey', (t) => { const reqHeaders = new Headers({ host: 'example.com' }); const dataDomeResHeaders = new Headers({ 'x-list': 'foo bar', foo: 'foo-value', bar: 'bar-value', }); const result = convertHeadersToMap(reqHeaders, dataDomeResHeaders, 'x-list'); t.is(result.size, 2); t.is(result.get('foo'), 'foo-value'); t.is(result.get('bar'), 'bar-value'); }); test('convertHeadersToMap skips headers in listKey that are missing in dataDomeResHeaders', (t) => { const reqHeaders = new Headers({ host: 'example.com' }); const dataDomeResHeaders = new Headers({ 'x-list': 'foo missing', foo: 'foo-value', }); const result = convertHeadersToMap(reqHeaders, dataDomeResHeaders, 'x-list'); t.is(result.size, 1); t.is(result.get('foo'), 'foo-value'); t.false(result.has('missing')); }); test('convertHeadersToMap replaces .vercel.app domain in set-cookie header', (t) => { const reqHeaders = new Headers({ host: 'mydomain.com' }); const setCookieValue = 'session=abc; Domain=.vercel.app; Path=/; HttpOnly'; const dataDomeResHeaders = new Headers({ 'x-list': 'set-cookie', 'set-cookie': setCookieValue, }); const result = convertHeadersToMap(reqHeaders, dataDomeResHeaders, 'x-list'); t.is(result.size, 1); t.true(result.has('set-cookie')); t.false(result.get('set-cookie')!.includes('.vercel.app')); t.true(result.get('set-cookie')!.includes('Domain=mydomain.com')); }); test('convertHeadersToMap does not replace domain if set-cookie does not contain .vercel.app', (t) => { const reqHeaders = new Headers({ host: 'mydomain.com' }); const setCookieValue = 'session=abc; Domain=mydomain.com; Path=/; HttpOnly'; const dataDomeResHeaders = new Headers({ 'x-list': 'set-cookie', 'set-cookie': setCookieValue, }); const result = convertHeadersToMap(reqHeaders, dataDomeResHeaders, 'x-list'); t.is(result.get('set-cookie'), setCookieValue); });