Skip to content

Angular CLI

Starting Wallaby

To start Wallaby in VS Code you may run Select Configuration command and then select Automatic Configuration <project directory> option once. After that you may keep using Wallaby Start command as usual and it will start Wallaby with automatic configuration.

To start Wallaby in Sublime Text you may use the Select for Wallaby.js Automatic Configuration context menu item for your project folder in the project’s file tree. After that you may keep using Wallaby Start command as usual and it will start Wallaby with automatic configuration.

To start Wallaby in Visual Studio, you may use the Start Wallaby.js (Automatic Configuration) context menu item for your project folder in the Solution Explorer. After the first start, the selected project will be remembered for your solution and Wallaby can be started with Tools->Start Wallaby.js (Alt-W, 1).

To start Wallaby in JetBrains IDEs, you may edit (or create a new) wallaby.js Run Configuration by selecting Edit configurations from the drop-down menu in the top right-hand corner of the navigation bar, or from the Run menu. In the run configuration editor set Configuration Type filed value to Automatic.

Automatic Configuration Workspace Overrides

When using Automatic Configuration to run tests for the entire workspace, Wallaby creates merged virtual copies of test.ts, polyfills.ts and tsconfig.spec.json files. If these files have been modified then it is possible they cannot be merged. Wallaby supports the ability to explicitly define the merged contents of these files.

To explicitly override the merged contents of test.ts, polyfills.ts and tsconfig.spec.json, you must create an override file for each file name. For example, to replace the merged override of all test.ts files, you must create a file in the workspace root named test.wallaby.ts. The same is true for polyfills.ts and tsconfig.spec.json which become polyfills.wallaby.ts and tsconfig.wallaby.spec.json respectively.

Example merge override for test.ts

test.wallaby.ts

import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
// shared imports for all your projects
// imports for app-a, lib-b, lib-c, app-d etc.
// shared code for all your projects
// code for app-a, lib-b, lib-c, app-d etc.
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
// shared code for all your projects
// code for app-a, lib-b, lib-c, app-d etc.

Example merge override for polyfills.ts

polyfills.wallaby.ts

import 'zone.js/dist/zone';
// shared code for all your projects
// code for app-a, lib-b, lib-c, app-d etc.

Example merge override for tsconfig.spec.json

tsconfig.wallaby.spec.json

{
"extends": "./tsconfig.json",
"compilerOptions": {
"types": [
"jasmine",
"node"
],
"paths": {
"lib-b": [
"projects/lib-b/src/public-api.ts"
],
"lib-b/*": [
"projects/lib-b/src/*"
],
"lib-c": [
"projects/lib-c/src/public-api.ts"
],
"lib-c/*": [
"projects/lib-c/src/*"
]
}
},
"files": [
"projects/app-a/src/test.ts",
"projects/app-a/src/polyfills.ts",
"projects/lib-b/src/test.ts",
"projects/lib-b/src/polyfills.ts"
"projects/lib-c/src/test.ts",
"projects/lib-c/src/polyfills.ts",
"projects/app-d/src/test.ts",
"projects/app-d/src/polyfills.ts"
],
"include": [
"projects/app-a/src/**/*.spec.ts",
"projects/app-a/src/**/*.d.ts",
"projects/lib-b/src/**/*.spec.ts",
"projects/lib-b/src/**/*.d.ts",
"projects/lib-c/src/**/*.spec.ts",
"projects/lib-c/src/**/*.d.ts",
"projects/app-d/src/**/*.spec.ts",
"projects/app-d/src/**/*.d.ts"
]
}

If you have created a polyfills.wallaby.ts override, then it must be added to your TypeScript files configuration section.

Automatic Configuration Project Overrides

When using Automatic Configuration to run tests for a specific project, Wallaby slightly modifies your project’s test.ts file. Wallaby has its own mechanism for resolving test files and removes the code that provides webpack with the list of tests to run. If this file has been modified then it is possible that Wallaby cannot safely find/delete this code then Angular CLI defaults for test.ts will be used. If desired, you can provide Wallaby with a differnet file to run by creating a test.wallaby.ts file in the same folder as your test.ts file.

Example override for: test.ts

test.wallaby.ts

import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
// your imports
declare const require: any;
// your code
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// your code
// ! TEST FILE IMPORTS ARE RESOLVED BY WALLABY AND !
// ! SHOULD BE COMMENTED OUT OR DELETED FROM THIS FILE !
//
// const context = require.context('./', true, /\.spec\.ts$/);
// context.keys().map(context);

Jest

If you have configured your project to use Angular Jest Builder or are using an Nx/Nrwl workspace, you can use Wallaby without any configuration.

If you have a custom configuration Angular/Jest configuration then please refer to our Jest docs.

Manual Configuration for versions of Angular prior to v8.2.0

If you are not using Automatic Configuration to run your Angular CLI project’s test, then you must provide a configuration file that tells Wallaby how to load and run your tests. We have created a configuration file that works for Angular CLI projects that use karma as the test runner.

