Компоненты модульного тестирования Angular 2 с помощью routerLink

Я пытаюсь протестировать свой компонент с помощью angular 2 final, но получаю сообщение об ошибке, потому что компонент использует директиву routerLink. Я получаю следующую ошибку:

Невозможно выполнить привязку к «routerLink», поскольку это неизвестное свойство «a».

Это соответствующий код шаблона ListComponent

<a 
  *ngFor="let item of data.list" 
  class="box"
  routerLink="/settings/{{collectionName}}/edit/{{item._id}}">

А вот и мой тест.

import { TestBed } from '@angular/core/testing';

import { ListComponent } from './list.component';
import { defaultData, collectionName } from '../../config';
import { initialState } from '../../reducers/reducer';


const data = {
  sort: initialState.sort,
  list: [defaultData, defaultData],
};

describe(`${collectionName} ListComponent`, () => {
  let fixture;
  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [
        ListComponent,
      ],
    }).compileComponents(); // compile template and css;
    fixture = TestBed.createComponent(ListComponent);
    fixture.componentInstance.data = data;
    fixture.detectChanges();
  });

  it('should render 2 items in list', () => {
    const el = fixture.debugElement.nativeElement;
    expect(el.querySelectorAll('.box').length).toBe(3);
  });
});

Я просмотрел несколько ответов на похожие вопросы, но не смог найти подходящего для меня решения.


person select    schedule 19.09.2016    source источник


Ответы (3)


Вам нужно настроить всю маршрутизацию. Для тестирования вместо использования RouterModule вы можете использовать RouterTestingModule из @angular/router/testing, где вы можете настроить некоторые фиктивные маршруты. Вам также потребуется импортировать CommonModule из @angular/common для вашего *ngFor. Ниже приведен полный проходной тест

import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { By } from '@angular/platform-browser';
import { Location, CommonModule } from '@angular/common';
import { RouterTestingModule } from '@angular/router/testing';
import { TestBed, inject, async } from '@angular/core/testing';

@Component({
  template: `
    <a routerLink="/settings/{{collName}}/edit/{{item._id}}">link</a>
    <router-outlet></router-outlet>
  `
})
class TestComponent {
  collName = 'testing';
  item = {
    _id: 1
  };
}

@Component({
  template: ''
})
class DummyComponent {
}

describe('component: TestComponent', function () {
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        CommonModule,
        RouterTestingModule.withRoutes([
         { path: 'settings/:collection/edit/:item', component: DummyComponent }
        ])
      ],
      declarations: [ TestComponent, DummyComponent ]
    });
  });

  it('should go to url',
    async(inject([Router, Location], (router: Router, location: Location) => {

    let fixture = TestBed.createComponent(TestComponent);
    fixture.detectChanges();

    fixture.debugElement.query(By.css('a')).nativeElement.click();
    fixture.whenStable().then(() => {
      expect(location.path()).toEqual('/settings/testing/edit/1');
      console.log('after expect');
    });
  })));
});

ОБНОВИТЬ

Другой вариант, если вы просто хотите проверить, правильно ли отображаются маршруты, не пытаясь перемещаться ...

Вы просто импортируете RouterTestingModule без настройки каких-либо маршрутов

imports: [ RouterTestingModule ]

затем просто убедитесь, что ссылка отображается с правильным URL-путем, например

let href = fixture.debugElement.query(By.css('a')).nativeElement
    .getAttribute('href');
expect(href).toEqual('/settings/testing/edit/1');
person Paul Samsotha    schedule 19.09.2016
comment
Спасибо, это уже очень помогает, но я не могу заставить модульный тест не работать. Похоже, что из-за async все в этом блоке разорилось. Я попытался добавить в it('...', (done) => {async(... done())} готовую функцию, но потом в результате теста я получил Error: Timeout. - person select; 19.09.2016
comment
Моя беда, у меня async был заключен в другую функцию, а не в качестве второго параметра it. Теперь это работает, спасибо. - person select; 19.09.2016
comment
Это фантастика. Наконец-то нашел ответ, который относится к 2.0 Final (я использую 2.1)! Поскольку во многих тестах мне нужна была такая же конфигурация, я создал тестовый модуль, который настроил RouterTestingModule и объявил DummyComponent. Затем я помещаю этот модуль и DummyComponent в подпапку test /, которую затем могу импортировать в любой из своих модульных тестов. Спасибо @peeskillet - person Mac; 28.10.2016
comment
На самом деле, если вам нужно только отобразить routerLink, вам не нужно настраивать маршрутизацию - person s-f; 06.02.2017
comment
Очень обстоятельный и основательный ответ, спасибо. Решает все проблемы тестирования routerLink, которые я видел. - person aphexddb; 10.04.2017
comment
getAttribute('href') возвращает null для меня, пока он работает в приложении. Я что-то скучаю? - person jlang; 28.11.2019
comment
@Paul Samsotha, знаете ли вы, как сделать то же самое с массивом провайдеров? Я не мог заставить это работать - person Shamitha Silva; 14.01.2020

Если вы не тестируете материал, связанный с маршрутизатором, вы можете настроить тест так, чтобы он игнорировал неизвестные директивы с помощью NO_ERRORS_SCHEMA.

 import { NO_ERRORS_SCHEMA } from '@angular/core';
 TestBed.configureTestingModule({
   declarations: [
     ListComponent,
   ],
   schemas: [ NO_ERRORS_SCHEMA ]
 });
person mahulst    schedule 20.09.2016
comment
Спасибо, что это даже более конкретное решение моей проблемы, хотя я тоже узнал из первого. Не могли бы вы также поделиться, откуда импортировать NO_ERRORS_SCHEMA. - person select; 22.09.2016
comment
NO_ERRORS_SCHEMA в настоящее время помечен как Experimental - person CalvinDale; 17.12.2016
comment
@CalvinDale Это не имеет значения. Многие вещи отмечены как экспериментальные (включая часто используемые классы, такие как Http). angular.io/docs/ts/latest/api/# !? статус = экспериментальный - person Kevin Babcock; 10.03.2017

Написать тестовый пример для routerLink. Вы можете выполнить следующие шаги.

  1. Импортируйте RouterTestingModule и RouterLinkWithHref.

    import { RouterTestingModule } from '@angular/router/testing';
    import { RouterLinkWithHref } from '@angular/router';
    
  2. Импортируйте RouterTestingModule в свой модуль

    TestBed.configureTestingModule({
      imports: [ RouterTestingModule.withRoutes([])],
      declarations: [ TestingComponent ]
    })
    
  3. В тестовом примере найдите директиву RouterLinkWithHref tot test на наличие ссылки.

    it('should have a link to /', () => {
      const debugElements = fixture.debugElement.queryAll(By.directive(RouterLinkWithHref));
      const index = debugElements.findIndex(de => {
        return de.properties['href'] === '/';
      });
      expect(index).toBeGreaterThan(-1);
    });
    
person Anurag Singh Bisht    schedule 03.08.2017
comment
Импорт работает также как imports: [ RouterTestingModule ] - person Spiral Out; 14.04.2018