with one click
testing
Testing standards and conventions for this project
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
Testing standards and conventions for this project
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
Standard skills and patterns an agent should apply when working in this codebase
Read-only access to WATER project Jira tickets for task context
Expectations and rules for making git commits in this project
| name | testing |
| description | Testing standards and conventions for this project |
vitest — not Jest, Mocha, Chai, or Sinonvitest runs with globals: false, so describe, it, expect, beforeAll, afterAll, beforeEach, afterEach, and vi must always be imported explicitly from 'vitest''use strict', no require() — use importTest files do not use JSDoc or @module. The top-of-file order is imports grouped by section comment:
// Test framework
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
// Test helpers
import SomeModelHelper from '../support/helpers/some-model.helper.js'
// Things we need to stub
import * as SomeDal from '../../app/dal/some.dal.js'
// Thing under test
import SubjectUnderTest from '../../app/services/subject-under-test.service.js'
Use these section comments in order, omitting any that are not needed:
// Test framework (omit entirely when only Vitest globals are needed — i.e. no other imports)// Test helpers// Things we need to stub// Thing under test// For running our service (controller tests only — the init import used to start the Hapi server)Alphabetical ordering within each section still applies (alanisms rule 2)
The top-level describe label must reflect the file's folder path. Each path segment is title-cased and joined with -, followed by the module type:
// test/services/notices/setup/fetch-notice.service.test.js
describe('Notices - Setup - Fetch Notice service', () => {
// ...
})
beforeAll and stop it in afterAll with await server.stop()Use vi.spyOn() and vi.fn() — vitest's built-in mocking, not Sinon.
import ReturnLogModel from '../../../app/models/return-log.model.js'
vi.spyOn(ReturnLogModel, 'query').mockReturnValue({
patch: vi.fn().mockReturnThis(),
findById: vi.fn().mockResolvedValue()
})
'default' property:import * as FetchBillService from '../../../app/services/bills/fetch-bill-service.js'
vi.spyOn(FetchBillService, 'default').mockResolvedValue(billData)
vi.restoreAllMocks() in afterEach whenever stubs are usedvi.mock() or vi.doMock(). They hoist to the top of the file, auto-mock every export, and behave inconsistently between CJS and ESM — they've caused real problems in this codebase and are bannedvi.spyOn() patterns above insteadvi.spyOn(Tar, 'create') against import * as Tar from 'tar'Proxyquire instead — see test/plugins/airbrake.plugin.test.js for an example. Don't reach for vi.mock()/vi.doMock() as a workaround.toEqual(), .toBe(), etc. directly on expect()expect() — assign them to a variable first, then wrap in the array at the assertion. Always leave a blank line between the assignment and the expect():// wrong
expect(results).to.equal([SomeSeeder.transform(record)])
// right
const expectedResult = SomeSeeder.transform(record)
expect(results).toEqual([expectedResult])
For comparing objects while ignoring specific fields (e.g. timestamps), use .toMatchObject():
// Checks all testRecord properties are present in result — ignores extra fields like createdAt
expect(result).toMatchObject(testRecord)
Use the docker exec wrapper to run tests. You can pass specific files or patterns as additional arguments:
docker compose exec dev /bin/bash -c 'cd /home/repos/water-abstraction-system && npm run test -- test/services/notices/setup/my-service.test.js'
docker compose exec dev /bin/bash -c 'cd /home/repos/water-abstraction-system && npm run test -- test/services/notices/setup/foo.test.js test/services/notices/setup/bar.test.js'
Do not use npx vitest directly.
test/ mirroring the app/ structure.test.js extension (e.g. delete-session.dal.test.js)describe.only() or it.only() in committed code — CI will fail on thesedescribe blocks to group scenarios (e.g. describe('when valid', ...), describe('when invalid', ...))