Prueba de Angular 2 - Llamada a función asíncrona - cuando usar

86

¿Cuándo usas la función asíncrona en TestBed cuando pruebas en Angular 2?

¿Cuándo usas esto?

 beforeEach(() => {
        TestBed.configureTestingModule({
            declarations: [MyModule],
            schemas: [NO_ERRORS_SCHEMA],
        });
    });

¿Y cuando usas esto?

beforeEach(async(() => {
    TestBed.configureTestingModule({
        declarations: [MyModule],
        schemas: [NO_ERRORS_SCHEMA],
    });
}));

¿Alguien puede iluminarme sobre esto?

xiotee
fuente

Respuestas:

95

asyncno permitirá que comience la siguiente prueba hasta que asyncfinalice todas sus tareas. Lo que asynchace es envolver la devolución de llamada en una Zona, donde setTimeoutse rastrean todas las tareas asincrónicas (p . Una vez que se completan todas las tareas asincrónicas, se asynccompleta.

Si alguna vez ha trabajado con Jasmine fuera de Angular, es posible que haya visto que donese pasa a la devolución de llamada

it('..', function(done) {
  someAsyncAction().then(() => {
    expect(something).toBe(something);
    done();
  });
});

Aquí, este es Jasmine nativo, donde le decimos a Jasmine que esta prueba debería retrasar la finalización hasta que llamemos done(). Si no llamamos done()y en su lugar hicimos esto:

it('..', function() {
  someAsyncAction().then(() => {
    expect(something).toBe(something);
  });
});

La prueba se completará incluso antes de la expectativa, porque la promesa se resuelve una vez que la prueba termina de ejecutar las tareas sincrónicas.

Con Angular (en un entorno Jasmine), Angular realmente llamará donedetrás de escena cuando usemos async. Realizará un seguimiento de todas las tareas asincrónicas en la Zona y, cuando estén todas terminadas, donese llamará entre bastidores.

En su caso particular con la TestBedconfiguración, lo usaría generalmente cuando lo desee compileComponents. Rara vez me encuentro con una situación en la que tendría que llamarlo de otra manera

beforeEach(async(() => {
   TestBed.configureTestingModule({
     declarations: [MyModule],
     schemas: [NO_ERRORS_SCHEMA],
   })
   .compileComponent().then(() => {
      fixture = TestBed.createComponent(TestComponent);
   });
}));

Al probar un componente que usa templateUrl(si no está usando un paquete web), entonces Angular necesita realizar una solicitud XHR para obtener la plantilla, por lo que la compilación del componente sería asincrónica. Por lo tanto, debemos esperar hasta que se resuelva antes de continuar con la prueba.

Paul Samsotha
fuente
Gran respuesta @peeskillet. Solo para asegurarme de que lo entiendo: cuando tienes una plantilla en línea, asyncno es necesario. Cuando lo está usando templateUrl, lo es. Sin embargo, la inclusión asyncno "romperá" un componente de plantilla en línea. ¿Crees que es seguro decir que se puede usar asyncde forma predeterminada para cada prueba?
vince
2
@vincecampanale El templateUrl solo importa durante la configuración en beforeEach. En cuyo caso debe llamar compileComponents. No tiene nada que ver con el uso asyncen cada prueba si eso es lo que está preguntando. En cuanto a estar seguro (cuándo debe llamar compileComponents), consulte ¿ Cuándo se supone que debo llamar a compileComponents
Paul Samsotha
2
@vincecampanale No siempre es el caso que desee que se llame antes de la prueba. A veces, es posible que desee llamarlo después de realizar alguna inicialización. Necesita comprender lo que realmente hace llamarlo. Sin embargo, la mayoría de las veces debería estar bien. Pero personalmente no me gusta que se hayan encargado de tomar esa decisión. Pero veo que mucha gente se encuentra con el problema de que se olvidan de llamarlo y se preguntan por qué algunas cosas no funcionan. Entonces, tal vez sea mejor que generen la llamada. La ubicación puede ser discutible, pero al menos lo llaman
Paul Samsotha
2
@vincecampanale Generalmente, cuando desea que la vista (re) renderizada es cuando debe llamarla. Por ejemplo, Crear componente -> renderizar vista. Pero si desea inicializar algo primero como Crear componente -> cambiar el valor en el componente que se usa para renderizar -> renderizar vista. Eso es lo que quiero decir con quizás quieras inicializar algo primero
Paul Samsotha
1
Ah, y una cosa más. La primera vez que lo llama, es cuando ngOnInitse llama al componente. A veces, esto es importante al realizar las pruebas
Paul Samsotha
26

Cuando realiza una llamada asíncrona en su prueba, la función de prueba real se completa antes de que se complete la llamada asíncrona. Cuando necesite verificar algún estado en el que se completó la llamada (que suele ser el caso), el marco de prueba informará que la prueba se completó mientras todavía hay trabajo asincrónico en curso.

Con el uso, async(...)le indica al marco de prueba que espere hasta que se complete la promesa de devolución o el observable antes de tratar la prueba como completada.

it('should show quote after getQuote promise (async)', async(() => {
  fixture.detectChanges();

  fixture.whenStable().then(() => { // wait for async getQuote
    fixture.detectChanges();        // update view with quote
    expect(el.textContent).toBe(testQuote);
  });
}));

El código pasado a then(...)se ejecutará después de que se complete la función de prueba. Con async()usted, hace que el marco de prueba sea consciente de que debe esperar a que se completen las promesas y los observables antes de tratar la prueba como completada.

Ver también

Günter Zöchbauer
fuente