Jest Test Component that Imports SVG with svg-sprite-loader - svg

Hi I'm getting an error when running my angular unit tests through jest.
Here is the error
Cannot find module '!svg-sprite-loader!node_modules/#my-package/brand-logos/laboratories/img.svg' from 'app.component.ts'
Here is my source code in my app component:
import '!svg-sprite-loader!node_modules/#my-package/brand-logos/laboratories/img.svg' from 'app.component.ts';
#Component({
selector: 'banner-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
...
Here is my jest.config.js
module.exports = {
globals: {
'ts-jest': {
tsConfig: './tsconfig.spec.json',
stringifyContentPathRegex: '\\.html$',
astTransformers: [
require.resolve('jest-preset-angular/InlineHtmlStripStylesTransformer')
]
}
},
setupFilesAfterEnv: [
'<rootDir>/node_modules/#angular-builders/jest/dist/jest-config/setup.js'
],
transform: {
'^.+\\.(ts|js|html)$': 'ts-jest'
},
testMatch: [
'**/+(*.)+(spec|test).+(ts|js)?(x)'
],
testEnvironment: 'jest-environment-jsdom-thirteen',
moduleNameMapper: {
'#core/(.*)': '<rootDir>/src/app/core/$1',
'#shared/(.*)': '<rootDir>/src/app/shared/$1'
},
transformIgnorePatterns: ['node_modules/(?!#ngrx)'],
collectCoverageFrom: [
'src/app/**/*.ts',
'!src/app/**/*.module.ts',
'!src/app/**/*.array.ts',
'!src/app/fragmentTypes.ts'
],
moduleFileExtensions: ['ts', 'tsx', 'js', 'json','svg'],
testPathIgnorePatterns: ['e2e','coverage', 'reports','/node_modules/', '/dist/', 'src/app/*.module.{js}'],
snapshotSerializers: [
'jest-preset-angular/AngularSnapshotSerializer.js',
'jest-preset-angular/HTMLCommentSerializer.js'
]
};
How do i modify my config so that jest can use the sprite loader or mock it out?

What I ended up doing was moving all my sprite loader imports into a file that we exclude from unit testing. It's kind of a hack but it works.

Related

babel-jest: Babel ignores app/utils/myfile.js - make sure to include the file in Jest's transformIgnorePatterns as well

I cannot get my jest tests to run when I have ignored a file with babel:
babel.config.js:
module.exports = {
ignore: ['./app/utils/myfile.js'],
presets: [
[
'#babel/preset-env',
{
targets: {
node: '14',
},
useBuiltIns: 'entry',
corejs: '3.8',
},
],
],
};
jest.config.js:
module.exports = {
coverageDirectory: 'coverage',
setupFiles: ['./jest.init.js'],
testEnvironment: 'node',
testMatch: ['**/?(*.)+(spec|test).js'],
transform: {
'^.+\\.(js|jsx)$': 'babel-jest',
},
transformIgnorePatterns: ['myfile'],
testPathIgnorePatterns: ['/node_modules/'],
};
i have added myfile.js to the babel ignore and to the jest transformIgnorePatterns. what could it be?

Jest: SyntaxError: Unexpected token 'export' happens at tslib.es6.js

