help-me-mom / ng-mocks

Angular testing library for mocking components, directives, pipes, services and facilitating TestBed setup
https://www.npmjs.com/package/ng-mocks
MIT License
1.05k stars 77 forks source link

Bug: MockBuilder failing with error after updating Angular version 12 to 14. #3274

Closed mdv27 closed 2 years ago

mdv27 commented 2 years ago

Description of the bug

Unit tests are failing with below error when Angular version is updated to 14.x.x from 12.x.x.

Dependency list:

 "dependencies": {
    "@angular/animations": "^14.0.0",
    "@angular/cdk": "^14.0.0",
    "@angular/common": "^14.0.0",
    "@angular/compiler": "^14.0.0",
    "@angular/core": "^14.0.0",
    "@angular/forms": "^14.0.0",
    "@angular/localize": "^14.0.0",
    "@angular/material": "^14.0.0",
    "@angular/platform-browser": "^14.0.0",
    "@angular/platform-browser-dynamic": "^14.0.0",
    "@angular/router": "^14.0.0",
    "@azure/msal-angular": "^2.0.0-beta.5",
    "@azure/msal-browser": "^2.14.1",
    "@babel/core": "^7.13.0",
    "@ngx-formly/core": "^5.0.0",
    "@ngx-formly/material": "^5.0.0",
    "@progress/kendo-angular-buttons": "^8.0.0",
    "@progress/kendo-angular-common": "^3.0.0",
    "@progress/kendo-angular-dateinputs": "^7.0.0",
    "@progress/kendo-angular-dropdowns": "^7.0.0",
    "@progress/kendo-angular-filter": "^2.1.2",
    "@progress/kendo-angular-inputs": "^9.0.0",
    "@progress/kendo-angular-intl": "^4.0.0",
    "@progress/kendo-angular-l10n": "^4.0.0",
    "@progress/kendo-angular-label": "^4.0.0",
    "@progress/kendo-angular-popup": "^5.0.0",
    "@progress/kendo-angular-treeview": "^7.0.0",
    "@progress/kendo-data-query": "^1.5.5",
    "@progress/kendo-drawing": "^1.16.0",
    "@progress/kendo-licensing": "^1.0.0",
    "@progress/kendo-theme-default": "^5.5.0",
    "ajv": "^6.12.6",
    "angular-material-icons": "^0.7.1",
    "bootstrap": "^4.6.0",
    "d3": "^6.6.2",
    "jquery": "^3.6.0",
    "ng-sidebar": "^9.4.2",
    "ngx-cookie-service": "^14.0.1",
    "ngx-device-detector": "^4.0.0",
    "ngx-guided-tour": "2.0.1",
    "ngx-toastr": "15.0.0",
    "popper.js": "^1.16.1",
    "rxjs": "7.5.6",
    "save-svg-as-png": "^1.4.17",
    "tslib": "^2.0.0",
    "zone.js": "~0.11.4"
  },
  "devDependencies": {
    "@angular-builders/jest": "^14.0.0",
    "@angular-devkit/build-angular": "^14.0.0",
    "@angular-eslint/eslint-plugin": "^14.0.0",
    "@angular-eslint/eslint-plugin-template": "^14.0.0",
    "@angular-eslint/template-parser": "^14.0.0",
    "@angular/cli": "^14.0.0",
    "@angular/compiler-cli": "^14.0.0",
    "@compodoc/compodoc": "1.1.11",
    "@istanbuljs/nyc-config-typescript": "^1.0.2",
    "@types/d3": "^6.3.0",
    "@types/jest": "^28.1.6",
    "@typescript-eslint/eslint-plugin": "4.3.0",
    "@typescript-eslint/parser": "4.3.0",
    "chance": "^1.1.8",
    "codelyzer": "^6.0.0",
    "cypress": "^9.6.1",
    "eslint": "^7.6.0",
    "eslint-plugin-cypress": "^2.12.1",
    "eslint-plugin-import": "2.22.1",
    "eslint-plugin-jsdoc": "30.7.6",
    "eslint-plugin-prefer-arrow": "1.2.2",
    "fs-extra": "^10.1.0",
    "jest": "^28.1.3",
    "jest-preset-angular": "^12.2.0",
    "ng-mocks": "^14.0.0",
    "nyc": "^15.1.0",
    "tslint": "~6.1.0",
    "typescript": "^4.6.2"
  }

Line of code where getting below error:

beforeEach(() => {
    return MockBuilder(
      myComponent,
      AppModule /*This has all myComponent dependency module imports*/
    );
  });

Error stack:

