--- applyTo: '**/*.spec.js,**/*.test.js' --- # JavaScript Unit Test Instructions (Quick Reference) ## Summary Table | Area | Key Rules/Practices | |----------------|-----------------------------------------------------| | Vue Components | Use `mountCompositionAPIComponent`, translations, a11y, group tests | | Utilities | Table-driven, pure, stateless, edge/error cases | | Stores | Mock APIs, test actions/mutations/getters | | General | Arrange-Act-Assert, descriptive names, linting | --- ## 1. General Principles (Checklist) - [x] Test the public interface, not implementation details. - [x] Use Arrange-Act-Assert structure in each test. - [x] Use descriptive names for tests (start with 'should...'). - [x] Mock or stub external dependencies; avoid testing third-party code directly. - [x] Always test edge and error conditions. - [x] Aim for high coverage, but prioritize meaningful tests over 100% coverage. - [x] Remove or refactor brittle tests tightly coupled to implementation. - [x] Use linting and formatting for test files. - [x] Document complex test logic with comments. - [x] Prefer pure functions and stateless modules for easier testing. - [x] Use path aliases from `moduleNameMapper` for all imports. - [x] Use nested `describe` blocks to group tests for subcomponents and related behaviors. - [x] Use `beforeAll`/`beforeEach` for setup at appropriate scopes. - [x] Add comments or TODOs for incomplete, brittle, or future test cases. - [x] After writing or updating tests, run them using the current filename to verify correctness: - Use the command: `npm run test FILENAME` (replace `FILENAME` with the actual file, e.g., `npm run test MyComponent.spec.js`). --- ## 2. Forbidden Patterns (Checklist) - [ ] Use of `mount` or `shallowMount` directly (always use `mountCompositionAPIComponent`) - [ ] Hard-coded translations (always use `getTranslation`) - [ ] Direct DOM manipulation - [ ] Skipping edge/error cases - [ ] Not testing accessibility for UI components --- ## 3. Vue Components - [x] Use [Vue Test Utils](https://vue-test-utils.vuejs.org/) and Jest or Vitest. - [x] Use `mountCompositionAPIComponent` from `@@/store-config` for mounting. - [x] Use `getTranslation` for translation assertions. - [x] Simulate user interactions and assert DOM/events. Prefer simulating user events (emit, click, etc.) over direct state mutation. - [x] Use `await`/`nextTick` for DOM updates after events. - [x] Assert on both UI and state after interactions. - [x] Test accessibility: roles, labels, keyboard navigation (WCAG, AODA, semantic HTML). Require at least one explicit accessibility test per UI component. - [x] Use path aliases from `moduleNameMapper` for imports. - [x] Always use `beforeAll` to set up the component under test. - [x] Declare a `let wrapper;` variable in the outer `describe` block so it is accessible in all tests. - [x] Test with different props, slots, and edge-case data. - [x] Mock stores, router, and APIs as needed. - [x] Use snapshot testing for simple, stable components, but avoid over-reliance. - [x] Explicitly test i18n/translation for all user-facing text. - [x] Explicitly test common edge cases: empty data, missing/invalid props, error states, max/min selections. - [x] Always mock browser APIs (e.g., canvas, ResizeObserver) if the component or its children use them. - [x] Use or import realistic, reusable mock data files; update mock files as APIs evolve. Add TODOs if mock data is incomplete. **Example:** ```javascript import { mountCompositionAPIComponent, getTranslation } from '@@/store-config'; import MyButton from '@/components/MyButton.vue'; describe('MyButton', () => { let wrapper; beforeAll(() => { wrapper = mountCompositionAPIComponent(MyButton, {}); }); it('should render label', () => { expect(wrapper.text()).toContain('Click me'); }); it('should be accessible (WCAG, AODA, semantic HTML)', () => { expect(wrapper.attributes('role')).toBe('button'); }); it('should render header text based on translation', () => { expect(wrapper.find('.header').text()).toBe(getTranslation('en', 'webComponents.marketResearch.marketSnapshot.marketMovers.subheader')); }); // TODO: Add tests for error state when API changes }); ``` --- ## 4. Utility Files (Helpers, Formatters, etc.) - [x] Test all input/output combinations, including edge and invalid cases. - [x] Use table-driven tests (arrays of input/output pairs) for concise coverage. - [x] Ensure utilities are stateless and have no side effects. - [x] Test error handling for invalid inputs. - [x] Prefer pure functions for easier testing and predictability. **Example:** ```javascript import { formatDate } from '../formatDate'; describe('formatDate', () => { it.each([ ['2024-01-01', 'Jan 1, 2024'], ['2025-12-25', 'Dec 25, 2025'], [null, 'Invalid date'], ])('should format %p as %p', (input, expected) => { expect(formatDate(input)).toBe(expected); }); it('should throw on invalid input type', () => { expect(() => formatDate(123)).toThrow(); }); }); ``` --- ## 5. Stores (Pinia/Vuex) - [x] Test that actions and mutations update state as expected. - [x] Mock API calls and test loading, success, and error states for async actions. - [x] Test getters for various state scenarios. - [x] Isolate store state between tests using setup/teardown hooks. - [x] Test error handling for failed actions or invalid mutations. **Example:** ```javascript import { setActivePinia, createPinia } from 'pinia'; import { useUserStore } from '../userStore'; describe('userStore', () => { beforeEach(() => { setActivePinia(createPinia()); }); it('should set user on login when username and password are provided', async () => { const store = useUserStore(); await store.login({ username: 'test', password: 'pass' }); expect(store.user).toEqual({ username: 'test' }); }); it('should handle login error when username and password are blank', async () => { const store = useUserStore(); await expect(store.login({ username: '', password: '' })).rejects.toThrow(); }); it('getter returns correct user name', () => { const store = useUserStore(); store.user = { username: 'alice' }; expect(store.userName).toBe('alice'); }); }); ``` --- ## 6. Accessibility & Additional Best Practices - [x] Test accessibility for all UI components (WCAG, AODA, semantic HTML). Require at least one explicit accessibility test per UI component. - [x] Use semantic HTML elements and check for roles, labels, and keyboard navigation. - [x] Write code that is easily testable with unit tests. - [x] Avoid magic numbers; use named constants. - [x] Remove dead or unused code. - [x] Use ES module syntax for imports/exports. - [x] Document public APIs and exported functions with JSDoc or comments. - [x] Add comments/TODOs for incomplete, brittle, or complex test logic. --- ## 7. Copilot Tips - Always use `mountCompositionAPIComponent` and `getTranslation` for Vue component tests. - Always use path aliases from `moduleNameMapper` for imports. - Always test accessibility for UI components. - Always test edge and error cases, including empty data, missing/invalid props, error states, and max/min selections. - Always mock browser APIs (e.g., canvas, ResizeObserver) if the component or its children use them. - Use or import realistic, reusable mock data files; update mock files as APIs evolve. Add TODOs if mock data is incomplete. - Use nested `describe` blocks to group tests for subcomponents and related behaviors. - Prefer simulating user interactions/events (emit, click) over direct state mutation. Use `await`/`nextTick` for DOM updates. - Assert on both UI and state after interactions. - Add comments/TODOs for incomplete, brittle, or complex test logic. - Never use forbidden patterns listed above. ---