4

I'm running the Banner-Spec.testing take it from here. While running npm test got this error:

Chrome 57.0.2987 (Mac OS X 10.11.6): Executed 0 of 3 SUCCESS (0 secs / 0 secs)
Chrome 57.0.2987 (Mac OS X 10.11.6) BannerComponent (templateUrl) no title in the DOM until manually call `detectChanges` FAILED
Failed: Uncaught (in promise): Failed to load app/banner.component.html
Error: Uncaught (in promise): Failed to load app/banner.component.html
Error: This test module uses the component BannerComponent which is using a "templateUrl" or "styleUrls", but they were never compiled. Please call "TestBed.compileComponents" before your test.
TypeError: Cannot read property 'textContent' of undefined
WARN [web-server]: 404: /base/app/banner.component.html
ERROR: 'Unhandled Promise rejection:', 'Failed to load app/banner.component.html', '; Zone:', 'ProxyZone', '; Task:', 'Promise.then', '; Value:', 'Failed to load app/banner.component.html', undefined

This is my package.json:

{
  "name": "angular-io-example",
  "version": "1.0.0",
  "private": true,
  "description": "Example project from an angular.io guide.",
  "scripts": {
    "test:once": "karma start karma.conf.js --single-run",
    "build": "tsc -p src/",
    "serve": "lite-server -c=bs-config.json",
    "prestart": "npm run build",
    "start": "concurrently \"npm run build:watch\" \"npm run serve\"",
    "pretest": "npm run build",
    "test": "concurrently \"npm run build:watch\" \"karma start karma.conf.js\"",
    "pretest:once": "npm run build",
    "build:watch": "tsc -p src/ -w",
    "build:upgrade": "tsc",
    "serve:upgrade": "http-server",
    "build:aot": "ngc -p tsconfig-aot.json && rollup -c rollup-config.js",
    "serve:aot": "lite-server -c bs-config.aot.json",
    "build:babel": "babel src -d src --extensions \".es6\" --source-maps",
    "copy-dist-files": "node ./copy-dist-files.js",
    "i18n": "ng-xi18n",
    "lint": "tslint ./src/**/*.ts -t verbose"
  },
  "keywords": [],
  "author": "",
  "license": "MIT",
  "dependencies": {
    "@angular/common": "~4.0.0",
    "@angular/compiler": "~4.0.0",
    "@angular/compiler-cli": "~4.0.0",
    "@angular/core": "~4.0.0",
    "@angular/forms": "~4.0.0",
    "@angular/http": "~4.0.0",
    "@angular/platform-browser": "~4.0.0",
    "@angular/platform-browser-dynamic": "~4.0.0",
    "@angular/platform-server": "~4.0.0",
    "@angular/router": "~4.0.0",
    "@angular/tsc-wrapped": "~4.0.0",
    "@angular/upgrade": "~4.0.0",
    "angular-in-memory-web-api": "~0.3.1",
    "core-js": "^2.4.1",
    "rxjs": "5.0.1",
    "systemjs": "0.19.39",
    "zone.js": "^0.8.4"
  },
  "devDependencies": {
    "@types/angular": "^1.5.16",
    "@types/angular-animate": "^1.5.5",
    "@types/angular-cookies": "^1.4.2",
    "@types/angular-mocks": "^1.5.5",
    "@types/angular-resource": "^1.5.6",
    "@types/angular-route": "^1.3.2",
    "@types/angular-sanitize": "^1.3.3",
    "@types/jasmine": "^2.5.36",
    "@types/node": "^6.0.45",
    "babel-cli": "^6.16.0",
    "babel-preset-angular2": "^0.0.2",
    "babel-preset-es2015": "^6.16.0",
    "canonical-path": "0.0.2",
    "concurrently": "^3.0.0",
    "http-server": "^0.9.0",
    "jasmine": "~2.4.1",
    "jasmine-core": "~2.4.1",
    "karma": "^1.3.0",
    "karma-chrome-launcher": "^2.0.0",
    "karma-cli": "^1.0.1",
    "karma-jasmine": "^1.0.2",
    "karma-jasmine-html-reporter": "^0.2.2",
    "karma-phantomjs-launcher": "^1.0.2",
    "lite-server": "^2.2.2",
    "lodash": "^4.16.2",
    "phantomjs-prebuilt": "^2.1.7",
    "protractor": "~4.0.14",
    "rollup": "^0.36.0",
    "rollup-plugin-commonjs": "^4.1.0",
    "rollup-plugin-node-resolve": "^2.0.0",
    "rollup-plugin-uglify": "^1.0.1",
    "source-map-explorer": "^1.3.2",
    "tslint": "^3.15.1",
    "typescript": "~2.2.0"
  },
  "repository": {}
}

