Skip to content

Commit

Permalink
feat(pci.ai.notebook): add unit test on logs and backups page (#14832)
Browse files Browse the repository at this point in the history
REF: DATATR-1823,DATATR-1822

Signed-off-by: Arthur Bullet <[email protected]>
  • Loading branch information
abullet33 authored Jan 8, 2025
1 parent 9849d53 commit 4781b0d
Show file tree
Hide file tree
Showing 6 changed files with 345 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ const Backups = () => {
<>
<h4>{t('title')}</h4>
<p>{t('description')}</p>
{backupsQuery.isSuccess && <BackupsList backups={backupsQuery.data} />}
{backupsQuery.isSuccess ? (
<BackupsList backups={backupsQuery.data} />
) : (
<BackupsList.Skeleton />
)}
<Outlet />
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import {
act,
fireEvent,
render,
screen,
waitFor,
} from '@testing-library/react';
import { UseQueryResult } from '@tanstack/react-query';
import * as ai from '@/types/cloud/project/ai';
import { mockedNotebook } from '@/__tests__/helpers/mocks/notebook';
import { Locale } from '@/hooks/useLocale';
import { RouterWithQueryClientWrapper } from '@/__tests__/helpers/wrappers/RouterWithQueryClientWrapper';
import { mockedBackup } from '@/__tests__/helpers/mocks/backup';
import Backups, { breadcrumb as Breadcrumb } from './Backups.page';

const mockedUsedNavigate = vi.fn();
describe('Backups page', () => {
beforeEach(() => {
vi.restoreAllMocks();
// Mock necessary hooks and dependencies
vi.mock('react-i18next', () => ({
useTranslation: () => ({
t: (key: string) => key,
}),
}));

vi.mock('@/pages/notebooks/[notebookId]/Notebook.context', () => ({
useNotebookData: vi.fn(() => ({
projectId: 'projectId',
notebook: mockedNotebook,
serviceQuery: {} as UseQueryResult<ai.notebook.Notebook, Error>,
})),
}));

vi.mock('@/data/api/ai/notebook/backups/backups.api', () => ({
getBackups: vi.fn(() => [mockedBackup]),
}));

vi.mock('@ovh-ux/manager-react-shell-client', async (importOriginal) => {
const mod = await importOriginal<
typeof import('@ovh-ux/manager-react-shell-client')
>();
return {
...mod,
useShell: vi.fn(() => ({
i18n: {
getLocale: vi.fn(() => Locale.fr_FR),
onLocaleChange: vi.fn(),
setLocale: vi.fn(),
},
})),
};
});

vi.mock('react-router-dom', async () => {
const mod = await vi.importActual('react-router-dom');
return {
...mod,
useNavigate: () => mockedUsedNavigate,
};
});
});

afterEach(() => {
vi.clearAllMocks();
});

it('renders the breadcrumb component', async () => {
const translationKey = 'breadcrumb';
render(<Breadcrumb />, { wrapper: RouterWithQueryClientWrapper });
await waitFor(() => {
expect(screen.getByText(translationKey)).toBeInTheDocument();
});
});

it('renders Skeleton while loading', async () => {
render(<Backups />, { wrapper: RouterWithQueryClientWrapper });
expect(
screen.getByTestId('backup-list-table-skeleton'),
).toBeInTheDocument();
});

it('renders backups page', async () => {
render(<Backups />, { wrapper: RouterWithQueryClientWrapper });
expect(screen.getByText(mockedBackup.id)).toBeInTheDocument();
});
});

describe('Action table button', () => {
// Helper function to open a button in the table menu
const openButtonInMenu = async (buttonId: string) => {
act(() => {
const trigger = screen.getByTestId('backup-action-trigger');
fireEvent.focus(trigger);
fireEvent.keyDown(trigger, {
key: 'Enter',
code: 'Enter',
keyCode: 13,
charCode: 13,
});
});
const actionButton = screen.getByTestId(buttonId);
await waitFor(() => {
expect(actionButton).toBeInTheDocument();
});
act(() => {
fireEvent.click(actionButton);
});
};
beforeEach(async () => {
render(<Backups />, { wrapper: RouterWithQueryClientWrapper });
await waitFor(() => {
expect(screen.getByText(mockedBackup.id)).toBeInTheDocument();
});
});
afterEach(() => {
vi.clearAllMocks();
});

it('open fork backup modal', async () => {
await openButtonInMenu('backup-action-fork-button');
await waitFor(() => {
expect(mockedUsedNavigate).toHaveBeenCalledWith(
`./fork/${mockedBackup.id}`,
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ BackupsList.Skeleton = function BackupsListSkeleton() {
return (
<>
<div
data-testid="volume-list-table-skeleton"
data-testid="backup-list-table-skeleton"
className="flex justify-between w-100 mb-2 items-end"
>
<Skeleton className="h-10 w-48" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import {
act,
fireEvent,
render,
screen,
waitFor,
} from '@testing-library/react';
import { UseQueryResult } from '@tanstack/react-query';
import * as ai from '@/types/cloud/project/ai';
import { mockedNotebook } from '@/__tests__/helpers/mocks/notebook';
import { Locale } from '@/hooks/useLocale';
import { RouterWithQueryClientWrapper } from '@/__tests__/helpers/wrappers/RouterWithQueryClientWrapper';
import { mockedBackup } from '@/__tests__/helpers/mocks/backup';
import Fork from './Fork.modal';
import * as backupApi from '@/data/api/ai/notebook/backups/backups.api';
import { useToast } from '@/components/ui/use-toast';
import { apiErrorMock } from '@/__tests__/helpers/mocks/aiError';

describe('Backups page', () => {
beforeEach(() => {
vi.restoreAllMocks();
// Mock necessary hooks and dependencies
vi.mock('react-i18next', () => ({
useTranslation: () => ({
t: (key: string) => key,
}),
}));

vi.mock('@/pages/notebooks/[notebookId]/Notebook.context', () => ({
useNotebookData: vi.fn(() => ({
projectId: 'projectId',
notebook: mockedNotebook,
serviceQuery: {} as UseQueryResult<ai.notebook.Notebook, Error>,
})),
}));

vi.mock('@/data/api/ai/notebook/backups/backups.api', () => ({
getBackup: vi.fn(() => mockedBackup),
forkBackup: vi.fn((backup) => backup),
}));

vi.mock('@ovh-ux/manager-react-shell-client', async (importOriginal) => {
const mod = await importOriginal<
typeof import('@ovh-ux/manager-react-shell-client')
>();
return {
...mod,
useShell: vi.fn(() => ({
i18n: {
getLocale: vi.fn(() => Locale.fr_FR),
onLocaleChange: vi.fn(),
setLocale: vi.fn(),
},
})),
useNavigation: () => ({
getURL: vi.fn(
(app: string, path: string) => `#mockedurl-${app}${path}`,
),
}),
};
});

vi.mock('react-router-dom', async () => {
const mod = await vi.importActual('react-router-dom');
return {
...mod,
useParams: () => ({
backupId: 'backupId',
}),
};
});

vi.mock('@/components/ui/use-toast', () => {
const toastMock = vi.fn();
return {
useToast: vi.fn(() => ({
toast: toastMock,
})),
};
});
});

afterEach(() => {
vi.clearAllMocks();
});

it('renders modal skeleton while loading', async () => {
render(<Fork />, { wrapper: RouterWithQueryClientWrapper });
expect(screen.getByTestId('dialog-container')).toBeInTheDocument();
});

it('renders Fork modal', async () => {
render(<Fork />, { wrapper: RouterWithQueryClientWrapper });
expect(screen.getByTestId('fork-modal')).toBeInTheDocument();
});

it('trigger onError on API Error', async () => {
vi.mocked(backupApi.forkBackup).mockImplementation(() => {
throw apiErrorMock;
});
render(<Fork />, { wrapper: RouterWithQueryClientWrapper });
act(() => {
fireEvent.click(screen.getByTestId('fork-backup-submit-button'));
});
await waitFor(() => {
expect(backupApi.forkBackup).toHaveBeenCalled();
expect(useToast().toast).toHaveBeenCalledWith({
title: 'forkToastErrorTitle',
description: apiErrorMock.response.data.message,
variant: 'destructive',
});
});
});

it('trigger onSuccess on summit click', async () => {
render(<Fork />, { wrapper: RouterWithQueryClientWrapper });
expect(screen.getByTestId('fork-modal')).toBeInTheDocument();
act(() => {
fireEvent.click(screen.getByTestId('fork-backup-submit-button'));
});
await waitFor(() => {
expect(backupApi.forkBackup).toHaveBeenCalled();
expect(useToast().toast).toHaveBeenCalledWith({
title: 'forkToastSuccessTitle',
description: 'forkToastSuccessDescription',
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ const Logs = () => {
</div>
<ScrollArea className="p-2 h-[500px] bg-[#122844]">
{logsQuery.isSuccess ? (
<ul ref={listLogRef}>
<ul data-testid="logs-area" ref={listLogRef}>
{logsQuery.data.logs.map((log, index) => (
<li
className="whitespace-pre text-white font-mono text-sm"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import { UseQueryResult } from '@tanstack/react-query';
import * as ai from '@/types/cloud/project/ai';
import { Locale } from '@/hooks/useLocale';
import { RouterWithQueryClientWrapper } from '@/__tests__/helpers/wrappers/RouterWithQueryClientWrapper';
import { mockedNotebook } from '@/__tests__/helpers/mocks/notebook';
import Logs, { breadcrumb as Breadcrumb } from './Logs.page';
import { mockedLogs } from '@/__tests__/helpers/mocks/logs';

describe('Logs page', () => {
beforeEach(() => {
vi.restoreAllMocks();
// Mock necessary hooks and dependencies
vi.mock('react-i18next', () => ({
useTranslation: () => ({
t: (key: string) => key,
}),
}));

vi.mock('@/pages/notebooks/[notebookId]/Notebook.context', () => ({
useNotebookData: vi.fn(() => ({
projectId: 'projectId',
notebook: mockedNotebook,
serviceQuery: {} as UseQueryResult<ai.notebook.Notebook, Error>,
})),
}));

vi.mock('@/data/api/ai/notebook/logs/logs.api', () => ({
getLogs: vi.fn(() => mockedLogs),
}));

const mockScrollIntoView = vi.fn();
window.HTMLElement.prototype.scrollIntoView = mockScrollIntoView;

vi.mock('@ovh-ux/manager-react-shell-client', async (importOriginal) => {
const mod = await importOriginal<
typeof import('@ovh-ux/manager-react-shell-client')
>();
return {
...mod,
useShell: vi.fn(() => ({
i18n: {
getLocale: vi.fn(() => Locale.fr_FR),
onLocaleChange: vi.fn(),
setLocale: vi.fn(),
},
})),
useNavigation: () => ({
getURL: vi.fn(
(app: string, path: string) => `#mockedurl-${app}${path}`,
),
}),
};
});
});

afterEach(() => {
vi.clearAllMocks();
});

it('renders the breadcrumb component', async () => {
const translationKey = 'breadcrumb';
render(<Breadcrumb />, { wrapper: RouterWithQueryClientWrapper });
await waitFor(() => {
expect(screen.getByText(translationKey)).toBeInTheDocument();
});
});

it('renders skeleton while loading', async () => {
render(<Logs />, { wrapper: RouterWithQueryClientWrapper });
expect(screen.getByTestId('skeleton-container')).toBeInTheDocument();
});

it('renders Logs', async () => {
render(<Logs />, { wrapper: RouterWithQueryClientWrapper });
expect(screen.getByTestId('logs-area')).toBeInTheDocument();
});
});

0 comments on commit 4781b0d

Please sign in to comment.