Copy the configuration shown below and paste it into a file named wallaby.js in your project root. The configuration file below may seem foreign or scary but you don’t need to worry about what the configuration file is doing in order to use Wallaby.js with Angular.

You may read more about how to configure wallaby in our configuration settings docs.

module.exports = function(wallaby) {
const wallabyWebpack = require('wallaby-webpack');
const path = require('path');
const fs = require('fs');
const specPattern = '/**/*spec.ts';
const angularConfig = require('./angular.json');
const projects = Object.keys(angularConfig.projects).map(key => {
return { name: key, ...angularConfig.projects[key] };
}).filter(project => project.sourceRoot)
.filter(project => project.projectType !== 'application' ||
(project.architect &&
project.architect.test &&
project.architect.test.builder === '@angular-devkit/build-angular:karma'));
const applications = projects.filter(project => project.projectType === 'application');
const libraries = projects.filter(project => project.projectType === 'library');
const tsConfigFile = projects
.map(project => path.join(__dirname, project.root, 'tsconfig.spec.json'))
.find(tsConfig => fs.existsSync(tsConfig));
const tsConfigSpec = tsConfigFile ? JSON.parse(fs.readFileSync(tsConfigFile)) : {};
const compilerOptions = Object.assign(require('./tsconfig.json').compilerOptions, tsConfigSpec.compilerOptions);
compilerOptions.emitDecoratorMetadata = true;
return {
files: [
{ pattern: path.basename(__filename), load: false, instrument: false },
...projects.map(project => ({
pattern: project.sourceRoot + '/**/*.+(ts|js|css|less|scss|sass|styl|html|json|svg)',
load: false
})),
...projects.map(project => ({
pattern: project.sourceRoot + specPattern,
ignore: true
})),
...projects.map(project => ({
pattern: project.sourceRoot + '/**/*.d.ts',
ignore: true
}))
],
tests: [
...projects.map(project => ({
pattern: project.sourceRoot + specPattern,
load: false
}))
],
testFramework: 'jasmine',
compilers: {
'**/*.ts': wallaby.compilers.typeScript({
...compilerOptions,
getCustomTransformers: program => {
return {
before: [
require('@ngtools/webpack/src/transformers/replace_resources').replaceResources(
path => true,
() => program.getTypeChecker(),
false
)
]
};
}
})
},
preprocessors: {
/* Initialize Test Environment for Wallaby */
[path.basename(__filename)]: file => `
import '@angular-devkit/build-angular/src/angular-cli-files/models/jit-polyfills';
import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting} from '@angular/platform-browser-dynamic/testing';
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());`
},
middleware: function(app, express) {
const path = require('path');
applications.forEach(application => {
if (
!application.architect ||
!application.architect.test ||
!application.architect.test.options ||
!application.architect.test.options.assets
) {
return;
}
application.architect.test.options.assets.forEach(asset => {
if (asset && !asset.glob) {
// Only works for file assets (not globs)
// (https://github.com/angular/angular-cli/blob/master/docs/documentation/stories/asset-configuration.md#project-assets)
app.use(asset.slice(application.sourceRoot.length), express.static(path.join(__dirname, asset)));
}
});
});
},
env: {
kind: 'chrome'
},
postprocessor: wallabyWebpack({
entryPatterns: [
...applications
.map(project => project.sourceRoot + '/polyfills.js')
.filter(polyfills => fs.existsSync(path.join(__dirname, polyfills.replace(/js$/, 'ts')))),
path.basename(__filename),
...projects.map(project => project.sourceRoot + specPattern.replace(/ts$/, 'js'))
],
module: {
rules: [
{ test: /\.css$/, loader: ['raw-loader'] },
{ test: /\.html$/, loader: 'raw-loader' },
{
test: /\.ts$/,
loader: '@ngtools/webpack',
include: /node_modules/,
query: { tsConfigPath: 'tsconfig.json' }
},
{ test: /\.styl$/, loaders: ['raw-loader', 'stylus-loader'] },
{ test: /\.less$/, loaders: ['raw-loader', { loader: 'less-loader' }] },
{
test: /\.scss$|\.sass$/,
loaders: [{ loader: 'raw-loader' }, { loader: 'sass-loader', options: { implementation: require('sass') } }]
},
{ test: /\.(jpg|png|svg)$/, loader: 'raw-loader' }
]
},
resolve: {
extensions: ['.js', '.ts'],
modules: [
wallaby.projectCacheDir,
...(projects.length ? projects.filter(project => project.root)
.map(project => path.join(wallaby.projectCacheDir, project.root)) : []),
...(projects.length ? projects.filter(project => project.sourceRoot)
.map(project => path.join(wallaby.projectCacheDir,project.sourceRoot)) : []),
'node_modules'
],
alias: libraries.reduce((result, project) => {
const alias = project.name.replace(/([a-zA-Z])(?=[A-Z])/g, '$1-').toLowerCase();
result[alias] = path.join(wallaby.projectCacheDir, project.sourceRoot, 'public-api');
return result;
}, {})
}
}),
setup: function() {
window.__moduleBundler.loadTests();
}
};
};