Overview
Citizen uses a comprehensive testing strategy with multiple linters and test suites:- JavaScript/Vue: ESLint + Vitest
- PHP: PHPCS, Phan, PHPUnit
- Styles: Stylelint
- i18n: Banana checker
- Markdown: markdownlint
Quick Reference
Run only what’s relevant to the files you changed:| Files Changed | Command |
|---|---|
*.php | composer preflight |
*.js, *.vue | npm run lint:js then npm test |
*.less, *.css, *.vue | npm run lint:styles |
i18n/ | npm run lint:i18n |
*.md | npm run lint:md |
Node.js Testing
Running All Checks
Run all Node-based linters and tests in one command:- JavaScript linting (ESLint)
- Style linting (Stylelint)
- i18n validation (Banana checker)
- Markdown linting
- JavaScript unit tests (Vitest)
Individual Checks
JavaScript Linting
- Code quality issues
- CommonJS module syntax
- Browser compatibility (via eslint-plugin-compat)
- MediaWiki coding standards
Style Linting
- LESS/CSS syntax
- Property ordering (via stylelint-config-recess-order)
- MediaWiki style conventions
- Vue component styles
i18n Validation
- JSON syntax in
i18n/*.json - Message key consistency
- Required documentation in
qqq.json
Markdown Linting
JavaScript Unit Tests
Citizen uses Vitest for JavaScript testing:tests/vitest/.
Writing Vitest Tests
Follow the Arrange-Act-Assert pattern with blank lines separating each phase:Use
document.body.innerHTML with HTML strings for DOM fixtures rather than imperative createElement chains. This is more readable and mirrors actual markup.PHP Testing
Running All Checks
Run all PHP linters, static analysis, and tests:- Parallel lint (syntax check)
- PHPCS (code style)
- minus-x (executable bit check)
- Phan (static analysis)
- PHPUnit (unit tests)
Individual Checks
Code Style (PHPCS)
fix command runs:
minus-x fix .(fix executable bits)phpcbf(auto-fix code style)
Static Analysis (Phan)
- Type errors
- Undefined variables
- Deprecated API usage
- Security issues
Unit Tests (PHPUnit)
tests/phpunit/.
Syntax Check
Writing PHPUnit Tests
Test files go intests/phpunit/ mirroring the source structure.
PHPUnit Conventions
- Test class names match the class under test with
Testsuffix (FooTestforFoo) - Use
@coversannotation with fully qualified name - Follow Arrange-Act-Assert with blank lines
- Use native PHP types
- Use named parameters when constructing objects
Browser Testing
When testing features that require browser interaction:- Use automation tools when available (Chrome DevTools MCP, Playwright MCP)
- Test against the dev environment URL before asking for manual testing
- Always check the browser console for warnings and errors, not just visual correctness
Manual Testing Checklist
When manually testing in a browser:- Feature works as expected visually
- No JavaScript errors in console
- No console warnings
- Works in responsive layouts (mobile, tablet, desktop)
- Keyboard navigation functional
- Screen reader accessible (if applicable)
- Dark mode appearance correct
- No LESS compilation errors
Pre-commit Workflow
Citizen uses Lefthook for Git hooks:- Validates commit message format (Conventional Commits)
- Auto-adds emojis based on commit type
- Runs basic linting checks
Commit Message Format
Use Conventional Commits:Running Full Test Suite
Before submitting a pull request, run both preflight commands:Continuous Integration
GitHub Actions automatically runs tests on:- Pull requests
- Pushes to main branch
- All linters (JS, CSS, PHP, i18n, markdown)
- JavaScript tests (Vitest)
- PHP static analysis (Phan)
- PHP unit tests (PHPUnit)
Coverage
Vitest can generate coverage reports:Troubleshooting
Docker Command Fails
If composer commands fail in Docker:PHPCS Warnings Not Failing
PHPCS exits 0 even with warnings. Always read the full output:Cache Issues
ESLint and other tools use caching. If you see unexpected results:Tests Pass Locally But Fail in CI
Ensure you’ve committed all files:Next Steps
- Review Coding Conventions
- Learn about Components
- Understand the Architecture