Una herramienta poderosa para simplificar sus pruebas angulares
Spectator lo ayuda a deshacerse de todo el trabajo de gruñidos de Boilerplate, dejándolo con pruebas unitarias legibles, elegantes y simplificadas.
✅ Soporte para probar componentes angulares, directivas y servicios
✅ consultas de DOM fáciles
✅ Limpie la API para activar eventos de teclado/mouse/táctil
✅ Probar ng-content
✅ Custom Jasmine/Jest Matchers (Tohaveclass, Tobedisable ...)
✅ Soporte de pruebas de enrutamiento
✅ Soporte de pruebas HTTP
✅ Soporte incorporado para componentes de entrada
✅ Soporte incorporado para proveedores de componentes
✅ Proveedores de automovilismo
✅ fuertemente escrito
Soporte Jest
Los patrocinios ayudan en el desarrollo continuo y el mantenimiento de las bibliotecas Ngneat. Considere pedirle a su empresa que patrocine a NGNEAT como su núcleo para su desarrollo de negocios y aplicaciones.
Eleve su apoyo al convertirse en un patrocinador de oro y tenga su logotipo de manera prominente en nuestro ReadMe en los 5 repositorios principales.
Aumente su respaldo convirtiéndose en un patrocinador de oro y disfrute de la atención con su logotipo de manera prominente en los 3 repositorios principales en nuestro readme.
Conviértase en un patrocinador de bronce y obtenga su logotipo en nuestro Readme en Github.
Características
Tabla de contenido
Instalación
Npm
Hilo
Componentes de prueba
Vistas aplazables anidadas
Selector de cadenas
Tipo selector
Selector de DOM
Prueba de elementos seleccionados
Componentes de burla
Prueba de módulos angulares de componente único/directiva
Eventos personalizados
Creadores de eventos
API de eventos
Ayudantes de teclado
Ayudantes de ratón
Consultas
Vistas aplazables
Prueba con host
Componente de host personalizado
Prueba con enrutamiento
Desencadenando una navegación
Prueba de integración con RouterTestingModule
Opciones de enrutamiento
Directivas de prueba
Servicios de prueba
Opciones adicionales
Tuberías de prueba
Uso del componente host personalizado
Mirando a los proveedores
Burlarse de las dependencias de la entrada
Burlarse de las dependencias del constructor
Jest Support
Prueba con HTTP
Inyecciones globales
Proveedores de componentes
Matchers personalizados
Esquema
Colección de esquemas predeterminados
Comparación de Repo de Spectator & Jest de Working Spectator y Karma
Equipo central
Colaboradores
npm install @ngneat/spectator --save-dev
yarn add @ngneat/spectator --dev
Cree una fábrica de componentes utilizando la función createComponentFactory()
, pasando la clase de componentes que desea probar. createComponentFactory()
devuelve una función que creará un componente nuevo en cada bloque it
:
import {spectator, createComponentFactory} de '@ngneat/spectator'; import {buttonComponent} desde './button.component';Describe('ButtonComponent', () => { Let Spectator: Spectator <ButtonComponent>; const createComponent = CreateComponentFactory (ButtonComponent); ANTERIOREACH (() => Spectator = CreateComponent ()); it ('debería tener una clase de éxito por defecto', () => {spear (spectator.Query ('botón')). tohaveclass ('éxito'); }); ('debería establecer el nombre de clase de acuerdo con la entrada [classname]', () => {spectator.setInput ('classname', 'peligro'); esperar (spectator.query ('botón')). tohaveclass (' peligro '); esperar (spectator.query (' botón ')). no.tohaveclass (' éxito '); });});
La función createComponentFactory
puede tomar opcionalmente las siguientes opciones que extienden las opciones básicas del módulo de prueba angular:
const createComponent = CreateComponentFactory ({ Componente: ButtonComponent, importaciones: [], Proveedores: [], Declaraciones: [], EntryComponents: [], ComponentProviders: [], // anular los proveedores del componente ComponentViewProviders: [], // anular los proveedores de vista del componente anveridemodules: [], // módulos de anulación anveridecomponents: [], // anular componentes en caso de prueba componente independiente anveredicirectives: [], // anular las directivas en caso de probar la directiva independiente anularpipes: [], // anular tuberías en caso de probar tubería independiente simulacros: [], // proveedores que se burlarán automáticamente ComponentMocks: [], // proveedores de componentes que se burlarán automáticamente ComponentViewProvidersMocks: [], // Componente Ver proveedores que se burlarán automáticamente detectChanges: false, // predeterminado a verdadero declareComponent: false, // predeterminado a verdadero discleanimations: false, // predeterminado a verdadero Shallow: verdadero, // El valor predeterminado a falso DeferblockBehavior: DeferblockBehavior // predeterminado a diferirblockbehavior.playthrough});
La función createComponent()
opcionalmente toma las siguientes opciones:
it ('debería ...', () => { spectator = createComponent ({// El componente inputSprops: {title: 'click'}, // anula los proveedores del componente // Tenga en cuenta que debe declararlo una vez en `createComponentFactory`providers: [], // si ejecutar detección de cambio de cambio de cambio (predeterminado es verdadero) DetectChanges: FALSO }); esperar (spectator.query ('botón')). tohaveText ('hacer clic');});
Al proporcionar opciones de overrideComponents
en el alcance de nuestra función createComponent()
podemos definir la forma de anular el componente independiente y sus dependencias
@Componente({ Selector: `App-standalone-with-importación ', Template: `<Div id =" Standalone "> Componente independiente con import! </div> <App-standalone-with-dependency> </pp-standalone-with-dependency>`,, Importaciones: [standalOnecomponentWithDependency], Standalone: true,}) Clase de exportación standalonewithImportsComponent {} @Component ({ Selector: `app-standalone-with-dependency ', Template: `<Div id =" StandalOneWithDependency "> ¡Componente independiente con dependencia! </div>`, Standalone: True,}) Clase de exportación standalOnEcomponentWithDependency { Constructor (Public Query: QueryService) {}}@componente ({ Selector: `app-standalone-with-dependency ', Plantilla: `<Div id =" standalOneWithDependency "> Componente independiente con dependencia de anulación! </div>`, Standalone: True,}) Export Class MockStandalonecomponentWithDependency { constructor () {}} it ('debería ...', () => { const spectator = createHostFactory ({componente: standalOneWithImportSComponent, plantlate: `<div> <app-standalone-with-importación> </pp-standalone-with-importación> </div>`, anevidecomponents: [standalonewithimportsComponent, {eliminar:: {importaciones: [standalOnEcomponentWithDependency]}, add: {importaciones: [mockStandalOnecomponentWithDependency]},},],],], }); Espere (host.query ('#standalone')). toContaintext ('componente independiente con importación!'); Espere (host.query ('#standalOneWithDependency').
El método createComponent()
devuelve una instancia de Spectator
que expone la siguiente API:
fixture
: el accesorio del componente probado
component
: la instancia del componente probado
element
: el elemento nativo del componente probado
debugElement
: el elemento de depuración del accesorio probado
flushEffects()
- Proporciona un envoltorio para TestBed.flushEffects()
inject()
- proporciona un contenedor para TestBed.inject()
:
const servicio = spectator.inject (QueryService); const fromComponentInjector = true; const Service = Spectator.Inject (QueryService, fromComponentInjector);
detectChanges()
- Ejecuta detectChanges en el elemento probado/host:
spectator.detectChanges ();
detectComponentChanges()
: ejecuta detectChanges
en el componente probado (no en el host
). Necesitará este método en casos raros cuando se use un host
y el componente probado es onPush
, y desea obligarlo a ejecutar un ciclo de detección de cambios.
spectator.detectComponentChanges ();
setInput()
: cambia el valor de un @Input () del componente probado. El método ejecuta ngOnChanges
con SimpleChanges
manualmente si existe.
it ('debería ...', () => { spectator.setInput ('classname', 'peligro'); spectator.setInput ({className: 'Danger' });});
output
: devuelve un @output () observable del componente probado:
it ('debería emitir el evento $ en click', () => { dejar la salida; spectator.output ('hacer clic'). Suscríbete (resultado => (salida = resultado)); spectator.component.onclick ({type: 'hacer clic'}); esperar (salida) .toequal ({type: 'hacer clic'});});
tick(millis?: number)
- Ejecute la función Fakeasync tick()
y llame detectChanges()
::
it ('debería funcionar con tick', fakeasync (() => { spectator = createComponent (ZippyComponent); spectator.component.update (); esperar (spectator.component.UpdatedAsync) .tobefalsy (); Spectator.Tick (6000); Espere (spectator.component.UpdatedAsync) .not.tobefalsy ();})))
Cada uno de los eventos puede aceptar un SpectatorElement
que puede ser uno de los siguientes:
Tipo SpectatorElement = String | Elemento | Depuración | ElementRef | Ventana | Documento | DomSelector;
Si no se proporciona, el elemento predeterminado será el elemento host del componente en prueba.
click()
- desencadena un evento de clic:
spectator.click (SpectatorElement); Spectator.click (bytext ('elemento'));
blur()
- desencadena un evento Blur:
Spectator.blur (SpectatorElement); Spectator.blur (bytext ('elemento'));
Tenga en cuenta que si se usa el marco Jest, Blur () solo funciona si el elemento está enfocado. Detalles.
focus()
- desencadena un evento de enfoque:
Spectator.focus (SpectatorElement); Spectator.focus (bytext ('elemento'));
typeInElement()
- Simulando la escritura del usuario:
spectator.typeInElement (valor, spectatorElement); spectator.typeInElement (valor, bytext ('elemento'));
dispatchMouseEvent()
- desencadena un evento de ratón:
spectator.dispatchMouseEvent (SpectatorElement, 'Mouseout'); Spectator.DispatchMoUeEvent (SpectatorElement, 'Mouseout'), X, Y, Event); Spectator.DispatchMouseEvent (Bytext ('Element'), 'Mouseout'); Spectator.IspatchMoUSEEVE (bytext ('Elemento'), 'mouseOut', x, y, evento);
dispatchKeyboardEvent()
- desencadena un evento de teclado:
spectator.dispatchKeyBoardEvent (SpectatorElement, 'KeyUp', 'Escape'); Spectator.DispatchKeyBoardEvent (SpectatorElement, 'KeyUp', {Key: 'Escape', KeyCode: 27}) Spectator.DispatchKeyBoardEvent (Bytext ('Element'), 'Keyup ',' Escapar '); spectator.dispatchkeyboardEvent (bytext (' elemento '),' keyUp ', {Key:' Escape ', KeyCode: 27})
dispatchTouchEvent()
- desencadena un evento táctil:
spectator.dispatchTouchEvent (SpectatorElement, type, x, y); spectator.dispatchTouchEvent (bytext ('elemento'), type, x, y);
Puede activar eventos personalizados (@output () de componentes infantiles) utilizando el siguiente método:
Spectator.triggereVenthandler (myChildComponent, 'myCustomEvent', 'eventValue'); spectator.triggereVenthandler (myChildComponent, 'myCustomEvent', 'EventValue', {root: true}); spectator.triggereVenthandler ('app-child', 'mycustomevent ',' eventValue '); spectator.triggereventhandler (' app-child-component ',' mycustomeVent ',' eventValue ', {root: true});
En caso de que desee probar eventos independientemente de cualquier plantilla (por ejemplo, en los servicios de presentadores), puede retirarse a los creadores de eventos subyacentes. Básicamente proporcionan la misma firma sin el elemento anterior.
const keyboardEvent = createKeyBoardEvent ('KeyUp', 'Arrowdown'/ *, TargetElement */); const MouseEvent = CreateMoUeEvent ('MouseOut'); const touchEvent = CreateTouchEvent ('touchmove'); const falsevent = createFakeEvent ('input');
spectator.keyboard.pressenter (); spectator.keyboard.pressescape (); spectator.keyboard.presstab (); spectator.keyboard.pressbackspace (); spectator.keyboard.presskey ('a'); spectator.keyboard.presskey (' ctrl.a '); spectator.keyboard.presskey (' ctrl.hift.a ');
Spectator.Mouse.ContextMenu ('. Selector'); Spectator.Mouse.DblClick ('. Selector');
Tenga en cuenta que cada uno de los métodos anteriores también ejecutará detectChanges()
.
La API de Spectator incluye métodos convenientes para consultar el DOM como parte de una prueba: query
, queryAll
, queryLast
, queryHost
y queryHostAll
. Todos los métodos de consulta son polimórficos y le permiten consultar utilizando cualquiera de las siguientes técnicas.
Pase un selector de cadenas (en el mismo estilo que lo haría al usar jQuery o document.Queryselector) para consultar elementos que coincidan con esa ruta en el DOM. Este método para la consulta es equivalente a Angular BY BY.CSS predicada. Tenga en cuenta que se devolverán elementos HTML nativos. Por ejemplo:
// Devuelve un solo htmlelementspectator.Query ('div> ul.nav li: first-child'); // Devuelve una matriz de todos los htmlelementsspectator.Queryall ('div> ul.nav li'); // consulta desde la consulta de la consulta de la consulta de la consulta de la consulta de la consulta Document contextSpectator.query ('div', {root: true}); spectator.query ('app-child', {read: childServiceservice});
Pase un tipo (como una clase de componente, directiva o proveedor) para consultar para instancias de ese tipo en el DOM. Esto es equivalente a Angular por predicado By.directive
. Opcionalmente, puede pasar en un segundo parámetro para leer un token de inyección específico de los inyectores de los elementos coincidentes. Por ejemplo:
// Devuelve una sola instancia de myComponent (si presente) spectator.query (myComponent); // Devuelve la instancia de `Someservice` encontrada en el caso de` myComponent` que existe en el domin (si presente) Spectator.Query , {Read: Someservice}); Spectator.Query (myComponent, {Read: ElementRef}); host.QueryLast (ChildComponent); Host.Queryall (ChildComponent);
Spectator le permite consultar para elementos que usan selectores inspirados en DOM-testing-bibrary. Los selectores disponibles son:
Spectator.Query (byplaceHolder ('Ingrese su dirección de correo electrónico')); Spectator.Query (ByValue ('por valor')); Spectator.Query (bytitle ('by title'); alt text ')); spectator.query (bylabel (' por etiqueta ')); spectator.query (bytext (' by text ')); spectator.query (bytext (' by text ', {selector:' #Some. selector '})); spectator.query (byTextContent (' por contenido de texto ', {selector:' #some .selector '})); spectator.query (byrole (' checkbox ', {checked: true}));
La diferencia entre byText
y byTextContent
es que el primero no coincide con el texto dentro de un elemento anidado.
Por ejemplo, en este siguiente byText('foobar', {selector: 'div'})
no coincidirá con el siguiente div
, pero byTextContent
:
<div> <span> foo </span> <span> bar </span> </div>
Spectator le permite consultar elementos anidados dentro de un elemento principal. Esto es útil cuando tiene múltiples instancias del mismo componente en la página y desea consultar para niños dentro de uno específico. El selector principal es un selector de cadenas que se usa para encontrar el elemento principal. El selector principal se pasa como el segundo parámetro a los métodos de consulta. Por ejemplo:
Spectator.Query (ChildComponent, {PadreseLector: '#parent-componente-1'}); spectator.queryall (childComponent, {parentSelector: '#parent-componente-1'});
Spectator le permite probar <select></select>
elementos fácilmente y admite múltiples select.
Ejemplo:
it ('debería establecer las opciones correctas en multi select', () => { const select = spectator.query ('#test-multi-select') como htmlselectelement; spectator.selectOption (seleccionar, ['1', '2']); Espere (select) .TohaveSelectedOptions (['1', '2']);}); it ('debería establecer la opción correcta en el estándar select', () => { const select = spectator.query ('#test-single-select') como htmlselectelement; Spectator.SelectOption (seleccionar '1'); esperar (select) .tohaveSelectectOptions ('1' ');});
También le permite verificar si su controlador de eventos change
está actuando correctamente para cada elemento seleccionado. Puede deshabilitar esto si necesita establecer las opciones sin enviar el evento de cambio.
API:
spectator.selectOption (selectElement: htmlselectelement, opciones: cadena | string [] | htmloptionElement | htmloptionElement [], config: {emiteVents: boolean} = {emitevents: true});
Ejemplo:
it ('debería enviar un número correcto de eventos de cambio', () => { const onChangespy = Spyon (Spectator.Component, 'HandLechange'); const select = spectator.query ('#test-onchange-select') como htmlselectelement; spectator.selectOption (seleccionar, ['1', '2'], {emiteVents: true}); esperar (select) .tohaveSelectectOptions (['1', '2']); Espere (OnChangespy) .TohaveBeenLedTimes (2);}); it (no debe enviar el número correcto de eventos de cambio ', () => { const onChangespy = Spyon (Spectator.Component, 'HandLechange'); const select = spectator.query ('#test-onchange-select') como htmlselectelement; spectator.selectOption (seleccionar, ['1', '2'], {emiteVents: false}); esperar (select) .tohaveSelectectOptions (['1', '2']); Espere (onChangespy) .not.TohaveBeencalledTimes (2);});
También puede aprobar HTMLOptionElement
como argumentos para selectOption
y el toHaveSelectedOptions
Matcher. Esto es particularmente útil cuando está utilizando la vinculación [ngValue]
en <option>
:
it ('debe establecer la opción correcta en selección única al pasar el elemento', () => { const select = Spectator.Query ('#Test-Single-Select-Element') como htmlselectelement; spectator.selectOption (select, spectator.query (bytext ('dos')) como htmloptionElement); Espere (select) .ToHaveSelectectOptions (Spectator.Query (bytext ('dos')) como htmLOptionElement);});
Si necesita burlarse de los componentes, puede usar la biblioteca NG-Mocks. En lugar de usar CUSTOM_ELEMENTS_SCHEMA
, que podría ocultar algunos problemas y no lo ayudará a establecer entradas, salidas, etc., ng-mocks
se burlarán automáticamente de las entradas, salidas, etc. para usted.
Ejemplo:
import {createHostFactory} de '@ngneat/spectator'; import {mockComponent} de 'ng-mocks'; import {foocomponent} desde './path/to/foo.component';const createHost = createHfactory ({ Componente: YourComponentTotest, Declaraciones: [MockComponent (Foocomponent) ]});
Los componentes (o directivas) que se declaran en su propio módulo se pueden probar definiendo el módulo de componentes en la lista de importaciones de la fábrica de componentes junto con el componente. Por ejemplo:
const createComponent = CreateComponentFactory ({ Componente: ButtonComponent, Importaciones: [ButtonComponentModule],});
Sin embargo, cuando se usa así, Spectator agrega internamente el ButtonComponent
de componente al nuevo módulo creado internamente. Por lo tanto, verá el siguiente error:
Type ButtonComponent is part of the declarations of 2 modules [...]
Es posible decirle a Spectator que no agregue el componente a las declaraciones del módulo interno y, en su lugar, use el módulo explícitamente definido tal como está. Simplemente establezca la propiedad declareComponent
de las opciones de fábrica en false
:
const createComponent = CreateComponentFactory ({ Componente: ButtonComponent, Importaciones: [ButtonComponentModule], declareComponent: false,});
Cuando se usa creativeFactory, establezca la propiedad declareDirective
de las opciones de fábrica a false
:
const creatective = createctiveFactory ({ componente: resaltar componente, Importaciones: [destacadoComponentModule], Declaredirective: falso,});
El Spectator proporciona una API conveniente para acceder a las vistas aplazables ( @defer {}
).
Acceda al bloque de diferencias deseado utilizando el método spectator.deferBlock(optionalIndex)
. El parámetro optionalIndex
es opcional y le permite especificar el índice del bloque de diferencias al que desea acceder.
Acceso al primer bloque de diferencias : simplemente llame spectator.deferBlock()
.
Acceso a los bloques de diferencias posteriores : use el índice correspondiente como argumento. Por ejemplo, spectator.deferBlock(1)
accede al segundo bloque (indexación basada en cero).
El spectator.deferBlock(optionalIndex)
devuelve cuatro métodos para representar diferentes estados del bloque de diferencias especificadas:
renderComplete()
- Rendera el estado completo del bloque de diferencias.
renderPlaceholder()
- Rendera el estado de marcador de posición del bloque de diferencias.
renderLoading()
- Rendera el estado de carga del bloque de diferencias.
renderError()
- Rendera el estado de error del bloque de diferencias.
Ejemplo:
@Component ({Selector: 'APP-CMP', Template: `@defer (en la vista) {<div> estado completo del primer bloque de diferencias </div> <!-Estado completo completo->} @placeholder { <Viv> PLODIGHER </div>} `,}) clase dummyComponent {} const createComponent = CreateComponentFactory ({componente: dummyComponent, DeferblockBehavior: DeferblockBehavior.Manual,}); it ('debería render el estado completo', asnC () = = = = = = > {// organizar const spectator = createComponent ();
Para acceder a los estados dentro de los bloques de diferencias anidadas, llame al método deferBlock
encadenamiento del método de estado de bloque devuelto.
Ejemplo: Acceder al estado completo anidado:
// Suponiendo `spectator.deferblock (0) .rendercomplete ()` Renderiza el estado completo del matriz blockconst matretestate = a espera spectator.deferblock (). RenderComplete (); // Acceda al estado completo anidado del parent inofer blockconst completestate = espera ParentCompletestate.renderComplete (). Deferblock ();
Ejemplo completo :
@Component ({Selector: 'App-CMP', Template: `@defer (en Viewport) {<Viv> Estado completo del primer bloque de diferencias </div> <!-Estado completo completo-> @defer {< Div> Estado completo del bloque de diferencias anidadas </div> <!-Estado completo anidado->}} @placeholder {<div> PLADELLOVER </div>} `,}) class DummyComponent {} const CreateComPonent = CreateComponentFactory ( {componente: dummyComponent, Deferblockbebhavior: DeferblockBehavior.Manual,}); it ('debería representar el primer estado completo anidado', async () => {// organizar const spectator = createComponent (); // Act // se convierte en el padre padre Estado completo const parentCompletestate = ALEA SPECTATOR.DEFERBLOCK (). RenderComplete (); diferir el bloque ');});
Probar un componente con un componente host es una técnica más elegante y potente para probar su componente. Básicamente le brinda la capacidad de escribir sus pruebas de la misma manera que escribe su código. Veamos en acción:
import {createHostFactory, SpectatorHost} de '@ngneat/spectator'; describir ('zippyComponent', () => { Let Spectator: SpectatorHost <ZippyComponent>; const createHost = createHostFactory (ZippyComponent); it ('debería mostrar el título de la propiedad host', () => {spectator = createHost (`<zippy [title] =" title "> </ Zippy>`, {hostprops: {title: 'Spectator es increíble'} }); esperar (Spectator.Query ('. Zippy__title')). TohaveText ('Spectator es impresionante'); }); it ('debería mostrar la palabra "cerrar" if abre', () => {spectator = createHost (`<zippy title =" zippy title "> contenido zippy </zippy>`); spectator.click ('. zippy__title' ); esperar (Spectator.Query ('. Arrow')). TohaveText ('Cerrar'); Espere (Spectator.Query ('. Arrow')). Not.ToHaveText ('Open'); });});
El método de host devuelve una instancia de SpectatorHost
que extiende Spectator
con la siguiente API adicional:
hostFixture
: el accesorio del huésped
hostComponent
: la instancia de componente del host
hostElement
: el elemento nativo del anfitrión
hostDebugElement
- Elemento de depuración del accesorio del anfitrión
setHostInput
: cambia el valor de un @Input()
del componente host
queryHost
: lea más sobre la consulta en Spectator
queryHostAll
: lea más sobre la consulta en Spectator
Establecer entradas directamente en un componente usando setInput
o props
no es posible al probar con un componente de host. En su lugar, las entradas deben establecerse a través de hostProps
o setHostInput
, y pasar a su componente en la plantilla.
A veces es útil aprobar su propia implementación del host. Podemos pasar un componente de host personalizado al createHostFactory()
que reemplazará el predeterminado:
@Component ({Selector: 'Custom-Host', Template: '' '}) clase CustomHostComponent { title = 'Custom HostComponent';} describe ('con componente host personalizado', function () { Let Spectator: SpectatorHost <ZippyComponent, CustomHostComponent>; const createHost = createHostFactory ({componente: zippyComponent, host: customHostComponent }); it ('debería mostrar el título del componente del host', () => {spectator = createHost (`<zippy [title] =" title "> </zippy>`); WIEP (spectator.query ('. Zippy__title')))) .tohaveText ('personalizado hostcomponent'); });});
Para los componentes que usan el enrutamiento, hay una fábrica especial disponible que extiende la predeterminada y proporciona un ActivatedRoute
robado para que pueda configurar opciones de enrutamiento adicionales.
Describa ('ProductDetailsComponent', () => { Let Spectator: Spectatoruring <ProductDetailsComponent>; const createComponent = CreateRoutingFactory ({componente: ProductDetailSComponent, Params: {ProductId: '3'}, Data: {Título: 'Some Title'} }); ANTERIOREACH (() => Spectator = CreateComponent ()); it ('debería mostrar el título de datos de la ruta', () => {spear (spectator.query ('. title')). thaveText ('algún título'); }); it ('debería reaccionar a los cambios de ruta', () => {spectator.setrouteparam ('productID', '5'); // su prueba aquí ... });});
La API SpectatorRouting
incluye métodos convenientes para actualizar la ruta actual:
interfaz spectatorrouting <c> extiende Spectator <c> { /*** Simula una navegación de ruta actualizando los parámetros, consulta y secuencias observables de datos. */ TriggerNavigation (Opciones?: RouteOptions): Void; /*** Actualiza los parámetros de ruta y desencadena una navegación de ruta. */ setRouteparam (nombre: cadena, valor: string): void; /*** Actualiza los parámetros de consulta de ruta y desencadena una navegación de ruta. */ setRouteEkeryParam (nombre: cadena, valor: string): void; /*** Actualiza los datos de la ruta y desencadena una navegación de ruta. */ setRoutedata (nombre: cadena, valor: any): void; /*** Actualiza el fragmento de ruta y desencadena una navegación de ruta. */ setRouteFragment (fragmento: string | null): void; /*** Actualiza la URL de la ruta y desencadena una navegación de ruta. */ setrouteurl (url: urlsegment []): void;}
RouterTestingModule
Si establece la opción stubsEnabled
en false
, puede pasar una configuración de enrutamiento real y configurar una prueba de integración utilizando RouterTestingModule
de Angular.
Tenga en cuenta que esto requiere promesas para resolver. Una forma de lidiar con esto es hacer que su prueba asíndía:
describir ('prueba de integración de enrutamiento', () => { const createComponent = CreaterOutingFactory ({componente: myComponent, Declaraciones: [OtroComponent], stubSenabled: false, rutas: [{ruta: '', componente: myComponent}, {ruta: 'foo', componente: otro componente}] }); it ('debería navegar usando el enlace del enrutador', async () => {const spectator = createComponent (); // Espera para que las promesas se resuelvan ... espera spectator.fixture.whenstable (); // Prueba la ruta actual por afirmar la ubicaciónxpect (spectator.inject (ubicación) .path ()). tobe ('/'); // Haga clic en un enrutador LinkSpectator.Click ('. Link-1'); // No olvide esperar promete resolver ... espera spectator.fixture.WhenStable (); // prueba la nueva ruta afirmando la ubicación (spectator.inject (ubicación) .path ()). tobe ('/foo'); });});
La función createRoutesFactory
puede tomar las siguientes opciones, además de las opciones de espectador predeterminadas:
params
: parámetros iniciales para usar en ActivatedRoute
stub
queryParams
: parámetros de consulta inicial para usar en ActivatedRoute
Stub
data
: datos iniciales que se usarán en ActivatedRoute
Stub
fragment
: fragmento inicial para usar en el talón ActivatedRoute
url
: segmentos de URL iniciales para usar en ActivatedRoute
Stub
root
: el valor para root
del talón ActivatedRoute
parent
: El valor para parent
para el talón ActivatedRoute
children
: El valor para children
para el talón ActivatedRoute
firstChild
: El valor para firstChild
para el talón ActivatedRoute
stubsEnabled
(predeterminado: true
): habilita el stub ActivatedRoute
, si se establece en false
usa RouterTestingModule
en su lugar
routes
: si stubsEnabled
se establece en False, puede pasar una configuración Routes
para RouterTestingModule
Hay una fábrica de prueba especial para las directivas de prueba. Digamos que tenemos la siguiente directiva:
@Directive ({Selector: '[destacado]'}) Clase de exportación SPOWDirective { @HostBinding ('style.background-color') BackgroundColor: String; @HostListener ('Mouseover') onhover () {this.backgroundcolor = '#000000'; } @HostListener ('Mouseout') onleeave () {this.backgroundcolor = '#ffffff'; }}
Veamos cómo podemos probar las directivas fácilmente con Spectator:
Describa ('spoopDirective', () => { Let Spectator: SpectatordIrective <SpightIrective>; const creatective = createctiveFactory (stoppectDirective); ANTERIOREACH (() => {Spectator = creatective (`<Div destacado> Prueba de prueba Directiva </div>`); }); it ('debería cambiar el color de fondo', () => {spectator.dispatchMouseEvent (spectator.element, 'mouseover'); esperar (spectator.element) .tohavestyle ({backgroundColor: 'rgba (0,0,0, 0.1 ) '}); spectator.dispatchmouseEvent (Spectator.Element,' MouseOut '); ESPERS (Spectator.Element) .ToHaveStyle ({BackgroundColor:' #fff '}); }); it ('debería obtener la instancia', () => {const instancy = spectator.directive; wepe (instancia) .tobedefined (); });});
No es posible establecer entradas directamente en una directiva utilizando setInput
o props
. En su lugar, las entradas deben establecerse a través de hostProps
o setHostInput
, y pasar a su directiva en la plantilla.
El siguiente ejemplo muestra cómo probar un servicio con Spectator:
import {CreateServiceFactory, SpectatorService} de '@ngneat/spectator'; import {authservice} de 'auth.service.ts'; describir ('authservice', () => { Let Spectator: Spectatorservice <OftService>; const createService = CreateServiceFactory (authService); antes de antes (() => spectator = createService ()); it ('no debe registrarse', () => {spect (spectator.service.isloggedIn ()). tobefalsy (); });});
La función createService()
devuelve SpectatorService
con las siguientes propiedades:
service
: obtenga una instancia del servicio
inject()
- un proxy para angular TestBed.inject()
También es posible pasar un objeto con opciones. Por ejemplo, al probar un servicio, a menudo desea burlarse de sus dependencias, ya que nos enfocamos en el servicio que se está probando.
Por ejemplo:
@Injectable () Exportar clase AuthService { constructor (servicio privado de fechas: Dateservice) {} isloggedIn () {if (this.sdateservice.isexpired ('timestamp')) {return false;} return true; }}
En este caso, podemos burlarnos de la dependencia DateService
.
import {CreateServiceFactory, SpectatorService} de '@ngneat/spectator'; import {authservice} de 'auth.service.ts'; describir ('authservice', () => { Let Spectator: Spectatorservice <OftService>; const createService = CreateServiceFactory ({Service: AuthService, Providers: [], EntryComponents: [], Mocks: [Dateservice] }); antes de antes (() => spectator = createService ()); it ('debe registrarse en', () => {const Dateservice = Spectator.inject (Dateservice); Dateservice.isexpired.and.returnValue (false); spect (spectator.service.isloggedin ()). tobetruthy (); });});
El siguiente ejemplo muestra cómo probar una tubería con Spectator:
import {SpectatorPipe, CreatePipeFactory} de '@ngneat/spectator'; import {statsservice} de './stats.service';import {Sumpipe} de' ./sum.pipe' ;Describe('Sumpipe ', () => { Let Spectator: SpectatorPipe <Sumpipe>; const createpipe = createPipeFactory (SUMPIPE); it ('debería resumir la lista dada de números (plantilla)', () => {spectator = createPipe (`{{{[1, 2, 3] | suma}}`); esperar (spectator.element). ('6'); }); it ('debería resumir la lista dada de números (prop)', () => {spectator = createPipe (`{{prop | sum}}`, {hostprops: {prop: [1, 2, 3]}} ); esperar (Spectator.Element) .ToHaveText ('6'); }); it ('debería delegar la suma al servicio', () => {const sum = () => 42; const Provider = {proporcionar: statsservice, useValue: {sum}}; spectator = createPipe (`{{PROP | Sum}} `, {hostprops: {Prop: [2, 40]}, Proveedores: [proveedor]}); esperar (spectator.element) .tohavetext ('42 '); });});
La función createPipe()
devuelve SpectatorPipe
con las siguientes propiedades:
hostComponent
- instancia del componente host
debugElement
: el elemento de depuración del accesorio en torno al componente del host
element
: el elemento nativo del componente host
detectChanges()
- Un proxy para angular TestBed.fixture.detectChanges()
inject()
- un proxy para angular TestBed.inject()
No es posible configurar las entradas directamente en una tubería usando setInput
o props
. En su lugar, las entradas deben establecerse a través de hostProps
o setHostInput
, y pasar a su tubería en la plantilla.
El siguiente ejemplo ilustra cómo probar una tubería utilizando un componente de host personalizado:
import {componente, entrada} de '@angular/core'; import {spectatorPipe, createPipeFactory} de '@ngneat/spectator'; import {promedioPipe} de './average.pipe';import {statsservice} de' ./stats .service ';@componente ({ Plantilla: `<Div> {{Prop | AVG}} </div> `}) clase CustomHostComponent { @Input () Public Prop: Número [] = [1, 2, 3];} Describe ('promedioPipe', () => { Let Spectator: SpectatorPipe <vomiodPipe>; const createPipe = CreatePipeFactory ({Pipe: promediopipe, host: customhostComponent }); it ('debería calcular el promedio de una lista dada de números', () => {spectator = createPipe (); esperar (spectator.element) .tohaveText ('2'); }); it ('debería dar como resultado 0 cuando la lista de números está vacía', () => {spectator = createPipe ({hostprops: {prop: []}}); esperar (spectator.element) .tohavetext ('0'); }); it ('debería delegar el cálculo al servicio', () => {const avg = () => 42; const Provider = {proporcionar: statsservice, useValue: {AVG}}; Spectator = CreatePipe ({Providers: [Provider ]}); esperar (spectator.element) .tohaveText ('42 '); });});
Para cada fábrica de espectadores, podemos burlarnos fácilmente de cualquier proveedor.
Cada servicio que pase a la propiedad mocks
se burlará utilizando la función mockProvider()
. La función mockProvider()
convierte cada método en un espía de jazmín. (es decir, jasmine.createSpy()
).
Estos son algunos de los métodos que expone:
Dateservice.isexpired.and.callthrough (); Dateservice.isexpired.and.callfake (() => falso); Dateservice.isexpired.and.throwerror ('Error'); Dateservice.isexpired.andCallFake (() => Fake) ;
Sin embargo, si usa Jest como marco de prueba y desea utilizar su mecanismo de burla, importe el mockProvider()
desde @ngneat/spectator/jest
. Esto usará automáticamente la función jest.fn()
para crear un simulacro compatible en su lugar.
mockProvider()
no incluye propiedades. En caso de que necesite tener propiedades en su simulacro, puede usar el segundo argumento:
const createService = CreateServiceFactory ({ Servicio: AuthService, Providers: [MockProvider (OtherService, {nombre: 'Martin', emitter: new Sujem (), Mockedmethod: () => 'Mocked'}) ],});
Si un componente se basa en un servicio burlado en el método OnInit Lifecycle, la detección de cambios debe deshabilitarse hasta después de que se haya inyectado los servicios.
Para configurar esto, cambie el método createComponent
para que la opción detectChanges
establezca en falso y luego llame manualmente detectChanges
en el espectador después de configurar los servicios inyectados.
const createComponent = CreateComponentFactory ({ Componente: WeatherDashBoardComponent}); it ('debería llamar a la API meteorológica en init', () => { const spectator = createComponent ({DetectChanges: False }); const weatherservice = spectator.inject (WeatherDataapi); weatherservice.getweatherdata.andreturn (de (Mockweatherdata)); spectator.detectChanges (); esperar (weatherservice.getweatherData) .tohaveBeenLed ();});
Si un componente se basa en un servicio que se burla en su constructor, debe crear y configurar el simulacro, y proporcionar el simulacro al crear el componente.
const createComponent = CreateComponentFactory ({ Componente: WeatherDashBoardComponent}); it ('debería llamar a la API meteorológica en el constructor', () => { const weatherservice = CreateSpyObject (WeatherDataApi); weatherservice.getweatherdata.andreturn (de (Mockweatherdata)); Spectator = CreateComponent ({Providers: [{proporcionar: WeatherDataApi, UseValue: Weatherservice}] }); esperar (weatherservice.getweatherData) .tohaveBeenLed ();});
Por defecto, Spectator usa Jasmine para crear espías. Si está utilizando Jest como marco de prueba, puede dejar que Spectator cree espías compatibles con Jest.
Simplemente importe una de las siguientes funciones de @ngneat/spectator/jest
(en lugar de @ngneat/spectator), y usará broma en lugar de jasmine. createComponentFactory()
, createHostFactory()
, createServiceFactory()
, createHttpFactory()
, mockProvider()
.
import {createServiceFactory, SpectatorService} de '@ngneat/spectator/jest'; import {authService} de './auth.service';import {Dateservice} de' ./Date.Service';Describe('Authservice ', () => { Let Spectator: Spectatorservice <OftService>; const createService = CreateServiceFactory ({Service: AuthService, Mocks: [Dateservice] }); antes de antes (() => spectator = createService ()); it ('no debe registrarse en', () => {const Dateservice = Spectator.inject <ScalService> (Dateservice); Dateservice.isexpired.mockReturnValue (true); spect (spectator.service.isloggedin ()). Tobefalsy ( ); }); it ('debe registrarse en', () => {const Dateservice = Spectator.inject <ScatesService> (Dateservice); Dateservice.isexpired.mockReturnValue (falso); esperar (spectator.service.isLoggedIn ()). Tobetruthy () () ; });});
Al usar el esquema de componentes, puede especificar el indicador --jest
para utilizar las importaciones de Jest. Para que Jest importe el valor predeterminado, actualice angular.json
:
"Schematics": {"@Ngneat/Spectator: Spectator-Component": {"Jest": True } }
Spectator facilita la prueba de datos, que utilizan el módulo HTTP angular, mucho más fácil. Por ejemplo, supongamos que tiene servicio con tres métodos, uno realiza una publicación, una y otra realiza solicitudes concurrentes:
clase de exportación TodosdataService { constructor (privado httpclient: httpclient) {} getTodos () {return this.httpClient.get ('API/TODOS'); } posttodo (id: número) {return this.httpclient.post ('api/toDos', {id}); } CollectTodos () {return fusion (this.httpclient.get ('/api1/toDos'), this.httpclient.get ('/api2/toDos')); }}
La prueba para el servicio anterior debe parecerse:
import {createHttpFactory, httpmethod} de '@ngneat/spectator'; import {TodosdataService} de './todos-data.service';Describe('httpClient testing', () => { Let Spectator: SpectatorHTTP <TDOSDATAservice>; const createHttp = createHttpFactory (TodosDataService); ANTERIOREACH (() => Spectator = CreateHttp ()); it ('puede probar httpclient.get', () => {spectator.service.getTodos (). suscripción (); spectator.expectone ('api/toDos', httpmethod.get); }); it ('puede probar httpclient.post', () => {spectator.service.posttodo (1) .subscribe (); const req = spectator.expectone ('api/toDos', httpmethod.post); supptar (req. request.body ['id']). toqual (1); }); it ('puede probar las solicitudes HTTP actuales', () => {spectator.service.getTodos (). suscribe (); const reqs = spectator.expectconcurrent ([{url: '/api1/diDos', método: httpmethod.get.get.get.get.get.get.get.get.get.get.get.get.get.get }, {Url: '/api2/Todos', método: httpmethod.get}]); spectator.flushall (reqs, [{}, {}, {}]); });});
Necesitamos crear una fábrica HTTP utilizando la función createHttpFactory()
, pasando el servicio que desea probar. createHttpFactory()
devuelve una función que se puede llamar para obtener una instancia de SpectatorHTTP con las siguientes propiedades:
controller
: un proxy para Angular HttpTestingController
httpClient
- un proxy para angular HttpClient
service
: la instancia del servicio
inject()
- un proxy para angular TestBed.inject()
expectOne()
- Espere que se haya realizado una sola solicitud que coincida con la URL dada y su método, y devuelva su solicitud simulada
Es posible definir inyecciones que estarán disponibles para cada prueba sin la necesidad de volver a decidirlas en cada prueba:
// test.tsimport {defineGlObalSInjections} de '@ngneat/spectator'; import {translocomodule} de '@ngneat/transloco'; defineGlObalsInjections ({ importaciones: [translocomodule],});
Tenga en cuenta que defineGlobalsInjections()
debe llamarse antes de cargar los módulos. En la test.ts
angular predeterminada. Esto significa antes de esta línea:
context.keys (). map (contexto);
Por defecto, los proveedores de componentes originales (por ejemplo, los providers
en el @Component
) no se tocan.
Sin embargo, en la mayoría de los casos, desea acceder a los proveedores del componente en su prueba o reemplazarlos con simulacros.
Por ejemplo:
@Componente({ plantilla: '...', Proveedores: [Fooservice]}) Clase Foocomponent { Constructor (Fooservice privado: Fooservice} {} // ...}
Use los componentProviders
para reemplazar el proveedor FooService
:
const createComponent = CreateComponentFactory ({ componente: foocomponent, ComponentProviders: [{proporcionar: Fooservice, Use Value: SomethingEelse} ]})
O burlarse del servicio utilizando componentMocks
:
const createComponent = CreateComponentFactory ({ componente: foocomponent, ComponentMocks: [Fooservice]});
Para acceder al proveedor, obténlo desde el inyector de componentes utilizando el parámetro fromComponentInjector
:
spectator.inject (Fooservice, verdadero)
De la misma manera, también puede anular los proveedores de la vista de componentes utilizando componentViewProviders
y componentViewProvidersMocks
.
Las mismas reglas también se aplican a las directivas utilizando los parámetros directiveProviders
y directiveMocks
.
Espere ('. Zippy__Content'). Not.ToExist (); Espere ('. Zippy__Content'). ToHavel Longitud (3); Expect ('. Zippy__Content'). Zippy ')). ). )). Si el pedido es irrelevante, desactive el modo estricto manualmente.expect ('. Zippy__Content'). Tohaveclass ('class'); esperar ('. Zippy__Content'). zippy__content '). not.tohaveclass (' class-b, class-a '); expect ('. Zippy__Content '). ) .not.tohavecLass (['class-b', 'class-a']); expects ('. Zippy__Content'). tohaveclass ('class-a, class-b', {Strict: false}); WIEPT ('. Zippy__Content'). Tohaveclass ('class-b, class-a', {strict: false}); supe ('. zippy__content '). tohaveclass ([' class-b ',' class-a '], {Strict: false}); supe ('. Zippy__content '). Tohaveclass ([' class-b ',' class-a ']] , {Strict: False}); // Tenga en cuenta que TohaveText solo busca la existencia de una cadena, no si la cadena es exactamente la misma. Si desea verificar que la cadena es completamente la misma, use TohaveExactText.// Tenga en cuenta que si desea verificar que la cadena es completamente la misma, pero se recorta primero, use TohaveExactTrimmedText.// Tenga en cuenta que si pasa múltiples valores, Spectator verifica el texto de cada elemento de matriz contra el índice del elemento encontrado.expect ('. Zippy__Content'). ']); espere ('. Zippy__Content '). ') .Tocontaintext ([' Content A ',' Content B ']); Expect ('. Zippy__Content '). TohaveExActText (' Content '); Expect ('. Zippy__Content '). TohaveExactText ([' Content A ',', ',' Contenido b ']); expect ('. Zippy__Content '). ) .ToHaveValue ('valor'); esperar ('. Zippy__content'). ToContainValue ('Value'); // Tenga en cuenta ('.zippy__content'). tohaveValue (['valor a', 'valor b']); esperar ('. Zippy__content'). ) .ToHaveStyle ({backgroundColor: 'rgba (0, 0, 0, 0.1)'}); esperar ('. Zippy__Content'). Tohavedata ({Data: 'rol', val: 'admin'}); espere (' .CHECKBOX '). TOBECHECKED (); Espere ('. CheckBox '). TobeIndeterminate (); Espere ('.. .tobehidden (); esperar ('elemento'). tobeselected (); // Observe que debido a las restricciones dentro de Jest (sin aplicar la lógica de diseño real en DOM virtual), ciertos maticeros pueden dar lugar a falsos positivos. Por ejemplo, ancho y altura establecidas en 0Expect ('Element'). TOBEVISIBLE (); Espere ('Entrada'). TobeFocused (); ESPIE ('Div'). TobematchedBy ('. JS-SomTing'); Spectator. componente.Object) .tobePartial ({APROperty: 'Avalue'}); Expect ('div'). 'texto'});
Genere componentes, servicio y directiva con plantillas de especificaciones de Spectator con CLI angular: (cuando lo usa como predeterminado)
Componente
Especificación predeterminada: ng g cs dashrized-name
Especificación con un host: ng g cs dashrized-name --withHost=true
Especificación con un host personalizado: ng g cs dashrized-name --withCustomHost=true
Servicio:
Especificación predeterminada: ng g ss dashrized-name
Spec para probar el servicio de datos HTTP: ng g ss dashrized-name --isDataService=true
Directiva:
ng g ds dashrized-name
Para usar spectator
como la colección predeterminada en su proyecto Angular CLI, agrégalo a su angular.json
:
ng config cli.defaultCollection @ngneat/spectator
Los spectator
Schematics extienden la colección predeterminada @schematics/angular
. Si desea establecer valores predeterminados para esquemas, como generar componentes con el archivo SCSS, debe cambiar el nombre del paquete de esquemas de @schematics/angular
a @ngneat/spectator
en angular.json
:
"Schematics": {"@ngneat/spectator: spectator-component": {"style": "scss" } }
Los ejemplos en Karma de la Guía del desarrollador de pruebas de Docs Angular se han reproducido en Spectator y Jest. (Por conveniencia, esta es la versión local de los ejemplos de karma).
Se puede acceder a la versión Spectator & Jest aquí.
Netanel basal | Dirk luijk | Ben Elliott |
Gracias a estas personas maravillosas (Key Emoji): ~~~~
I. Sinaí ? ? | Valentin Buryakov ? | Ben Grynhaus ? | Martin nuc | Lars Gyrup Brink Nielsen ? | Andrew Grekov ? | Jeroen Zwartepoorte |
Oliver Schlegel | Rex ye ? | tchmura | Yoeri nijs | Anders Skarby | Gregor Woiwode | Alexander Sheremetev ? |
Micro | Mehmet erim | Brett Eckert | Ismail faizi | Máximo | Jonathan Bonnefoy | Ferry de colum |
Chris Cooper | Marc Scheib | dgsmith2 | Dedwardstech ? | tamasfoldi ? | Paolo Caleffi | Toni Villena |
Itay Oded | Guillaume de Jabrun | Anand tiwary | Cervezas Doganoc | Zoltan | Vitalii baziuk | Clementlemarc-Certua |
Yuriy Grunin | Andrey Chalkin | Steven Harris | Richard Sahrakorpi | Dominik Kremer | Mehmet Ozan Turhan | Vlad Lashko |
William Tjondrosuharto | Chaz gatiano | Pavel Korobov | Enno lohmann | Pawel Boguslawski | Tobias Wittwer | Mateo tibaquirá |
Este proyecto sigue la especificación de todos los contribuyentes. ¡Contribuciones de cualquier tipo bienvenido!