2017-10-31 20 views
5

최근에 나는 webpack에 모든 종류의 물건을 돌 보았던 커스텀 꿀풀 스크립트에서 이동을 시작했습니다. 브라우저에서 클라이언트 응용 프로그램을 번들링하고 제공하는 것이 더 효과적 일 때까지 작업하고 있습니다.karma-webpack 로딩하지 않음 AngularJS 번들

이제 gulp를 사용하여 번들로 제공된 app.js 파일에 대해 karma 테스트를 실행할 때 gulp 스크립트는 먼저 app.js 파일을 번들로 만든 다음 dist 폴더로 침을 뱉습니다. 이 파일은 karma가 테스트를 실행하는 데 사용됩니다. 내 꿀꺽 꿀꺽 마력 테스트 작업은 또한 테스트 파일 변경 또는 번들 파일 변경을 감시하고이를 바탕으로 테스트를 다시 실행합니다.

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") 
    } 
}; 

이이 기본적으로있는 t 엔트리 포인트가되는 boot.ts 내 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 
    }); 
}; 

입니다 그는 앱 :

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("[email protected]")); 
     expectValidPassword(_AccountService.validatePassword("Ma#38Hr$")); 
     expectValidPassword(_AccountService.validatePassword("aA1\"#$%(#/$\"#$/(=/#$=!\")(\")(")); 
     }) 
    }); 
    }); 
}); 

그리고 이것은 다음을 실행했을 때의 결과입니다 : karma start

> npm test 

> [email protected] 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 [email protected] 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 
     [email protected]_modules/angular/angular.js:410:24 
     [email protected]_modules/angular/angular.js:4917:12 
     [email protected]_modules/angular/angular.js:4839:30 
     [email protected]_modules/angular-mocks/angular-mocks.js:3172:60 
     [email protected]://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 
     [email protected]://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 
     [email protected]_modules/angular/angular.js:410:24 
     [email protected]_modules/angular/angular.js:4917:12 
     [email protected]_modules/angular/angular.js:4839:30 
     [email protected]_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.log를 남긴 몇 군데를주의하십시오. 앱이로드되지 않는다는 것을 알 수있는 방법입니다. 재스민이 내가 테스트하고 싶은 서비스를 주입 할 수 없다는 사실.

내가 사용하고 있습니다 :

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 

편집 :

"src/boot.ts" 

하지만 같으면 '와 카르마 설정에서

"dist/app.js" 

:

은 내가 대체하여 실행 테스트를 만들기 위해 관리 드릴 다운 또는로드/i 나머지 응용 프로그램을 mport하십시오. 그런 다음 테스트 할 클래스 만 가져 오려고 시도했지만 테스트 할 클래스에 DI 주입 서비스를 모의 할 수 없습니다. 어쨌든, 저는이 단계에서 이것을 거의 포기하고 ang2 +로 이동하는 방법을 알아 내려고하지 않았습니다.

+0

나는 당신의 app과 실행중인'npm run serve : dev' 명령어를 복제하려고 시도했다. 콘솔에서 에러가 발생하고 app의 기본 html이기 때문에'App renders fine'이 보일 것이다. 'ts-loader가 예상치 못한 로더 옵션과 함께 제공되었습니다. '오류가 발생했습니다. – varit05

+0

@ varit05 - 미안하지만, 나는 그것을 repro 수 없습니다. :/나는 이전에 아무 것도 설정하지 않은 별도의 컴퓨터에서이 응용 프로그램을 정상적으로 시작했습니다. (콘솔에서 예상되는 출력을 얻지 못했다고 생각하는 devtools에도 있습니까?) . – pootzko

+1

이 모든 것이 잘못되었거나 적어도 karma + webpack + angular와 다른 점이 있습니다. 테스트를 실행하기 위해 'npm run test'를 제외하고는 아무 것도 필요하지 않습니다. 카르마 설정이 아닌 테스트 파일에 app.ts/js를 포함시켜야합니다. 등등. 당신은 angular + karma + webpack에 대한 웹 설정에서 사용할 수있는 것을 시도 했습니까? –

답변

1

저는 Grunt에서 Webpack으로 AngularJS 프로젝트 건물을 이전하는 동안 비슷한 문제에 직면하여 2 가지 접근 방식을 시도했습니다.

1. Webpack과 Karma는 두 개의 별도 프로세스입니다.webpackkarma을 동시에 실행하는 npm 스크립트를 만들었습니다. 그것은

"dev-build": "webpack --config webpack/development.js", 
"dev-test": "karma start test/karma.development.conf.js", 
"test": "concurrently --kill-others --raw \"npm run dev-build\" \"npm run dev-test\"" 

대신 concurrently 다른 작업을 수행 할 수 있습니다, npm-run-all 또는 &처럼 보였다. 이 구성에서 Karma는 Webpack에 대한 정보를 얻지 못했고, 빌드 된 배포판에 대한 ./temp 폴더를 보았고 독립형으로 작동하여 테스트 또는 배포본이 변경 될 때마다 자신을 다시 실행했습니다. Webpack은 dev-mode에서 ("dev-build"스크립트를 통해) 시작되었고 ./src 폴더를보고 ./temp 폴더로 배포판을 컴파일했습니다. 그가 ./temp를 업데이트 할 때 카르마는 테스트를 다시 시작했습니다.

첫 번째 카르마의 문제에도 불구하고 효과가있었습니다. Karma는 Webpack의 첫 컴파일이 끝나기 전에 테스트를 시작했습니다. 그것은 중요하지 않습니다. 또한 restartOnFileChange 설정을 사용하면 도움이 될 수 있습니다. 다른 좋은 해결 방법이있을 수 있습니다. 나는이 이야기를 끝내지 못했고, 나는 옵션 2로 전환했다. 나는 이것이 단지 Webpack-way에 맞다고 생각했다.

2. Karma는 Webpack을 사용하는 유일한 프로세스입니다. ./temp 폴더를 거부하고 dev-mode에서 모든 작업이 메모리에 있어야한다고 결정했습니다. 데브 - 모드 웹팩은 다음 얻었다 설정 (./webpack/development.js) :

entry: { 'ui-scroll': path.resolve(__dirname, '../src/ui-scroll.js') }, 
output: { filename: '[name].js' }, // + path to ./dist in prod 
devtool: 'inline-source-map', // 'source-map' in prod 
compressing: false, 
watch: true 

데브 - 모드 카르마 (./test/karma.development.conf.js) :

files: [ 
    // external libs 
    // tests specs 
    '../src/ui-scroll.js' // ../dist in prod 
], 
preprocessors: { // no preprocessors in prod 
    '../src/ui-scroll.js': ['webpack', 'sourcemap'] 
}, 
webpack: require('../webpack/development.js'), // no webpack in prod 
autoWatch: true, 
keepalive: true, 
singleRun: false 

이를 또한 설치된 두 개의 npm 패키지 : karma-webpackkarma-sourcemap-loader이 필요합니다. 첫 번째 옵션은 Grunt/gulp 이후에 더 익숙해 보이지만,이 옵션은 더 간단하고 짧으며 안정적입니다.

+0

답장을 보내 주셔서 감사합니다. 불행하게도 나는 다음 주까지 그것을 시험 할 수 없을 것이다. 그러나 나는 그것을 시험해보고, 당신에게 돌아갈 것이다. 건배! – pootzko