Модульное тестирование Jasmine, как запустить событие щелчка ngx-modal-dialog

Я работаю над угловым приложением, и я тестирую приложение с помощью Jasmine.

В приложении используется плагин ngx-modal-dialog (введите здесь описание ссылки) для всплывающего диалогового окна Поле, такое как окно подтверждения, как динамический компонент.

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

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

Код для всплывающего диалогового окна приведен ниже:

export class SomeComponent {

constructor(private modalService: ModalDialogService) {}
cancleEditConfirmDialog() {
   this.modalService.openDialog(this.viewRef, {
   title: 'Discard Changes ',
   childComponent: SimpleModalComponent,
   data: {
     text: 'Changes will not be saved. Do you want to proceed?'
   },
   settings: {
     closeButtonClass: 'close theme-icon-close'
   },
   actionButtons: [
     {
       text: 'Discard',
       buttonClass: 'btn btn-success',
       onAction: () => new Promise((resolve: any) => {
         // invoke delete
         // do something such as discard changes
         resolve()
       })
     },
     {
       text: 'Cancel',
       buttonClass: 'btn btn-danger',
       onAction: () => new Promise((resolve: any) => {
         // cancel and close popup
         setTimeout(() => {
           resolve();
         }, 20);
       })
     }
   ]
 });
}
}

как запустить onAction: => () в событии щелчка для кнопки отмены и кнопки отмены.

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


