在 Angular 8 (Karma 4.1.0) 升级后,在 Angular 7 (Karma 2.0.4) 中成功完成的 Karma 测试失败

Posted

技术标签:

【中文标题】在 Angular 8 (Karma 4.1.0) 升级后,在 Angular 7 (Karma 2.0.4) 中成功完成的 Karma 测试失败【英文标题】:Karma tests which run to successful completion in Angular 7 (Karma 2.0.4) fail after Angular 8 (Karma 4.1.0) upgrade 【发布时间】:2019-12-03 02:40:03 【问题描述】:

我们有一套约 1100 个单元在“ng 测试”中运行,目前在 Angular 7.2.5 中运行在约 4 分钟内完成,在 Angular 7.2.5 中没有任何故障,并且由于随机故障、减速和在 4 之前断开连接而无法完成Angular 8.0.0 中的分钟数。

测试在 Angular 7 中的 Chrome 或 ChromeHeadless 中成功运行。

已经试过了:

    为了消除已知的样式元素内存泄漏,我们实施了“样式清理”here:

为 1100 次测试中的每个 describe 块运行 cleanStylesFromDOM in afterAll

    在 Angular 8 中,我们尝试将 Karma 从 4.1.0 回归到 3.0.0,并将 jasmine-core 从 3.4.0 回归到 2.99.1,但没有成功。

    使用 Karma 4.1.0 和 jasmine-core 3.4.0 尝试了 Angular 8.1.1,但没有成功。

    增加业力超时:

