This document explains the package.json and related configuration files needed in the main eform-angular-frontend repository to support running unit tests for the time-planning-pn plugin.
Add these dependencies and scripts to your package.json:
{
"scripts": {
"test": "ng test",
"test:ci": "ng test --no-watch --no-progress --browsers=ChromeHeadless --code-coverage"
},
"devDependencies": {
"@types/jasmine": "~5.1.0",
"jasmine-core": "~5.1.0",
"karma": "~6.4.0",
"karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0"
}
}Then run:
npm install
# or
yarn installThe zone.js import paths have changed in newer versions. Update your src/test.ts file:
Remove these old imports:
import 'zone.js/dist/long-stack-trace-zone';
import 'zone.js/dist/proxy.js';
import 'zone.js/dist/sync-test';
import 'zone.js/dist/jasmine-patch';
import 'zone.js/dist/async-test';
import 'zone.js/dist/fake-async-test';Replace with these new imports:
import 'zone.js';
import 'zone.js/testing';Complete example of src/test.ts:
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js';
import 'zone.js/testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
declare const require: {
context(path: string, deep?: boolean, filter?: RegExp): {
<T>(id: string): T;
keys(): string[];
};
};
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting(),
);
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);Add @types/jasmine to the types array:
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": [
"jasmine",
"node"
]
},
"include": [
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}Ensure your karma.conf.js includes the coverage reporter:
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
jasmine: {
// you can add configuration options for Jasmine here
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
// for example, you can disable the random execution with `random: false`
// or set a specific seed with `seed: 4321`
},
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
jasmineHtmlReporter: {
suppressAll: true // removes the duplicated traces
},
coverageReporter: {
dir: require('path').join(__dirname, './coverage'),
subdir: '.',
reporters: [
{ type: 'html' },
{ type: 'text-summary' },
{ type: 'lcovonly' }
]
},
reporters: ['progress', 'kjhtml'],
browsers: ['Chrome'],
customLaunchers: {
ChromeHeadless: {
base: 'Chrome',
flags: [
'--headless',
'--disable-gpu',
'--no-sandbox',
'--remote-debugging-port=9222'
]
}
},
restartOnFileChange: true
});
};The GitHub Actions workflows will try to run tests using one of these approaches (in order):
If your package.json has a test:ci script, it will use that:
{
"scripts": {
"test:ci": "ng test --no-watch --no-progress --browsers=ChromeHeadless --code-coverage"
}
}If test:ci is not available, it will try to use the test script with additional parameters:
{
"scripts": {
"test": "ng test"
}
}The workflow will add --watch=false --browsers=ChromeHeadless automatically.
Error message:
Error: Cannot find module 'karma'
Cause: The frontend repository doesn't have Karma installed, which is required for running Angular unit tests with ng test.
Solution: Add Karma and related dependencies to the frontend's package.json (see section 1 above).
Note: The GitHub Actions workflow will now detect if Karma is missing and skip the tests gracefully with a helpful message instead of failing.
Error message:
ERROR [reporter]: Can not load reporter "coverage", it is not registered!
Cause: The karma-coverage package is not installed or not properly configured in karma.conf.js.
Solution:
- Install
karma-coverage:npm install --save-dev karma-coverage - Add it to the plugins array in karma.conf.js (see section 4 above)
- Configure the coverageReporter in karma.conf.js (see section 4 above)
Error messages:
Error: Module not found: Error: Package path ./dist/long-stack-trace-zone is not exported
Error: Module not found: Error: Package path ./dist/proxy.js is not exported
Error: Module not found: Error: Package path ./dist/sync-test is not exported
Error: Module not found: Error: Package path ./dist/jasmine-patch is not exported
Error: Module not found: Error: Package path ./dist/async-test is not exported
Error: Module not found: Error: Package path ./dist/fake-async-test is not exported
Cause: Zone.js v0.12.0+ changed its module exports. The old import paths no longer work.
Solution: Update src/test.ts to use the new import paths (see section 2 above):
// Remove old imports:
// import 'zone.js/dist/long-stack-trace-zone';
// import 'zone.js/dist/proxy.js';
// etc...
// Use new imports:
import 'zone.js';
import 'zone.js/testing';Error messages:
error TS2593: Cannot find name 'describe'
error TS2304: Cannot find name 'beforeEach'
error TS2304: Cannot find name 'it'
error TS2304: Cannot find name 'expect'
Cause: TypeScript can't find the Jasmine type definitions.
Solution:
- Install
@types/jasmine:npm install --save-dev @types/jasmine - Update
tsconfig.spec.jsonto include jasmine in the types array (see section 3 above)
If you're using Karma with Jasmine, the --include parameter might not work. Instead, you can:
Solution A: Use a karma.conf.js configuration that supports file filtering:
// karma.conf.js
module.exports = function(config) {
config.set({
// ... other config
files: [
{ pattern: './src/**/*.spec.ts', included: true, watched: true }
],
});
};Solution B: Update package.json to support include patterns:
{
"scripts": {
"test:ci": "ng test --no-watch --no-progress --browsers=ChromeHeadless --code-coverage",
"test:plugin": "ng test --no-watch --browsers=ChromeHeadless --include='**/time-planning-pn/**/*.spec.ts'"
}
}If ChromeHeadless browser is not configured:
Solution: Configure Chrome headless in karma.conf.js (see section 4 above for the customLaunchers configuration).
For Angular 15+, you might need to use the new test configuration:
{
"scripts": {
"test": "ng test",
"test:ci": "ng test --no-watch --no-progress --browsers=ChromeHeadless --code-coverage"
}
}If your project uses Jest instead of Karma:
{
"scripts": {
"test": "jest",
"test:ci": "jest --ci --coverage --testPathPattern='time-planning-pn'"
}
}To enable unit tests in the frontend repository, complete these steps:
- Add dependencies to package.json (karma, jasmine, etc.)
- Run
npm installoryarn install - Update
src/test.tswith new zone.js imports - Update
tsconfig.spec.jsonto include jasmine types - Update
karma.conf.jswith coverage reporter configuration - Add
test:ciscript to package.json - Test locally:
npm run test:ci
For the most compatibility with the time-planning-pn plugin tests, use this configuration:
{
"scripts": {
"test": "ng test",
"test:ci": "ng test --no-watch --no-progress --browsers=ChromeHeadless --code-coverage",
"test:headless": "ng test --no-watch --browsers=ChromeHeadless"
},
"devDependencies": {
"@angular-devkit/build-angular": "^15.0.0",
"@types/jasmine": "~5.1.0",
"jasmine-core": "~5.1.0",
"karma": "~6.4.0",
"karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0"
}
}The GitHub Actions workflow (.github/workflows/dotnet-core-master.yml and dotnet-core-pr.yml) will:
- Check if Karma is installed in node_modules
- If not, skip tests with a helpful message
- If yes, check if
test:ciscript exists in package.json - If yes, run:
npm run test:ci -- --include='**/time-planning-pn/**/*.spec.ts' - If no, check if
testscript exists - If yes, run:
npm run test -- --watch=false --browsers=ChromeHeadless --include='**/time-planning-pn/**/*.spec.ts' - If neither exists, skip the tests with a message
- The step has
continue-on-error: true, so it won't fail the entire workflow
To test if your configuration works:
# Clone both repositories
git clone https://github.com/microting/eform-angular-frontend.git
git clone https://github.com/microting/eform-angular-timeplanning-plugin.git
# Copy plugin files
cp -r eform-angular-timeplanning-plugin/eform-client/src/app/plugins/modules/time-planning-pn \
eform-angular-frontend/eform-client/src/app/plugins/modules/
# Install dependencies
cd eform-angular-frontend/eform-client
npm install
# Try running tests
npm run test:ci -- --include='**/time-planning-pn/**/*.spec.ts'
# or
npm run test -- --watch=false --browsers=ChromeHeadlessIf you need help configuring the tests, check:
- Angular CLI testing documentation: https://angular.io/guide/testing
- Karma configuration: https://karma-runner.github.io/latest/config/configuration-file.html
- The test files in this repository for examples
If you're using Karma with Jasmine, the --include parameter might not work. Instead, you can:
Solution A: Use a karma.conf.js configuration that supports file filtering:
// karma.conf.js
module.exports = function(config) {
config.set({
// ... other config
files: [
{ pattern: './src/**/*.spec.ts', included: true, watched: true }
],
});
};Solution B: Update package.json to support include patterns:
{
"scripts": {
"test:ci": "ng test --watch=false --code-coverage --browsers=ChromeHeadless",
"test:plugin": "ng test --watch=false --browsers=ChromeHeadless --include='**/time-planning-pn/**/*.spec.ts'"
}
}If ChromeHeadless browser is not configured:
Solution: Install and configure Chrome headless in karma.conf.js:
// karma.conf.js
module.exports = function(config) {
config.set({
browsers: ['ChromeHeadless'],
customLaunchers: {
ChromeHeadlessCI: {
base: 'ChromeHeadless',
flags: ['--no-sandbox', '--disable-gpu']
}
}
});
};Then update package.json:
{
"scripts": {
"test:ci": "ng test --watch=false --browsers=ChromeHeadlessCI"
}
}For Angular 15+, you might need to use the new test configuration:
{
"scripts": {
"test": "ng test",
"test:ci": "ng test --no-watch --no-progress --browsers=ChromeHeadless --code-coverage"
}
}If your project uses Jest instead of Karma:
{
"scripts": {
"test": "jest",
"test:ci": "jest --ci --coverage --testPathPattern='time-planning-pn'"
}
}For the most compatibility with the time-planning-pn plugin tests, use this configuration:
{
"scripts": {
"test": "ng test",
"test:ci": "ng test --no-watch --no-progress --browsers=ChromeHeadless --code-coverage",
"test:headless": "ng test --no-watch --browsers=ChromeHeadless"
},
"devDependencies": {
"@angular-devkit/build-angular": "^15.0.0",
"karma": "~6.4.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.0.0"
}
}The GitHub Actions workflow (.github/workflows/dotnet-core-master.yml and dotnet-core-pr.yml) will:
- Check if
test:ciscript exists in package.json - If yes, run:
npm run test:ci -- --include='**/time-planning-pn/**/*.spec.ts' - If no, check if
testscript exists - If yes, run:
npm run test -- --watch=false --browsers=ChromeHeadless --include='**/time-planning-pn/**/*.spec.ts' - If neither exists, skip the tests with a message
- The step has
continue-on-error: true, so it won't fail the entire workflow
To test if your configuration works:
# Clone both repositories
git clone https://github.com/microting/eform-angular-frontend.git
git clone https://github.com/microting/eform-angular-timeplanning-plugin.git
# Copy plugin files
cp -r eform-angular-timeplanning-plugin/eform-client/src/app/plugins/modules/time-planning-pn \
eform-angular-frontend/eform-client/src/app/plugins/modules/
# Install dependencies
cd eform-angular-frontend/eform-client
npm install
# Try running tests
npm run test:ci -- --include='**/time-planning-pn/**/*.spec.ts'
# or
npm run test -- --watch=false --browsers=ChromeHeadlessError messages:
Error: Can't resolve 'src/styles.scss' in '/path/to/eform-client'
Error: Can't resolve 'src/theme.scss' in '/path/to/eform-client'
ERROR [karma-server]: Error: Found 1 load error
Cause: The Angular configuration references style files that don't exist or aren't needed for running tests. This typically happens when angular.json specifies global styles that aren't present in the repository.
Solution - Option A: Create Placeholder Files (Quick Fix)
If these files are referenced but not needed for tests, create empty placeholders:
cd eform-client
touch src/styles.scss
touch src/theme.scssSolution - Option B: Update angular.json (Recommended)
Modify the test configuration in angular.json to exclude missing style files:
{
"projects": {
"your-project-name": {
"architect": {
"test": {
"options": {
"styles": [],
"scripts": []
}
}
}
}
}
}If you have existing style files that should be included, reference only those:
{
"projects": {
"your-project-name": {
"architect": {
"test": {
"options": {
"styles": [
"src/styles.css" // Only include files that exist
],
"scripts": []
}
}
}
}
}
}Solution - Option C: Update karma.conf.js
Alternatively, you can configure Karma to ignore missing files by updating the preprocessors section in karma.conf.js:
module.exports = function (config) {
config.set({
// ... other config
files: [
// Only include files that exist
],
preprocessors: {
// Add preprocessors only for existing files
}
});
};Error messages:
Chrome Headless 140.0.0.0 (Linux 0.0.0) ERROR
Disconnected , because no message in 60000 ms.
Error: Process completed with exit code 1.
Cause: The browser connects but tests never execute, usually indicating:
- Compilation errors in test files preventing execution
- Missing dependencies or circular imports
- Test setup errors that halt initialization
- Memory/CPU constraints in the CI environment
Solution - Option A: Enable Verbose Logging (Recommended First Step)
To diagnose what's preventing tests from executing, enable detailed logging:
1. Update package.json:
{
"scripts": {
"test:ci": "ng test --no-watch --browsers=ChromeHeadless --code-coverage --include='**/time-planning-pn/**/*.spec.ts' --source-map"
}
}2. Update karma.conf.js:
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
captureConsole: true, // Capture all console output
clearContext: false, // Keep Jasmine Spec Runner output visible
jasmine: {
random: false // Run tests in deterministic order for debugging
}
},
jasmineHtmlReporter: {
suppressAll: false // Show all test output, not just failures
},
logLevel: config.LOG_DEBUG, // Enable detailed Karma logging
browserNoActivityTimeout: 120000, // 2 minutes to allow for debugging
browserDisconnectTimeout: 10000,
browserDisconnectTolerance: 3,
captureTimeout: 210000,
// ... rest of config
});
};What verbose logging shows:
- Which test files are being loaded
- Compilation progress and any errors
- Console output from the test runner
- Detailed timing information
- Any uncaught exceptions or initialization errors
Debugging Steps:
-
Run locally with verbose output:
cd eform-client ng test --no-watch --browsers=ChromeHeadless --source-map
-
Test a single spec file to isolate the issue:
ng test --no-watch --include='**/time-plannings-container.component.spec.ts'
-
Check for compilation errors:
- Look for TypeScript errors in the test output
- Verify all imports are correct
- Ensure all test dependencies are mocked
-
Common causes:
- Import errors: Missing or circular imports in spec files
- Missing mocks: Services/dependencies not properly mocked in TestBed
- Module configuration: Incorrect TestBed.configureTestingModule setup
- Memory issues: Too many test files loaded at once
Solution - Option B: Increase Browser Timeout
Solution - Option B: Increase Browser Timeout (If tests are just slow)
Update karma.conf.js to increase the timeout values:
module.exports = function (config) {
config.set({
// ... other config
browserNoActivityTimeout: 120000, // Increase to 2 minutes
browserDisconnectTimeout: 10000,
browserDisconnectTolerance: 3,
captureTimeout: 210000,
});
};Solution - Option C: Add Chrome Flags for CI
Solution - Option C: Add Chrome Flags for CI
Update karma.conf.js to add Chrome flags that improve performance in CI:
module.exports = function (config) {
config.set({
// ... other config
customLaunchers: {
ChromeHeadlessCI: {
base: 'ChromeHeadless',
flags: [
'--no-sandbox',
'--disable-gpu',
'--disable-dev-shm-usage',
'--disable-software-rasterizer',
'--disable-extensions',
]
}
},
browsers: ['ChromeHeadlessCI'],
browserNoActivityTimeout: 120000,
});
};Then update package.json to use this custom launcher:
{
"scripts": {
"test:ci": "ng test --no-watch --no-progress --browsers=ChromeHeadlessCI --code-coverage --include='**/time-planning-pn/**/*.spec.ts'"
}
}Solution - Option D: Optimize Test Configuration
Solution - Option D: Optimize Test Configuration
In angular.json, ensure optimization is disabled for tests:
{
"projects": {
"your-project-name": {
"architect": {
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"optimization": false,
"sourceMap": true,
"vendorChunk": true,
"buildOptimizer": false
}
}
}
}
}
}Solution - Option E: Use Single Quotes for Glob Pattern
Solution - Option E: Use Single Quotes for Glob Pattern
Make sure the test:ci script uses single quotes around the glob pattern:
{
"scripts": {
"test:ci": "ng test --no-watch --no-progress --browsers=ChromeHeadlessCI --code-coverage --include='**/time-planning-pn/**/*.spec.ts'"
}
}Combined Recommended Configuration for Debugging:
For the best results when diagnosing timeout issues, use this comprehensive karma.conf.js:
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
captureConsole: true, // Capture console output for debugging
clearContext: false, // Keep test runner output visible
jasmine: {
random: false // Deterministic test order
}
},
jasmineHtmlReporter: {
suppressAll: false // Show all output when debugging
},
coverageReporter: {
dir: require('path').join(__dirname, './coverage'),
subdir: '.',
reporters: [
{ type: 'html' },
{ type: 'text-summary' },
{ type: 'lcovonly' }
]
},
reporters: ['progress', 'kjhtml', 'coverage'],
port: 9876,
colors: true,
logLevel: config.LOG_DEBUG, // Verbose logging
autoWatch: false,
browsers: ['ChromeHeadlessCI'],
customLaunchers: {
ChromeHeadlessCI: {
base: 'ChromeHeadless',
flags: [
'--no-sandbox',
'--disable-gpu',
'--disable-dev-shm-usage',
'--disable-software-rasterizer',
'--disable-extensions',
]
}
},
singleRun: true,
restartOnFileChange: false,
browserNoActivityTimeout: 120000, // 2 minutes
browserDisconnectTimeout: 10000,
browserDisconnectTolerance: 3,
captureTimeout: 210000,
});
};This configuration provides:
- Verbose logging to see what's happening
- Extended timeouts for slow compilation
- Chrome flags optimized for CI environments
- Console capture for debugging test issues
Once you identify the issue, you can switch logLevel back to config.LOG_INFO and jasmineHtmlReporter.suppressAll to true for cleaner output.
If you need help configuring the tests, check:
- Angular CLI testing documentation: https://angular.io/guide/testing
- Karma configuration: https://karma-runner.github.io/latest/config/configuration-file.html
- The test files in this repository for examples