I get this error:
C:\Users\myname\Projects\ConfigEditor\MesConfiguration.WebClient\node_modules\tslib\tslib.es6.js:24
export function __extends(d, b) {
^^^^^^
SyntaxError: Unexpected token 'export'
My jest-esm.config.mjs looks like this
const jestConfig = {
preset: 'jest-preset-angular/presets/defaults-esm',
extensionsToTreatAsEsm: ['.ts'],
globals: {
'ts-jest': {
useESM: true,
stringifyContentPathRegex: '\\.(html|svg)$',
tsconfig: '<rootDir>/tsconfig-esm.spec.json',
},
},
testEnvironment: 'jsdom',
moduleFileExtensions: ['ts', 'html', 'js', 'json', 'mjs'],
resolver: 'jest-preset-angular/build/resolvers/ng-jest-resolver.js',
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
transform: {
'^.+\\.(ts|js|mjs|html|svg)$': 'jest-preset-angular',
},
globalSetup: 'jest-preset-angular/global-setup',
moduleNameMapper: {
//tslib: 'tslib/tslib.mjs',
tslib: 'tslib/tslib.es6.js',
"#shared/(.*)": "<rootDir>/src/app/shared/$1",
"#editors/(.*)": "<rootDir>/src/app/editors/$1",
"#dashboard/(.*)": "<rootDir>/src/app/dashboard/$1",
"#env": "<rootDir>/src/environments/environment",
},
setupFilesAfterEnv: ['<rootDir>/src/setup-jest.ts'],
}
export default jestConfig;
package.json has
"type": "module",
I start the test with
"test-esm": "node --experimental-vm-modules --no-warnings node_modules/jest/bin/jest.js -c=jest-esm.config.mjs --no-cache",
What ist wrong?
After renaming the tslib.es6.js to tslib.mjs the error is gone, but this is no solution. It should work after any yarn install
The error is gone because you have set
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)']
you are basically using the preset jest-preset-angular/presets/defaults-esm So most of the properties you are typing in the config are redundant
One thing is that the transformIgnorePatterns somehow does not work with multiple items in that array (in some cases) so it is better to put everything at once like in my case
transformIgnorePatterns: ['node_modules/(?!rxjs|tslib)']
here is my full jest.config.js and setup-jest.ts file I am using with Angular14 with the ESM execution node --experimental-vm-modules node_modules/jest/bin/jest.js
// jest-config.ts
module.exports = {
preset: 'jest-preset-angular/presets/defaults-esm',
testRegex: '.*spec.ts$',
transformIgnorePatterns: [
'node_modules/(?!rxjs|tslib)'
],
moduleNameMapper: {
"^dnd-core$": "dnd-core/dist",
"^react-dnd$": "react-dnd/dist",
"^react-dnd-html5-backend$": "react-dnd-html5-backend/dist",
"^react-dnd-touch-backend$": "react-dnd-touch-backend/dist",
"^react-dnd-test-backend$": "react-dnd-test-backend/dist",
"^react-dnd-test-utils$": "react-dnd-test-utils/dist"
},
setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'],
};
// setup-jest.ts
import 'jest-preset-angular/setup-jest.mjs';
Object.defineProperty(window, "getComputedStyle", {
value: () => ["-webkit-appearance"]
});

Nest.js - Imported service not recognized by another service in production mode

