Angular 4 компонента прибора сохраняется в DOM во время тестов Jasmine

При запуске Jasmine в реальном браузере я заметил, что компонент TestBed fixture не разрушен в DOM и сохраняется после завершения тестов:

введите описание изображения здесь

Здесь тестируемый компонент:

@Component({
  selector: 'test-app',
  template: `<div>Test</div>`,
})
class Test {}

И тест (plunk).

  let component;
  let fixture;
  let element;

  beforeAll(() => {
    TestBed.resetTestEnvironment();

    TestBed.initTestEnvironment(
      BrowserDynamicTestingModule,
      platformBrowserDynamicTesting()
    );
  });

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [Test],
    })
    .compileComponents();

    fixture = TestBed.createComponent(Test);
    component = fixture.componentInstance;
    element = fixture.debugElement.query(By.css('div')).nativeElement;

    fixture.detectChanges();
  });

  afterEach(() => {
    fixture.destroy();
  });

  it('should compile Test', () => {
    expect(element).toBeTruthy();
  });

Почему экземпляр компонента Test не удаляется из DOM и как это должно быть исправлено?

Почему компоненты DOM добавляются в DOM? Могут ли они быть отделены от DOM, как $rootElement в AngularJS?

Ответы

Ответ 1

Я думаю, что Angular не удаляет его автоматически, чтобы помочь вам получить более подробную информацию о выполнении теста. Чтобы удалить его, вы просто используете afterEach:

beforeEach(() => {
  fixture = TestBed.createComponent(MyComponent);
  comp = fixture.componentInstance;
  debugElement = fixture.debugElement;
  element = debugElement.nativeElement;
});

 afterEach(() => {
  document.body.removeChild(element);
});

Ответ 2

Пожалуйста, взгляните на следующие проблемы:

1) прежде всего вы вызываете

fixture.destroy();

в afterEach, поэтому он вызывается после раздела it. То есть в он блок крепления все еще не разрушен

2) каким кодом вы обнаруживаете, что элемент все еще присутствует в DOM? С другой точки зрения: почему этот элемент должен быть удален жасмином/браузером (какая причина должна сделать жасмин/браузер)? Я мог бы предложить следующие варианты:

2.1) один компонент используется в другом и должен быть создан/уничтожен некоторым изменением. То есть ngIf или ngSwitchCase:

<parent-component>
    <child-component *ngIf="someChangeInComponent1"></child-component>
</parent-component>

или

<parent-component [ngSwitch]="type">
    <child-component *ngSwitchCase="'something'"></child-component>
</parent-component>

2.2) изменена маршрутизация (но это не предмет для модульных тестов AFAIK)

3) текущий код получает ссылку на элемент DOM только один раз. Должно быть что-то вроде:

beforeEach(() => {
    ...
    element = ...
});

it('...', () => {
    ...
    fixture.detectChanges();
    element = ... // try to get element again <--------------------- here
})

4), если вы пытаетесь найти ошибки, такие как ngOnDestroy(), но реализует OnDestroy, он больше не подходит для npm run lint, чем для модульных тестов (ознакомьтесь с интерфейсом использования-жизненного цикла в tslint.json). После запуска npm run lint вы увидите:

Implement lifecycle hook interface OnDestroy for method ngOnDestroy in class ...

Хорошая практика не иметь ошибок не только для unit test, но и для tslint.

Ответ 3

Более сжатое решение:

afterEach(() => {
  element.remove()
});