My banner.component.spec.ts:

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By }              from '@angular/platform-browser';
import { DebugElement }    from '@angular/core';

import { BannerComponent } from './banner.component';

describe('BannerComponent (templateUrl)', () => {

  let comp:    BannerComponent;
  let fixture: ComponentFixture<BannerComponent>;
  let de:      DebugElement;
  let el:      HTMLElement;

  // async beforeEach
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ BannerComponent ], // declare the test component
    })
    .compileComponents();  // compile template and css
  }));

  // synchronous beforeEach
  beforeEach(() => {
    fixture = TestBed.createComponent(BannerComponent);

    comp = fixture.componentInstance; // BannerComponent test instance

    // query for the title <h1> by CSS element selector
    de = fixture.debugElement.query(By.css('h1'));
    el = de.nativeElement;
  });

  it('no title in the DOM until manually call `detectChanges`', () => {
    expect(el.textContent).toEqual('');
  });

  it('should display original title', () => {
    fixture.detectChanges();
    expect(el.textContent).toContain(comp.title);
  });

  it('should display a different test title', () => {
    comp.title = 'Test Title';
    fixture.detectChanges();
    expect(el.textContent).toContain('Test Title');
  });

});

My banner.component.ts:

import { Component } from '@angular/core';

@Component({
  selector: 'app-banner',
  //moduleId: module.id,
  templateUrl: './banner.component.html',
  styleUrls:  ['./banner.component.css']
})
export class BannerComponent {
  title = 'Test Tour of Heroes';
}

This is weird because I took the code from the page and is not working. If I tried to run the app as npm start get a Cannot GET / message. Also check with the live example and all my files seem to be the same. With another project got the same error message.

I tried suggestions from here and from github's packages pages but couldn't find an answer.

My guess would be with packages versions.

Edited: with the correct files names

Aravind
  • 40,391
  • 16
  • 91
  • 110
Gabriel Muñumel
  • 1,876
  • 6
  • 34
  • 57

2 Answers2

3

I ended up just overriding the component with the reference (styleUrls in my case), like so:

TestBed.configureTestingModule({
  declarations: [ BannerComponent ], // declare the test component
})
.overrideComponent(BannerComponent, {
  set: {
    styleUrls: []
    // I assume you can do the same for templateUrl here
  }
})
.compileComponents();  // compile template and css
melanie johnson
  • 597
  • 3
  • 16
2

This problem appeared while following the Angular Testing guide, using the quickstart setup. The Angular CLI approach probably wouldn't suffer from the same problem due to webpack inlining the styles and templates.

It appears to be due to a out of date systemjs-angular-loader.js in the quickstart repository.

If you use take the version from the angular.io repository, you can see it was fixed to work with karma a few days ago. See this commit.

Specifically, it seems like the fix is replacing

basePath = basePath.replace(baseHref, '');

with

if (!baseHref.startsWith('/base/')) { // it is not karma
    basePath = basePath.replace(baseHref, '');
}

The changelog entry "Component relative paths" cookbook deleted (2017-03-13) which describes these changes specifically recommends against using module: module.id – this should no longer be necessary.

Joe Taylor
  • 2,145
  • 1
  • 19
  • 35
  • That made the trick. Need to add `moduleId: module.id` to my component. – Gabriel Muñumel Apr 12 '17 at 17:56
  • You shouldn't need it actually, see the latest notes in the changelog: https://angular.io/docs/ts/latest/guide/change-log.html "All mention of moduleId removed. "Component relative paths" cookbook deleted (2017-03-13)" – Joe Taylor Apr 12 '17 at 17:59