SyntaxError: Unexpected token '-'
        at new Function (<anonymous>)

      at newTrustedFunctionForJIT (node_modules/@angular/compiler/fesm2020/compiler.mjs:5769:16)
      at JitEvaluator.evaluateCode (node_modules/@angular/compiler/fesm2020/compiler.mjs:5864:20)
      at JitEvaluator.evaluateStatements (node_modules/@angular/compiler/fesm2020/compiler.mjs:5834:21)
      at CompilerFacadeImpl.jitExpression (node_modules/@angular/compiler/fesm2020/compiler.mjs:19562:39)
      at CompilerFacadeImpl.compileComponentFromMeta (node_modules/@angular/compiler/fesm2020/compiler.mjs:19517:21)
      at CompilerFacadeImpl.compileComponent (node_modules/@angular/compiler/fesm2020/compiler.mjs:19506:21)
      at Function.get (node_modules/@angular/core/fesm2020/core.mjs:25069:34)
      at getComponentDef (node_modules/@angular/core/fesm2020/core.mjs:1130:12)
      at node_modules/@angular/core/fesm2020/core.mjs:24820:34
          at Array.forEach (<anonymous>)
      at setScopeOnDeclaredComponents (node_modules/@angular/core/fesm2020/core.mjs:24816:18)
      at flushModuleScopingQueueAsMuchAsPossible (node_modules/@angular/core/fesm2020/core.mjs:24462:21)
      at TestBedRender3.checkGlobalCompilationFinished (node_modules/@angular/core/fesm2020/testing.mjs:26637:13)
      at TestBedRender3.configureTestingModule (node_modules/@angular/core/fesm2020/testing.mjs:26512:14)
      at Function.configureTestingModule (node_modules/@angular/core/fesm2020/testing.mjs:26360:30)
      at Function.resetTestingModule (node_modules/ng-mocks/webpack:/ng-mocks/libs/ng-mocks/src/lib/common/ng-mocks-global-overrides.ts:208:7)
      at Function.i.TestBed.ngMocksFasterInstalled.i.TestBed.configureTestingModule (node_modules/ng-mocks/webpack:/ng-mocks/libs/ng-mocks/src/lib/mock-helper/mock-helper.faster-install.ts:51:5)    
      at configureTestingModule (node_modules/ng-mocks/webpack:/ng-mocks/libs/ng-mocks/src/lib/mock-builder/mock-builder.promise.ts:193:31)
      at new ZoneAwarePromise (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:1351:25)
      at t.<anonymous> (node_modules/ng-mocks/webpack:/ng-mocks/libs/ng-mocks/src/lib/mock-builder/mock-builder.promise.ts:192:33)
      at node_modules/ng-mocks/index.js:1:57374
      at Object.next (node_modules/ng-mocks/index.js:1:57479)
      at node_modules/ng-mocks/index.js:1:56391
      at new ZoneAwarePromise (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:1351:25)
      at n (node_modules/ng-mocks/index.js:1:56136)
      at t.Promise [as then] (node_modules/ng-mocks/webpack:/ng-mocks/libs/ng-mocks/src/lib/mock-builder/mock-builder.promise.ts:191:6)
      at t.set (node_modules/ng-mocks/webpack:/ng-mocks/libs/ng-mocks/src/lib/mock-builder/mock-builder.performance.ts:59:12)
      at node_modules/ng-mocks/index.js:1:52968
      at Object.next (node_modules/ng-mocks/index.js:1:53073)
      at node_modules/ng-mocks/index.js:1:51985
      at new ZoneAwarePromise (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:1351:25)
      at i (node_modules/ng-mocks/index.js:1:51730)
      at t.Promise [as then] (node_modules/ng-mocks/webpack:/ng-mocks/libs/ng-mocks/src/lib/mock-builder/mock-builder.performance.ts:42:6)

An example of the bug

Above error stack.

Link:

Expected vs actual behavior

Test should run without error.

satanTime commented 2 years ago

Hi @mdv27, thanks for the report.

Please provide a repo which fails the error.

satanTime commented 2 years ago

If it's easier you can upload an archive with the project and node_modules right here in your comment.

mdv27 commented 2 years ago

@satanTime Created repo from scratch and it does fail with same error. Let me know if more details are required.

satanTime commented 2 years ago

Thanks! checking it!

satanTime commented 2 years ago

So, the problem comes from @progress/kendo-angular-inputs and only in jest. I'm working on a fix for it.

mdv27 commented 2 years ago

That's so quick! šŸ˜® šŸ‘ May I know how did you find the root cause? Looking forward for the fix soon šŸ˜„

satanTime commented 2 years ago

Basically I removed everything from your component, the test was failing, then I started to remove module by module and found out this dependency.

The final test is:

import {MockBuilder, MockRender} from 'ng-mocks';
import {TestBed} from "@angular/core/testing";
import {NgModule} from '@angular/core';
import {InputsModule} from '@progress/kendo-angular-inputs';
import {Component} from '@angular/core';

@Component({
  selector: 'app-header',
  template: '',
})
class HeaderComponent {}

@NgModule({
  declarations: [HeaderComponent],
  imports: [
    InputsModule,
  ],
})
class AppModule {}

describe('HeaderComponent', () => {
  describe('ng-mocks', () => {
    beforeEach(() => MockBuilder(HeaderComponent, AppModule));

    it('should create component', () => {
      const fixture = MockRender(HeaderComponent, {});
      const component = fixture.point.componentInstance;

      expect(component).toBeDefined();
    });
  });

  describe('TestBed', () => {
    beforeEach(() => {
      return TestBed.configureTestingModule({
        imports: [AppModule],
      }).compileComponents();
    });

    it('should create component', () => {
      const fixture = TestBed.createComponent(HeaderComponent);
      fixture.detectChanges();
      const component = fixture.componentInstance;

      expect(component).toBeDefined();
    });
  });
});
mdv27 commented 2 years ago

Ideally if module/dependency is mocked/stubbed, test should not trigger/run the dependency code, I assume this is not honored with @progress/kendo-angular-inputs dep usage?

satanTime commented 2 years ago

I think there is a problem how the mock of a dependency has been defined, so when Angular is creating a TestBed env, it stumbles over it.

satanTime commented 2 years ago

So. Some of declarations of @progress have empty class / function names, because of that ng-mocks treated them as arrow-function, whereas - is a wrong symbol for a class / function name. jest is creating a file with a mock class called MockOfarrow-function, and this dash has caused the failure.

Now ng-mocks uses arrowFunction and MockOfarrowFunction is compatible with a class / function name and doesn't cause the issue.

satanTime commented 2 years ago

v14.1.3 has been released and contains a fix for the issue. Feel free to reopen the issue or to submit a new one if you meet any problems.

mdv27 commented 2 years ago

This change is working for me. Thank you @satanTime šŸ‘