person Saurabh Gupta    schedule 01.03.2019    source источник
comment
Если вы настроили свой TestBed с исходным диалоговым окном ngx-modal-dialog, вы можете просто открыть модальное окно с помощью debugElem.triggerEventHandler (‚щелкнуть ') на элементе, открывающем диалоговое окно, и затем вы можете просто снова получить доступ к кнопкам отмены и отмены как debugElem и используйте triggerEventHandler. Если у ngx-modal-dialog слишком много зависимостей, которые вы не хотите добавлять в свой тест, потому что вы хотите неглубоко протестировать свой компонент, вы можете имитировать ngx-modal-dialog   -  person Erbsenkoenig    schedule 01.03.2019
comment
@Erbsenkoenig спасибо за ответ. Я пробовал, но это компонент начальной загрузки, поэтому он по-прежнему отображается как cannot find nativeElement of null.   -  person Saurabh Gupta    schedule 04.03.2019
comment
можешь ли ты сказать мне, как можно поиздеваться над этим?   -  person Saurabh Gupta    schedule 04.03.2019
comment
Попробую сделать стекблиц.   -  person Erbsenkoenig    schedule 04.03.2019
comment
Не могли бы вы сделать мне одолжение и отредактировать этот stackblitz (stackblitz.com/edit/angular-xawnbl ) так что диалог работает. Я раньше не работал с этим конкретным модальным диалогом. Потом займусь тестированием.   -  person Erbsenkoenig    schedule 05.03.2019
comment
У меня это работает. Теперь вы можете продолжить. Вероятно, проблема была в click - ›(click)   -  person Saurabh Gupta    schedule 05.03.2019
comment
Ах да, верно ^^. Посмотрю тест.   -  person Erbsenkoenig    schedule 05.03.2019
comment
В качестве ответа опубликовал тестовую настройку и т. Д. Чтобы протестировать диалог, я использовал подход к фактическому использованию ngx-modal-dialog. Был бы способ издеваться над ним, если вы предпочитаете такой подход, дайте мне знать.   -  person Erbsenkoenig    schedule 05.03.2019


Ответы (1)


При тестировании этого модального диалогового окна возникает проблема, если viewRef, переданный в modalService, является самим тестируемым компонентом. Это связано с тем, что модальный диалог добавляется в dom за пределами viewRef. Таким образом, вы могли получить доступ только к элементам внутри теста с помощью document.getElementById, что было бы возможно, но у вас не было бы возможности использовать все эти прекрасные функции debugElement и так далее.

Однако есть способ: если не проблема использовать div внутри компонента в качестве viewRef, можно провести тест.

stackblitz

Это означает, что ваш шаблон должен выглядеть так:

шаблон

<div #parentDialog>
  <button type="button" (click)="cancleEditConfirmDialog()">Open Dialog</button>
</div>


В этом случае компонент будет выглядеть так:

component.ts

  @ViewChild('parentDialog', {read: ViewContainerRef}) parentVCR;

  constructor(private modalService: ModalDialogService) {}

  cancleEditConfirmDialog() {
   this.modalService.openDialog(this.parentVCR, {
   title: 'Discard Changes ',
   childComponent: SimpleModalComponent,
   data: {
     text: 'Changes will not be saved. Do you want to proceed?'
   },
   settings: {
     closeButtonClass: 'close theme-icon-close'
   },
   actionButtons: [
     {
       text: 'Discard',
       buttonClass: 'btn btn-success',
       onAction: () => new Promise((resolve: any) => {
         // invoke delete
         // do something such as discard changes
         resolve()
       })
     },
     {
       text: 'Cancel',
       buttonClass: 'btn btn-danger',
       onAction: () => new Promise((resolve: any) => {
         // cancel and close popup
         setTimeout(() => {
            resolve();
         }, 20);
       })
     }
   ]});
 }



И, наконец, ваш тестовый пример:

тест

describe('AppComponent', () => {
  let fixture: ComponentFixture<AppComponent>;
  let component: AppComponent;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [ModalDialogModule.forRoot()],
      declarations: [ AppComponent],
      schemas: [NO_ERRORS_SCHEMA]
    });

    fixture = TestBed.createComponent(AppComponent);
    component = fixture.componentInstance;

    fixture.detectChanges();
  });

  it('open dialog and cancel', fakeAsync(() => {
     let buttonDebugElems: DebugElement[] = fixture.debugElement.queryAll(By.css('button'));
    expect(buttonDebugElems.length).toEqual(1);
    expect(buttonDebugElems[0].nativeElement.innerText).toEqual('Open Dialog');

    // Open
    buttonDebugElems[0].triggerEventHandler('click', null);
    fixture.detectChanges();

    buttonDebugElems = fixture.debugElement.queryAll(By.css('button'));
    expect(buttonDebugElems.length).toEqual(3);

    expect(buttonDebugElems[1].nativeElement.innerText).toEqual('Discard');
    expect(buttonDebugElems[2].nativeElement.innerText).toEqual('Cancel');

    // cancel
    buttonDebugElems[2].triggerEventHandler('click', null);
    // needed to wait for the promise to resolve (20 needed due to the timeout of the cancel promise)
    tick(20);

    buttonDebugElems = fixture.debugElement.queryAll(By.css('button'));
    expect(buttonDebugElems.length).toEqual(1);

     // todo expect the things the action changed inside you component.
  }));

  it('open dialog and discard', fakeAsync(() => {
    let buttonDebugElems: DebugElement[] = fixture.debugElement.queryAll(By.css('button'));
    expect(buttonDebugElems.length).toEqual(1);
    expect(buttonDebugElems[0].nativeElement.innerText).toEqual('Open Dialog');

    // open
    buttonDebugElems[0].triggerEventHandler('click', null);
    fixture.detectChanges();

    buttonDebugElems = fixture.debugElement.queryAll(By.css('button'));
    expect(buttonDebugElems.length).toEqual(3);

    expect(buttonDebugElems[1].nativeElement.innerText).toEqual('Discard');
    expect(buttonDebugElems[2].nativeElement.innerText).toEqual('Cancel');

    // discard
    buttonDebugElems[1].triggerEventHandler('click', null);
    // needed to wait for the promise to resolve
    tick();

    buttonDebugElems = fixture.debugElement.queryAll(By.css('button'));
    expect(buttonDebugElems.length).toEqual(1);

    // todo expect the things the action changed inside you component.

  }));
});
person Erbsenkoenig    schedule 05.03.2019
comment
Большое вам спасибо за усилия и помощь. Хотя это нарушило UI компонента, я заставил его работать над решением для тестирования. Большое спасибо. - person Saurabh Gupta; 06.03.2019
comment
Используете viewref из div внутри компонента? Вам не нужно оборачивать этот div вокруг кнопки, это может быть div где угодно внутри вашего компонента, если это помогает с вашим пользовательским интерфейсом. Единственное, что важно - не использовать внедренный viewRef внутри конструктора. Пожалуйста. - person Erbsenkoenig; 06.03.2019
comment
Это пока не помогает. Пытался дать #parentDialog на существующей div кнопке выше, но пользовательский интерфейс все еще искажается :(. - person Saurabh Gupta; 06.03.2019
comment
Как ты думаешь, сможешь ли ты воссоздать это в стеке? Возможно, разветвите его здесь и поделитесь URL-адресом (это тот, который я использовал, чтобы взглянуть на само диалоговое окно, прежде чем выполнять бит тестирования): stackblitz.com/edit/angular-xawnbl - person Erbsenkoenig; 06.03.2019
comment
Другой способ - добавить его в новый div с абсолютной позицией, которая размещается за пределами представления или имеет видимость: скрытую или что-то в этом роде. Но это всего лишь догадки, не видя реальной проблемы. - person Erbsenkoenig; 06.03.2019
comment
Пытался создать его с помощью stackblitz, но его немного большой компонент и классы тоже исходят из bootstrap.css. Невозможно создать фактический интерфейс - person Saurabh Gupta; 06.03.2019
comment
И, кстати, пользовательский интерфейс, который искажается, предназначен для модального всплывающего окна, то есть z-index модального всплывающего окна смешивается с фоновыми элементами после открытия всплывающего окна. - person Saurabh Gupta; 06.03.2019
comment
как перейти в чаты @Erbsenkoenig - person Saurabh Gupta; 06.03.2019
comment
Давайте продолжим это обсуждение в чате. - person Erbsenkoenig; 06.03.2019