Can someone please help me around this deadend of 1 vs 2?
1) Angular project as AoT in production. This required my source code to be changed to have templateUrl and styleUrls that are relative to the component.ts file.
2) Angular karma as JiT for unit tests. This required my source code to be changed to have templateUrl and styleUrls that are absolute, or the unit test will throw a 404 looking for the .html file.
I would like to avoid maintaining a relative AND an absolute path in the source code.
What are my options here? What is the best practice?
(I'm USING WEBPACK with aot and Karma, NOT angular-cli)
Thanks!!
UPDATE: we're also going to explore converting to angular-cli, but this is a huge project and this is a blocker for us, if anyone knows the trick that angular-cli uses in order to pull this off. or even a work-around so we can get our unit tests back!
I need to know a trick to run Unit tests WITH AoT or at least ALONG SIDE AoT (in other words run aot production and jit unit tests with one set of templateUrls)
Thanks again!
PS.. This worked without AoT perfectly (with the absolute urls), but switching to AoT (with urls relative to the component file) has blocked us.
UPDATE 2: (including all my config files) if I have to create another config file to run tests with (which makes sense) but I'd like to know what 'magic' that test config needs in order to run JiT components, now that my urls are all relative.
webpack.config.js
let webpack = require('webpack');
let path = require('path');
let aot = require('@ngtools/webpack');
module.exports = {
entry: {
main: './Angular/main'
},
output: {
path: __dirname,
filename: './dist/smartcommand-[name].min.js',
// Lazy load modules by route & chunk
chunkFilename: './dist/smartcommand-[name].chunk.[hash].min.js'
},
resolve: {
extensions: ['.ts', '.js'],
modules: [
path.resolve('./'),
path.resolve('./node_modules')
],
alias: {
'ng2-charts/charts/charts': 'node_modules/ng2-charts/bundles/ng2-charts.umd.min.js'
//'ng2-dragula': 'node_modules/ng2-dragula/bundles/ng2-dragula.umd.min.js'
}
},
module: {
rules: [
// Ahead of Time Compilation
{ test: /\.ts$/, loader: '@ngtools/webpack', exclude: [/\.(spec)\.ts$/] },
// AoT requires all files to be loaded
{ test: /\.html$/, loader: 'html-loader' },
{ test: /\.css$/, loader: 'raw-loader' },
{
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
loader: 'file-loader', options: { name: '[path][name].[ext]' }
}
]
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({ name: 'main' }),
// Ahead of Time Plugin
new aot.AngularCompilerPlugin({
tsConfigPath: path.resolve('./Angular/tsconfig.json'),
entryModule: path.resolve('./Angular/_app.module#SmartCommandModule')
// Use this setting to turn off AoT
//,skipCodeGeneration: true
}),
// Only load the necessary locales for moment
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /en|es/)
],
// Minimize webpack console output
stats: { assets: false, children: false }
};
karma.config.js
/* Karma Configuration */
'use strict';
module.exports = function (config) {
let appBase = 'Angular/'; // transpiled app JS and map files
config.set({
plugins: [
'karma-jasmine',
'karma-jasmine-html-reporter',
//'karma-chrome-launcher',
'karma-firefox-launcher',
// preprocessors
'karma-webpack',
'karma-sourcemap-loader', // show proper (un-bundled) stack traces
'karma-coverage', // capture unit test code coverage
'karma-trx-reporter' // report coverage in VSTS
],
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine'],
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
//browsers: ['Chrome'],
browsers: ['Firefox'],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'karma-test-shim.js': ['webpack', 'coverage']
// for debugging the tests
//'karma-test-shim.js': ['webpack', 'sourcemap']
},
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// list of files / patterns to load in the browser
files: [
// polyfills
'node_modules/core-js/client/shim.js',
'Scripts/jquery-3.1.1.min.js',
'Scripts/jquery-ui-1.12.1.min.js',
'node_modules/moment/moment.js',
'node_modules/leaflet/dist/leaflet.js',
'node_modules/nipplejs/dist/nipplejs.js',
'node_modules/zone.js/dist/zone.js',
'node_modules/zone.js/dist/long-stack-trace-zone.js',
'node_modules/zone.js/dist/proxy.js',
'node_modules/zone.js/dist/sync-test.js',
'node_modules/zone.js/dist/jasmine-patch.js',
'node_modules/zone.js/dist/async-test.js',
'node_modules/zone.js/dist/fake-async-test.js',
// rxJS
{ pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false },
{ pattern: 'node_modules/rxjs/**/*.js.map', included: false, watched: false },
// other dependencies
{ pattern: 'node_modules/applicationinsights-js/**/*.js', included: false, watched: false },
{ pattern: 'node_modules/applicationinsights-js/**/*.js.map', included: false, watched: false },
{ pattern: 'node_modules/ng2-charts/**/*.js', included: false, watched: false },
{ pattern: 'node_modules/ng2-charts/**/*.js.map', included: false, watched: false },
'node_modules/chart.js/dist/Chart.bundle.js',
{ pattern: 'node_modules/primeng/**/*.js', included: false, watched: false },
{ pattern: 'node_modules/ngx-slick/**/*.js', included: false, watched: false },
{ pattern: 'node_modules/ng2-dragula/**/*.js', included: false, watched: false },
{ pattern: 'node_modules/ng2-dragula/**/*.js.map', included: false, watched: false },
// our SmartCommand bundle
'dist/smartcommand-main.min.js',
// our Karma tests
{ pattern: 'karma-test-shim.js', included: true, watched: true },
// paths for debugging with source maps in dev tools
{ pattern: appBase + '**/*.ts', included: false, watched: false },
{ pattern: appBase + '**/*.js.map', included: false, watched: false },
// our assets (HTML & CSS) paths loaded via Angular's component compiler
{ pattern: appBase + '**/*.html', included: false, watched: true },
{ pattern: appBase + '**/*.css', included: false, watched: true },
{ pattern: 'Content/*.css', included: true, watched: false },
{ pattern: 'Content/*.css.map', included: false, watched: false },
{ pattern: 'Content/Images/**/*', included: false, watched: false },
{ pattern: 'Content/images/**/*', included: false, watched: false }
],
// proxied base paths for loading assets
proxies: {
// required for component assets fetched by Angular's compiler
'/Angular/': '/base/Angular/',
'/Content/': '/base/Content/'
},
// test results reporter to use
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress', 'kjhtml', 'coverage', 'trx'],
// karma code coverage
coverageReporter: {
// specify a common output directory
dir: 'coverage',
reporters: [
// reporters not supporting the `file` property
{ type: 'html', subdir: 'report-html' },
{ type: 'lcov', subdir: 'report-lcov' },
// reporters supporting the `file` property, use `subdir` to directly
// output them in the `dir` directory
{ type: 'cobertura', subdir: '.', file: 'cobertura.txt' },
{ type: 'lcovonly', subdir: '.', file: 'report-lcovonly.txt' },
{ type: 'teamcity', subdir: '.', file: 'teamcity.txt' },
{ type: 'text', subdir: '.', file: 'text.txt' },
{ type: 'text-summary', subdir: '.', file: 'text-summary.txt' }
]
},
// get code coverage in VSTS
trxReporter: { outputFile: 'test-results.trx', shortTestName: false },
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// continuous integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false,
// concurrency level
// how many browsers should be started simultaneous
concurrency: Infinity,
client: {
captureConsole: false, // set to true if you need console output
builtPaths: [appBase], // add more spec base paths as needed
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
// workaround for disconnects
browserDisconnectTolerance: 5,
browserNoActivityTimeout: 50000
});
};
karma test shim
// 'No stack trace' is usually best for app testing.
Error.stackTraceLimit = 0;
// Uncomment to get full stacktrace output. Sometimes helpful, usually not.
//Error.stackTraceLimit = Infinity;
// Import all .spec.js files in our Angular folder
let appContext = require.context('./Angular', true, /\.spec\.js$/);
appContext.keys().forEach(appContext);
// Start the Test Environment
let testing = require('@angular/core/testing');
let browser = require('@angular/platform-browser-dynamic/testing');
testing.TestBed.initTestEnvironment(browser.BrowserDynamicTestingModule, browser.platformBrowserDynamicTesting());
Here's the problem I'm seeing. You are in fact using two different Webpack configurations. Obviously, there's your webpack.config.js
which is set for AoT.
However, you are using another, different, configuration when you run Karma. The karma-webpack
plugin provides the Webpack instance that runs in the Karma process with its own configuration. Unless you yourself write code in your karma.config.js
to read webpack.config.js
, then Karma will completely ignore that file. So effectively, when you are running Karma, you are running with a different Webpack configuration. The problem is that currently your configuration is empty, which means that Angular is processing templateUrl
and styleUrls
"raw", and you get the results you are getting.
You need to setup Webpack with a loader that will process the templateUrl
and stylesUrls
to have Webpack handle them. I would use angular2-template-loader
for this.
Looking at your configuration, it seems that by the time Karma sees your files, they've all been transpiled to JavaScript. Normally, angular2-template-loader
is used on TypeScript files, but since it does its job using regular expressions, it also works on JavaScript files.
I'd expect adding Webpack configuration with angular2-template-loader
to your karma.config.js
should work, and adjust for needs specific to your project:
webpack: {
module: {
loaders: [
{
test: /\.js$/,
loaders: ['angular2-template-loader'],
// exclude: [...] You may want to exclude your test files here
// to save some build time.
},
// etc. with raw-loader, html-loader and file-loader as needed.
]},
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With