I'm trying to use ModelsService from ModelsModule in AppService from AppModule.
In development mode, everything works ok. But on production mode I'm getting an error:
[Nest] 16460 - 03/13/2021, 11:14:00 PM [ExceptionsHandler] this.modelsService.countOnlineModels is not a function +1136ms
TypeError: this.modelsService.countOnlineModels is not a function
at _.createAppStore (/Users/egor.kamenev/Desktop/camoncam/dist/static/server/serverBundle.js:1:76579)
app.service.tsx
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import { createStore, Store } from 'redux';
import { Provider } from 'react-redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import { Inject, Injectable, forwardRef } from '#nestjs/common';
import { ModelsService } from './models/models.service';
import App from '../client/components/app/app';
import reducers from '../client/store/reducers';
import epics from '../client/store/epics';
import History from '../client/components/router/history';
import _merge from 'lodash/merge';
#Injectable()
export class AppService {
constructor(
#Inject(forwardRef(() => ModelsService))
private readonly modelsService: ModelsService,
) {}
async createAppStore(
cookies: Record<string, string>,
params: string,
): Promise<Store> {
const calculatedState: CommonStateType = {
main: _merge({}, initState.main, {
onlineModelsCount: await this.modelsService.countOnlineModels(),
allModelsCount: await this.modelsService.countAllModels(),
}),
};
return createStore(
reducers,
calculatedState,
composeWithDevTools(...epics),
);
}
}
app.module.ts
import { TypeOrmModule } from '#nestjs/typeorm';
import { Module } from '#nestjs/common';
import { join } from 'path';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ModelsModule } from './models/models.module';
import { ServeStaticModule } from '#nestjs/serve-static';
import { Models } from './models/schemas/modelTable.entity';
import { serverConfig } from './configs/appConfig';
#Module({
imports: [
ModelsModule,
ServeStaticModule.forRoot({
rootPath: join(__dirname, serverConfig.clientPath),
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
models.module.ts
import { Module } from '#nestjs/common';
import { ModelsService } from './models.service';
import { ModelsController } from './models.controller';
import { TypeOrmModule } from '#nestjs/typeorm';
import { Models } from './schemas/modelTable.entity';
#Module({
imports: [TypeOrmModule.forFeature([Models])],
controllers: [ModelsController],
providers: [ModelsService],
exports: [ModelsService],
})
export class ModelsModule {}
webpack.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
mode: "production",
entry: path.resolve(__dirname, './src/server/main.ts'),
target: 'node',
optimization: {
minimize: true,
minimizer: [
`...`,
new CssMinimizerPlugin(),
]
},
devtool: 'inline-source-map',
externals: [nodeExternals({
modulesFromFile: true,
})],
output: {
filename: 'serverBundle.js',
path: path.resolve(__dirname, 'dist/static/server'),
},
stats: 'errors-warnings',
resolve: {
modules: [__dirname, 'node_modules'],
extensions: ["css", ".ts", ".tsx", ".scss", ".js", ".json"]
},
output: {
publicPath: "/"
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
chunkFilename: '[id].[contenthash].css'
})
],
module: {
rules: [
{
test: /\.ts(x?)$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.scss$/i,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[name]-[local]-[contenthash:base64:6]'
}
}
},
'sass-loader'
],
},
{
test: /\.svg$/,
loader: 'react-svg-loader',
options: {
classIdPrefix: '[name]-[hash:8]__',
uniqueIdPrefix: true,
}
},
{
test: /\.(png|webp|jpe?g|avif)$/i,
loader: 'file-loader',
options: {
publicPath: '/images/',
outputPath: '../client/images',
name:'[name].[contenthash].[ext]'
},
}
]
}
}
Does anyone experience this? what is the correct way to call an imported service in another module service?
The problem was with webpack minimizer. It sets the wrong class names for services.
optimization.minimizer = false
decided this problem.

Angular CLI doesn't render html

Few days ago everything worked, then I created few more routes and since that moment Angular stopped rendering templates. There is no errors, it navigates URL in browser but no template..
Here is the routing module:
const AppRoutes: Routes = [
{ path: '', component: BlogListComponent },
{ path: ':id', component: BlogDetailComponent },
{ path: 'new', component: BlogAddComponent },
{ path: ':id/edit', component: BlogEditComponent },
{ path: 'register', component: RegisterComponent },
{ path: 'login', component: LoginComponent }
];
#NgModule({
imports: [
CommonModule,
RouterModule.forRoot(AppRoutes)
],
exports: [
RouterModule
],
declarations: []
})
export class RoutingModule { }
App module:
#NgModule({
declarations: [
AppComponent,
HeaderComponent,
BlogDetailComponent,
RegisterComponent,
LoginComponent,
BlogListComponent,
BlogAddComponent,
BlogEditComponent
],
imports: [
BrowserModule,
RoutingModule,
NgbModule.forRoot(),
HttpClientModule,
FormsModule,
ReactiveFormsModule
],
exports: [
RouterModule
],
providers: [RouterModule, AuthService, PostService],
bootstrap: [AppComponent]
})
export class AppModule { }
I believe there is problem with forms. I tried to change this.formBuilder.group to new FormGroup but it doesn't change anything.

angular2 nested routing not working,no error reported,but blank page

