diff --git a/tests/crypto-adapter.test.ts b/tests/crypto-adapter.test.ts index de85b7b..83d9e3f 100644 --- a/tests/crypto-adapter.test.ts +++ b/tests/crypto-adapter.test.ts @@ -2,6 +2,48 @@ import { getCryptoRandomValues } from '../src/utils/crypto-adapter'; describe('crypto-adapter', () => { describe('getCryptoRandomValues', () => { + it('should use window.crypto in browser environment', () => { + // Save reference to global + const globalRef = global as any; + const originalWindow = globalRef.window; + + try { + // Mock browser environment with window.crypto + const mockGetRandomValues = jest.fn((array: any) => { + // Fill with mock random values + for (let i = 0; i < array.length; i++) { + array[i] = Math.floor(Math.random() * 256); + } + return array; + }); + + globalRef.window = { + crypto: { + getRandomValues: mockGetRandomValues + } + }; + + // Clear module cache to force re-evaluation + jest.resetModules(); + + // Re-import the function + const { getCryptoRandomValues: reloadedGetCryptoRandomValues } = require('../src/utils/crypto-adapter'); + + // Should use window.crypto + const array = new Uint8Array(32); + const result = reloadedGetCryptoRandomValues(array); + + expect(result).toBe(array); + expect(mockGetRandomValues).toHaveBeenCalledWith(array); + } finally { + // Restore original window + globalRef.window = originalWindow; + + // Clear module cache again to restore normal state + jest.resetModules(); + } + }); + it('should fill Uint8Array with random values', () => { const array = new Uint8Array(32); const result = getCryptoRandomValues(array); @@ -52,5 +94,73 @@ describe('crypto-adapter', () => { expect(medium.every(val => val >= 0 && val <= 255)).toBe(true); expect(large.every(val => val >= 0 && val <= 255)).toBe(true); }); + + it('should use Node.js crypto.webcrypto when window.crypto is not available', () => { + // Save references to global object and original values + const globalRef = global as any; + const originalWindow = globalRef.window; + const originalCrypto = originalWindow?.crypto; + + try { + // Mock window without crypto to force Node.js crypto path + globalRef.window = { ...originalWindow }; + delete globalRef.window.crypto; + + // Clear module cache to force re-evaluation + jest.resetModules(); + + // Re-import the function + const { getCryptoRandomValues: reloadedGetCryptoRandomValues } = require('../src/utils/crypto-adapter'); + + // Should work using Node.js crypto.webcrypto + const array = new Uint8Array(32); + const result = reloadedGetCryptoRandomValues(array); + + expect(result).toBe(array); + expect(result.length).toBe(32); + // Verify not all zeros + const hasNonZero = Array.from(result).some(val => val !== 0); + expect(hasNonZero).toBe(true); + } finally { + // Restore original values + globalRef.window = originalWindow; + if (originalWindow && originalCrypto) { + originalWindow.crypto = originalCrypto; + } + + // Clear module cache again to restore normal state + jest.resetModules(); + } + }); + + it('should throw error when no crypto API is available', () => { + // Save references to global object and original values + const globalRef = global as any; + const originalWindow = globalRef.window; + const originalGlobal = globalRef.global; + + try { + // Remove window.crypto and global access + delete globalRef.window; + delete globalRef.global; + + // Clear module cache to force re-evaluation + jest.resetModules(); + + // Re-import the function + const { getCryptoRandomValues: reloadedGetCryptoRandomValues } = require('../src/utils/crypto-adapter'); + + // Verify error is thrown + const array = new Uint8Array(32); + expect(() => reloadedGetCryptoRandomValues(array)).toThrow('No Web Crypto API available in this environment'); + } finally { + // Restore original values + globalRef.window = originalWindow; + globalRef.global = originalGlobal; + + // Clear module cache again to restore normal state + jest.resetModules(); + } + }); }); });