browserNoActivityTimeout: 120000, captureTimeout: 60000, 报告SlowerThan:2000,browserDisconnectTolerance:2, browserDisconnectTimeout: 20000, browserSocketTimeout: 20000, processKillTimeout: 20000

    将 Node.js 的内存增加到 --max_old_space_size=8192

    关闭“ng test”源映射生成和观察

    在 karma.conf.js 中随机关闭 Jasmine:jasmine: 
  random: false,
  failFast: true,
  timeoutInterval: 1000


    对于每个'describe'块中的每个'it',使用fixture.destroy调用afterEach

    尝试按照建议 here 将 beforeEach TestBed 设置更改为 beforeAll:

    package.json

    
      "name": "myapp",
      "version": "0.0.0",
      "scripts": 
        "ng": "ng",
        "build": "ng build",
        "test": "ng test",
        "lint": "ng lint",
        "e2e": "ng e2e"
      ,
      "private": true,
      "dependencies": 
        "@angular/animations": "~8.0.0",
        "@angular/common": "~8.0.0",
        "@angular/compiler": "~8.0.0",
        "@angular/core": "~8.0.0",
        "@angular/forms": "~8.0.0",
        "@angular/platform-browser": "~8.0.0",
        "@angular/platform-browser-dynamic": "~8.0.0",
        "@angular/router": "~8.0.0",
        "@ng-bootstrap/ng-bootstrap": "^4.0.0",
        "@ng-select/ng-select": "^2.20.0",
        "@ngrx/effects": "^8.0.1",
        "@ngrx/entity": "^8.0.1",
        "@ngrx/router-store": "^8.0.1",
        "@ngrx/store": "^8.0.1",
        "@ngrx/store-devtools": "^8.0.1",
        "@ngx-translate/core": "^11.0.1",
        "angular-resizable-element": "^3.2.4",
        "angular-split": "^3.0.1",
        "bootstrap": "^4.1.3",
        "core-js": "^2.6.9",
        "jquery": "^3.3.1",
        "jquery-ui": "^1.12.1",
        "jquery-ui-bundle": "^1.11.4",
        "jquery.fancytree": "^2.26.0",
        "lodash": "^4.17.11",
        "moment": "^2.17.1",
        "ngx-infinite-scroll": "^7.2.0",
        "ngx-nvd3": "^1.0.9",
        "ngx-restangular": "^5.0.0-rc1",
        "popper.js": "^1.15.0",
        "rxjs": "~6.4.0",
        "tslib": "^1.9.0",
        "ui-contextmenu": "^1.18.1",
        "urijs": "^1.18.6",
        "zone.js": "~0.9.1"
      ,
      "devDependencies": 
        "@angular-devkit/build-angular": "~0.800.0",
        "@angular/cli": "~8.0.2",
        "@angular/compiler-cli": "~8.0.0",
        "@angular/language-service": "~8.0.0",
        "@types/jasmine": "~3.3.8",
        "@types/jasminewd2": "~2.0.3",
        "@types/jquery": "^3.3.29",
        "@types/jquery.fancytree": "^2.7.32",
        "@types/node": "^8.9.5",
        "codelyzer": "^5.0.0",
        "jasmine-core": "~3.4.0",
        "jasmine-marbles": "^0.6.0",
        "jasmine-spec-reporter": "~4.2.1",
        "karma": "~4.1.0",
        "karma-chrome-launcher": "~2.2.0",
        "karma-coverage-istanbul-reporter": "~2.0.1",
        "karma-jasmine": "~2.0.1",
        "karma-jasmine-html-reporter": "^1.4.0",
        "protractor": "~5.4.0",
        "ts-mockito": "^2.3.1",
        "ts-node": "~7.0.0",
        "tslint": "~5.15.0",
        "typescript": "~3.4.3",
        "webpack": "^4.37.0"
      
    
    

    karma.conf.js

    module.exports = function (config) 
      config.set(
        basePath: '',
        frameworks: ['jasmine', '@angular-devkit/build-angular'],
        browsers: ['ChromeHeadless'],
        plugins: [
          require('karma-jasmine'),
          require('karma-chrome-launcher'),
          require('karma-jasmine-html-reporter'),
          require('karma-coverage-istanbul-reporter'),
          require('@angular-devkit/build-angular/plugins/karma')
        ],
        client: 
          clearContext: false // leave Jasmine Spec Runner output visible in browser
        ,
        coverageIstanbulReporter: 
          dir: require('path').join(__dirname, './coverage/webr3'),
          reports: ['html', 'lcovonly', 'text-summary'],
          fixWebpackSourcePaths: true
        ,
        reporters: ['progress', 'kjhtml'],
        port: 9876,
        colors: true,
        logLevel: config.LOG_INFO,
        autoWatch: true,
        singleRun: false,
        restartOnFileChange: true
      );
    ;
    

测试示例:

