【问题标题】:Cannot properly bundle tests for Angular with HTML templates无法正确地将 Angular 测试与 HTML 模板捆绑在一起
【发布时间】:2019-10-16 10:06:07
【问题描述】:

在我们当前的项目中,我们构建了一个自定义混合 NGJS/NGX 应用程序作为完全迁移到 Angular 的中间步骤。

混合将每个 Angular 版本都包含在一个单独的目录中。它们在两个方向上互通——我们在 AngularJS 中包含降级的 Angular 文件,在 Angular 中包含升级的 AngularJS 文件。

构建工作完全符合预期(所有文件都正确输出),但是,我们无法使测试工作(Karma + Webpack)。

它们在一个非常特定的点失败 - 当您包含需要任何类型 HTML 的 AngularJS 文件时,例如import Tpl from '../templates/my-template.tpl.html.

错误如下:

TypeError: Cannot read property 'module' of undefined
at eval (webpack-internal:///./src/ngjs/Account/templates/account.password.edit.tpl.html:4:16)
at Module../src/ngjs/Account/templates/account.password.edit.tpl.html (http://localhost:9879/absolute/path-to-repo/karma.bundle.js?b7d10f4cb57d9b36c6b149128e3c9810b2901be0:7594:1)
at __webpack_require__ (http://localhost:9879/absolute/path-to-repo/karma.bundle.js?b7d10f4cb57d9b36c6b149128e3c9810b2901be0:20:30)
at eval (webpack-internal:///./src/ngjs/Core/services/user.service.ts:11:64)
at Object../src/ngjs/Core/services/user.service.ts (http://localhost:9879/absolute/path-to-repo/karma.bundle.js?b7d10f4cb57d9b36c6b149128e3c9810b2901be0:7610:1)
at __webpack_require__ (http://localhost:9879/absolute/path-to-repo/karma.bundle.js?b7d10f4cb57d9b36c6b149128e3c9810b2901be0:20:30)
at eval (webpack-internal:///./src/ngx/core/components/display-groups-dropdown/display-groups-dropdown.component.ts:14:22)
at Object../src/ngx/core/components/display-groups-dropdown/display-groups-dropdown.component.ts (http://localhost:9879/absolute/path-to-repo/karma.bundle.js?b7d10f4cb57d9b36c6b149128e3c9810b2901be0:8092:1)
at __webpack_require__ (http://localhost:9879/absolute/path-to-repo/karma.bundle.js?b7d10f4cb57d9b36c6b149128e3c9810b2901be0:20:30)
at eval (webpack-internal:///./src/ngx/core/components/display-groups-dropdown/display-groups-dropdown.component.spec.ts:4:43)

ngx 是应用程序的 Angular 部分,ngjs 是 AngularJS)。

我们的 Karma 配置:

export default (config) => {
config.set({
    basePath: 'src',
    frameworks: ['jasmine'],
    plugins: [
        karmaJasminePlugin,
        karmaChromeLauncherPlugin,
        karmaWebpackPlugin,
        tsLoaderPlugin,
        karmaMochaReporterPlugin,
        karmaCoverageIstanbulReporterPlugin,
    ],
    preprocessors: {
        '../karma.bundle.ts': ['webpack'],
    },
    client: { clearContext: false }, // leave Jasmine Spec Runner output visible in browser
    files: [
        { pattern: '../karma.bundle.ts', watched: false },
    ],
    mime: {
        'text/x-typescript': ['ts', 'tsx'],
    },
    coverageIstanbulReporter: {
        dir: require('path').join(__dirname, 'coverage'),
        reports: ['html', 'lcovonly', 'text-summary'],
        combineBrowserReports: true,
        fixWebpackSourcePaths: true
    },
    reporters: config.codeCoverage ? ['mocha', 'coverage-istanbul'] : ['mocha'],
    mochaReporter: { ignoreSkipped: true },
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: false,
    singleRun: true,
    browsers: ['ChromeHeadless'],
    customLaunchers: {
        ChromeDebug: {
            base: 'Chrome',
            flags: ['--remote-debugging-port=9333'],
            debug: true
        },
    },
    webpack: config.codeCoverage ? webpackMerge(webpackConf,
        {
            module: {
                rules: [
                    {
                        test: /\.ts$/,
                        exclude: /\.spec\.ts$/,
                        enforce: 'post',
                        use: {
                            loader: 'istanbul-instrumenter-loader',
                            options: {
                                esModules: true
                            },
                        }
                    }
                ]
            }
        }
    ) : webpackConf,
    webpackMiddleware: {
        noInfo: true,
        stats: 'errors-only'
    },
    concurrency: Infinity,
    browserDisconnectTolerance: 3,
    browserDisconnectTimeout: 210000,
    browserNoActivityTimeout: 210000,
});
};

我们用于测试的 tsconfig:

{
"extends": "../tsconfig.json",
"compilerOptions": {
    "outDir": "../out-tsc/spec",
    "types": [
        "jasmine",
        "node"
    ]
},
"include": [
    "../karma.bundle.ts",
    "**/*.spec.ts",
    "**/*.d.ts"
]
}

karma.bundle.ts(相当标准):

// First, initialize the Angular testing environment.
beforeAll(() => {
    testing.TestBed.resetTestEnvironment();
    testing.TestBed.initTestEnvironment(browser.BrowserDynamicTestingModule,
        browser.platformBrowserDynamicTesting());
});

/**
 * Get all the files, for each file, call the context function
 * that will require the file and load it up here. Context will
 * loop and require those spec files here
 */
function requireAll(requireContext) {
    return requireContext.keys().map((key) => {
        requireContext(key);
    });
}

/**
 * Requires and returns all modules that match
 */
const context = (require as any).context('./src', true, /\.spec\.ts$/);
console.log('Keys: ', context.keys());
requireAll(context);

到目前为止,我有以下怀疑:

  • Karma 在加载模块时看不到类型,因此 HTML 不是可识别的类型
  • Webpack 没有按应有的方式处理 HTML,尽管配置正确,但仅在 Karma 上下文中

我很乐意提供任何帮助,因为我们完全陷入困境,我们的测试暂时无法使用。

【问题讨论】:

    标签: angular typescript webpack karma-jasmine


    【解决方案1】:

    经过进一步调查,我们发现了一个允许测试通过并忽略module 错误的部分解决方案。我们修改了代码以在 Karma 中要求上下文:

    function requireAll(requireContext) {
        return requireContext.keys().map((key) => {
            try {
                requireContext(key);
            } catch (err) {
                console.log('Cannot require:', err);
            }
        }
    }
    

    另外值得一提的是:导入顺序在捆绑文件中很重要(这是我们在使用karma.bundle.ts 时遇到的另一个问题)。我们从:

    import * as testing from '@angular/core/testing';
    import * as browser from '@angular/platform-browser-dynamic/testing';
    import 'core-js/es7/reflect';
    import 'zone.js/dist/zone';
    import 'zone.js/dist/zone-testing';
    

    到:

    import 'core-js/es7/reflect';
    import 'zone.js/dist/zone';
    import 'zone.js/dist/zone-testing';
    
    import * as testing from '@angular/core/testing';
    import * as browser from '@angular/platform-browser-dynamic/testing';
    

    这并不能直接解决我们的问题,但允许测试通过,只要在测试中不使用导致错误的导入模板(所有导入错误将被catch() 子句抑制)。

    解决方案的另一部分是修改 Webpack 配置以进行测试 - 我们添加了额外的规则,以最简单的方式处理 HTML。发生了 Karma 可能更改了 Webpack 管道中使用的路径,并且 Webpack 无法正确处理 HTML。这个:

    rules: [
                {
                    test: /\.tpl\.html$/,
                    use: [
                        'raw-loader',
                        'html-loader'
                    ]
                },
                { // ts
                    test: /\.ts$/,
                    exclude: [/node_modules/],
                    use: [
                        {
                            loader: 'ts-loader',
                            options: {
                                configFile: path.join(srcDir, 'tsconfig.spec.json'),
                                onlyCompileBundledFiles: true,
                                experimentalWatchApi: true,
                                transpileOnly: true
                            },
                        },
                        'angular2-template-loader'
                    ],
                },
            ]
    

    解决了这个问题。

    【讨论】:

      猜你喜欢
      • 2017-08-21
      • 1970-01-01
      • 1970-01-01
      • 2016-10-05
      • 2019-07-15
      • 1970-01-01
      • 1970-01-01
      • 2015-09-13
      • 1970-01-01
      相关资源
      最近更新 更多