Skip to content

Commit

Permalink
Merge pull request #51 from bartoval/linkform_tests
Browse files Browse the repository at this point in the history
increase code coverage
  • Loading branch information
bartoval authored Feb 14, 2025
2 parents c1106d9 + 5a12f65 commit 018f2c7
Show file tree
Hide file tree
Showing 6 changed files with 416 additions and 148 deletions.
119 changes: 119 additions & 0 deletions __tests__/DeploymentNetworkConsoleButton.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { render, screen, fireEvent } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';

import DeploymentNetworkConsoleButton from '../src/console/pages/components/DeploymentNetworkConsoleButton';

const mockUseK8sWatchResource = vi.hoisted(() => vi.fn());
const mockUseMutationImpl = vi.hoisted(() => vi.fn());
const mockRESTApiCreateDeployment = vi.hoisted(() => vi.fn());
const mockRESTApiDeleteDeployment = vi.hoisted(() => vi.fn());
const mockNamespaceManagerGetNamespace = vi.hoisted(() => vi.fn());

vi.mock('@openshift-console/dynamic-plugin-sdk', () => ({
useK8sWatchResource: mockUseK8sWatchResource
}));

vi.mock('../src/console/API/REST.api', () => ({
RESTApi: {
createDeployment: mockRESTApiCreateDeployment,
deleteDeployment: mockRESTApiDeleteDeployment
}
}));

vi.mock('../src/console/config/db', () => ({
NamespaceManager: {
getNamespace: mockNamespaceManagerGetNamespace
}
}));

vi.mock('@tanstack/react-query', () => ({
useMutation: mockUseMutationImpl
}));

const defaultMutationMock = {
mutate: vi.fn(),
isLoading: false,
isError: false,
error: null
};

type ResourceOptions = { name?: string; selector?: { matchLabels?: Record<string, string> } };

const loadedResourceMock = (resourceName: string) => (options: ResourceOptions) => {
if (options.name === resourceName) {
return [{ spec: { host: 'example.com', port: { targetPort: '8080' } } }, false, undefined];
}
if (options.selector?.matchLabels?.['app.kubernetes.io/name'] === 'network-observer') {
return [{ status: { phase: 'Running' } }, false, undefined];
}

return [undefined, false, undefined];
};

const BUTTON_LABELS = {
deploy: 'Deploy the Network Console',
open: 'Open the Network Console',
delete: 'Delete the Network Console'
};

const setupMocks = (namespace = 'test-namespace') => {
vi.clearAllMocks();
mockNamespaceManagerGetNamespace.mockReturnValue(namespace);
};

describe('DeploymentNetworkConsoleButton', () => {
beforeEach(() => setupMocks());

it('renders the deploy button when not loaded', () => {
mockUseK8sWatchResource.mockReturnValue([undefined, false, undefined]);
mockUseMutationImpl.mockReturnValue(defaultMutationMock);

render(<DeploymentNetworkConsoleButton />);
expect(screen.getByText(BUTTON_LABELS.deploy)).toBeInTheDocument();
});

it('renders the open and delete buttons when loaded', () => {
mockUseK8sWatchResource.mockImplementation(loadedResourceMock('network-observer'));
mockUseMutationImpl.mockReturnValue(defaultMutationMock);

render(<DeploymentNetworkConsoleButton />);
expect(screen.getByText(BUTTON_LABELS.open)).toBeInTheDocument();
expect(screen.getByText(BUTTON_LABELS.delete)).toBeInTheDocument();
});

it('calls the create mutation when the deploy button is clicked', () => {
const mutateMock = vi.fn();
mockUseK8sWatchResource.mockReturnValue([undefined, false, undefined]);
mockUseMutationImpl.mockReturnValue({ ...defaultMutationMock, mutate: mutateMock });

render(<DeploymentNetworkConsoleButton />);
fireEvent.click(screen.getByText(BUTTON_LABELS.deploy));
expect(mutateMock).toHaveBeenCalled();
});

it('calls the delete mutation when the delete button is clicked and calls onSuccess', () => {
const mutateMock = vi.fn();
let onSuccessCallback: (() => void) | undefined;

mockUseK8sWatchResource.mockImplementation(loadedResourceMock('network-observer'));
mockUseMutationImpl.mockImplementation(({ onSuccess }) => {
onSuccessCallback = onSuccess;

return { ...defaultMutationMock, mutate: mutateMock };
});

render(<DeploymentNetworkConsoleButton />);
fireEvent.click(screen.getByText(BUTTON_LABELS.delete));
expect(mutateMock).toHaveBeenCalled();

onSuccessCallback?.();
});

it('updates URL when route data changes', () => {
mockUseK8sWatchResource.mockImplementation(loadedResourceMock('network-observer'));
mockUseMutationImpl.mockReturnValue(defaultMutationMock);

render(<DeploymentNetworkConsoleButton />);
expect(screen.getByText(BUTTON_LABELS.open)).toBeInTheDocument();
});
});
72 changes: 72 additions & 0 deletions __tests__/LinkFormHowTo.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { render, screen } from '@testing-library/react';
import { describe, it, expect, vi } from 'vitest';

