diff --git a/src/components/GeneratePassword/index.test.tsx b/src/components/GeneratePassword/index.test.tsx index 9f30f86..d38cc87 100644 --- a/src/components/GeneratePassword/index.test.tsx +++ b/src/components/GeneratePassword/index.test.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { PasswordMode } from '@enums/passwordMode'; +import * as generatePasswordModule from '@functions/generate/randomPassword'; import { cleanup, fireEvent, render, screen } from '@testing-library/react'; import { waitFor } from '@testing-library/react'; import { afterEach, describe, expect, it, vi } from 'vitest'; @@ -361,4 +362,141 @@ describe('GeneratePassword', () => { expect(passwordStrengthIndicatorSecondChild).toHaveClass('bg-green-500'); }); + + it('should copy an empty string if the password content is null or undefined', async () => { + const mockClipboard = { + writeText: vi.fn(), + }; + + Object.defineProperty(navigator, 'clipboard', { + value: mockClipboard, + writable: true, + }); + + render( + + ); + + // Mocking to return null for textContent + const passwordPre = screen.getByTitle('generated password'); + + Object.defineProperty(passwordPre, 'textContent', { + get: () => null, + }); + + const copyIcon = screen.getByTitle('Copy Password'); + + fireEvent.click(copyIcon); + + await waitFor(() => { + expect(mockClipboard.writeText).toHaveBeenCalledWith(''); + }); + }); +}); + +describe('GeneratePassword Error Handling', () => { + afterEach(() => { + vi.restoreAllMocks(); + }); + + it('should log "Failed to generate password" when an error occurs during password generation', async () => { + vi.spyOn(generatePasswordModule, 'randomPassword').mockImplementation( + () => { + throw new Error('Simulated error'); + } + ); + + // eslint-disable-next-line @typescript-eslint/no-empty-function + const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + + render( + + ); + + const generateButton = screen.getByRole('button', { name: /Generate/i }); + + fireEvent.click(generateButton); + + expect(consoleSpy).toHaveBeenCalledWith('Failed to generate password'); + }); + + it('should log "Error generating password" when an error occurs during password generation from slider change', async () => { + vi.spyOn(generatePasswordModule, 'randomPassword').mockImplementation( + () => { + throw new Error('Simulated slider error'); + } + ); + + // eslint-disable-next-line @typescript-eslint/no-empty-function + const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + + render( + + ); + + const slider = screen.getByRole('slider') as HTMLInputElement; + + fireEvent.change(slider, { target: { value: '20' } }); + + expect(consoleSpy).toHaveBeenCalledWith('Error generating password'); + + vi.restoreAllMocks(); + }); + + it('should log "Failed to copy password" when an error occurs during password copy', async () => { + const mockClipboard = { + writeText: vi + .fn() + .mockRejectedValue(new Error('Simulated clipboard error')), + }; + + Object.defineProperty(navigator, 'clipboard', { + value: mockClipboard, + writable: true, + }); + + render( + + ); + + const passwordPre = screen.getByTitle('generated password'); + + passwordPre.textContent = 'testPassword123!'; // Ensure there is text to copy + + const copyIcon = screen.getByTitle('Copy Password'); + + fireEvent.click(copyIcon); + + const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + + await vi.waitFor(() => + expect(consoleSpy).toHaveBeenCalledWith('Failed to copy password') + ); + + consoleSpy.mockRestore(); + }); }); diff --git a/vite.config.ts b/vite.config.ts index 10a6fdc..eadabd7 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -19,17 +19,17 @@ export default defineConfig({ coverage: { clean: true, provider: 'istanbul', - reporter: ['html', 'text', 'json'], + reporter: ['html', 'text'], include: ['src/**/*.ts?(x)'], exclude: ['src/**/*.js?(x)', 'src/index.tsx', 'src/**/*.test.ts?(x)'], all: true, reportsDirectory: './coverage', thresholds: { autoUpdate: true, - statements: 98.63, - branches: 96.73, + statements: 100, + branches: 98.19, functions: 100, - lines: 98.6, + lines: 100, }, }, globals: true, @@ -66,4 +66,4 @@ export default defineConfig({ }, ], }, -}); +}); \ No newline at end of file