angularjestjsts-jestangular-library

Testing an Angular shared library with Jest


I have an angular library with the following structure

projects/
   |..... app/
       |..... src/
          |..... app/       
              |..... app.component.spec.ts
              |..... app.component.ts
              |..... app.module.ts    
   |..... lib/
       |..... sso/
          |...... index.ts
          |...... ng-package.json
          |...... ...
          |...... sso.service.ts
          |...... ss.module.ts
       |..... ui/
          |...... menu/
              |...... menu.component.ts
              |...... menu.service.ts
              |...... menu.module.ts
          |...... index.ts
          |...... ng-package.json
       |..... ng-package.json
       |..... package.json
   |..... jest.config.ts
   |..... package.json

I want to test my app.component

// app.component.ts

import {SSOService} from "my-lib/sso";

@Component({
  selector: 'app-root',
  template: `
    <my-menu>
      <router-outlet></router-outlet>
    </my-menu>
  `,
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
  constructor(protected ssoService: SSOService) { }
}

Here my current test

// app.component.spec.ts

import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';
import {SSOService} from "my-lib/sso";
import {MenuComponent} from "my-lib/ui";

describe('AppComponent', () => {
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [
        RouterTestingModule
      ],
      declarations: [
        AppComponent, MenuComponent
      ],
      providers: [
        {
          provide: SSOService,
          useValue: {
            setRoles: jest.fn()
          }
        }
      ]
    }).compileComponents();
  });

  it('should create the app', () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.componentInstance;
    expect(app).toBeTruthy();
  });
});

I had to mock my sso_service even it's in the same project! But still have the same issue with MenuComponent

  ● Test suite failed to run

    TypeError: Cannot read properties of undefined (reading 'toLowerCase')

      289 |         }] });
      290 |
    > 291 | registerLocaleData(FR);
          | ^
      292 | /**
      293 |  * Custom date adapter for Angular Material.
      294 |  *

      at registerLocaleData (node_modules/@angular/core/fesm2022/core.mjs:22410:25)
      at registerLocaleData (node_modules/@angular/common/fesm2022/common.mjs:2562:12)
      at Object.<anonymous> (dist/lib/fesm2022/my-lib-ui.mjs:291:1)
      at Object.<anonymous> (projects/app/src/app/app.component.spec.ts:5:1)

I don't want to mock the component too, is there an issue with library or the Jest Config maybe ?

PS: the tests works well with karma before moving to jest

Please find below the different config files

// lib/ui/index.ts
import { CommonMenuService } from './menu/menu.service';

export * from './menu/menu.component';
export * from './menu/menu.module';
export * from './menu/menu.service';


// lib/ui/ng-package.json
{
  "lib": {
    "entryFile": "index.ts"
  }
}
// lib/ui/pacakge.json
{
  "name": "my-lib",
  "version": "2.5.2",
  "peerDependencies": {
    "@angular/cdk": "^17.0.0",
    "@angular/common": "^17.0.1",
    "@angular/core": "^17.0.1",
    "@angular/material": "^17.0.0",
    "@awesome-cordova-plugins/in-app-browser": "^6.3.0",
    "@capacitor/device": "^5.0.6",
    "angular-oauth2-oidc": "^15.0.1",
    "jwt-decode": "^4.0.0"
  },
  "dependencies": {
    "tslib": "^2.6.2"
  },
  "sideEffects": false,
  "exports": {
    ".": {
      "sass": "./styles/_index.scss"
    }
  }
}

This is my Jest.config

// jest.config.ts

import type { Config } from 'jest';

const config: Config = {
  clearMocks: true,
  collectCoverage: true,
  coverageDirectory: 'coverage',
  coverageProvider: 'v8',
  preset: 'jest-preset-angular',
  setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'],
};

export default config;

and my tsconfig.json looks like this

// tsconfig.json
{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "noImplicitOverride": true,
    "noPropertyAccessFromIndexSignature": true,
    "noImplicitReturns": true,
    "paths": {
      "my-lib/*": ["projects/lib/*"],
      "my-lib": ["projects/lib"]
    },
    "noFallthroughCasesInSwitch": true,
    "sourceMap": true,
    "declaration": false,
    "downlevelIteration": true,
    "experimentalDecorators": true,
    "moduleResolution": "node",
    "importHelpers": true,
    "target": "ES2022",
    "module": "ES2022",
    "useDefineForClassFields": false,
    "lib": ["ES2022", "dom"]
  },
  "angularCompilerOptions": {
    "enableI18nLegacyMessageIdFormat": false,
    "strictInjectionParameters": true,
    "strictInputAccessModifiers": true,
    "strictTemplates": true
  }
}


Solution

  • I think that I've found an answer to my question ! it seems to have been quicker than writing the question itself ^^'

    The answer was in this medium article https://fireflysemantics.medium.com/unit-testing-your-angular-library-project-with-jest-42429a8716eb

    in my tsconfig.json I have

    // tsconfig.json
    
        "paths": {
          "my-lib/*": ["projects/lib/*"],
          "my-lib": ["projects/lib"]
        },
    

    So I have to add the following in my jest config

    // jest.config.ts
    
      moduleNameMapper: {
        "^my-lib/(.*)$": "<rootDir>/projects/lib/$1",
        "^my-lib/": "<rootDir>/projects/lib/",
      },
    
    

    yeah!it works now