|  | 
|  | 1 | +import { http, HttpResponse } from 'msw' | 
|  | 2 | +import { expect, test, vi } from 'vitest' | 
|  | 3 | +import { server } from '#tests/mocks' | 
|  | 4 | +import { checkIsCommonPassword, getPasswordHashParts } from './auth.server.ts' | 
|  | 5 | + | 
|  | 6 | +test('checkIsCommonPassword returns true when password is found in breach database', async () => { | 
|  | 7 | +	const password = 'testpassword' | 
|  | 8 | +	const [prefix, suffix] = getPasswordHashParts(password) | 
|  | 9 | + | 
|  | 10 | +	server.use( | 
|  | 11 | +		http.get(`https://api.pwnedpasswords.com/range/${prefix}`, () => { | 
|  | 12 | +			// Include the actual suffix in the response with another realistic suffix | 
|  | 13 | +			return new HttpResponse( | 
|  | 14 | +				`1234567890123456789012345678901234A:1\n${suffix}:1234`, | 
|  | 15 | +				{ status: 200 }, | 
|  | 16 | +			) | 
|  | 17 | +		}), | 
|  | 18 | +	) | 
|  | 19 | + | 
|  | 20 | +	const result = await checkIsCommonPassword(password) | 
|  | 21 | +	expect(result).toBe(true) | 
|  | 22 | +}) | 
|  | 23 | + | 
|  | 24 | +test('checkIsCommonPassword returns false when password is not found in breach database', async () => { | 
|  | 25 | +	const password = 'sup3r-dup3r-s3cret' | 
|  | 26 | +	const [prefix] = getPasswordHashParts(password) | 
|  | 27 | + | 
|  | 28 | +	server.use( | 
|  | 29 | +		http.get(`https://api.pwnedpasswords.com/range/${prefix}`, () => { | 
|  | 30 | +			// Response with realistic suffixes that won't match | 
|  | 31 | +			return new HttpResponse( | 
|  | 32 | +				'1234567890123456789012345678901234A:1\n' + | 
|  | 33 | +					'1234567890123456789012345678901234B:2', | 
|  | 34 | +				{ status: 200 }, | 
|  | 35 | +			) | 
|  | 36 | +		}), | 
|  | 37 | +	) | 
|  | 38 | + | 
|  | 39 | +	const result = await checkIsCommonPassword(password) | 
|  | 40 | +	expect(result).toBe(false) | 
|  | 41 | +}) | 
|  | 42 | + | 
|  | 43 | +// Error cases | 
|  | 44 | +test('checkIsCommonPassword returns false when API returns 500', async () => { | 
|  | 45 | +	const password = 'testpassword' | 
|  | 46 | +	const [prefix] = getPasswordHashParts(password) | 
|  | 47 | + | 
|  | 48 | +	server.use( | 
|  | 49 | +		http.get(`https://api.pwnedpasswords.com/range/${prefix}`, () => { | 
|  | 50 | +			return new HttpResponse(null, { status: 500 }) | 
|  | 51 | +		}), | 
|  | 52 | +	) | 
|  | 53 | + | 
|  | 54 | +	const result = await checkIsCommonPassword(password) | 
|  | 55 | +	expect(result).toBe(false) | 
|  | 56 | +}) | 
|  | 57 | + | 
|  | 58 | +test('checkIsCommonPassword times out after 1 second', async () => { | 
|  | 59 | +	const consoleWarnSpy = vi.spyOn(console, 'warn') | 
|  | 60 | +	server.use( | 
|  | 61 | +		http.get('https://api.pwnedpasswords.com/range/:prefix', async () => { | 
|  | 62 | +			const twoSecondDelay = 2000 | 
|  | 63 | +			await new Promise((resolve) => setTimeout(resolve, twoSecondDelay)) | 
|  | 64 | +			return new HttpResponse( | 
|  | 65 | +				'1234567890123456789012345678901234A:1\n' + | 
|  | 66 | +					'1234567890123456789012345678901234B:2', | 
|  | 67 | +				{ status: 200 }, | 
|  | 68 | +			) | 
|  | 69 | +		}), | 
|  | 70 | +	) | 
|  | 71 | + | 
|  | 72 | +	const result = await checkIsCommonPassword('testpassword') | 
|  | 73 | +	expect(result).toBe(false) | 
|  | 74 | +	expect(consoleWarnSpy).toHaveBeenCalledWith('Password check timed out') | 
|  | 75 | +	consoleWarnSpy.mockRestore() | 
|  | 76 | +}) | 
|  | 77 | + | 
|  | 78 | +test('checkIsCommonPassword returns false when response has invalid format', async () => { | 
|  | 79 | +	const consoleWarnSpy = vi.spyOn(console, 'warn') | 
|  | 80 | +	const password = 'testpassword' | 
|  | 81 | +	const [prefix] = getPasswordHashParts(password) | 
|  | 82 | + | 
|  | 83 | +	server.use( | 
|  | 84 | +		http.get(`https://api.pwnedpasswords.com/range/${prefix}`, () => { | 
|  | 85 | +			// Create a response that will cause a TypeError when text() is called | 
|  | 86 | +			const response = new Response() | 
|  | 87 | +			Object.defineProperty(response, 'text', { | 
|  | 88 | +				value: () => Promise.resolve(null), | 
|  | 89 | +			}) | 
|  | 90 | +			return response | 
|  | 91 | +		}), | 
|  | 92 | +	) | 
|  | 93 | + | 
|  | 94 | +	const result = await checkIsCommonPassword(password) | 
|  | 95 | +	expect(result).toBe(false) | 
|  | 96 | +	expect(consoleWarnSpy).toHaveBeenCalledWith( | 
|  | 97 | +		'Unknown error during password check', | 
|  | 98 | +		expect.any(TypeError), | 
|  | 99 | +	) | 
|  | 100 | +	consoleWarnSpy.mockRestore() | 
|  | 101 | +}) | 
0 commit comments