一键导入
test-frontend-unit
// Generates frontend unit tests for PwnDoc using Vitest and Vue Test Utils. Handles services (axios mock), components (mount with Quasar), pages (full setup), and Pinia stores. Run with ./pwndoc-cli test --frontend-unit.
// Generates frontend unit tests for PwnDoc using Vitest and Vue Test Utils. Handles services (axios mock), components (mount with Quasar), pages (full setup), and Pinia stores. Run with ./pwndoc-cli test --frontend-unit.
Generates backend API integration tests for PwnDoc using Jest and supertest. Tests run against an ephemeral MongoDB instance via ./pwndoc-cli test --backend.
Generates Playwright E2E specs for PwnDoc. Tests run against the full stack (frontend + backend + MongoDB) with pre-authenticated browser sessions. Run with ./pwndoc-cli test --frontend-e2e.
Test orchestrator for PwnDoc. Analyzes a feature or the full project to determine test gaps across backend (Jest), frontend unit (Vitest), and frontend E2E (Playwright), then delegates to /test-backend, /test-frontend-unit, and /test-frontend-e2e skills.
| name | test-frontend-unit |
| description | Generates frontend unit tests for PwnDoc using Vitest and Vue Test Utils. Handles services (axios mock), components (mount with Quasar), pages (full setup), and Pinia stores. Run with ./pwndoc-cli test --frontend-unit. |
| context | fork |
| agent | general-purpose |
| allowed-tools | ["Bash","Glob","Grep","Read","Write","Edit"] |
| argument-hint | [type:name] e.g. service:audit, component:breadcrumb, page:profile, store:index |
You generate frontend unit tests for PwnDoc using Vitest + Vue Test Utils + Quasar.
$ARGUMENTS - Format: {type}:{name} where type is one of: service, component, page, store.
Examples:
service:audit - test frontend/src/services/audit.jscomponent:breadcrumb - test frontend/src/components/breadcrumb.vuepage:profile - test pages in frontend/src/pages/profile/store:index - test frontend/src/stores/index.jsIf $ARGUMENTS is "all" or "gaps", scan for all untested files and generate tests for each.
If $ARGUMENTS starts with --fix, the format is:
--fix {test-file} "{failure summary}" [--no-run]
Example: --fix frontend/tests/unit/services/audit.test.js "TypeError: Cannot read properties of undefined (reading 'get')" --no-run
In fix mode:
--no-run is present, STOP — do not run tests. Otherwise proceed to Step 3 (Run and Fix)Before writing any tests, ALWAYS read:
frontend/tests/unit/utils/test-utils.js and frontend/tests/unit/setup.jsfrontend/tests/unit/services/user.test.jsfrontend/tests/unit/components/audit-state-icon.test.jsfrontend/tests/unit/pages/login.test.jsfrontend/tests/unit/stores/user.test.jsfrontend/tests/unit/services/{name}.test.jsfrontend/tests/unit/components/{name}.test.jsfrontend/tests/unit/pages/{name}.test.jsfrontend/tests/unit/stores/{name}.test.jsService tests mock boot/axios and verify each method calls the correct API endpoint.
import { describe, it, expect, beforeEach, vi } from 'vitest'
// Mock axios BEFORE importing the service
vi.mock('boot/axios', () => ({
api: {
get: vi.fn(),
post: vi.fn(),
put: vi.fn(),
delete: vi.fn()
}
}))
import { api } from 'boot/axios'
import ServiceUnderTest from '@/services/{name}'
describe('{Name}Service', () => {
beforeEach(() => {
vi.clearAllMocks()
})
describe('{methodName}', () => {
it('should call the correct API endpoint', async () => {
const mockResponse = { data: { datas: [/* mock data */] } }
api.get.mockResolvedValue(mockResponse)
const result = await ServiceUnderTest.{methodName}()
expect(api.get).toHaveBeenCalledWith('{endpoint}')
expect(result).toEqual(mockResponse)
})
})
// One describe block per public method
})
vi from vitest, NOT from jestvi.mock('boot/axios', ...) BEFORE importing the servicedescribe blockdocument (like backup.downloadBackup), add DOM mocksvi.doMock + vi.resetModules pattern from services/user.test.jsSee template-service-test.md for a complete scaffold.
Component tests use createTestWrapper from test-utils:
import { describe, it, expect } from 'vitest'
import { createTestWrapper } from '../utils/test-utils'
import MyComponent from '@/components/{name}.vue'
describe('{Name} Component', () => {
const defaultProps = { /* required props */ }
const createWrapper = (overrides = {}) => {
return createTestWrapper(MyComponent, {
props: { ...defaultProps, ...overrides.props },
global: {
mocks: {
$settings: { /* mock settings if needed */ },
...(overrides.mocks || {})
}
}
})
}
it('should render', () => {
const wrapper = createWrapper()
expect(wrapper.exists()).toBe(true)
})
// Test computed properties via wrapper.vm.{prop}
// Test emitted events via wrapper.emitted()
// Test rendered content via wrapper.text() or wrapper.find()
})
createTestWrapper for components needing Pinia/i18n/router$settings if the component accesses itSee template-component-test.md for a complete scaffold.
Pages are more complex — they interact with services and have routing:
import { describe, it, expect, beforeEach, vi } from 'vitest'
import { mount } from '@vue/test-utils'
import { createRouter, createWebHistory } from 'vue-router'
import { createPinia, setActivePinia } from 'pinia'
import { createI18n } from 'vue-i18n'
import PageComponent from '@/pages/{path}/index.vue'
// Mock services used by the page
vi.mock('@/services/{name}', () => ({
default: {
methodA: vi.fn(),
methodB: vi.fn()
}
}))
vi.mock('quasar', async () => {
const actual = await vi.importActual('quasar')
return {
...actual,
Loading: { show: vi.fn(), hide: vi.fn() }
}
})
describe('{Page} Page', () => {
let router, pinia, i18n
beforeEach(() => {
pinia = createPinia()
setActivePinia(pinia)
router = createRouter({
history: createWebHistory(),
routes: [{ path: '/{route}', component: PageComponent }]
})
i18n = createI18n({
legacy: false,
locale: 'en-US',
messages: { 'en-US': {} }
})
vi.clearAllMocks()
})
const createWrapper = (options = {}) => {
return mount(PageComponent, {
global: {
plugins: [pinia, router, i18n],
stubs: {
'q-page': true, 'q-card': true, 'q-card-section': true,
'q-input': true, 'q-btn': true, 'q-table': true,
'q-dialog': true, 'q-select': true,
...(options.stubs || {})
},
mocks: {
$t: (key) => key,
$settings: {},
...(options.mocks || {})
}
}
})
}
// Test initialization, data loading, form validation, user actions, errors
})
.js file (e.g., pages/audits/list/audits-list.js + index.vue). Read BOTH.See template-page-test.md for a complete scaffold.
import { describe, it, expect, beforeEach } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { useMyStore } from '@/stores/{name}'
describe('{Name} Store', () => {
beforeEach(() => {
setActivePinia(createPinia())
})
describe('initial state', () => {
it('should have default values', () => {
const store = useMyStore()
// Assert all initial state values
})
})
describe('actions', () => {
// Test each action
})
describe('getters', () => {
// Test each getter
})
})
See template-store-test.md for a complete scaffold.
setup.js. Do NOT re-register it in individual tests.vi.mock() at the top level, before imports of modules that depend on the mock.@/ = src/, boot/ = src/boot/, stores/ = src/stores/@quasar/quasar-app-extension-testing-unit-vitest — Quasar is set up in setup.jsvi.doMock + vi.resetModules pattern from services/user.test.jsIf $ARGUMENTS contains --no-run, STOP HERE. Do not run tests — the calling orchestrator will handle test execution. Strip --no-run from arguments before processing the type:name in earlier steps.
Otherwise, run tests with:
./pwndoc-cli test --frontend-unit
If coverage is requested, use:
./pwndoc-cli test --frontend-unit --coverage
If tests fail, read the error output, fix the test file, and re-run. Iterate until all tests pass.