5

私は最近、あらゆる種類のものを処理していたカスタム gulp スクリプトから webpack への移行を開始しました。ブラウザーでのクライアント アプリのトランスパイル、バンドル、および提供がうまく機能するところまで機能しています。

ここで、バンドルされた app.js ファイルに対してカルマ テストを実行するために gulp を使用していたとき、gulp スクリプトは最初に app.js ファイルをバンドルし、それを dist フォルダーに吐き出しました。このファイルは、それに対してテストを実行するためにカルマによって使用されます。私の gulp テスト タスクは、テスト ファイルの変更やバンドル ファイルの変更も監視し、それに基づいてテストを再実行します。

webpack を使用すると、この dist/app.js がディスクに書き込まれるのではなく、メモリ内に存在することを理解しています (少なくともそれが私が設定した方法です)。それに関する問題は、バンドルされたアプリ (で正常に提供webpack-dev-server --openされる) が何らかの理由でカルマによって読み込まれず、欠けているパズルのピースが何であるかを理解できないことです。

これは、私のフォルダー構造がどのように見えるかです (問題に関連する可能性のある最も基本的なものだけを残しました):

package.json
webpack.config.js
karma.conf.js
src/
--app/
----[other files/subfolders]
----app.ts
----index.ts
--boot.ts
--index.html
tests/
--common/
----services/
------account.service.spec.js

これは私のwebpack.config.jsです

var path = require("path");

const webpack = require("webpack");

const HtmlWebpackPlugin = require("html-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");

module.exports = {
  context: path.join(__dirname),
  entry: "./src/boot.ts",
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new ForkTsCheckerWebpackPlugin(),
    new CleanWebpackPlugin(["dist"]),
    new HtmlWebpackPlugin({
      template: "./src/index.html"
    })
  ],
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [{
          loader: "style-loader"
        }, {
          loader: "css-loader"
        }, {
          loader: "sass-loader"
        }]
      },
      {
        test: /\.tsx?$/,
        use: [{
          loader: "ts-loader",
          options: {
            transpileOnly: true,
            exclude: /node_modules/
          }
        }]
      },
      {
        test: /\.html$/,
        loaders: "html-loader",
        options: {
          attrs: [":data-src"],
          minimize: true
        }
      }
    ]
  },
  resolve: {
    extensions: [".tsx", ".ts", ".js"],
    alias: {
      "common": path.resolve(__dirname, "src/app/common"),
      "common/*": path.resolve(__dirname, "src/app/common/*"),
      "modules": path.resolve(__dirname, "src/app/modules"),
      "modules/*": path.resolve(__dirname, "src/app/modules/*"),
    }
  },
  output: {
    filename: "app.js",
    path: path.resolve(__dirname, "dist")
  },
  devtool: "inline-source-map",
  devServer: {
    historyApiFallback: true,
    hot: false,
    contentBase: path.resolve(__dirname, "dist")
  }
};

これは私の karma.conf.js です

const webpackConfig = require("./webpack.config");

module.exports = function (config) {
  config.set({
    frameworks: ["jasmine"],

    files: [
      "node_modules/angular/angular.js",
      "node_modules/angular-mocks/angular-mocks.js",
      "dist/app.js", // not sure about this
      "tests/common/*.spec.js",
      "tests/common/**/*.spec.js"
    ],

    preprocessors: {
      "dist/app.js": ["webpack", "sourcemap"], // not sure about this either
      "tests/common/*.spec.js": ["webpack", "sourcemap"],
      "tests/common/**/*.spec.js": ["webpack", "sourcemap"]
    },

    webpack: webpackConfig,

    webpackMiddleware: {
      noInfo: true,
      stats: {
        chunks: false
      }
    },

    reporters: ["progress", "coverage"], // , "teamcity"],

    coverageReporter: {
      dir: "coverage",
      reporters: [
        { type: "html", subdir: "html" },
        { type: "text-summary" } 
      ]
    },

    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: [
      "PhantomJS"
      //"Chrome"
    ],
    singleRun: false,
    concurrency: Infinity,
    browserNoActivityTimeout: 100000
  });
};

これは、基本的にアプリへのエントリ ポイントである boot.ts です。

import * as app from "./app/app";
import "./styles/app.scss";

// This never gets written to the console
// so I know it never gets loaded by karma
console.log("I NEVER OUTPUT TO CONSOLE"); 

