fix: test cases (#9561)

* fix: test cases

* fix: test errors
This commit is contained in:
chenos
2026-05-22 19:11:51 +08:00
committed by GitHub
parent 2e8e7d5e76
commit 627bdfd858
10 changed files with 339 additions and 174 deletions
@@ -1,24 +1,20 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { observer } from '@formily/react';
import * as nocobaseClient from '@nocobase/client';
import { SchemaComponentProvider } from '@nocobase/client';
import { sleep } from '@nocobase/test';
import { sleep } from '@nocobase/test/web';
import { act, render, screen, userEvent } from '@nocobase/test/client';
import { App } from 'antd';
import MockAdapter from 'axios-mock-adapter';
import React from 'react';
import { BackupSettings } from '../components/BackupSettings';
vi.mock('@nocobase/client', async () => {
const actual = await vi.importActual<typeof nocobaseClient>('@nocobase/client');
return {
...actual,
useApp: () => ({
i18n: {
t: vi.fn().mockImplementation((key) => key), // Mock translation function, return the key directly
},
}),
};
});
import { createMockAppWrapper } from './testUtils';
const storagesData = {
data: [
@@ -85,20 +81,30 @@ const settingsData = {
};
describe('BackupSettings', () => {
const mockedStorages = vi.fn().mockReturnValue(storagesData);
const mockedGetSettings = vi.fn().mockReturnValue(settingsData);
const mockedUpdateSettings = vi.fn().mockReturnValue({ data: { status: 'ok' } });
const { Wrapper, mockRequest } = createMockAppWrapper();
const mockedStorages = vi.fn();
const mockedGetSettings = vi.fn();
const mockedUpdateSettings = vi.fn();
beforeEach(() => {
mockRequest.reset();
mockedStorages.mockReset().mockReturnValue(storagesData);
mockedGetSettings.mockReset().mockReturnValue(settingsData);
mockedUpdateSettings.mockReset().mockReturnValue({ data: { status: 'ok' } });
});
afterEach(() => {
vi.restoreAllMocks();
});
const MockedBackupSettings = observer(() => {
const api = nocobaseClient.useAPIClient();
const axioMocked = new MockAdapter(api.axios);
axioMocked.onGet(`backupSettings:get/1`).reply(() => {
mockRequest.onGet(`backupSettings:get/1`).reply(() => {
return [200, mockedGetSettings()];
});
axioMocked.onGet(`storages:list`).reply(() => {
mockRequest.onGet(`storages:list`).reply(() => {
return [200, mockedStorages()];
});
axioMocked.onPost(`backupSettings:update/1`).reply((config) => {
mockRequest.onPost(`backupSettings:update/1`).reply((config) => {
return [200, mockedUpdateSettings(config.data)];
});
@@ -110,20 +116,19 @@ describe('BackupSettings', () => {
});
test('should render backup settings', async () => {
render(<MockedBackupSettings />);
expect(screen.getByText('Restore password')).toBeInTheDocument();
render(<MockedBackupSettings />, { wrapper: Wrapper });
expect(await screen.findByText('Restore password')).toBeInTheDocument();
});
test('should list "sync backup to cloud storage" options', async () => {
const user = userEvent.setup();
render(<MockedBackupSettings />);
render(<MockedBackupSettings />, { wrapper: Wrapper });
await sleep(3000);
const inputEle: HTMLElement = document.querySelector('div.ant-formily-item-control') as HTMLInputElement;
const storageCombobox = screen.getAllByRole('combobox').at(-1) as HTMLElement;
await act(async () => {
await user.click(inputEle);
await user.click(storageCombobox);
});
const optionItems = document.querySelectorAll('span.ant-select-selection-item');
expect(optionItems.length).toBe(2);
expect(await screen.findByText('ali')).toBeInTheDocument();
});
test('should trigger update backup settings api', async () => {
@@ -134,14 +139,13 @@ describe('BackupSettings', () => {
},
});
const user = userEvent.setup();
render(<MockedBackupSettings />);
render(<MockedBackupSettings />, { wrapper: Wrapper });
await sleep(3000);
const passwordInput = document.querySelector('input[type=password]') as HTMLInputElement;
await act(async () => {
await user.click(screen.getByText('Restore password').parentElement.firstElementChild);
await user.click(document.querySelector('div.ant-formily-item-control'));
await user.click(screen.getByText('ali'));
await user.type(document.querySelector('input[type=password]'), '123456');
await user.click(screen.getByText('Submit'));
await user.clear(passwordInput);
await user.type(passwordInput, '123456');
await user.click(screen.getByRole('button', { name: /Submit/ }));
});
expect(mockedUpdateSettings).toHaveBeenCalled();
expect(mockedUpdateSettings.mock.calls[0][0]).toEqual(
@@ -1,32 +1,50 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import * as nocobaseClient from '@nocobase/client';
import { render, waitFor } from '@nocobase/test/client';
import React from 'react';
import { vi } from 'vitest';
import { BackupsManagement } from '../components/BackupsManagement';
import { NAMESPACE } from '../constants';
import { createMockAppWrapper } from './testUtils';
vi.mock('@nocobase/client', async () => {
const actual = await vi.importActual<typeof nocobaseClient>('@nocobase/client');
return {
...actual,
useApp: () => ({
i18n: {
t: vi.fn().mockImplementation((key) => key), // Mock translation function, return the key directly
},
}),
};
});
vi.mock('../BackupsTable', async () => {
vi.mock('../components/BackupsTable', async () => {
return {
BackupsTable: vi.fn().mockImplementation(() => <div>Backup Table</div>),
};
});
vi.mock('../components/NewBackup', async () => {
return {
NewBackup: vi.fn().mockImplementation(() => <div>New Backup</div>),
};
});
vi.mock('../components/RefreshBackups', async () => {
return {
RefreshBackups: vi.fn().mockImplementation(() => <div>Refresh Backups</div>),
};
});
vi.mock('../components/RestoreFromLocal', async () => {
return {
RestoreFromLocal: vi.fn().mockImplementation(() => <div>Restore From Local</div>),
};
});
describe('BackupsManagement', () => {
const { Wrapper } = createMockAppWrapper();
test('should query the backups list data on render', async () => {
const spy = vi.spyOn(nocobaseClient, 'useRequest').mockReturnValue({} as any);
render(<BackupsManagement />);
render(<BackupsManagement />, { wrapper: Wrapper });
await waitFor(() => {
expect(spy).toHaveBeenCalledWith({
url: `${NAMESPACE}:list`,
@@ -10,13 +10,13 @@
import * as nocobaseClient from '@nocobase/client';
import { render, screen, userEvent, waitFor } from '@nocobase/test/client';
import { App } from 'antd';
import MockAdapter from 'axios-mock-adapter';
import { saveAs } from 'file-saver';
import React from 'react';
import { describe, vi } from 'vitest';
import { BackupFile, BackupsTable } from '../components/BackupsTable';
import { NAMESPACE } from '../constants';
import { BackupsContext } from '../contexts';
import { createMockAppWrapper } from './testUtils';
const mockedData = {
data: [
@@ -33,19 +33,6 @@ const mockedData = {
],
};
vi.mock('@nocobase/client', async () => {
const actual = await vi.importActual<typeof nocobaseClient>('@nocobase/client');
return {
...actual,
useApp: () => ({
i18n: {
t: vi.fn().mockImplementation((key) => key),
},
}),
useCurrentAppInfo: () => undefined,
};
});
vi.mock('file-saver', async () => {
return {
saveAs: vi.fn(),
@@ -53,14 +40,28 @@ vi.mock('file-saver', async () => {
});
describe('BackupsTable', () => {
let mocked: MockAdapter;
const { Wrapper, mockRequest } = createMockAppWrapper();
beforeEach(() => {
mockRequest.reset();
vi.spyOn(nocobaseClient, 'useCurrentAppInfo').mockReturnValue(undefined as any);
mockRequest.onGet(`${NAMESPACE}:appInfo`).reply(200, {
data: {
database: {
dialect: 'sqlite',
},
},
});
});
afterEach(() => {
vi.restoreAllMocks();
});
const MockedTable = () => {
const api = nocobaseClient.useAPIClient();
mocked = new MockAdapter(api.axios);
mocked.onGet('backups:list').reply(200, mockedData);
mocked.onGet('backups:download').reply(200, 'mocked-backup-content');
mocked.onPost('backups:destroy').reply(200, {});
mockRequest.onGet('backups:list').reply(200, mockedData);
mockRequest.onGet('backups:download').reply(200, 'mocked-backup-content');
mockRequest.onPost('backups:destroy').reply(200, {});
const useRequestValues = nocobaseClient.useRequest<{ data: BackupFile[] }>({
url: `${NAMESPACE}:list`,
@@ -75,7 +76,7 @@ describe('BackupsTable', () => {
};
test('should render table with correct columns and data', async () => {
render(<MockedTable />);
render(<MockedTable />, { wrapper: Wrapper });
await waitFor(() => {
expect(screen.getByText('Backup list')).toBeInTheDocument();
expect(screen.getByText('backup_20240818_182301_9056.nbdata')).toBeInTheDocument();
@@ -84,7 +85,7 @@ describe('BackupsTable', () => {
test('should handle download action', async () => {
const user = userEvent.setup();
render(<MockedTable />);
render(<MockedTable />, { wrapper: Wrapper });
await waitFor(() => {
expect(screen.getAllByText('Download')[0]).toBeInTheDocument();
});
@@ -92,7 +93,7 @@ describe('BackupsTable', () => {
await user.click(screen.getAllByText('Download')[0]);
await waitFor(() => {
expect(mocked.history.get).toEqual(
expect(mockRequest.history.get).toEqual(
expect.arrayContaining([
expect.objectContaining({
url: 'backups:download',
@@ -116,7 +117,7 @@ describe('BackupsTable', () => {
},
});
const user = userEvent.setup();
render(<MockedTable />);
render(<MockedTable />, { wrapper: Wrapper });
await waitFor(async () => {
await user.click(screen.getAllByText('Delete')[0]);
expect(modalConfirmSpy).toHaveBeenCalled();
@@ -124,7 +125,7 @@ describe('BackupsTable', () => {
});
test('should handle backing up data', async () => {
render(<MockedTable />);
render(<MockedTable />, { wrapper: Wrapper });
await waitFor(async () => {
expect(screen.getByText('Backup list')).toBeInTheDocument();
expect(screen.getByRole('cell', { name: /Backing up/i })).toBeInTheDocument();
@@ -1,46 +1,52 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import * as nocobaseClient from '@nocobase/client';
import { useAPIClient, useRequest } from '@nocobase/client';
import { useRequest } from '@nocobase/client';
import { act, render, screen, userEvent, waitFor } from '@nocobase/test/client';
import { App } from 'antd';
import MockAdapter from 'axios-mock-adapter';
import React from 'react';
import { BackupFile } from '../components/BackupsTable';
import { NewBackup } from '../components/NewBackup';
import { NAMESPACE } from '../constants';
import { BackupsContext } from '../contexts';
vi.mock('@nocobase/client', async () => {
const actual = await vi.importActual<typeof nocobaseClient>('@nocobase/client');
return {
...actual,
useApp: () => ({
i18n: {
t: vi.fn().mockImplementation((key) => key), // Mock translation function, return the key directly
},
}),
};
});
import { createMockAppWrapper } from './testUtils';
describe('NewBackup', () => {
let axioMocked: MockAdapter;
const mockedRefresh = vi.fn().mockReturnValue({ data: [] });
const mockedCreate = vi
.fn()
.mockReturnValue({ data: { name: 'backup_20240818_182302_2122.nbdata', inProgress: true } });
const mockedStatus = vi
.fn()
.mockReturnValue({ data: { 'backup_20240818_182302_2122.nbdata': { inProgress: false } } });
const { Wrapper, mockRequest } = createMockAppWrapper();
const mockedRefresh = vi.fn();
const mockedCreate = vi.fn();
const mockedStatus = vi.fn();
beforeEach(() => {
mockRequest.reset();
mockedRefresh.mockReset().mockReturnValue({ data: [] });
mockedCreate.mockReset().mockReturnValue({
data: { name: 'backup_20240818_182302_2122.nbdata', inProgress: true },
});
mockedStatus.mockReset().mockReturnValue({
data: { 'backup_20240818_182302_2122.nbdata': { inProgress: false } },
});
});
afterEach(() => {
vi.restoreAllMocks();
});
const MockedNewBackupBtn = () => {
const api = useAPIClient();
axioMocked = new MockAdapter(api.axios);
axioMocked.onGet(`${NAMESPACE}:list`).reply(() => {
mockRequest.onGet(`${NAMESPACE}:list`).reply(() => {
return [200, mockedRefresh()];
});
axioMocked.onPost(`${NAMESPACE}:create`).reply(() => {
mockRequest.onPost(`${NAMESPACE}:create`).reply(() => {
return [200, mockedCreate()];
});
axioMocked.onGet(`${NAMESPACE}:taskStatus`).reply(() => {
mockRequest.onGet(`${NAMESPACE}:taskStatus`).reply(() => {
return [200, mockedStatus()];
});
@@ -57,7 +63,7 @@ describe('NewBackup', () => {
};
test('should render new backup button', async () => {
render(<MockedNewBackupBtn />);
render(<MockedNewBackupBtn />, { wrapper: Wrapper });
expect(screen.getByText('New backup')).toBeInTheDocument();
});
@@ -73,18 +79,20 @@ describe('NewBackup', () => {
},
});
const user = userEvent.setup();
render(<MockedNewBackupBtn />);
render(<MockedNewBackupBtn />, { wrapper: Wrapper });
const newBackupBtn = screen.getByText('New backup');
await act(async () => {
await user.click(newBackupBtn);
});
await waitFor(() => {
expect(mockedCreate).toHaveBeenCalled();
expect(mockedRefresh).toHaveBeenCalled();
});
await waitFor(
() => {
expect(mockedCreate).toHaveBeenCalled();
expect(mockedStatus).toHaveBeenCalled();
expect(mockedRefresh).toHaveBeenCalled();
},
{ interval: 1000 },
{ timeout: 5000 },
);
});
});
@@ -1,32 +1,31 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import * as nocobaseClient from '@nocobase/client';
import MockAdapter from 'axios-mock-adapter';
import { NAMESPACE } from '../constants';
import { BackupFile } from '../components/BackupsTable';
import { BackupsContext } from '../contexts';
import React from 'react';
import { act, render, screen, userEvent, waitFor } from '@nocobase/test/client';
import { RefreshBackups } from '../components/RefreshBackups';
vi.mock('@nocobase/client', async () => {
const actual = await vi.importActual<typeof nocobaseClient>('@nocobase/client');
return {
...actual,
useApp: () => ({
i18n: {
t: vi.fn().mockImplementation((key) => key), // Mock translation function, return the key directly
},
}),
};
});
import { createMockAppWrapper } from './testUtils';
describe('RefreshBackups', () => {
let axioMocked: MockAdapter;
const { Wrapper, mockRequest } = createMockAppWrapper();
const mockedRefresh = vi.fn().mockReturnValue({ data: [] });
beforeEach(() => {
mockRequest.reset();
});
const MockedRefreshBackupsBtn = () => {
const api = nocobaseClient.useAPIClient();
axioMocked = new MockAdapter(api.axios);
axioMocked.onGet(`${NAMESPACE}:list`).reply(() => {
mockRequest.onGet(`${NAMESPACE}:list`).reply(() => {
return [200, mockedRefresh()];
});
@@ -43,20 +42,23 @@ describe('RefreshBackups', () => {
};
test('should render refresh backups button', async () => {
render(<MockedRefreshBackupsBtn />);
render(<MockedRefreshBackupsBtn />, { wrapper: Wrapper });
expect(screen.getByText('Refresh')).toBeInTheDocument();
});
test('should trigger refresh backup api', async () => {
const user = userEvent.setup();
render(<MockedRefreshBackupsBtn />);
render(<MockedRefreshBackupsBtn />, { wrapper: Wrapper });
expect(mockedRefresh).toHaveBeenCalledTimes(1);
const newBackupBtn = screen.getByText('Refresh');
const newBackupBtn = await screen.findByRole('button', { name: /Refresh/ });
await waitFor(() => {
expect(newBackupBtn).toBeEnabled();
});
await act(async () => {
user.click(newBackupBtn);
await user.click(newBackupBtn);
});
await waitFor(() => {
expect(mockedRefresh).toHaveBeenCalledTimes(2);
expect(mockedRefresh.mock.calls.length).toBeGreaterThan(1);
});
});
});
@@ -1,31 +1,37 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import * as nocobaseClient from '@nocobase/client';
import MockAdapter from 'axios-mock-adapter';
import { NAMESPACE } from '../constants';
import { BackupFile } from '../components/BackupsTable';
import React from 'react';
import { act, render, screen, userEvent, waitFor } from '@nocobase/test/client';
import { RestoreFromBackup } from '../components/RestoreFromBackup';
vi.mock('@nocobase/client', async () => {
const actual = await vi.importActual<typeof nocobaseClient>('@nocobase/client');
return {
...actual,
useApp: () => ({
i18n: {
t: vi.fn().mockImplementation((key) => key), // Mock translation function, return the key directly
},
}),
};
});
import { createMockAppWrapper } from './testUtils';
describe('RestoreFromBackup', () => {
let axioMocked: MockAdapter;
const { Wrapper, mockRequest } = createMockAppWrapper();
const mockedRestore = vi.fn().mockReturnValue({ data: { status: 'ok' } });
beforeEach(() => {
mockRequest.reset();
mockRequest.onGet(`${NAMESPACE}:appInfo`).reply(200, {
data: {
database: {
dialect: 'sqlite',
},
},
});
});
const MockedRestoreFromBackup = () => {
const api = nocobaseClient.useAPIClient();
axioMocked = new MockAdapter(api.axios);
axioMocked.onPost(`${NAMESPACE}:restore`).reply(() => {
mockRequest.onPost(`${NAMESPACE}:restore`).reply(() => {
return [200, mockedRestore()];
});
@@ -40,21 +46,21 @@ describe('RestoreFromBackup', () => {
};
test('should render restore from backup button', async () => {
render(<MockedRestoreFromBackup />);
render(<MockedRestoreFromBackup />, { wrapper: Wrapper });
expect(screen.getByText('Restore')).toBeInTheDocument();
});
test('should trigger restore api', async () => {
const user = userEvent.setup();
render(<MockedRestoreFromBackup />);
render(<MockedRestoreFromBackup />, { wrapper: Wrapper });
await act(async () => {
user.click(screen.getByText('Restore'));
await user.click(screen.getByText('Restore'));
});
await waitFor(() => {
expect(screen.getByText('Submit')).toBeInTheDocument();
});
await act(async () => {
user.click(screen.getByText('Submit'));
await user.click(screen.getByText('Submit'));
});
await waitFor(() => {
expect(mockedRestore).toHaveBeenCalled();
@@ -1,55 +1,59 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import * as nocobaseClient from '@nocobase/client';
import { act, fireEvent, render, screen, userEvent, waitFor } from '@nocobase/test/client';
import MockAdapter from 'axios-mock-adapter';
import React from 'react';
import { RestoreFromLocal } from '../components/RestoreFromLocal';
import { NAMESPACE } from '../constants';
vi.mock('@nocobase/client', async () => {
const actual = await vi.importActual<typeof nocobaseClient>('@nocobase/client');
return {
...actual,
useApp: () => ({
i18n: {
t: vi.fn().mockImplementation((key) => key), // Mock translation function, return the key directly
},
}),
};
});
import { createMockAppWrapper } from './testUtils';
describe('RestoreFromLocal', () => {
let axioMocked: MockAdapter;
const { Wrapper, mockRequest } = createMockAppWrapper();
const mockedRestore = vi.fn().mockReturnValue({ data: { status: 'ok' } });
beforeEach(() => {
mockRequest.reset();
mockRequest.onGet(`${NAMESPACE}:appInfo`).reply(200, {
data: {
database: {
dialect: 'sqlite',
},
},
});
});
const MockedRestoreFromLocal = () => {
const api = nocobaseClient.useAPIClient();
axioMocked = new MockAdapter(api.axios);
axioMocked.onPost(`${NAMESPACE}:upload`).reply(() => {
mockRequest.onPost(`${NAMESPACE}:upload`).reply(() => {
return [200, mockedRestore()];
});
return <RestoreFromLocal />;
};
test('should render restore from backup button', async () => {
render(<MockedRestoreFromLocal />);
render(<MockedRestoreFromLocal />, { wrapper: Wrapper });
expect(screen.getByText('Restore backup from local')).toBeInTheDocument();
});
test('should trigger restore api', async () => {
const file = new File([''], 'backup_20240818_182302_2122.nbdata', { type: 'application/octet-stream' });
const user = userEvent.setup();
render(<MockedRestoreFromLocal />);
render(<MockedRestoreFromLocal />, { wrapper: Wrapper });
await act(async () => {
user.click(screen.getByText('Restore backup from local'));
await user.click(screen.getByText('Restore backup from local'));
});
await waitFor(() => {
const fileBtn = screen.getByText((content, element) => {
return element.tagName.toLowerCase() === 'input' && element['type'] === 'file';
});
const fileBtn = document.querySelector('input[type="file"]') as HTMLInputElement;
fireEvent.change(fileBtn, { target: { files: [file] } });
});
await act(async () => {
user.click(screen.getByText('Submit'));
await user.click(screen.getByText('Submit'));
});
await waitFor(() => {
expect(mockedRestore).toHaveBeenCalled();
@@ -0,0 +1,58 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { APIClientProvider, Application, ApplicationContext, mockAPIClient } from '@nocobase/client';
import { App as AntdApp } from 'antd';
import React from 'react';
if (typeof window !== 'undefined') {
Object.defineProperty(window, 'matchMedia', {
configurable: true,
writable: true,
value: (query: string) => ({
matches: false,
media: query,
onchange: null,
addListener: () => {},
removeListener: () => {},
addEventListener: () => {},
removeEventListener: () => {},
dispatchEvent: () => false,
}),
});
}
export const createMockAppWrapper = () => {
const { apiClient, mockRequest } = mockAPIClient();
const app = new Application({
apiClient,
router: {
type: 'memory',
},
});
app.i18n.t = ((key: string) => key) as any;
const Wrapper = ({ children }: { children?: React.ReactNode }) => {
return (
<ApplicationContext.Provider value={app}>
<APIClientProvider apiClient={app.apiClient}>
<AntdApp>{children}</AntdApp>
</APIClientProvider>
</ApplicationContext.Provider>
);
};
return {
app,
apiClient: app.apiClient,
mockRequest,
Wrapper,
};
};
@@ -17,6 +17,8 @@ import fs from 'fs';
import * as cp from 'child_process';
import PluginFileManagerServer from '@nocobase/plugin-file-manager';
import yauzl from 'yauzl';
import { EventEmitter } from 'events';
import { Readable, Writable } from 'stream';
vi.mock('child_process', async (importOriginal) => {
const actual = await importOriginal<typeof cp>();
@@ -31,6 +33,24 @@ vi.mock('child_process', async (importOriginal) => {
}
callback(null, 'done');
}),
spawn: vi.fn().mockImplementation(() => {
const stdout = Readable.from(['mocked database backup']);
const stderr = Readable.from([]);
const stdin = new Writable({
write(_chunk, _encoding, callback) {
callback();
},
});
const childProcess = new EventEmitter() as any;
childProcess.stdout = stdout;
childProcess.stderr = stderr;
childProcess.stdin = stdin;
setImmediate(() => {
childProcess.emit('exit', 0);
childProcess.emit('close', 0);
});
return childProcess;
}),
};
});
@@ -69,6 +89,7 @@ describe('BackupManager', async () => {
beforeEach(async () => {
app = await getApp();
await fs.promises.mkdir(backupFilesFolder, { recursive: true });
await fs.promises.unlink(finalBackupFilePath).catch(() => {});
});
afterEach(async () => {
@@ -19,11 +19,32 @@ import { BackupManager, BackupSettings } from '../../managers/backup';
import { RestoreManager } from '../../managers/restore';
import backupCliResource from '../../resourcers/backup-cli';
import backupsResource from '../../resourcers/backups';
import { EventEmitter } from 'events';
import { Readable, Writable } from 'stream';
let mockExecImplementation = (command, _options, callback) => {
callback(null, 'done');
};
let mockSpawnImplementation = () => {
const stdout = Readable.from(['mocked database backup']);
const stderr = Readable.from([]);
const stdin = new Writable({
write(_chunk, _encoding, callback) {
callback();
},
});
const childProcess = new EventEmitter() as any;
childProcess.stdout = stdout;
childProcess.stderr = stderr;
childProcess.stdin = stdin;
setImmediate(() => {
childProcess.emit('exit', 0);
childProcess.emit('close', 0);
});
return childProcess;
};
vi.mock('child_process', async (importOriginal) => {
const actual = await importOriginal<typeof cp>();
return {
@@ -32,6 +53,7 @@ vi.mock('child_process', async (importOriginal) => {
exec: vi
.fn()
.mockImplementation((command, options, callback) => mockExecImplementation(command, options, callback)),
spawn: vi.fn().mockImplementation((command, args, options) => mockSpawnImplementation(command, args, options)),
};
});
@@ -71,6 +93,8 @@ describe('RestoreManager', () => {
beforeEach(async () => {
app = await getApp();
await fs.promises.mkdir(backupFilesFolder, { recursive: true });
await fs.promises.unlink(finalBackupFilePath).catch(() => {});
await fs.promises.unlink(schemaMismatchBackupFilePath).catch(() => {});
mockExecImplementation = (command, _options, callback) => {
if (command.includes('-f')) {
@@ -94,6 +118,25 @@ describe('RestoreManager', () => {
}
callback(null, 'done');
};
mockSpawnImplementation = () => {
const stdout = Readable.from(['mocked database backup']);
const stderr = Readable.from([]);
const stdin = new Writable({
write(_chunk, _encoding, callback) {
callback();
},
});
const childProcess = new EventEmitter() as any;
childProcess.stdout = stdout;
childProcess.stderr = stderr;
childProcess.stdin = stdin;
setImmediate(() => {
childProcess.emit('exit', 0);
childProcess.emit('close', 0);
});
return childProcess;
};
});
afterEach(async () => {