In an Angular and Jest project, we are looking to improve the response times of unit tests. Looking for solutions, everything pointed to using SWC within the project, we have already implemented it, but we received an error in the components when we passed the tests.
package.json
{
"name": "app-ui",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"postinstall": "ngcc && husky install",
"start": "ng serve --proxy-config proxy.conf.json",
"start:dev": "ng serve -o --live-reload --configuration development --proxy-config proxy.conf.json",
"start:local": "ng serve -o --live-reload --configuration development --proxy-config proxy.conf.local.json",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "jest --detect-open-handles",
"test1": "cross-env NODE_ENV=test jest --config ./jest.config.mjs",
"test2": "node --experimental-vm-modules --no-warnings ./node_modules/jest/bin/jest.js --config ./jest.config.mjs --ci --coverage",
"test:browser": "node --experimental-vm-modules --no-warnings ./node_modules/jest/bin/jest.js --config ./jest.config.mjs",
"test:watch": "jest --watch",
"test:coverage": "jest --ci --coverage",
"test:cc": "jest --ci --coverage --coverageReporters='text-summary'",
"test:pre": "jest --ci --coverage --coverageReporters='text-summary' --silent --detectOpenHandles",
"test:deploy": "jest --ci --coverage --detect-open-handles --forceExit",
"test:report": "allure serve allure-results/",
"eslint": "eslint -c .eslintrc.json --ext .ts src/ --ignore-pattern node_modules/ --fix",
"lint-report": "eslint -c .eslintrc.json --ext .ts src/ --ignore-pattern node_modules/ --fix -f node_modules/eslint-html-reporter/reporter.js -o report.html",
"format": "prettier --write \"src/**/*.{js,ts,css,json,html,scss}\" --config ./.prettierrc.json",
"sonar": "sonar-scanner",
"unused-css": "ngx-unused-css"
},
"private": true,
"type": "module",
"dependencies": {
"@angular/animations": "^15.1.1",
"@angular/cdk": "^15.1.1",
"@angular/common": "^15.1.1",
"@angular/compiler": "^15.1.1",
"@angular/core": "^15.1.1",
"@angular/forms": "^15.1.1",
"@angular/material": "^15.1.1",
"@angular/material-moment-adapter": "^15.1.1",
"@angular/platform-browser": "^15.1.1",
"@angular/platform-browser-dynamic": "^15.1.1",
"@angular/router": "^15.1.1",
"@azure/storage-blob": "^12.12.0",
"@ngx-translate/core": "^14.0.0",
"@ngx-translate/http-loader": "^7.0.0",
"@popperjs/core": "^2.11.6",
"@types/event-source-polyfill": "^1.0.1",
"angular-auth-oidc-client": "15.0.3",
"apexcharts": "^3.36.3",
"bootstrap": "^5.2.3",
"classlist.js": "^1.1.20150312",
"esbuild-wasm": "0.17.4",
"event-source-polyfill": "^1.0.31",
"moment": "^2.29.4",
"ng-apexcharts": "^1.7.4",
"ngx-material-timepicker": "^5.5.3",
"rxjs": "~7.8.0",
"tslib": "^2.4.1",
"web-animations-js": "^2.3.2",
"zone.js": "~0.12.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "^15.1.2",
"@angular-eslint/builder": "15.2.0",
"@angular-eslint/eslint-plugin": "15.2.0",
"@angular-eslint/eslint-plugin-template": "15.2.0",
"@angular-eslint/schematics": "15.2.0",
"@angular-eslint/template-parser": "15.2.0",
"@angular/cli": "^15.1.2",
"@angular/compiler-cli": "^15.1.1",
"@babel/core": "^7.20.12",
"@babel/plugin-transform-typescript": "^7.20.13",
"@babel/preset-env": "^7.20.2",
"@babel/preset-typescript": "^7.18.6",
"@briebug/jest-schematic": "^6.0.0",
"@jest/globals": "^29.4.0",
"@ngneat/spectator": "^14.0.0",
"@swc/cli": "^0.1.59",
"@swc/core": "^1.3.28",
"@swc/jest": "^0.2.24",
"@types/jest": "^29.4.0",
"@types/node": "^18.11.18",
"@typescript-eslint/eslint-plugin": "5.49.0",
"@typescript-eslint/eslint-plugin-tslint": "^5.49.0",
"@typescript-eslint/parser": "5.49.0",
"@typescript-eslint/typescript-estree": "^5.49.0",
"allure-commandline": "^2.20.1",
"babel-core": "^6.26.3",
"babel-jest": "^29.4.0",
"babel-preset-jest": "^29.4.0",
"cross-env": "^7.0.3",
"cypress": "^12.4.0",
"esbuild": "^0.17.4",
"esbuild-jest": "^0.5.0",
"eslint": "^8.32.0",
"eslint-config-prettier": "^8.6.0",
"eslint-html-reporter": "^0.7.4",
"eslint-plugin-angular": "^4.1.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsdoc": "^39.6.8",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-sonarjs": "^0.18.0",
"husky": "^8.0.3",
"jest": "^29.4.0",
"jest-allure": "^0.1.3",
"jest-allure-image-snapshot": "^0.0.10",
"jest-browser": "^0.1.0",
"jest-css-modules-transform": "^4.4.2",
"jest-environment-jsdom": "^29.4.0",
"jest-jasmine2": "^29.4.0",
"jest-junit-reporter": "^1.1.0",
"jest-preset-angular": "^12.2.5",
"jest-raw-loader": "^1.0.1",
"lint-staged": "^13.1.0",
"ngx-unused-css": "^4.0.0-1",
"prettier": "^2.8.3",
"prettier-eslint": "^15.0.1",
"sonar-scanner": "^3.1.0",
"ts-jest": "^29.0.5",
"ts-node": "^10.9.1",
"tslint": "^6.1.3",
"tslint-angular": "^3.0.3",
"typescript": "~4.8.4"
},
"prettier": {
"printWidth": 150,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"trailingComma": "none",
"bracketSpacing": true,
"arrowParens": "always",
"proseWrap": "preserve",
"htmlWhitespaceSensitivity": "css",
"endOfLine": "auto",
"quoteProps": "consistent",
"overrides": [
{
"files": [
"**/*.css",
"**/*.scss",
"**/*.html"
],
"options": {
"singleQuote": false
}
}
]
},
"lint-staged": {
"src/**/*.{js,ts,scss,md,html,json}": [
"prettier --write",
"git add"
],
"src/**/*.{js,ts}": [
"npm run eslint",
"git add"
]
},
"husky": {
"hooks": {
"pre-commit": "lint-staged",
"pre-push": "npm run eslint && ng build --aot true"
}
}
}
.swcrc
{
"test": ".*.ts$",
"jsc": {
"target": "es2022",
"parser": {
"syntax": "typescript",
"tsx": false,
"decorators": false,
"dynamicImport": false
},
"externalHelpers": true
},
"module": {
"type": "commonjs"
},
"sourceMaps": true
}
tsconfig.spec.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": ["jest","node"],
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"esModuleInterop": true,
"module": "CommonJs",
"moduleResolution": "node",
"target": "ES2022",
"sourceMap": true,
"inlineSources": true,
"inlineSourceMap": true,
"paths": {
"@shared/*": ["./src/app/shared/*"],
"@services/*": ["./src/app/services/*"],
"@utils/*": ["./src/app/utils/*"],
"@pages/*": ["./src/app/pages/*"],
"@global/*": ["./src/app/global/*"],
"@guards/*": ["./src/app/guards/*"],
"@auth/*": ["./src/app/auth/*"],
"@mock/*": ["./src/mock/*"],
"@helpers/*": ["./src/helpers/*"],
"@pipes/*": ["./src/app/pipes/*"],
"@directives/*": ["./src/app/directives/*"],
"@constants/*": ["./src/app/constants/*"],
"@interceptors/*": ["./src/app/interceptors/*"]
}
},
"include": ["src/**/*.spec.ts","src/**/*.d.ts"]
}
jest.config.mjs
const esModules = ['@angular'].join('|');
export default {
collectCoverage: true,
testRunner: 'jest-jasmine2',
coverageReporters: ['json', 'lcov', 'html'],
collectCoverageFrom: [
'src/**/*.{js,ts}',
'!src/**/*.module.{js,ts}',
'!src/**/*-routing.module.{js,ts}',
'!src/**/index.{js,ts}',
'!src/**/main.{js,ts}',
'!src/**/polyfills.{js,ts}',
'!src/**/vendor.{js,ts}'
],
extensionsToTreatAsEsm: ['.ts', '.tsx'],
testEnvironment: 'jsdom',
globalSetup: 'jest-preset-angular/global-setup.mjs',
timers: 'fake',
setupFilesAfterEnv: ['<rootDir>/setup-jest.mjs', 'jest-allure/dist/setup'],
globals: {
'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json',
isolatedModules: true,
stringifyContentPathRegex: '\\.(html|svg)$',
allowSyntheticDefaultImports: true,
useESM: true
}
},
roots: ['<rootDir>/src'],
transformIgnorePatterns: [`/node_modules/(?!${esModules})`],
moduleNameMapper: {
'tslib': 'tslib/tslib.es6.js',
'^rxjs$': '<rootDir>/node_modules/rxjs/dist/bundles/rxjs.umd.js',
'^rxjs/operators$': '<rootDir>/node_modules/rxjs/dist/bundles/rxjs.umd.js',
'^rxjs/testing$': '<rootDir>/node_modules/rxjs/dist/cjs/testing/index.js',
'^rxjs/webSocket$': '<rootDir>/node_modules/rxjs/dist/cjs/webSocket/index.js',
'^rxjs/ajax$': '<rootDir>/node_modules/rxjs/dist/cjs/ajax/index.js',
'@angular/core/testing': '<rootDir>/node_modules/@angular/core/fesm2020/testing.mjs',
'@angular/platform-browser/testing': '<rootDir>/node_modules/@angular/platform-browser/fesm2020/testing.mjs',
'@angular/platform-browser-dynamic/testing': '<rootDir>/node_modules/@angular/platform-browser-dynamic/fesm2020/testing.mjs',
'^app/(.*)$': '<rootDir>/src/app/$1',
'^assets/(.*)$': '<rootDir>/src/assets/$1',
'^environments/(.*)$': '<rootDir>/src/environments/$1',
'^@shared/(.*)$': '<rootDir>/src/app/shared/$1',
'^@constants/(.*)$': '<rootDir>/src/app/constants/$1',
'^@services/(.*)$': '<rootDir>/src/app/services/$1',
'^@utils/(.*)$': '<rootDir>/src/app/utils/$1',
'^@pages/(.*)$': '<rootDir>/src/app/pages/$1',
'^@global/(.*)$': '<rootDir>/src/app/global/$1',
'^@guards/(.*)$': '<rootDir>/src/app/guards/$1',
'^@mock/(.*)$': '<rootDir>/src/mock/$1',
'^@helpers/(.*)$': '<rootDir>/src/helpers/$1',
'^@pipes/(.*)$': '<rootDir>/src/app/pipes/$1',
'^@directives/(.*)$': '<rootDir>/src/app/directives/$1',
'^@auth/(.*)$': '<rootDir>/src/app/auth/$1',
'^@interceptors/(.*)$': '<rootDir>/src/app/interceptors/$1'
},
transform: {
'^.+\\.[tj]s?$': [
'@swc/jest',
{
jsc: {
target: 'es2022'
},
sourceMaps: true
}
]
},
maxWorkers: '8'
};
Resultado:
Test Suites: 206 failed, 1 passed, 207 total
Tests: 5 passed, 5 total
Snapshots: 0 total
Time: 31.545 s
Ran all test suites.
Resultado de app.component
FAIL src/app/app.component.spec.ts
● Test suite failed to run
x Expression expected
,-[C:\Users\xxxxxxxx\src\app\app.component.ts:6:1]
6 | import { Subscription } from 'rxjs';
7 | import { SidebarService } from '@services/sidebar/sidebar.service';
8 |
9 | @Component({
: ^
10 | selector: 'app-root',
11 | templateUrl: './app.component.html',
11 | styleUrls: ['./app.component.scss'],
`----
Caused by:
Syntax Error
,-[C:\Users\xxxxxxxx\src\app\app.component.ts:6:1]
6 | import { Subscription } from 'rxjs';
7 | import { SidebarService } from '@services/sidebar/sidebar.service';
8 |
9 | @Component({
: ^
10 | selector: 'app-root',
11 | templateUrl: './app.component.html',
11 | styleUrls: ['./app.component.scss'],
`----
Caused by:
Syntax Error
otros resultados
FAIL src/app/pipes/numbercomparatorpipe.pipe.spec.ts
● Test suite failed to run
x Expression expected
,-[C:\Users\XXXXXXXX\src\app\pipes\numbercomparatorpipe.pipe.ts:1:1]
1 | import { Pipe, PipeTransform } from '@angular/core';
2 |
3 | @Pipe({
: ^
4 | name: 'comparatorpipe'
5 | })
5 | export class NumberComparatorPipe implements PipeTransform {
`----
Caused by:
Syntax Error
,-[C:\Users\XXXXXXXX\src\app\pipes\numbercomparatorpipe.pipe.ts:1:1]
1 | import { Pipe, PipeTransform } from '@angular/core';
2 |
3 | @Pipe({
: ^
4 | name: 'comparatorpipe'
5 | })
5 | export class NumberComparatorPipe implements PipeTransform {
`----
Caused by:
Syntax Error
FAIL src/app/interceptors/login/NotEmployees.interceptor.spec.ts
● Test suite failed to run
x Expression expected
,-[C:\Users\XXXXXXXX\src\app\interceptors\login\NotEmployees.interceptor.ts:6:1]
6 | import { TranslateService } from '@ngx-translate/core';
7 | import { OidcSecurityService } from 'angular-auth-oidc-client';
8 | import { UserApiService } from '@services/api/user-api/user-api.service';
9 | @Injectable()
: ^
10 | export class NotEmployees implements HttpInterceptor {
11 | size: string;
11 |
`----
Caused by:
Syntax Error
,-[C:\Users\XXXXXXXX\src\app\interceptors\login\NotEmployees.interceptor.ts:6:1]
6 | import { TranslateService } from '@ngx-translate/core';
7 | import { OidcSecurityService } from 'angular-auth-oidc-client';
8 | import { UserApiService } from '@services/api/user-api/user-api.service';
9 | @Injectable()
: ^
10 | export class NotEmployees implements HttpInterceptor {
11 | size: string;
11 |
`----
Caused by:
Syntax Error
FAIL src/app/pipes/form-control-pipe.pipe.spec.ts
● Test suite failed to run
x Expression expected
,-[C:\Users\XXXXXXXX\src\app\pipes\form-control-pipe.pipe.ts:1:1]
1 | import { Pipe, PipeTransform } from '@angular/core';
2 | import { AbstractControl, UntypedFormControl } from '@angular/forms';
3 |
4 | @Pipe({
: ^
5 | name: 'formControlPipe'
6 | })
6 | export class FormControlPipe implements PipeTransform {
`----
Caused by:
Syntax Error
,-[C:\Users\XXXXXXXX\src\app\pipes\form-control-pipe.pipe.ts:1:1]
1 | import { Pipe, PipeTransform } from '@angular/core';
2 | import { AbstractControl, UntypedFormControl } from '@angular/forms';
3 |
4 | @Pipe({
: ^
5 | name: 'formControlPipe'
6 | })
6 | export class FormControlPipe implements PipeTransform {
`----
Caused by:
Syntax Error
I already tried implementing babel vs esbuild and both give me similar errors, so I do not think it is the library but something in the jest or angular configuration.