Почему асинхронный угловой модульный тест не находит элемент DOM? - PullRequest
0 голосов
/ 09 мая 2018

У меня не пройден тест DOM асинхронного углового компонента, но его синхронный эквивалент не пройден, и я не понимаю, почему.

Вот тест жасмина:

describe('Availability Component', () => {

    let fixture: ComponentFixture<AvailabilityComponent>;

    const absenceService = jasmine.createSpyObj('AbsenceService', ['findAbsences']);
    absenceService.findAbsences.and.returnValue(of([{}]));

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            declarations: [AvailabilityComponent],
            imports: [CalendarModule.forRoot()],
            providers: [{provide: AbsenceService, useValue: absenceService}]
        }).compileComponents();
    }));

    beforeEach(() => {
        fixture = TestBed.createComponent(AvailabilityComponent);
    });

    const printAbsenceReasons = function () {
        console.log(fixture.debugElement.queryAll(By.css('.calendarAbsence'))
        .map(e => e.nativeElement.textContent)
        .join(','));
    };

    it('should synchronously find absences in calendar view', () => {
        fixture.detectChanges();

        console.log('synchronous test');
        printAbsenceReasons();
    });

    it('should  asynchronously find absences in calendar view', fakeAsync(() => {
        fixture.detectChanges();
        tick();
        fixture.detectChanges();
        tick();

        console.log('asynchronous test');
        printAbsenceReasons();
    }));
});

, который создает правильный вывод в синхронном случае, но неверный в асинхронном случае:

LOG: 'processing absences'
HeadlessChrome 0.0.0 (Mac OS X 10.13.4): Executed 0 of 51 SUCCESS (0 secs / 0 secs)
LOG: 'synchronous test'
HeadlessChrome 0.0.0 (Mac OS X 10.13.4): Executed 0 of 51 SUCCESS (0 secs / 0 secs)
LOG: 'A,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,'
HeadlessChrome 0.0.0 (Mac OS X 10.13.4): Executed 0 of 51 SUCCESS (0 secs / 0 secs)
ERROR: 'Spec 'Availability Component should synchronously find absences in calendar view' has no expectations.'
HeadlessChrome 0.0.0 (Mac OS X 10.13.4): Executed 0 of 51 SUCCESS (0 secs / 0 secs)
LOG: 'processing absences'
HeadlessChrome 0.0.0 (Mac OS X 10.13.4): Executed 1 of 51 SUCCESS (0 secs / 0 secs)
LOG: 'asynchronous test'
HeadlessChrome 0.0.0 (Mac OS X 10.13.4): Executed 1 of 51 SUCCESS (0 secs / 0 secs)
LOG: ''
HeadlessChrome 0.0.0 (Mac OS X 10.13.4): Executed 1 of 51 SUCCESS (0 secs / 0 secs)
ERROR: 'Spec 'Availability Component should  asynchronously find absences in calendar view' has no expectations.'

Я не уверен, что это как-то связано с angular-calendar компонентом, который я использую, или это более простая проблема с моим тестовым кодом.

Для справки вот мой компонент, шаблон и сервисный код:

@Component({
    selector: 'app-availability',
    templateUrl: './availability.component.html',
    styleUrls: ['availability.component.scss']
})
export class AvailabilityComponent implements OnInit {
    viewDate: Date = new Date();
    absenceEvents: CalendarEvent[] = [];

    constructor(private absenceService: AbsenceService) {
    }

    ngOnInit() {
        this.getAbsences();
    }

    getAbsences() {
        this.absenceService.findAbsences()
        .subscribe(ignored => {
            console.log('processing absences');
            this.absenceEvents = [{
                start: new Date(2018, 3, 29), title: 'A'
            }];
        });
    }

    getAbsence(events: CalendarEvent[]) {
        return events[0] ? events[0].title : '';
    }
}

код шаблона:

<div>
    <div>
        <mwl-calendar-month-view
            [viewDate]="viewDate"
            [events]="absenceEvents"
            [cellTemplate]="availabilityCellTemplate">
        </mwl-calendar-month-view>
    </div>
    <ng-template #availabilityCellTemplate let-day="day">
        <div class="calendarAbsence">{{ getAbsence(day.events) }}</div>
    </ng-template>
</div>  

сервисный код:

@Injectable()
export class AbsenceService {

    private url = environment.APP_SHIFT_SERVICE_BASE_URL + '/api/absences';

    constructor(private http: HttpClient) {
    }

    findAbsences(): Observable<Absence[]> {
        console.error('Actual findAbsences() called');
        return this.http.get<Absence[]>(this.url);
    }
}

Ответы [ 2 ]

0 голосов
/ 04 июня 2018

К сожалению, похоже, это как-то связано с зоной fakeAsync, в частности с асинхронными тестами, в частности.

Мне удалось получить работающий асинхронный тест для работы с async вместо fakeAsync:

it('should asynchronously find absences in calendar view', async(() => {
        fixture.detectChanges();

        fixture.whenStable().then(() => {
            console.log('asynchronous test');
            printAbsenceReasons(fixture);

            expect(getAbsenceElements(fixture).length).toEqual(35);
        });
    });
}));

Я отлаживал как неудачные fakeAsync, так и успешные синхронные тесты.Они оба вызывают метод с именем getMonthView в библиотеке «calendar-utils» того же автора, что и «angular-calendar»: https://github.com/mattlewis92/calendar-utils/blob/master/src/calendar-utils.ts

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

В настоящее время я могу только предполагать, что это связано с этой известной проблемой в zone.js .Я на Angular 5.2, но я предполагаю, что это все еще связано.В любом случае я уверен, что мой тестовый код в основном правильный, но проблема кроется в другом месте.

0 голосов
/ 28 мая 2018

Я почти уверен, что причина, по которой это не работает, в том, как вы определили своего шпиона Он определен вне блока beforeEach.

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

Могу поспорить, что если вы переключите свой тестовый порядок, то увидите, что асинхронный тест работает, но синхронный - нет.

Чтобы исправить, просто переместите это в блок beforeEach:

const absenceService = jasmine.createSpyObj('AbsenceService', ['findAbsences']);
absenceService.findAbsences.and.returnValue(of([{}]));
...