I'm trying to run my angular test with jasmine+karma. When i run karma start karma.conf.js
it compile but i have a karma_error Uncaught TypeError: Cannot set properties of undefined (setting 'jasmineRequire')
on browser and my files are not seen.
Here's my karma.conf.js :
// Karma configuration
// Generated on Mon Dec 02 2024 15:28:03 GMT+0100 (Central European Standard Time)
module.exports = function(config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
frameworks: ['jasmine', 'requirejs', 'karma-typescript'],
plugins: [
require('jasmine'),
require('karma-jasmine'),
require('karma-requirejs'),
require('karma-typescript'),
require('karma-babel-preprocessor'),
require('karma-chrome-launcher'),
require('@angular-devkit/build-angular')
],
// list of files / patterns to load in the browser
files: [
'test-main.js',
{
pattern: 'src/app/**/*.ts',
type: 'module'
},
],
// list of files / patterns to exclude
exclude: [
''
],
// preprocess matching files before serving them to the browser
preprocessors: {
'**/*.ts': ['babel'],
'**/*.js': ['babel']
},
babelPreprocessor: {
// options go here
options: {
presets: [ "@babel/preset-typescript", "@babel/preset-env"],
sourceMap: "inline"
},
},
karmaTypescriptConfig: {
compilerOptions: {
emitDecoratorMetadata: true,
experimentalDecorators: true,
jsx: "react",
sourceMap: true,
moduleResolution: "node",
target: "esnext",
module: "esnext"
},
tsconfig: 'tsconfig.json',
exclude: ["node_modules"]
},
// test results reporter to use
// possible values: 'dots', 'progress'
reporters: ['progress', 'karma-typescript'],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_DEBUG,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
browsers: ['ChromeHeadless'],
customLaunchers: {
ChromeHeadless: {
base: 'Chrome',
flags: ['--no-sandbox']
}
},
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false,
// Concurrency level
// how many browser instances should be started simultaneously
concurrency: Infinity
})
}
my tsconfig.json :
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"declaration": false,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "ESNext",
"module": "ESNext",
"types": ["karma", "jasmine"],
"lib": [
"ESNext",
"dom"
]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}
my tsconfig.spec.json :
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": [
"jasmine",
"node",
"@angular/localize"
],
"target": "ESNext",
"module": "ESNext"
},
"include": [
"src/app/**/*.spec.ts",
"src/**/*.d.ts"
],
"exclude": ["node_modules"]
}
and my package.json :
{
"name": "simulator",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test",
"serve:ssr:simulator": "node dist/simulator/server/server.mjs",
"lint": "ng lint"
},
"private": true,
"dependencies": {
"@angular/animations": "^18.1.0",
"@angular/cdk": "^18.2.5",
"@angular/common": "^18.1.0",
"@angular/compiler": "^18.1.0",
"@angular/core": "^18.1.0",
"@angular/fire": "^18.0.1",
"@angular/forms": "^18.1.0",
"@angular/material": "^18.2.9",
"@angular/platform-browser": "^18.1.0",
"@angular/platform-browser-dynamic": "^18.1.0",
"@angular/platform-server": "^18.1.0",
"@angular/router": "^18.1.0",
"@angular/ssr": "^18.1.1",
"@ng-bootstrap/ng-bootstrap": "^17.0.1",
"@popperjs/core": "^2.11.8",
"bootstrap": "^5.3.2",
"express": "^4.18.2",
"firebase": "^11.0.1",
"lint": "^0.8.19",
"ngx-currency": "^18.0.0",
"rxjs": "~7.8.0",
"tslib": "^2.3.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "^18.1.1",
"@angular/cli": "^18.2.12",
"@angular/compiler-cli": "^18.1.0",
"@angular/localize": "^18.1.4",
"@babel/core": "^7.26.0",
"@babel/plugin-proposal-decorators": "^7.25.9",
"@babel/plugin-transform-typescript": "^7.25.9",
"@babel/preset-env": "^7.26.0",
"@babel/preset-typescript": "^7.26.0",
"@types/express": "^4.17.17",
"@types/jasmine": "~5.1.0",
"@types/karma": "^6.3.9",
"@types/node": "^18.18.0",
"angular-eslint": "18.4.1",
"eslint": "^9.15.0",
"jasmine": "^5.4.0",
"jasmine-core": "^5.4.0",
"karma": "~6.4.0",
"karma-babel-preprocessor": "^8.0.2",
"karma-chrome-launcher": "~3.2.0",
"karma-cli": "^2.0.0",
"karma-coverage": "~2.2.0",
"karma-jasmine": "^5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
"karma-requirejs": "^1.1.0",
"karma-typescript": "^5.5.4",
"ts-node": "^10.9.2",
"typescript": "~5.5.2",
"typescript-eslint": "8.15.0"
}
}
I retried to run karma init
to have an initial setup but my test files are not seen by karma.
I added babel as preprocessor but I have the error karma_error Uncaught TypeError: Cannot set properties of undefined (setting 'jasmineRequire')
so, I need some help to resolve this issue. Thanks
UPDATE
I installed webpack
and webpack-cli
, add a webpack.config.js
and still have an error : ERROR [karma-server]: TypeError [ERR_INVALID_ARG_TYPE]: The "data" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received undefined
the webpack.config.js :
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const isProduction = process.env.NODE_ENV == "production";
const stylesHandler = isProduction
? MiniCssExtractPlugin.loader
: "style-loader";
const config = {
entry: "./src/index.ts",
output: {
path: path.resolve(__dirname, "dist")
},
plugins: [
// Add your plugins here
],
module: {
rules: [
{
test: /\.(ts|tsx)$/i,
loader: "ts-loader",
exclude: ["/node_modules/"]
},
{
test: /\.css$/i,
use: [stylesHandler, "css-loader"]
},
{
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
type: "asset"
}
// Add your rules for custom modules here
]
},
resolve: {
extensions: [".tsx", ".ts", ".jsx", ".js", "..."]
}
};
module.exports = () => {
if (isProduction) {
config.mode = "production";
config.plugins.push(new MiniCssExtractPlugin());
} else {
config.mode = "development";
}
return config;
};
UPDATE 2
After update my karma.conf.js file like this :
preprocessors: {
'src/app/**/*.spec.ts': ['webpack'],
'src/**/*.js': ['webpack']
},
webpack preprocess test files but now I have an error related to the loader :
ERROR in ./src/app/app.component.spec.ts 17:13
Module parse failed: Unexpected token (17:13)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| describe('AppComponent', () => {
|
> let fixture: ComponentFixture<AppComponent>;
| let modalService: NgbModal;
| let modalRef: NgbModalRef;
ERROR in ./src/app/email-checker-api.service.spec.ts 7:13
Module parse failed: Unexpected token (7:13)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
|
| describe('EmailCheckerApiService', () => {
> let service: EmailCheckerApiService;
|
| beforeEach(() => {
ERROR in ./src/app/email.service.spec.ts 8:13
Module parse failed: Unexpected token (8:13)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
|
| describe('EmailService', () => {
> let service: EmailService;
|
| beforeEach(() => {
ERROR in ./src/app/form/form.component.spec.ts 9:15
Module parse failed: Unexpected token (9:15)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
|
| describe('FormComponent', () => {
> let component: FormComponent;
| let fixture: ComponentFixture<FormComponent>;
|
ERROR in ./src/app/message.service.spec.ts 6:13
Module parse failed: Unexpected token (6:13)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
|
| describe('MessageService', () => {
> let service: MessageService;
|
| beforeEach(() => {
1 error has detailed information that is not shown.
Use 'stats.errorDetails: true' resp. '--stats-error-details' to show it.
I installed the ts-loader
package and removed node_modules and reinstall it. No luck, the package seems not to be loaded by thee webpack config
ok, finally I switched to jest framework and followed the setup from the doc here.
My jest.conf.js is like :
module.exports = {
testEnvironment: "jsdom",
preset: "jest-preset-angular",
setupFilesAfterEnv: ["<rootDir>/setup-jest.ts"],
moduleNameMapper: {
'^.+\\.html$': '<rootDir>/src/__mocks__/htmlMock.js',
'^.+\\.(css|scss)$': 'identity-obj-proxy',
},
transform: {
"^.+.(tsx?)$": ["jest-preset-angular"],
"^.+.jsx?$": 'babel-jest',
},
transformIgnorePatterns: [
"node_modules/(?!(@angular|@ng-bootstrap|ngx-*)/*)"
],
moduleFileExtensions: ['js', 'ts', 'tsx', 'json', 'node'],
};
I added the jest-preset-angular
as additional package and add htmlMocks.js
file :
module.exports = '';
My setup-jest.ts
is like :
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
import './jest-global-mocks';
setupZoneTestEnv();
I also added jest-global-mocks.ts
to handle html
files as explained by this resource as it :
Object.defineProperty(document, 'doctype', {
value: '<!DOCTYPE html>',
});
Object.defineProperty(window, 'getComputedStyle', {
value: () => {
return {
display: 'none',
appearance: ['-webkit-appearance'],
};
},
});
/**
* ISSUE: https://github.com/angular/material2/issues/7101
* Workaround for JSDOM missing transform property
*/
Object.defineProperty(document.body.style, 'transform', {
value: () => {
return {
enumerable: true,
configurable: true,
};
},
});
and voila!