Generated test fails when unit testing component inside the library
Asked Answered
O

3

5

My project was created using nx schematics, and I'm having some components inside libraries that I want to unit test using jest.js. Every test fails with following errors:

● MyComponent › should create

    Failed: "Zone is needed for the async() test helper but could not be found. Please make sure that your environment includes zone.js/dist/zone.js"

       7 |   let fixture: ComponentFixture<MyComponent>;
       8 | 
    >  9 |   beforeEach(async(() => {
         |   ^
      10 |     TestBed.configureTestingModule({
      11 |       declarations: [ MyComponent ]
      12 |     })

      at Env.beforeEach (node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:41:24)
      at Suite.<anonymous> (libs/componentlib/src/lib/components/my-component/my-component.component.spec.ts:9:3)
      at Object.<anonymous> (libs/componentlib/src/lib/components/my-component/my-component.component.spec.ts:5:1)

  ● MyComponent › should create

    TypeError: Cannot read property 'getComponentFromError' of null

      at TestBedViewEngine._initIfNeeded (../../packages/core/testing/src/test_bed.ts:393:46)
      at TestBedViewEngine.createComponent (../../packages/core/testing/src/test_bed.ts:594:10)
      at Function.TestBedViewEngine.createComponent (../../packages/core/testing/src/test_bed.ts:247:36)
      at Object.<anonymous> (libs/componentlib/src/lib/components/my-component/my-component.component.spec.ts:17:23)

  ● MyComponent › should create

    expect(received).toBeTruthy()

    Received: undefined

      21 | 
      22 |   it('should create', () => {
    > 23 |     expect(component).toBeTruthy();
         |                       ^
      24 |   });
      25 | });
      26 | 

      at Object.<anonymous> (libs/componentlib/src/lib/components/my-component/my-component.component.spec.ts:23:23)

I've tried already to import zone.js in spec files, importing modules, removing async, reseting the test environment before each test, but everything fails with some different error. I should mention also that I'm using clarity components from vmware.

Here's the .spec file:

import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { MyComponent } from './my-component.component';

describe('MyComponent', () => {
  let component: MyComponent;
  let fixture: ComponentFixture<MyComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ MyComponent ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(MyComponent);
    component = fixture.componentInstance;
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

I was expecting that this should work like intended when using nx. What am I missing here?

Outsider answered 27/3, 2019 at 10:26 Comment(0)
O
2

I have found the solution!

The problem was that jest was not configured out of box, when creating nx workspace. So I took this steps to make it work:

1. Install jest-zone-patch

npm install jest-zone-patch --save-dev

2. Edit files

For each library you have to edit test-setup.ts file to look like this:

import 'zone.js/dist/zone.js';
import 'zone.js/dist/proxy';
import 'zone.js/dist/sync-test';
import 'zone.js/dist/async-test.js';
import 'zone.js/dist/proxy.js';

import 'jest-zone-patch';
import 'jest-preset-angular';
import './jestGlobalMocks';

Also, add setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'] to jest.config.js file of your library, so it looks something like this:

module.exports = {
  name: 'my-library',
  preset: '../../../jest.config.js',
  coverageDirectory: '../../../coverage/libs/administration/identification',
  setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts']
};

and add jestGlobalMocks.ts file in the same folder as test-setup.ts file. You can find it here, or just copy the code bellow:

Object.defineProperty(window, 'CSS', {value: null});
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,
    };
  },
});

3. Change spec files

Change your generated spec file to something like this:

describe('MyComponent', () => {
  let component: MyComponent;
  let fixture: ComponentFixture<MyComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [MyComponent]
    })
      .compileComponents()
      .then(() => {
        fixture = TestBed.createComponent(MyComponent);
        component = fixture.componentInstance;

        fixture.detectChanges();
      });
  }));

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

This way, component and fixture are created, after compileComponents promise has finished, thus avoiding race conditions and potential undefined error in 'should create' unit test.

4. Run library test

Finnaly, you can run your test and hopefully it will pass.

ng test my-library

Hope that this will help someone.

Outsider answered 28/3, 2019 at 14:22 Comment(0)
B
4

I just encountered the same problem.

Using Nrwl's Nx to scaffold a new application plus a "feature-shell" library (the design pattern suggested by Nx's "Enterprise Angular Monorepo Patterns" book), I was also confused why my Jest unit tests for Angular component classes worked out of the box inside of apps/, but not libs/.

I may have found a simpler solution:

Look inside of angular.json in the workspace root. Take note of the property projects.<your-app>.architect.test.options.setupFile. Its value should be something like "apps/<your-app>/src/test-setup.ts".

The solution that worked for me was adding that exact property and value in angular.json to projects.<your-lib>.architect.test.options.

Example Solution

// angular.json
{
  ...
  "projects": {
    "my-app": {
      ...
      "architect": {
        ...
        "test": {
          ...
          "setupFile": "apps/my-app/src/test-setup.ts" // <- This was already here...
        }
      }
    },
    "my-lib": {
      ...
      "architect": {
        ...
        "test": {
          ...
          "setupFile": "apps/my-app/src/test-setup.ts" // <- ...and I just added it here
        }
      }
    }
  }
}

Hopefully that one-liner works for you, too!

Bethina answered 4/7, 2019 at 16:37 Comment(0)
O
2

I have found the solution!

The problem was that jest was not configured out of box, when creating nx workspace. So I took this steps to make it work:

1. Install jest-zone-patch

npm install jest-zone-patch --save-dev

2. Edit files

For each library you have to edit test-setup.ts file to look like this:

import 'zone.js/dist/zone.js';
import 'zone.js/dist/proxy';
import 'zone.js/dist/sync-test';
import 'zone.js/dist/async-test.js';
import 'zone.js/dist/proxy.js';

import 'jest-zone-patch';
import 'jest-preset-angular';
import './jestGlobalMocks';

Also, add setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'] to jest.config.js file of your library, so it looks something like this:

module.exports = {
  name: 'my-library',
  preset: '../../../jest.config.js',
  coverageDirectory: '../../../coverage/libs/administration/identification',
  setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts']
};

and add jestGlobalMocks.ts file in the same folder as test-setup.ts file. You can find it here, or just copy the code bellow:

Object.defineProperty(window, 'CSS', {value: null});
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,
    };
  },
});

3. Change spec files

Change your generated spec file to something like this:

describe('MyComponent', () => {
  let component: MyComponent;
  let fixture: ComponentFixture<MyComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [MyComponent]
    })
      .compileComponents()
      .then(() => {
        fixture = TestBed.createComponent(MyComponent);
        component = fixture.componentInstance;

        fixture.detectChanges();
      });
  }));

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

This way, component and fixture are created, after compileComponents promise has finished, thus avoiding race conditions and potential undefined error in 'should create' unit test.

4. Run library test

Finnaly, you can run your test and hopefully it will pass.

ng test my-library

Hope that this will help someone.

Outsider answered 28/3, 2019 at 14:22 Comment(0)
H
2

If anyone is using Jest with Angular 11 and experiencing this issue, what fixed it for me was.

Making sure I had these two properties in my package.json file.

{
  "jest": {
    "preset": "jest-preset-angular",
    "setupFilesAfterEnv": [
      "<rootDir>/setupJest.ts"
    ],
  }
}

setupJest.ts

import 'jest-preset-angular'

Also make sure your jest config doesn't include "testEnvironment": "node",. I copied this over from a node project and it broke the tests for me as well.

Helen answered 30/12, 2020 at 7:41 Comment(1)
I have the same files as yours, just add Jest for Angular project, the error still existsErkan

© 2022 - 2024 — McMap. All rights reserved.