My team updated the Rails version of our application to 5.1 so we could use Webpacker, a wrapper to use Webpack with Rails and then use Angular 2 properly.
We started setting up the test suite for the Angular 2 modules using Karma + Jasmine + Webpack following this article.
If I write simple test cases, without Angular Component, TestBed and ComponentFixture, everything looks fine. However, if I try to import Angular modules and test some components, Karma raises the following error message for every component and module:
ERROR in ./app/javascript/app/app.module.ts
Module parse failed: /[application path omitted]/app/javascript/app/app.module.ts Unexpected character '@' (17:0)
You may need an appropriate loader to handle this file type.
| import { AppRoutingModule } from './app-routing.module';
|
| @NgModule({
| imports: [
| BrowserModule,
The project structure is:
- app
-- ...
-- javascript (webpacker create this folder in the first time running)
---- app (where all modules are stored)
------ ...
------ app.routing.module.ts
------ app.component.ts
------ app.module.ts
------ echo.pipe.ts (a file created just to test the Karma suite)
---- packs
---- test
------ echo.pipe.spec.ts
------ main.js (entry point of tests)
------ main.spec.ts
The karma.conf.js file:
module.exports = function(config) {
config.set({
basePath: '',
frameworks: ['jasmine'],
files: [
{ pattern: './app/javascript/app/**/*.ts', watched: false, served: true },
{ pattern: './app/javascript/test/main.js', watched: false }
],
plugins: [
require('karma-webpack'),
require('karma-jasmine'),
require('karma-phantomjs-launcher'),
require('karma-chrome-launcher'),
require('karma-sourcemap-loader'),
require('karma-babel-preprocessor'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter')
],
exclude: [
],
preprocessors: {
'app/javascript/**/*.ts': ['webpack', 'sourcemap'],
'app/javascript/test/main.js': ['webpack', 'sourcemap']
},
mime: { 'text/x-typescript': ['ts','tsx'] },
reporters: ['progress'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: false,
browsers: ['Chrome'],
singleRun: true,
concurrency: Infinity
})
}
The echo.pipe.ts file:
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'echo'
})
export class EchoPipe implements PipeTransform {
transform(value: any): any {
return value;
}
}
The main.js file:
describe('Meaningful Test', () => {
it('1 + 1 => 2', () => {
expect(1 + 1).toBe(2);
});
});
require('./main.spec.ts');
The main.spec.ts file:
import 'core-js/es6';
import 'core-js/es7/reflect';
import 'zone.js/dist/zone';
import 'zone.js/dist/proxy';
import 'zone.js/dist/sync-test';
import 'zone.js/dist/async-test';
import 'zone.js/dist/fake-async-test';
import 'zone.js/dist/jasmine-patch';
import 'rxjs/Rx';
import { TestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting,
} from '@angular/platform-browser-dynamic/testing';
TestBed.initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
describe('Meaningful Test 2', () => {
it('1 + 1 => 2', () => {
expect(1 + 1).toBe(2);
});
});
The echo.pipe.spec.ts file:
import { Component } from '@angular/core';
import { TestBed, ComponentFixture, async } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import { EchoPipe } from '../app/echo.pipe';
describe('EchoPipe', () => {
let comp: EchoPipe;
let fixture: ComponentFixture<EchoPipe>;
let de: DebugElement;
let el: HTMLElement;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ EchoPipe ],
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(EchoPipe);
comp = fixture.componentInstance;
comp.name = 'foo';
});
it('works well', () => {
fixture.detectChanges();
el = fixture.debugElement.nativeElement as HTMLElement;
expect(el.querySelector('p').textContent).toBe('foo');
});
});
const context = require.context('./', true, /\.spec\.ts$/);
context.keys().map(context);