import { HowToPage } from '../src/console/pages/components/forms/LinkForm/HowToPage';

vi.mock('../src/console/assets/step1.png', () => ({ default: 'step1.png' }));
vi.mock('../src/console/assets/step2.png', () => ({ default: 'step2.png' }));
vi.mock('../src/console/assets/step3.png', () => ({ default: 'step3.png' }));
vi.mock('../src/console/assets/step4.png', () => ({ default: 'step4.png' }));

vi.mock('../src/console/core/components/InstructionBlock', () => ({
default: ({
title,
description,
link1,
link1Text,
link2,
link2Text
}: {
title: string;
description: string;
link1?: string;
link1Text?: string;
link2?: string;
link2Text?: string;
}) => (
<div data-testid="instruction-block">
<h2>{title}</h2>
<p>{description}</p>
{link1 && <a href={link1}>{link1Text}</a>}
{link2 && <a href={link2}>{link2Text}</a>}
</div>
)
}));

describe('HowToPage', () => {
it('renders all instruction blocks', () => {
render(<HowToPage />);
const blocks = screen.getAllByTestId('instruction-block');
expect(blocks).toHaveLength(4);
});

it('displays correct step titles', () => {
render(<HowToPage />);

expect(screen.getByText('Step 1 - Visit a remote site')).toBeInTheDocument();
expect(screen.getByText('Step 2 - Generate a grant from the remote site')).toBeInTheDocument();
expect(screen.getByText('Step 3 - Download the grant file')).toBeInTheDocument();
expect(screen.getByText('Step 4 - Use the grant to create a link')).toBeInTheDocument();
});

it('displays step descriptions', () => {
render(<HowToPage />);

expect(screen.getByText('Open a new browser window or tab and visit the remote site.')).toBeInTheDocument();
expect(screen.getByText('Generate the grant with the web console or the CLI.')).toBeInTheDocument();
expect(screen.getByText('Download the grant file from the remote site after generating it.')).toBeInTheDocument();
expect(
screen.getByText('Use the grant to create a link from the local site to the remote site.')
).toBeInTheDocument();
});

it('includes documentation links in step 2', () => {
render(<HowToPage />);

const cliLink = screen.getByText('More information CLI');
const tokenLink = screen.getByText('More information on token creation');

expect(cliLink).toHaveAttribute('href', 'https://skupper.io/docs/cli/index.html');
expect(tokenLink).toHaveAttribute('href', 'https://skupper.io/docs/cli/tokens.html');
});
});
88 changes: 88 additions & 0 deletions __tests__/LinkFormPage.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { render, screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, it, expect, vi, beforeEach } from 'vitest';

import { FormPage } from '../src/console/pages/components/forms/LinkForm/FormPage';

const mockDispatch = vi.hoisted(() => vi.fn());

vi.mock('../src/console/pages/components/forms/LinkForm/hooks/useLinkForm', () => ({
useLinkForm: () => ({
state: {
name: '',
fileName: '',
cost: '',
file: ''
},
dispatch: mockDispatch
})
}));

describe('FormPage', () => {
beforeEach(() => {
vi.clearAllMocks();
});

it('renders all form fields', () => {
render(<FormPage />);
expect(screen.getByText('Token')).toBeInTheDocument();
expect(screen.getByText('Name')).toBeInTheDocument();
expect(screen.getByText('Cost')).toBeInTheDocument();
expect(screen.getByText('Upload')).toBeInTheDocument();
});

it('handles file upload selection', async () => {
render(<FormPage />);

const file = new File(['content'], 'test.yaml', { type: 'text/yaml' });
const fileUpload = screen.getByTestId('access-token-file');

const fileInputChangeHandler = fileUpload.querySelector('input[type="file"]') as HTMLElement;
if (fileInputChangeHandler) {
await userEvent.upload(fileInputChangeHandler, file);
}

expect(mockDispatch).toHaveBeenCalledWith({
type: 'SET_FILE_NAME',
payload: 'test'
});
});

it('handles name input change', () => {
render(<FormPage />);
const nameInput = screen.getByTestId('simple-form-name-01');

fireEvent.change(nameInput, { target: { value: 'test-name' } });

expect(mockDispatch).toHaveBeenCalledWith({
type: 'SET_NAME',
payload: 'test-name'
});
});

it('handles cost input change', () => {
render(<FormPage />);
const costInput = screen.getByTestId('form-cost');

fireEvent.change(costInput, { target: { value: '100' } });

expect(mockDispatch).toHaveBeenCalledWith({
type: 'SET_COST',
payload: '100'
});
});

it('shows file upload placeholder text', () => {
render(<FormPage />);
expect(screen.getByPlaceholderText('Drag and drop a file or upload one')).toBeInTheDocument();
});

it('validates required fields', () => {
render(<FormPage />);
const nameInput = screen.getByTestId('simple-form-name-01');
const costInput = screen.getByTestId('form-cost');

expect(nameInput).toBeRequired();
expect(costInput).toBeRequired();
});
});
Loading

0 comments on commit 018f2c7

Please sign in to comment.