これは app.ts です (これは、その下にあるものをすべて参照します。

import * as ng from "angular";
import * as _ from "lodash";

import "@uirouter/angularjs";
import "angular-cookies";
import "angular-material"
import "angular-local-storage";
import "angular-sanitize";
import "angular-messages";
import "angular-file-saver";
import "angular-loading-bar";
import "satellizer";

export * from "./index";

import * as Module from "common/module";
import * as AuthModule from "modules/auth/module";
import * as UserModule from "modules/user/module";

import { MyAppConfig } from "./app.config";
import { MyAppRun } from "./app.run";

export default ng.module("MyApp", [
  "ngCookies",
  "ngSanitize",
  "ngMessages",
  "ngFileSaver",
  "LocalStorageModule",
  "ui.router",
  "ngMaterial",
  "satellizer",
  "angular-loading-bar",
  Module.name,
  AuthModule.name,
  UserModule.name
])
.config(MyAppConfig)
.run(MyAppRun);

最後に、account.service.spec.js です。

describe("Account service", function () {
  // SETUP

  var _AccountService;

  beforeEach(angular.mock.module("MyApp.Common"));
  beforeEach(angular.mock.inject(function (_AccountService_) {
    // CODE NEVER GETS IN HERE EITHER
    console.log("I NEVER OUTPUT TO CONSOLE");
    _AccountService = _AccountService_;
  }));

  function expectValidPassword(result) {
    expect(result).toEqual({
      minCharacters: true,
      lowercase: true,
      uppercase: true,
      digits: true,
      isValid: true
    });
  }

  // TESTS

  describe(".validatePassword()", function () {
    describe("on valid password", function () {
      it("returns valid true state", function () {
        expectValidPassword(_AccountService.validatePassword("asdfASDF123"));
        expectValidPassword(_AccountService.validatePassword("as#dfAS!DF123%"));
        expectValidPassword(_AccountService.validatePassword("aA1234%$2"));
        expectValidPassword(_AccountService.validatePassword("YYyy22!@"));
        expectValidPassword(_AccountService.validatePassword("Ma#38Hr$"));
        expectValidPassword(_AccountService.validatePassword("aA1\"#$%(#/$\"#$/(=/#$=!\")(\")("));
      })
    });
  });
});

そして、これは実行の出力ですkarma start

> npm test

> myapp@1.0.0 test E:\projects\Whatever
> karma start

clean-webpack-plugin: E:\projects\Whatever\dist has been removed.
Starting type checking service...
Using 1 worker with 2048MB memory limit
31 10 2017 21:47:23.372:WARN [watcher]: Pattern "E:/projects/Whatever/dist/app.js" does not match any file.
31 10 2017 21:47:23.376:WARN [watcher]: Pattern "E:/projects/Whatever/tests/common/*.spec.js" does not match any file.
ts-loader: Using typescript@2.4.2 and E:\projects\Whatever\tsconfig.json
No type errors found
Version: typescript 2.4.2
Time: 2468ms
31 10 2017 21:47:31.991:WARN [karma]: No captured browser, open http://localhost:9876/
31 10 2017 21:47:32.004:INFO [karma]: Karma v1.7.1 server started at http://0.0.0.0:9876/
31 10 2017 21:47:32.004:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
31 10 2017 21:47:32.010:INFO [launcher]: Starting browser PhantomJS
31 10 2017 21:47:35.142:INFO [PhantomJS 2.1.1 (Windows 8 0.0.0)]: Connected on socket PT-pno0eF3hlcdNEAAAA with id 71358105
PhantomJS 2.1.1 (Windows 8 0.0.0) Account service .validatePassword() on valid password returns valid true state FAILED
        forEach@node_modules/angular/angular.js:410:24
        loadModules@node_modules/angular/angular.js:4917:12
        createInjector@node_modules/angular/angular.js:4839:30
        WorkFn@node_modules/angular-mocks/angular-mocks.js:3172:60
        loaded@http://localhost:9876/context.js:162:17
        node_modules/angular/angular.js:4958:53
        TypeError: undefined is not an object (evaluating '_AccountService.validatePassword') in tests/common/services/account.service.spec.js (line 742)
        webpack:///tests/common/services/account.service.spec.js:27:0 <- tests/common/services/account.service.spec.js:742:44
        loaded@http://localhost:9876/context.js:162:17
PhantomJS 2.1.1 (Windows 8 0.0.0) Account service .validatePassword() on valid amount of characters returns minCharacters true FAILED
        forEach@node_modules/angular/angular.js:410:24
        loadModules@node_modules/angular/angular.js:4917:12
        createInjector@node_modules/angular/angular.js:4839:30
        WorkFn@node_modules/angular-mocks/angular-mocks.js:3172:60
        node_modules/angular/angular.js:4958:53
        TypeError: undefined is not an object (evaluating '_AccountService.validatePassword') in tests/common/services/account.service.spec.js (line 753)
        webpack:///tests/common/services/account.service.spec.js:38:0 <- tests/common/services/account.service.spec.js:753:37
PhantomJS 2.1.1 (Windows 8 0.0.0): Executed 2 of 2 (2 FAILED) ERROR (0.017 secs / 0.015 secs)

トリガーされないconsole.logsを残したいくつかの場所に注意してください。それが、アプリがロードされないことを私が知っている方法です。それと、ジャスミンがテストしたいサービスを注入できないという事実。

私は使用しています:

karma v1.7.1
karma-webpack v2.0.5
webpack v3.3.0

何か案は?私は何を間違っていますか?私の webpack.config.js は、私の AngularJS/TS アプリをバンドルし、基本的にそれをカルマにフィードすることになっているという印象を受けていますが、何らかの理由で、それはうまくいかないようです。それとも、これがどのように機能するかについて根本的な誤解がありますか?

ありがとうございました。

問題を簡単に再現できるように、いくつかのファイルを単純なアプリに抽出してgithubに配置しました。

npm install # install deps
npm run serve:dev # run the app - works
npm run test # run karma tests - doesn't work

編集:

以下を置き換えることで、テストを実行することができました。

"dist/app.js"

カルマセットアップで

"src/boot.ts"

しかし、それはドリルダウンしたり、アプリの残りの部分をロード/インポートしたりしません。次に、テストしたいクラスだけを仕様にインポートしようとしましたが、テストしているクラスが使用している DI 注入サービスをモックできませんでした。とにかく、私はこの段階でこれをほとんどあきらめ、これを行う方法を理解しようとするのをやめ、ang2+ に移行しました。

4

1 に答える 1