bahmutov / cypress-angular-unit-test

Trying to load and bootstrap Angular component dynamically inside Cypress
160 stars 32 forks source link

Component Tests Not Working For Nx Lib #758

Open dgrbrady opened 2 years ago

dgrbrady commented 2 years ago

Current behavior

I have an Nx monorepo with 1 Angular app and 1 Angular lib (not buildable/publishable). I have successfully managed to implement cypress-angular-unit-test for the app, but when trying to implement in my lib, I get the following error when running a component unit test

Error: The following error originated from your test code, not from Cypress.

  > The injectable 'PlatformLocation' needs to be compiled using the JIT compiler, but '@angular/compiler' is not available.

The injectable is part of a library that has been partially compiled.
However, the Angular Linker has not processed the library such that JIT compilation is used as fallback.

Ideally, the library is processed using the Angular Linker to become fully AOT compiled.
Alternatively, the JIT compiler should be loaded by bootstrapping using '@angular/platform-browser-dynamic' or '@angular/platform-server',
or manually provide the compiler with 'import "@angular/compiler";' before bootstrapping.

When Cypress detects uncaught errors originating from your test code it will automatically fail the current test.

Cypress could not associate this error to any specific test.

We dynamically generated a new test to display this failure.
    at getCompilerFacade (http://localhost:8080/__cypress/src/vendors-node_modules_tslib_tslib_es6_js-node_modules_angular_core_fesm2020_core_mjs.js:7029:15)
    at Module.ɵɵngDeclareFactory (http://localhost:8080/__cypress/src/vendors-node_modules_tslib_tslib_es6_js-node_modules_angular_core_fesm2020_core_mjs.js:31535:22)
    at Module../node_modules/@angular/common/fesm2020/common.mjs (http://localhost:8080/__cypress/src/vendors-node_modules_rxjs_dist_esm5_internal_operators_take_js-node_modules_rxjs_dist_esm5_in-45b09b.js:252:89)
    at __webpack_require__ (http://localhost:8080/__cypress/src/main.js:4189:42)
    at Module../node_modules/@angular/forms/fesm2020/forms.mjs (http://localhost:8080/__cypress/src/vendors-node_modules_rxjs_dist_esm5_internal_BehaviorSubject_js-node_modules_angular_forms_fe-c92fb1.js:230:73)
    at __webpack_require__ (http://localhost:8080/__cypress/src/main.js:4189:42)
    at Module../libs/test/src/lib/browser/browser.component.ts (http://localhost:8080/__cypress/src/libs_test_src_lib_types_index_ts.js:238:72)
    at __webpack_require__ (http://localhost:8080/__cypress/src/main.js:4189:42)
    at Module../libs/test/src/lib/taskbar/taskbar.component.ts (http://localhost:8080/__cypress/src/libs_test_src_lib_types_index_ts.js:558:84)
    at __webpack_require__ (http://localhost:8080/__cypress/src/main.js:4189:42)
From previous event:
    at Object.runScripts (http://localhost:8080/__cypress/runner/cypress_runner.js:197880:62)
    at $Cypress.onSpecWindow (http://localhost:8080/__cypress/runner/cypress_runner.js:186565:76)
    at init (http://localhost:8080/__cypress/src/main.js:85:13)
    at Object../node_modules/@cypress/webpack-dev-server/dist/loader.js!./node_modules/@cypress/webpack-dev-server/dist/browser.js (http://localhost:8080/__cypress/src/main.js:64:3)
    at __webpack_require__ (http://localhost:8080/__cypress/src/main.js:4189:42)
    at render (http://localhost:8080/__cypress/src/main.js:4667:5)
    at http://localhost:8080/__cypress/src/main.js:4669:1
    at http://localhost:8080/__cypress/src/main.js:4671:3
    at http://localhost:8080/__cypress/src/main.js:4673:12

Desired behavior

Cypress Component testing should work inside an Nx library using the same setup that works for Nx application.

Test code to reproduce

I'm not exactly sure if this is a bug with the library because of the following:

  1. It works for the app, just not the lib
  2. I can get it working in the lib if I create a dummy inline component in my spec.ts file.

Component test in my lib:

// this component is inside my ui lib
// BROKEN test which produces error
describe('TaskbarComponent', () => {
  it('should create', () => {
    initEnv(TaskbarComponent, {
      declarations: [
        // MockComponent and MockService come from library ng-mocks and works fine for unit tests in app
        MockComponent(MenuComponent),
        MockComponent(WindowComponent),
      ],
      providers: [MockService(WindowService)],
    });
    const fixture = mount(TaskbarComponent);
    expect(fixture).to.exist;
  });
});

But if I do this instead,

// same test file, but DOES NOT produce error
@Component({
  template: '<div>Test</div>',
  selector: 'dgrbrady-test',
})
export class TestComponent {}

describe('TaskbarComponent', () => {
  it('should create', () => {
    initEnv(TestComponent);
    const fixture = mount(TestComponent);
    expect(fixture).to.exist;
  });
});

It works fine? I'm at a loss here. There's not a whole lot of documentation out there for getting Cypress component testing working in an Nx workspace. Anyone else ever get this library working in an Nx workspace? Any guidance is super appreciated!

Also, here's the code for the WORKING unit tests in my Nx app

describe('AppComponent', () => {
  it('should mount', () => {
    initEnv(AppComponent, { declarations: [MockComponent(TaskbarComponent)] });
    const fixture = mount(AppComponent);
    expect(fixture).to.exist;
  });

  it('should contain TaskbarComponent', () => {
    initEnv(AppComponent, { declarations: [MockComponent(TaskbarComponent)] });
    mount(AppComponent);
    cy.get('dgrbrady-taskbar');
  });
});

This is for my portfolio site, you can find the repo here. I'm using the command npx cypress open-ct -C libs\ui\cypress.json to run the Cypress runner for the ui lib, and npx cypress open-ct -C apps\desktop\cypress.json to run the Cypress runner for the app.

Versions

Output from npm ls:

+-- __ngcc_entry_points__.json@ extraneous
+-- @angular-devkit/build-angular@13.1.4
+-- @angular-eslint/eslint-plugin-template@13.0.1
+-- @angular-eslint/eslint-plugin@13.0.1
+-- @angular-eslint/template-parser@13.0.1
+-- @angular/animations@13.1.3
+-- @angular/cdk@13.1.3
+-- @angular/cli@13.1.4
+-- @angular/common@13.1.3
+-- @angular/compiler-cli@13.1.3
+-- @angular/compiler@13.1.3
+-- @angular/core@13.1.3
+-- @angular/forms@13.1.3
+-- @angular/language-service@13.1.3
+-- @angular/platform-browser-dynamic@13.1.3
+-- @angular/platform-browser@13.1.3
+-- @angular/router@13.1.3
+-- @compodoc/compodoc@1.1.18
+-- @cypress/webpack-dev-server@1.8.1
+-- @ngneat/until-destroy@8.0.4
+-- @nrwl/angular@13.5.3
+-- @nrwl/cli@13.5.3
+-- @nrwl/cypress@13.5.3
+-- @nrwl/eslint-plugin-nx@13.5.3
+-- @nrwl/jest@13.5.3
+-- @nrwl/linter@13.5.3
+-- @nrwl/tao@13.5.3
+-- @nrwl/workspace@13.5.3
+-- @twittwer/compodoc@1.6.6
+-- @types/jest@27.0.2
+-- @types/node@14.14.33
+-- @typescript-eslint/eslint-plugin@5.3.1
+-- @typescript-eslint/parser@5.3.1
+-- angular2-template-loader@0.6.2
+-- cypress-angular-unit-test@3.9.0
+-- cypress@9.4.1
+-- dotenv@10.0.0
+-- eslint_d@11.1.1
+-- eslint-config-prettier@8.1.0
+-- eslint-plugin-cypress@2.12.1
+-- eslint-plugin-jest@26.0.0
+-- eslint-plugin-prettier@4.0.0
+-- eslint-plugin-sort-imports-es6-autofix@0.6.0
+-- eslint@8.2.0
+-- html-webpack-plugin@5.5.0
+-- jest-preset-angular@11.0.0
+-- jest@27.2.3
+-- ng-mocks@13.0.3
+-- prettier@2.5.1
+-- raw-loader@1.0.0
+-- rxjs@7.4.0
+-- ts-jest@27.0.5
+-- ts-node@9.1.1
+-- tslib@2.3.1
+-- typescript@4.5.5
`-- zone.js@0.11.4

package.json

{
  "name": "dgrbrady",
  "version": "0.0.0",
  "license": "MIT",
  "scripts": {
    "ng": "nx",
    "postinstall": "node ./decorate-angular-cli.js && ngcc --properties es2015 browser module main",
    "nx": "nx",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "nx workspace-lint && ng lint",
    "e2e": "ng e2e",
    "affected:apps": "nx affected:apps",
    "affected:libs": "nx affected:libs",
    "affected:build": "nx affected:build",
    "affected:e2e": "nx affected:e2e",
    "affected:test": "nx affected:test",
    "affected:lint": "nx affected:lint",
    "affected:dep-graph": "nx affected:dep-graph",
    "affected": "nx affected",
    "format": "nx format:write",
    "format:write": "nx format:write",
    "format:check": "nx format:check",
    "update": "nx migrate latest",
    "workspace-generator": "nx workspace-generator",
    "dep-graph": "nx dep-graph",
    "help": "nx help"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "13.1.3",
    "@angular/cdk": "13.1.3",
    "@angular/common": "13.1.3",
    "@angular/compiler": "13.1.3",
    "@angular/core": "13.1.3",
    "@angular/forms": "13.1.3",
    "@angular/platform-browser": "13.1.3",
    "@angular/platform-browser-dynamic": "13.1.3",
    "@angular/router": "13.1.3",
    "@ngneat/until-destroy": "^8.0.4",
    "@nrwl/angular": "13.5.3",
    "@twittwer/compodoc": "^1.6.6",
    "rxjs": "7.4.0",
    "tslib": "^2.0.0",
    "zone.js": "0.11.4"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "13.1.4",
    "@angular-eslint/eslint-plugin": "13.0.1",
    "@angular-eslint/eslint-plugin-template": "13.0.1",
    "@angular-eslint/template-parser": "13.0.1",
    "@angular/cli": "13.1.4",
    "@angular/compiler-cli": "13.1.3",
    "@angular/language-service": "13.1.3",
    "@compodoc/compodoc": "^1.1.15",
    "@cypress/webpack-dev-server": "^1.8.1",
    "@nrwl/cli": "13.5.3",
    "@nrwl/cypress": "13.5.3",
    "@nrwl/eslint-plugin-nx": "13.5.3",
    "@nrwl/jest": "13.5.3",
    "@nrwl/linter": "13.5.3",
    "@nrwl/tao": "13.5.3",
    "@nrwl/workspace": "13.5.3",
    "@types/jest": "27.0.2",
    "@types/node": "14.14.33",
    "@typescript-eslint/eslint-plugin": "5.3.1",
    "@typescript-eslint/parser": "5.3.1",
    "angular2-template-loader": "^0.6.2",
    "cypress": "^9.4.1",
    "cypress-angular-unit-test": "^3.9.0",
    "dotenv": "10.0.0",
    "eslint": "8.2.0",
    "eslint_d": "^11.1.1",
    "eslint-config-prettier": "^8.1.0",
    "eslint-plugin-cypress": "^2.12.1",
    "eslint-plugin-jest": "^26.0.0",
    "eslint-plugin-prettier": "^4.0.0",
    "eslint-plugin-sort-imports-es6-autofix": "^0.6.0",
    "html-webpack-plugin": "^5.5.0",
    "jest": "27.2.3",
    "jest-preset-angular": "11.0.0",
    "ng-mocks": "^13.0.3",
    "prettier": "2.5.1",
    "raw-loader": "^1.0.0",
    "ts-jest": "27.0.5",
    "ts-node": "~9.1.1",
    "typescript": "4.5.5"
  }
}
dgrbrady commented 2 years ago

Update: I implemented unit tests in a different component in my ui lib, and it works just fine... so there's something funky about my TaskbarComponent code... Feel free to close, but if anyone has any ideas, I'd love to get some extra eyes on it!

dgrbrady commented 2 years ago

Update 2: I figured out what was causing the issue with TaskbarComponent, but I have no idea why this is an issue. It was failing due to the order of the imports in the spec.ts file.

So this would fail (also fails in any spec.ts file):

import { TaskbarComponent } from './taskbar.component';

import { initEnv, mount } from 'cypress-angular-unit-test';

But THIS fixes it??

import { initEnv, mount } from 'cypress-angular-unit-test';

import { TaskbarComponent } from './taskbar.component';

For some reason, cypress-angular-unit-test HAS to be imported before the component you're testing. Is this intended behavior? If so, it might be a useful thing to add to the README.