describe('PageNotFoundComponent', () => 
  let component: PageNotFoundComponent;
  let fixture: ComponentFixture<PageNotFoundComponent>;
  let selectedTextElement: HTMLElement;
  let router;
  let location;

  beforeEach(async(() => 
    TestBed.configureTestingModule(
      imports: [
        TranslateModule.forRoot(
          loader: 
            provide: TranslateLoader,
            useClass: WebpackTranslateLoader
          
        ),
        RouterTestingModule.withRoutes(
          [
            
              path: 'basepath',
              redirectTo: 'nwi'
            ,
            
              path: '**',
              component: PageNotFoundComponent
            
          ]
        ),
      ],
      declarations: [ PageNotFoundComponent ]
    )
    .compileComponents();
  ));

  afterAll(() => 
    cleanStylesFromDOM();
  );

  beforeEach(() => 
    fixture = TestBed.createComponent(PageNotFoundComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
    router = TestBed.get(Router);
    location = TestBed.get(Location);
  );

  it('should show 404 text', fakeAsync(() => 
    const navigationExtras: NavigationExtras = 
      queryParams: 
    ;
    router.navigate([`/unknown`], navigationExtras);
    tick();
    expect(decodeURI(location.path())).toBe(`/unknown`);
    const textElement: HTMLElement = fixture.nativeElement;
    selectedTextElement = textElement.querySelector('p');
    expect(selectedTextElement.innerText).toEqual('404');
  ));
);

我们希望 Angular 8 中的 ~1100 个测试能够像在 Angular 7 中那样运行完成,并且不会出现任何故障。

以下是不应该发生的故障:

Chrome 75.0.3770 (Mac OS X 10.13.6) VMComponent 应该验证 Vul 抑制正确渲染失败 TypeError:无法读取 null 的属性“className” 在 在用户上下文。 (http://localhost:9876/_karma_webpack_/webpack:/src/app/components/vm-disabled-risk-radius/vm-disabled-risk-radius.component.spec.ts:72:18) 在 ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:359:1) 在 ProxyZoneSpec.onInvoke (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:308:1) 在 ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:358:1) 在 Zone.run (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:124:1) 在 runInTestZone (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:561:1) 在用户上下文。 (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:576:1) 在

...以及另外 20 次随机故障 最后断开:

24 07 2019 12:30:11.055:WARN [Chrome 75.0.3770 (Mac OS X 10.13.6)]:在 2Chrome 75.0.3770 (Mac OS X 10.13.6) 超时之前断开连接(0 次)重新连接失败错误 2000ms 超时前断开重连失败(传输错误) Chrome 75.0.3770 (Mac OS X 10.13.6): 执行 582 of 1134 (20 FAILED) (跳过 3) DISCONNECTED (4 mins 7.005 secs / 3 mins 53.442 秒)

【问题讨论】:

您找到解决方案了吗?想知道,也想在我的项目中实现这个! 在 1 年内真是太神奇了,没人知道。我们很多人在工作中都有这个问题。在我看来,这确实使 karma 成为一种不可接受的使用工具。 【参考方案1】:

不确定您提到的cleanStylesFromDOM 做了什么,但最近我在 1800 测试大型套件中遇到了类似问题。症状相似:

运行结束时的测试超时:
FAILED
Error: Timeout - Async function did not complete within 5000ms (set by jasmine.DEFAULT_TIMEOUT_INTERVAL)
at <Jasmine>
在资源受限的环境(即 CI)中运行始终不稳定。

性能分析表明,每次测试后,&lt;head&gt; 中的&lt;style&gt; 标签数量稳步增加。团队不确定这是否是原因,但我们决定将次优资源管理作为主要嫌疑人,类似于您的cleanStylesFromDOM。幸运的是,去年 this PR 已合并,因此不再需要额外的 afterEach 调用。要在每次测试后强制 Angular 清理,请更新“test.ts”中的测试台初始化,如下所示:

getTestBed().initTestEnvironment(
  BrowserDynamicTestingModule,
  platformBrowserDynamicTesting(),
  teardown: destroyAfterEach: true
);

teardown: destroyAfterEach: true 是感兴趣的行。不幸的是,documentation 并没有对destroyAfterEach 说太多。对我来说,打开设置最终会导致稳定、始终绿色运行:

    它揭示了测试中的错误,这些错误在单个测试期间被资源重用所掩盖。我能够在本地重现和修复大量不稳定测试的实例。 没有更多的超时,&lt;style&gt;s 被清理。资源消耗下降。 CI 中的不稳定测试集变得稳定,我能够禁用这些测试以便以后解决它们。

【讨论】:

以上是关于在 Angular 8 (Karma 4.1.0) 升级后,在 Angular 7 (Karma 2.0.4) 中成功完成的 Karma 测试失败的主要内容,如果未能解决你的问题,请参考以下文章

模拟指令以测试组件 - Angular 8 与 jasmine 和 Karma

错误:在 Angular CLI >6.0 中,Karma 插件现在由“@angular-devkit/build-angular”导出

Angular5 / Karma'选择器'不是已知元素[重复]

使用 Karma 测试 Angular 时选择性地模拟服务

Angular 4:如何在没有任何浏览器的情况下通过 Karma 运行测试用例

有没有办法批量处理 Karma - Angular 单元测试?