it-swarm.com.de

Warum findet der asynchrone Winkeleinheitentest kein DOM-Element?

Ich habe einen fehlerhaften asynchronen Winkelkomponenten-DOM-Test erhalten, aber das synchrone Äquivalent schlägt fehl und ich kann nicht verstehen, warum.

Hier ist der Jasmin-Test:

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();
    }));
});

Welche erstellt die korrekte Ausgabe im synchronen Fall, aber im asynchronen Fall falsch:

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.'

Ich bin mir nicht sicher, ob dies etwas mit der von mir verwendeten Komponente angle-calendar zu tun hat oder ob es ein grundlegenderes Problem mit meinem Testcode ist.

Hier finden Sie meine Komponente, meine Vorlage und meinen Servicecode:

@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 : '';
    }
}

vorlagencode:

<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>  

service code:

@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);
    }
}
12
kossmoboleat

Leider scheint dies etwas mit der Zone fakeAsync zu tun zu haben und nicht mit asynchronen Tests.

Es ist mir gelungen, einen asynchronen Test zu erstellen, der mit async anstelle von fakeAsync arbeitet:

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);
        });
    });
}));

Ich habe sowohl die fehlerhaften fakeAsync als auch die erfolgreichen synchronen Tests debuggt. Beide nennen eine Methode namens getMonthView in einer Bibliothek "calendar-utils" vom selben Autor als "angle-calendar": https://github.com/mattlewis92/calendar-utils/blob/master/src/calendar- utils.ts

In dieser Methode scheinen sowohl die Date-Parameter als auch die anderen Date-Berechnungen selbst sehr schief zu gehen.

Ich kann derzeit nur davon ausgehen, dass es sich auf dieses bekannte Problem in zone.js bezieht. Ich bin auf Angular 5.2, aber ich gehe davon aus, dass es immer noch miteinander zusammenhängt. In jedem Fall bin ich sicher, dass mein Testcode im Wesentlichen korrekt ist, aber das Problem liegt woanders.

1
kossmoboleat

Ich bin mir ziemlich sicher, dass der Grund, warum dies nicht funktioniert, darin liegt, wie Sie Ihren Spion definiert haben. Es ist außerhalb eines beforeEach-Blocks definiert.

So wie Sie es jetzt haben, wird Ihr Spion einmal erstellt, wenn das Gerät startet. Und Jasmin entfernt alle alten Spione am Ende jedes Tests. Beim zweiten Test existiert Ihr Spion also nicht mehr.

Ich würde wetten, dass, wenn Sie Ihre Testreihenfolge wechseln würden, der async-Test funktioniert, der sync-Test aber nicht.

Um dies zu beheben, verschieben Sie das einfach in einen beforeEach-Block:

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