Please help me check the code...There is no compilation error or else output in the cli after npm start .But the brower appears to be a blank page.
I have checked over and over again,but still can't find what's wrong.
PS:im a freshman in angular2...
app.module
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AdminModule,
WaiterModule,
CookModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
app-routing.module
const appRoutes: Routes = [
{
path: "",
redirectTo: "/admin",
pathMatch:"full"
}
];
#NgModule({
imports: [
RouterModule.forRoot(appRoutes, { enableTracing: true })
],
exports: [RouterModule]
})
export class AppRoutingModule { }
app.component.html
<div style="text-align:center">
<h1>
Welcome to Angular2
</h1>
</div>
<router-outlet></router-outlet>
admin.module
#NgModule({
declarations: [
AdminComponent,
DishBoardComponent,
UserBoardComponent,
StatisticsBoardComponent,
AdminSiderBarComponent
],
imports: [
CommonModule,
AdminRoutingModule
]
})
export class AdminModule { }
admin-routing.module
const adminRoutes: Routes = [
{
path: "admin",
component: AdminComponent,
children: [
{ path: "", redirectTo: "/checkout",pathMatch:"full" },
{ path: "checkout", component: CheckoutBoardComponent },
{ path: "dish", component: DishBoardComponent },
{ path: "user", component: UserBoardComponent },
{ path: "statistics", component: StatisticsBoardComponent }
]
}
];
#NgModule({
imports: [
RouterModule.forChild(adminRoutes)
],
exports: [RouterModule]
})
export class AdminRoutingModule { }
admin.component.html
<p>
admin works!
</p>
<a routerLink="/checkout">Checkout</a>
<a routerLink="/user">User</a>
<a routerLink="/dish">Dish</a>
<a routerLink="/statistics">Statistics</a>
<router-outlet></router-outlet>
<br>
footer
It seems like you are not defining admin route and its children inside your app.routing.module.
You should get it to work with
app.module.ts:
No need to import other modules here. just import AppRoutingModule.
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
/** App Modules **/
import { AppRoutingModule } from './app.routing.module';
/** App Components**/
import { AppComponent } from './app.component';
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
app.routing.module.ts:
Load admin.module routes and pass them to admin route.
import { NgModule } from '#angular/core';
import { RouterModule } from '#angular/router';
/** App Modules**/
import { AdminModule} from './admin/admin.module';
export function exportAdminModule() {
return AdminModule;
}
const appRoutes: Routes = [
{
path: 'admin',
loadChildren: exportAdminModule
},
{
path: '',
redirectTo: '/admin',
pathMatch: 'full'
},
{
path: '**',
redirectTo: '/admin'
}
];
#NgModule({
imports: [
RouterModule.forRoot(appRoutes, { enableTracing: true })
], exports: [RouterModule]
})
export class AppRoutingModule { }
admin.module.ts:
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
// Import your components
/** App Routing **/
import { AdminRoutingModule} from './admin.routing.module';
#NgModule({
declarations: [
// your components
// your admin.component
],
imports: [
CommonModule,
AdminRoutingModule
]
})
export class AdminModule { }
admin.routing.module.ts:
Set up an empty path as base route ''.
import { NgModule } from '#angular/core';
import { RouterModule } from '#angular/router';
// Import your components
#NgModule({
imports: [
RouterModule.forChild([
{
path: '',
component: AdminComponent,
children: [
{ path: '', redirectTo: '/checkout', pathMatch: 'full' },
{ path: 'checkout', component: CheckoutBoardComponent },
. . .
]
}
])
], exports: [RouterModule]
})
export class AdminRoutingModule{ }
If you want to have more sub routes, for instance, nested router-outlet just replicate what I shown on app.module.routing with the export and the loadchildren.
I'm not quite sure that you want to achieve what you've shown on your app.routing.module. Are you sure you want to redirect everything to admin?
Something like:
#NgModule({
imports: [
RouterModule.forRoot([
{
path: 'login',
component: LoginPageComponent,
canActivate: [PreventLoggedInAccess]
},
{
path: 'admin',
loadChildren: exportAdminModule
},
{
path: '',
redirectTo: '/login',
pathMatch: 'full'
},
{
path: '**',
redirectTo: '/login'
}
], { useHash : true })
], exports: [RouterModule]
})
where PreventLoggedInAccess authguard prevents you to go to login if you are already logged in and
#NgModule({
imports: [
RouterModule.forChild([
{
path: '',
component: AdminComponent,
canActivateChild: [AuthGuardService],
children: [
. . .
]
}
])
], exports: [RouterModule]
})
with AuthGuardService allowing accessing to child routes only if you are logged in would make much more sense in my opinion.
Here you can read more about authguards.

Resources