Files
api/web/test/mocks/utils/examples/KeyActions.test.example.ts
Michael Datelle 0e008aaf1e test: setup initial test, config and testing libraries (#1309)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Introduced comprehensive testing utilities for Vue components
utilizing the composition API.
- Enhanced testing coverage for the `DownloadApiLogs` and `KeyActions`
components, ensuring robust functionality and user interaction
validation.
- Added mock implementations for various libraries and components to
facilitate isolated unit testing.
- Improved flexibility in the `DummyServerSwitcher` component's input
handling.
- Added a new test setup file to configure the testing environment for
Vue applications.
- Added new test files for `AuthComponent` and `KeyActions` with
comprehensive test cases.
- Introduced a new mock implementation for UI components to streamline
testing.
- Added a new mock implementation for the `useRequest` composable to
prevent hanging issues during tests.
- Added a new mock implementation for the server store used by the Auth
component.

- **Bug Fixes**
- Improved sanitization process to block inline styles for a safer and
more consistent display.

- **Documentation**
- Added README documentation for Vue Component Testing Utilities,
detailing usage and examples.
  - Updated ESLint configuration to ignore coverage directory files.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: mdatelle <mike@datelle.net>
Co-authored-by: Eli Bosley <ekbosley@gmail.com>
2025-04-03 15:50:49 -04:00

197 lines
5.6 KiB
TypeScript

/**
* Example: KeyActions component test using the component-mock utility
*
* This file shows how to implement tests for the KeyActions component using
* the createKeyActionsTest factory from key-actions-mock.ts
*/
import { ArrowTopRightOnSquareIcon } from '@heroicons/vue/24/solid';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import type { ServerStateDataAction, ServerStateDataActionType } from '~/types/server';
import { createKeyActionsTest } from './key-actions-mock';
// Sample actions for testing
const sampleActions: ServerStateDataAction[] = [
{
name: 'activate' as ServerStateDataActionType,
text: 'Action 1',
title: 'Action 1 Title',
href: '/action1',
external: true,
icon: ArrowTopRightOnSquareIcon,
click: vi.fn(),
},
{
name: 'purchase' as ServerStateDataActionType,
text: 'Action 2',
title: 'Action 2 Title',
href: '/action2',
external: false,
disabled: true,
click: vi.fn(),
},
{
name: 'upgrade' as ServerStateDataActionType,
text: 'Action 3',
href: '/action3',
icon: ArrowTopRightOnSquareIcon,
click: vi.fn(),
},
];
// Mock translation function
const tMock = (key: string) => `translated_${key}`;
describe('KeyActions', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('renders nothing when no actions are available', () => {
const wrapper = createKeyActionsTest({
storeActions: undefined,
t: tMock,
});
expect(wrapper.find('ul').exists()).toBe(false);
});
it('uses actions from store when no actions prop is provided', () => {
const wrapper = createKeyActionsTest({
storeActions: sampleActions,
t: tMock,
});
expect(wrapper.findAll('li').length).toBe(3);
expect(wrapper.find('button').text()).toContain('translated_Action 1');
});
it('uses actions from props when provided', () => {
const customActions: ServerStateDataAction[] = [
{
name: 'redeem' as ServerStateDataActionType,
text: 'Custom 1',
href: '/custom1',
click: vi.fn(),
},
];
const wrapper = createKeyActionsTest({
actions: customActions,
storeActions: sampleActions,
t: tMock,
});
expect(wrapper.findAll('li').length).toBe(1);
expect(wrapper.find('button').text()).toContain('translated_Custom 1');
});
it('filters actions by name when filterBy is provided', () => {
const wrapper = createKeyActionsTest({
storeActions: sampleActions,
filterBy: ['activate', 'upgrade'],
t: tMock,
});
expect(wrapper.findAll('li').length).toBe(2);
expect(wrapper.findAll('button')[0].text()).toContain('translated_Action 1');
expect(wrapper.findAll('button')[1].text()).toContain('translated_Action 3');
});
it('filters out actions by name when filterOut is provided', () => {
const wrapper = createKeyActionsTest({
storeActions: sampleActions,
filterOut: ['purchase'],
t: tMock,
});
expect(wrapper.findAll('li').length).toBe(2);
expect(wrapper.findAll('button')[0].text()).toContain('translated_Action 1');
expect(wrapper.findAll('button')[1].text()).toContain('translated_Action 3');
});
it('applies maxWidth class when maxWidth prop is true', () => {
const wrapper = createKeyActionsTest({
storeActions: sampleActions,
maxWidth: true,
t: tMock,
});
expect(wrapper.find('button').attributes('class')).toContain('sm:max-w-300px');
});
it('does not apply maxWidth class when maxWidth prop is false', () => {
const wrapper = createKeyActionsTest({
storeActions: sampleActions,
maxWidth: false,
t: tMock,
});
expect(wrapper.find('button').attributes('class')).not.toContain('sm:max-w-300px');
});
it('renders buttons with correct attributes', () => {
const wrapper = createKeyActionsTest({
storeActions: sampleActions,
t: tMock,
});
const buttons = wrapper.findAll('button');
// First button (action1)
expect(buttons[0].attributes('href')).toBe('/action1');
expect(buttons[0].attributes('data-external')).toBe('true');
expect(buttons[0].attributes('title')).toBe('translated_Action 1 Title');
expect(buttons[0].attributes('disabled')).toBeUndefined();
// Second button (action2)
expect(buttons[1].attributes('href')).toBe('/action2');
expect(buttons[1].attributes('data-external')).toBe('false');
expect(buttons[1].attributes('title')).toBe('translated_Action 2 Title');
expect(buttons[1].attributes('disabled')).toBe('');
// Third button (action3) - no title specified
expect(buttons[2].attributes('href')).toBe('/action3');
expect(buttons[2].attributes('title')).toBeUndefined();
});
it('handles button clicks correctly', async () => {
const wrapper = createKeyActionsTest({
storeActions: sampleActions,
t: tMock,
});
const buttons = wrapper.findAll('button');
// Click the first button
await buttons[0].trigger('click');
expect(sampleActions[0].click).toHaveBeenCalledTimes(1);
// Click the third button
await buttons[2].trigger('click');
expect(sampleActions[2].click).toHaveBeenCalledTimes(1);
});
it('handles undefined filters gracefully', () => {
const wrapper = createKeyActionsTest({
storeActions: sampleActions,
filterBy: undefined,
filterOut: undefined,
t: tMock,
});
expect(wrapper.findAll('li').length).toBe(3);
});
it('returns unfiltered actions when neither filterBy nor filterOut are provided', () => {
const wrapper = createKeyActionsTest({
storeActions: sampleActions,
t: tMock,
});
expect(wrapper.findAll('li').length).toBe(3);
});
});