From 7f517ff7202d3e15793ac1aa4086748cff57045b Mon Sep 17 00:00:00 2001 From: violetadev Date: Thu, 1 Aug 2024 23:31:36 +0200 Subject: [PATCH] add electron mock --- desktop-app/jest.config.js | 5 +- desktop-app/setupTests.js | 39 ++++ .../ManageSuitesTool.test.tsx | 180 ++++++++++++++++++ 3 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 desktop-app/setupTests.js create mode 100644 desktop-app/src/renderer/components/DeviceManager/PreviewSuites/ManageSuitesTool/ManageSuitesTool.test.tsx diff --git a/desktop-app/jest.config.js b/desktop-app/jest.config.js index 1ddd2461..1b25c698 100644 --- a/desktop-app/jest.config.js +++ b/desktop-app/jest.config.js @@ -6,7 +6,10 @@ module.exports = { '/.erb/mocks/fileMock.js', '\\.(css|less|sass|scss)$': 'identity-obj-proxy', }, - setupFiles: ['./.erb/scripts/check-build-exists.ts'], + setupFiles: [ + './.erb/scripts/check-build-exists.ts', + '/setupTests.js', + ], testEnvironment: 'jsdom', testEnvironmentOptions: { url: 'http://localhost/', diff --git a/desktop-app/setupTests.js b/desktop-app/setupTests.js new file mode 100644 index 00000000..911855a2 --- /dev/null +++ b/desktop-app/setupTests.js @@ -0,0 +1,39 @@ +window.electron = { + ipcRenderer: { + sendMessage(channel: Channels, ...args: T[]): void { + throw new Error('Function not implemented.'); + }, + on( + channel: string, + func: (...args: T[]) => void + ): (() => void) | undefined { + throw new Error('Function not implemented.'); + }, + once(channel: string, func: (...args: T[]) => void): void { + throw new Error('Function not implemented.'); + }, + invoke(channel: string, ...args: T[]): Promise

{ + throw new Error('Function not implemented.'); + }, + removeListener(channel: string, func: (...args: T[]) => void): void { + throw new Error('Function not implemented.'); + }, + removeAllListeners(channel: string): void { + throw new Error('Function not implemented.'); + }, + }, + store: { + set: jest.fn(), // Mock the `set` function + get: jest.fn(), // Mock the `get` function if needed in other parts of your tests + }, +}; + +global.IntersectionObserver = jest.fn(() => ({ + root: null, + rootMargin: '', + thresholds: [], + observe: jest.fn(), + unobserve: jest.fn(), + disconnect: jest.fn(), + takeRecords: jest.fn(), +})); diff --git a/desktop-app/src/renderer/components/DeviceManager/PreviewSuites/ManageSuitesTool/ManageSuitesTool.test.tsx b/desktop-app/src/renderer/components/DeviceManager/PreviewSuites/ManageSuitesTool/ManageSuitesTool.test.tsx new file mode 100644 index 00000000..34bd955e --- /dev/null +++ b/desktop-app/src/renderer/components/DeviceManager/PreviewSuites/ManageSuitesTool/ManageSuitesTool.test.tsx @@ -0,0 +1,180 @@ +import { render, screen, fireEvent, waitFor } from '@testing-library/react'; +import { Provider } from 'react-redux'; +import { configureStore } from '@reduxjs/toolkit'; +import { ManageSuitesTool } from './ManageSuitesTool'; +import deviceManagerReducer, { + addSuites, + deleteAllSuites, +} from 'renderer/store/features/device-manager'; +import { transformFile } from './utils'; +import { ReactNode } from 'react'; +import { JSX } from 'react/jsx-runtime'; +import '@testing-library/jest-dom'; +import { Channels } from 'common/constants'; + +jest.mock('renderer/store/features/device-manager', () => ({ + addSuites: jest.fn(() => ({ type: 'addSuites' })), + deleteAllSuites: jest.fn(() => ({ type: 'deleteAllSuites' })), +})); + +jest.mock('./utils', () => ({ + transformFile: jest.fn(), +})); + +jest.mock('./helpers', () => ({ + onFileDownload: jest.fn(), + setCustomDevices: jest.fn(), +})); + +const renderWithRedux = ( + component: + | string + | number + | boolean + | Iterable + | JSX.Element + | null + | undefined +) => { + const store = configureStore({ + reducer: { + deviceManager: deviceManagerReducer, + }, + }); + + return { + ...render({component}), + store, + }; +}; + +describe('ManageSuitesTool', () => { + let setCustomDevicesStateMock: jest.Mock; + + beforeAll(() => { + window.electron = { + ipcRenderer: { + sendMessage: function (channel: Channels, ...args: T[]): void { + throw new Error('Function not implemented.'); + }, + on: function ( + channel: string, + func: (...args: T[]) => void + ): (() => void) | undefined { + throw new Error('Function not implemented.'); + }, + once: function ( + channel: string, + func: (...args: T[]) => void + ): void { + throw new Error('Function not implemented.'); + }, + invoke: function (channel: string, ...args: T[]): Promise

{ + throw new Error('Function not implemented.'); + }, + removeListener: function ( + channel: string, + func: (...args: T[]) => void + ): void { + throw new Error('Function not implemented.'); + }, + removeAllListeners: function (channel: string): void { + throw new Error('Function not implemented.'); + }, + }, + store: { + set: jest.fn(), // Mock the `set` function + get: jest.fn(), // Mock the `get` function if needed in other parts of your tests + }, + }; + + global.IntersectionObserver = jest.fn(() => ({ + root: null, + rootMargin: '', + thresholds: [], + observe: jest.fn(), + unobserve: jest.fn(), + disconnect: jest.fn(), + takeRecords: jest.fn(), + })); + }); + + beforeEach(() => { + setCustomDevicesStateMock = jest.fn(); + + renderWithRedux( + + ); + }); + + it('renders the component correctly', () => { + expect(screen.getByTestId('download-btn')).toBeInTheDocument(); + expect(screen.getByTestId('upload-btn')).toBeInTheDocument(); + expect(screen.getByTestId('reset-btn')).toBeInTheDocument(); + }); + + it('opens the modal when download button is clicked', () => { + fireEvent.click(screen.getByTestId('download-btn')); + expect(screen.getByText('Import your devices')).toBeInTheDocument(); + }); + + it('opens the reset confirmation dialog when reset button is clicked', () => { + fireEvent.click(screen.getByTestId('reset-btn')); + expect( + screen.getByText('Do you want to reset all settings?') + ).toBeInTheDocument(); + }); + + it('closes the reset confirmation dialog when the close button is clicked', () => { + fireEvent.click(screen.getByTestId('reset-btn')); + fireEvent.click(screen.getByText('Cancel')); + expect( + screen.queryByText('Do you want to reset all settings?') + ).not.toBeInTheDocument(); + }); + + it.only('dispatches deleteAllSuites and clears custom devices on reset confirmation', async () => { + fireEvent.click(screen.getByTestId('reset-btn')); + fireEvent.click(screen.getByText('Confirm')); + + await waitFor(() => { + expect(deleteAllSuites).toHaveBeenCalled(); + expect(setCustomDevicesStateMock).toHaveBeenCalledWith([]); + }); + }); + + it('handles file upload and dispatches actions correctly', async () => { + const file = new File(['test'], 'test.json', { type: 'application/json' }); + + (transformFile as jest.Mock).mockResolvedValueOnce({ + customDevices: ['device1', 'device2'], + suites: ['suite1', 'suite2'], + }); + + fireEvent.click(screen.getByTestId('download-btn')); + + const input = screen.getByLabelText('Upload File'); + fireEvent.change(input, { target: { files: [file] } }); + + await waitFor(() => { + expect(setCustomDevicesStateMock).toHaveBeenCalled(); + expect(addSuites).toHaveBeenCalled(); + expect(screen.queryByText('Import your devices')).not.toBeInTheDocument(); + }); + }); + + it('handles file upload error and shows error message', async () => { + const file = new File(['test'], 'test.json', { type: 'application/json' }); + + (transformFile as jest.Mock).mockRejectedValueOnce(new Error('Test Error')); + + fireEvent.click(screen.getByTestId('download-btn')); + + const input = screen.getByLabelText('Upload File'); + fireEvent.change(input, { target: { files: [file] } }); + + await waitFor(() => { + expect(screen.getByText('An error occurred')).toBeInTheDocument(); + }); + }); +});