Overview
Proton WebClients uses Jest as the primary testing framework for applications and packages. Some packages also use Vitest, Karma, or Playwright for specific testing needs.
Test Frameworks
Jest Primary testing framework for most applications and packages
Vitest Used by select packages (e.g., @proton/wallet, @proton/meet)
Karma Legacy test runner used by @proton/shared
Running Tests
Single Application Tests
yarn workspace proton-mail test
With coverage: yarn workspace proton-mail test:coverage
Watch mode: yarn workspace proton-mail test:watch
yarn workspace proton-drive test
CI mode: yarn workspace proton-drive test:ci
Watch mode: yarn workspace proton-drive test:watch
# UTC timezone required for calendar tests
yarn workspace proton-calendar test
The script automatically sets TZ=UTC: yarn workspace proton-pass test
CI mode: yarn workspace proton-pass test:ci
Watch mode: yarn workspace proton-pass test:watch
Package Tests
Components
Shared (Karma)
Wallet (Vitest)
Utils
yarn workspace @proton/components test
Run All Tests
Run tests across all workspaces:
yarn workspaces foreach run test
This may take significant time and resources. Consider using CI mode with parallel execution.
Test Scripts Reference
Standard Jest Scripts
Most applications follow these script conventions:
Script Description Command testRun all tests jesttest:ciCI test run with coverage jest --ci --coverage --runInBandtest:watchWatch mode jest --watch --coverage=falsetest:coverageGenerate coverage report jest --collectCoverage
Application-Specific Test Scripts
{
"scripts" : {
"test" : "jest --logHeapUsage --forceExit" ,
"test:ci" : "jest --coverage --runInBand --ci --forceExit" ,
"test:coverage" : "jest --collectCoverage" ,
"test:watch" : "jest --watch --coverage=false"
}
}
Mail tests use --forceExit to ensure process termination and --logHeapUsage for memory monitoring.
{
"scripts" : {
"test" : "jest" ,
"test:ci" : "jest --coverage=false --runInBand --ci" ,
"test:watch" : "jest --watch --coverage=false"
}
}
{
"scripts" : {
"test" : "cross-env TZ=UTC jest" ,
"test:ci" : "yarn run test --ci --coverage --runInBand" ,
"test:watch" : "yarn run test --coverage=false --watch"
}
}
Calendar tests require UTC timezone to ensure consistent date/time behavior.
{
"scripts" : {
"test" : "jest" ,
"test:ci" : "jest --coverage --runInBand --ci --logHeapUsage" ,
"test:watch" : "jest --watch"
}
}
{
"scripts" : {
"test" : "NODE_ENV=test karma start test/karma.conf.js" ,
"test:ci" : "yarn test" ,
"test:watch" : "npm test -- --auto-watch --no-single-run"
}
}
The @proton/shared package uses Karma for historical reasons. New tests should prefer Jest.
Jest Configuration
Standard Jest Configuration
Example from applications/mail/jest.config.js:
module . exports = {
setupFilesAfterEnv: [ './jest.setup.js' ],
moduleDirectories: [ '<rootDir>/node_modules' , 'node_modules' ],
collectCoverage: true ,
collectCoverageFrom: [
'src/**/*.{js,jsx,ts,tsx}' ,
'!<rootDir>/src/app/locales.ts' ,
'!<rootDir>/src/app/*.{js,jsx,ts,tsx}' ,
],
testEnvironment: '@proton/jest-env' ,
transformIgnorePatterns: [
'node_modules/(?!(@proton/shared|@proton/components|pmcrypto|openpgp)/)' ,
],
transform: {
'^.+ \\ .(m?js|tsx?)$' : '<rootDir>/jest.transform.js' ,
},
moduleNameMapper: {
' \\ .(css|scss|less)$' : '@proton/components/__mocks__/styleMock.js' ,
' \\ .(jpg|jpeg|png|gif|svg|ttf|woff|woff2)$' : '@proton/components/__mocks__/fileMock.js' ,
},
coverageReporters: [ 'text-summary' , 'json' ],
reporters: [ 'default' , [ 'jest-junit' , {
suiteNameTemplate: '{filepath}' ,
outputName: 'test-report.xml'
}]],
};
Key Configuration Elements
testEnvironment
string
default: "@proton/jest-env"
Custom Jest environment package providing browser-like globals
Excludes node_modules except specified packages that need transformation
Maps static assets to mocks for testing
Specifies coverage report formats (text-summary, json, html, etc.)
Test Environment
@proton/jest-env
Custom Jest environment package used across applications:
testEnvironment : '@proton/jest-env'
Provides:
Browser-like globals (window, document, etc.)
DOM manipulation capabilities
JSDOM environment setup
Testing Libraries
Common testing dependencies:
@testing-library/react React component testing utilities
@testing-library/jest-dom Custom Jest matchers for DOM assertions
@testing-library/user-event User interaction simulation
@proton/testing Proton-specific testing utilities
Coverage Reports
Generating Coverage
Single Application
CI Mode
yarn workspace proton-mail test:coverage
Coverage output:
Console summary
coverage/ directory with detailed reports
coverage/lcov-report/index.html for browser viewing
yarn workspace proton-mail test:ci
Generates:
Coverage reports in coverage/
JUnit XML report: test-report.xml
Coverage Configuration
Configure coverage collection:
{
collectCoverage : true ,
collectCoverageFrom : [
'src/**/*.{js,jsx,ts,tsx}' ,
'!**/*.test.{js,jsx,ts,tsx}' ,
'!**/node_modules/**' ,
],
coverageThresholds : {
global : {
branches : 50 ,
functions : 50 ,
lines : 50 ,
statements : 50 ,
},
},
}
CI Testing
Turbo Configuration
Tests run through Turbo with dependency orchestration:
{
"tasks" : {
"test:ci" : {
"dependsOn" : [ "transit" ]
},
"test:coverage" : {
"outputs" : [ "coverage/**" ]
}
}
}
Running Tests in CI
# Run CI tests for all workspaces
yarn workspaces foreach run test:ci
# Run with Turbo for caching and orchestration
turbo run test:ci
Turbo caches test results. Only changed workspaces re-run tests.
Special Test Configurations
Playwright (Storybook)
yarn workspace @proton/storybook test
Configuration: applications/storybook/playwright.config.ts
Vitest Examples
yarn workspace @proton/wallet test
Configuration files: vitest.config.ts in respective packages
Debugging Tests
Run Specific Test File
yarn workspace proton-mail test path/to/test-file.test.ts
Debug in VS Code
Add to .vscode/launch.json:
{
"type" : "node" ,
"request" : "launch" ,
"name" : "Jest Debug" ,
"program" : "${workspaceFolder}/node_modules/.bin/jest" ,
"args" : [ "--runInBand" , "${file}" ],
"console" : "integratedTerminal" ,
"internalConsoleOptions" : "neverOpen"
}
Verbose Output
yarn workspace proton-mail test --verbose
Best Practices
Run Tests Locally
Always run tests before committing: yarn workspace < app-nam e > test
Watch Mode During Development
Use watch mode for faster feedback: yarn workspace < app-nam e > test:watch
Check Coverage
Maintain reasonable coverage levels: yarn workspace < app-nam e > test:coverage
Fix Failing Tests
Never commit with failing tests. Debug and fix before pushing.
Troubleshooting
Increase Jest timeout: jest . setTimeout ( 10000 ); // 10 seconds
Or for specific test: test ( 'long running test' , async () => {
// test code
}, 10000 );
Use --runInBand to run tests serially: yarn workspace proton-mail test --runInBand
Or increase Node memory: export NODE_OPTIONS = "--max-old-space-size=4096"
Verify moduleNameMapper includes necessary mappings: moduleNameMapper : {
'^@/(.*)$' : '<rootDir>/src/$1' ,
}
Some tests may depend on specific environment variables or external services. Check test setup files for requirements.