Skip to content

Actividad 5 - Pruebas en aplicaciones Ionic

Esta actividad consiste en implementar pruebas en una aplicación Ionic existente. La aplicación de ejemplo es un sistema de gestión que permite gestionar clientes, reservas y productos. Se implementan pruebas unitarias utilizando Jasmine con Karma, pruebas de componentes con Cypress y pruebas E2E (end-to-end) con Cypress.

1. Tipos de pruebas en aplicaciones híbridas

Section titled “1. Tipos de pruebas en aplicaciones híbridas”

Al igual que en el desarrollo de cualquier software, una aplicación híbrida debe ser sometida durante su desarrollo a un proceso de pruebas, preferiblemente mediante una aproximación de integración continua que favorezca un desarrollo ágil y flexible.

Entre los diferentes tipos de pruebas que podemos ejecutar sobre nuestras aplicaciones híbridas se encuentran:

  • Pruebas unitarias: se realizan sobre cada componente desarrollado para probar pequeñas unidades de código que están aisladas de otras partes o subsistemas de la aplicación.

  • Pruebas de integración: se realizan para probar el comportamiento de dos o más componentes que tienen algún tipo de relación durante la ejecución de cierta funcionalidad. También se pueden realizar pruebas de integración para probar el comportamiento de un componente con respecto a un servicio o a una parte del sistema que no es visible para el usuario.

  • Pruebas de interfaz de usuario o end-to-end (E2E): se realizan desde el front-end y con el objetivo de satisfacer las necesidades de negocio de dicho front-end. Para ello, se intenta simular la interacción de un usuario que hace uso de la aplicación, evaluando los resultados obtenidos.

Para esta sesión, utilizaremos Jasmine con Karma para las pruebas unitarias, y Cypress para las pruebas de integración entre componentes, y de interfaz de usuario (E2E).

Las pruebas unitarias tienen el objetivo de probar pequeñas unidades de código de forma aislada. La propia naturaleza de las aplicaciones híbridas desarrolladas con Ionic y Angular favorecen este tipo de pruebas debido a su construcción modular.

La escritura adicional del código para la ejecución de pruebas unitarias favorece no solo la verificación del código en el momento que se está desarrollando, sino que también sirve para la ejecución de pruebas de regresión cuando se realiza alguna modificación en otras partes de la aplicación. De forma adicional, el código de las pruebas unitarias sirve como parte de la documentación del software.

Para la ejecución de las pruebas unitarias, vamos a hacer uso de Cypress y también revisaremos cómo poder llevar a cabo este tipo de pruebas con Jasmine.

Las pruebas E2E se centran en detectar aquellos errores que ponen en peligro los objetivos de negocio de una aplicación híbrida, tratando de poner de manifiesto errores ocultos que no son detectados por las pruebas unitarias, errores generados por una mala definición del flujo funcional o errores que provienen de la comunicación entre partes o subsistemas de la aplicación.

Mediante este tipo de pruebas, se puede simular la interacción de un ratón o de un teclado para generar eventos que afecten a la aplicación. También se puede comprobar si son visibles algunos elementos de la vista o determinar si la posición es correcta. Se pueden validar si están disponibles algunas acciones, si el tiempo de respuesta es el correcto o si otras medidas de rendimiento son adecuadas.

Las herramientas de pruebas E2E suelen hacer uso de tecnologías basadas en Javascript para poder simular la interacción que el usuario lleva a cabo mediante el navegador web en el que se ejecuta la aplicación híbrida. Para la ejecución de las pruebas E2E, vamos a hacer uso de Cypress, aunque anteriormente se llevaban a cabo mediante el uso de Protractor.

2. Uso de Jasmine para la ejecución de pruebas unitarias

Section titled “2. Uso de Jasmine para la ejecución de pruebas unitarias”

Para la ejecución de las pruebas unitarias, Jasmine se utiliza para la implementación de los tests, mientras que Karma se utiliza para la ejecución de dichos tests.

Tenemos en cuenta la sintaxis descriptiva de Jasmine:

  • describe: equivalente a una colección (suite) de pruebas.

  • it: equivalente a una prueba específica (test) que debe ser contenida por una colección de pruebas.

  • expect: equivalente a una comprobación o aserción (assert) que debe ser contenida por una prueba.

Aunque la construcción de las pruebas es similar para cada elemento de una aplicación Ionic, vamos a distinguir cómo se construyen los tests para el caso de los servicios y cómo deben implementarse las pruebas en el caso de los componentes.

2.1. Prueba de servicios y proveedores de servicios

Section titled “2.1. Prueba de servicios y proveedores de servicios”

Para analizar la prueba unitaria de servicios, vamos a modificar la implementación del archivo de pruebas generate-text.service.spec.ts que se genera de forma automática:

src/app/core/services/generate-text.service.ts
import { Injectable } from "@angular/core";
@Injectable({
providedIn: "root",
})
export class GenerateTextService {
public words: string[] = [
"This",
"is",
"an",
"example",
"of",
"service",
"for",
"DAH",
];
constructor() {}
getWords() {
return this.words;
}
getRandomWord() {
return this.words[this.getRandomInt(0, this.words.length - 1)];
}
private getRandomInt(min: number, max: number) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
}
src/app/core/services/generate-text.service.spec.ts
import { TestBed } from "@angular/core/testing";
import { GenerateTextService } from "./generate-text.service";
describe("GenerateTextService", () => {
let service: GenerateTextService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(GenerateTextService);
});
it("should be created", () => {
expect(service).toBeTruthy();
});
it("should return a non-empty array", () => {
let result = service.getWords();
expect(Array.isArray(result)).toBeTruthy();
expect(result.length).toBeGreaterThan(0);
});
it("should return a random word as a string", () => {
expect(typeof service.getRandomWord()).toBe("string");
});
it("should have 'DAH' and 'service' in the list of words", () => {
let result = service.getWords();
expect(result).toContain("DAH");
expect(result).toContain("service");
});
});

La prueba de componentes requiere la realización de comprobaciones tanto en la clase TypeScript que lo define como en la plantilla HTML. Para ello, se hace uso de un entorno de pruebas que incluye los diferentes elementos requeridos durante la ejecución de dicho componente. Este entorno de pruebas recibe el nombre de TestBed.

Cuando se realiza la prueba de este componente, el acceso al mismo se realiza a través de un manejador (fixture) que permite hacer referencia a una instancia de dicho componente (fixture.componentInstance). Para acceder a los elementos del DOM, se hará uso de fixture.nativeElement.

src/app/features/home/home.page.ts
import { Component, inject, model, signal } from "@angular/core";
import { RouterLink } from "@angular/router";
import { FormsModule } from "@angular/forms";
import {
IonHeader,
IonToolbar,
IonTitle,
IonContent,
IonItem,
IonInput,
IonButton,
} from "@ionic/angular/standalone";
import { GenerateTextService } from "src/app/core/services/generate-text.service";
@Component({
selector: "app-home",
templateUrl: "home.page.html",
styleUrls: ["home.page.scss"],
imports: [
RouterLink,
IonHeader,
IonToolbar,
IonTitle,
IonContent,
IonItem,
IonInput,
IonButton,
FormsModule,
],
})
export class HomePage {
public title = signal("Home Page");
public word = model("Initial word");
public testservice = inject(GenerateTextService);
getWord() {
this.word.set(this.testservice.getRandomWord());
}
changeTitle(title: string) {
this.title.set(title);
}
}
src/app/features/home/home.page.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HomePage } from './home.page';
import { By } from '@angular/platform-browser';
describe('HomePage', () => {
let component: HomePage;
let fixture: ComponentFixture<HomePage>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [HomePage],
}).compileComponents();
fixture = TestBed.createComponent(HomePage);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('initialize the title from signal', () => {
const el: HTMLElement = fixture.nativeElement;
expect(el.querySelector('ion-title')?.textContent.trim()).toBe('Home Page');
});
it('should update the word in the DOM when button clicked', () => {
const button = fixture.debugElement.query(By.css('ion-button'));
button.triggerEventHandler('click', null);
fixture.detectChanges();
expect(component.word()).not.toBe('Hello World!');
});
it('should update the title in the DOM when changeTitle is called', () => {
component.changeTitle('New title');
fixture.detectChanges();
const el: HTMLElement = fixture.nativeElement;
expect(el.querySelector('ion-title')?.textContent).toContain('New title');
});
});

Para la ejecución de las pruebas unitarias de la aplicación, debemos ejecutar el siguiente comando:

Terminal window
npm test

Como resultado, se desplegará un servidor de Karma para ejecutar y visualizar el resultado de las pruebas realizadas:

Si alguna de las pruebas falla, se nos mostrará información sobre la causa que ha provocado el fallo.

3. Uso de Cypress para la ejecución de pruebas unitarias

Section titled “3. Uso de Cypress para la ejecución de pruebas unitarias”

Cypress es una herramienta que permite la automatización de pruebas de extremo a extremo (E2E) y de integración. Además, permite la realización de pruebas unitarias. Para la ejecución de pruebas unitarias con Cypress, se debe instalar la dependencia en el proyecto:

Terminal window
npm install -D cypress

Una vez instalada, se puede ejecutar la herramienta con el siguiente comando:

Terminal window
npx cypress open

En la ventana de configuración que se abre, seleccionaremos la opción Component Testing. A continuación, debemos seleccionar el framework de desarrollo utilizado para el front-end. En este caso, seleccionaremos Angular y avanzaremos en la configuración mediante Next step. Se nos informará sobre las dependencias necesarias y seleccionaremos Continue.

Una vez seleccionado el navegador, podemos crear las pruebas unitarias que deseemos mediante la selección de New spec. Para ejecutar las pruebas unitarias con Cypress, debemos ejecutar el archivo de pruebas (spec) creado haciendo clic en él en la ventana de Cypress.

4. Uso de Cypress para la ejecución de pruebas E2E

Section titled “4. Uso de Cypress para la ejecución de pruebas E2E”

Además de las pruebas unitarias, Cypress también permite la realización de pruebas E2E. Puesto que ya hemos instalado Cypress para la realización de pruebas unitarias, no es necesario realizar una nueva instalación para la ejecución de pruebas E2E. El siguiente paso es volver a ejecutar la herramienta con el siguiente comando:

Terminal window
npx cypress open

En la ventana de configuración que se abre, ahora seleccionaremos la opción E2E testing. Se nos mostrará una lista de los archivos de configuración de Cypress que existen en el proyecto. Seleccionamos Continue y en la siguiente ventana podemos seleccionar el navegador en el que se ejecutarán las pruebas. Una vez seleccionado, podemos crear las pruebas E2E que deseemos.

Para poder ejecutar las pruebas de la aplicación Ionic con Cypress, debemos establecer la URL base de la aplicación en el archivo cypress.config.ts:

cypress.config.ts
import { defineConfig } from 'cypress';
export default defineConfig({
component: {
devServer: {
framework: 'angular',
bundler: 'webpack',
options: {
projectConfig: {
root: './',
sourceRoot: 'src',
buildOptions: {
outputPath: 'dist/browser',
},
},
},
},
specPattern: '**/*.cy.ts',
},
e2e: {
baseUrl: 'http://localhost:8100',
setupNodeEvents(on, config) {
// implement node event listeners here
},
},
});

A continuación se describen los tests implementados para cada componente y servicio de la aplicación.

Los tests con Jasmine se ejecutan con Karma y permiten verificar el correcto funcionamiento de componentes y servicios de forma aislada.

  • Verifica que el componente se crea correctamente
  • Verifica que hay 5 clientes en la lista
  • Verifica que se muestran los items de clientes en la plantilla
  • Verifica los nombres de los clientes: John Doe, Jane Smith, Bob Johnson, Alice Brown, Charlie Wilson
src/app/features/clients/clients.page.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { provideRouter } from '@angular/router';
import { ClientsPage } from './clients.page';
describe('ClientsPage', () => {
let component: ClientsPage;
let fixture: ComponentFixture<ClientsPage>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ClientsPage],
providers: [provideRouter([])]
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ClientsPage);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should have 5 clients in the list', () => {
expect(component.clients.length).toBe(5);
});
it('should display client items in the template', () => {
const compiled = fixture.nativeElement as HTMLElement;
const items = compiled.querySelectorAll('ion-item');
expect(items.length).toBe(5);
});
it('should display correct client names', () => {
const compiled = fixture.nativeElement as HTMLElement;
const labels = compiled.querySelectorAll('ion-label h2');
const names = Array.from(labels).map(label => label.textContent?.trim());
expect(names).toEqual(['John Doe', 'Jane Smith', 'Bob Johnson', 'Alice Brown', 'Charlie Wilson']);
});
});
  • Verifica que el componente se crea correctamente
  • Verifica que hay 5 productos en la lista
  • Verifica que se muestran los items de productos en la plantilla
  • Verifica los nombres de los productos: Shampoo, Conditioner, Hair Oil, Face Mask, Body Lotion
src/app/features/products/products.page.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { provideRouter } from '@angular/router';
import { ProductsPage } from './products.page';
import {
IonHeader,
IonToolbar,
IonTitle,
IonContent,
IonButtons,
IonBackButton,
IonList,
IonItem,
IonLabel,
IonButton,
} from '@ionic/angular/standalone';
describe('ProductsPage', () => {
let component: ProductsPage;
let fixture: ComponentFixture<ProductsPage>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ProductsPage],
providers: [provideRouter([])],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ProductsPage);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should have 5 products in the list', () => {
expect(component.products.length).toBe(5);
});
it('should display product items in the template', () => {
const compiled = fixture.nativeElement as HTMLElement;
const items = compiled.querySelectorAll('ion-item');
expect(items.length).toBe(5);
});
it('should display correct product names', () => {
const compiled = fixture.nativeElement as HTMLElement;
const labels = compiled.querySelectorAll('ion-label h2');
const names = Array.from(labels).map((label) => label.textContent?.trim());
expect(names).equals([
'Shampoo',
'Conditioner',
'Hair Oil',
'Face Mask',
'Body Lotion',
]);
});
});
  • Verifica que el componente se crea correctamente
  • Verifica que hay 5 reservas en la lista
  • Verifica que se muestran los items de reservas en la plantilla
  • Verifica los nombres de los clientes de las reservas: John Doe, Jane Smith, Bob Johnson, Alice Brown, Charlie Wilson
src/app/features/reservations/reservations.page.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { provideRouter } from '@angular/router';
import { ReservationsPage } from './reservations.page';
describe('ReservationsPage', () => {
let component: ReservationsPage;
let fixture: ComponentFixture<ReservationsPage>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ReservationsPage],
providers: [provideRouter([])]
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ReservationsPage);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should have 5 reservations in the list', () => {
expect(component.reservations.length).toBe(5);
});
it('should display reservation items in the template', () => {
const compiled = fixture.nativeElement as HTMLElement;
const items = compiled.querySelectorAll('ion-item');
expect(items.length).toBe(5);
});
it('should display correct reservation client names', () => {
const compiled = fixture.nativeElement as HTMLElement;
const labels = compiled.querySelectorAll('ion-label h2');
const names = Array.from(labels).map(label => label.textContent?.trim());
expect(names).toEqual(['John Doe', 'Jane Smith', 'Bob Johnson', 'Alice Brown', 'Charlie Wilson']);
});
});
  • Verifica que el componente se crea correctamente
  • Verifica que hay 3 botones de tabs
  • Verifica que tab1 tiene el atributo correcto
  • Verifica que tab2 tiene el atributo correcto
  • Verifica que tab3 tiene el atributo correcto
src/app/features/tabs/tabs.page.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { provideRouter } from '@angular/router';
import { TabsPage } from './tabs.page';
describe('TabsPage', () => {
let component: TabsPage;
let fixture: ComponentFixture<TabsPage>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [TabsPage],
providers: [provideRouter([])],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(TabsPage);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should have 3 tab buttons', () => {
const compiled = fixture.nativeElement as HTMLElement;
const tabButtons = compiled.querySelectorAll('ion-tab-button');
expect(tabButtons.length).toBe(3);
});
it('should have tab1 with correct tab attribute', () => {
const compiled = fixture.nativeElement as HTMLElement;
const tab1Button = compiled.querySelector('ion-tab-button[tab="tab1"]');
expect(tab1Button).toBeTruthy();
});
it('should have tab2 with correct tab attribute', () => {
const compiled = fixture.nativeElement as HTMLElement;
const tab2Button = compiled.querySelector('ion-tab-button[tab="tab2"]');
expect(tab2Button).toBeTruthy();
});
it('should have tab3 with correct tab attribute', () => {
const compiled = fixture.nativeElement as HTMLElement;
const tab3Button = compiled.querySelector('ion-tab-button[tab="tab3"]');
expect(tab3Button).toBeTruthy();
});
});

Los tests con Cypress Component Testing permiten probar componentes de forma aislada, verificando su renderización y comportamiento en el navegador.

  • Verifica que se muestran 5 clientes en la lista
  • Verifica los nombres: John Doe, Jane Smith, Bob Johnson, Alice Brown, Charlie Wilson
cypress/component/clients.cy.ts
import { ClientsPage } from '../../src/app/features/clients/clients.page';
import { provideRouter } from '@angular/router';
describe('ClientsPage Cypress Component Tests', () => {
beforeEach(() => {
cy.mount(ClientsPage, {
providers: [provideRouter([])],
});
});
it('should display 5 client items', () => {
cy.get('ion-item').should('have.length', 5);
});
it('should display correct client names', () => {
cy.get('ion-label h2').eq(0).should('contain.text', 'John Doe');
cy.get('ion-label h2').eq(1).should('contain.text', 'Jane Smith');
cy.get('ion-label h2').eq(2).should('contain.text', 'Bob Johnson');
cy.get('ion-label h2').eq(3).should('contain.text', 'Alice Brown');
cy.get('ion-label h2').eq(4).should('contain.text', 'Charlie Wilson');
});
});
  • Verifica que se muestran 5 productos en la lista
  • Verifica los nombres: Shampoo, Conditioner, Hair Oil, Face Mask, Body Lotion
  • Verifica el botón de logout con texto “Cerrar Sesión”
cypress/component/products.cy.ts
import { ProductsPage } from '../../src/app/features/products/products.page';
import { provideRouter } from '@angular/router';
describe('ProductsPage Cypress Component Tests', () => {
beforeEach(() => {
cy.mount(ProductsPage, {
providers: [provideRouter([])],
});
});
it('should display 5 product items', () => {
cy.get('ion-item').should('have.length', 5);
});
it('should display correct product names', () => {
cy.get('ion-label h2').eq(0).should('contain.text', 'Shampoo');
cy.get('ion-label h2').eq(1).should('contain.text', 'Conditioner');
cy.get('ion-label h2').eq(2).should('contain.text', 'Hair Oil');
cy.get('ion-label h2').eq(3).should('contain.text', 'Face Mask');
cy.get('ion-label h2').eq(4).should('contain.text', 'Body Lotion');
});
it('should display a logout button with text "Cerrar Sesión"', () => {
cy.get('ion-button.logout-btn').should('contain.text', 'Cerrar Sesión');
});
});
  • Verifica que se muestran 5 reservas en la lista
  • Verifica los nombres de clientes: John Doe, Jane Smith, Bob Johnson, Alice Brown, Charlie Wilson
cypress/component/reservations.cy.ts
import { ReservationsPage } from '../../src/app/features/reservations/reservations.page';
import { provideRouter } from '@angular/router';
import { NavController } from '@ionic/angular/standalone';
describe('ReservationsPage Cypress Component Tests', () => {
beforeEach(() => {
cy.mount(ReservationsPage, {
providers: [
provideRouter([]),
{ provide: NavController, useValue: {} },
],
});
});
it('should display 5 reservation items', () => {
cy.get('ion-item').should('have.length', 5);
});
it('should display correct reservation client names', () => {
cy.get('ion-label h2').eq(0).should('contain.text', 'John Doe');
cy.get('ion-label h2').eq(1).should('contain.text', 'Jane Smith');
cy.get('ion-label h2').eq(2).should('contain.text', 'Bob Johnson');
cy.get('ion-label h2').eq(3).should('contain.text', 'Alice Brown');
cy.get('ion-label h2').eq(4).should('contain.text', 'Charlie Wilson');
});
});
  • Verifica el texto de cada tab: “Clientes”, “Reservas”, “Productos”
  • Verifica los iconos: “people”, “calendar”, “cube”
cypress/component/tabs.cy.ts
import { TabsPage } from '../../src/app/features/tabs/tabs.page';
import { provideRouter } from '@angular/router';
describe('TabsPage Cypress Component Tests', () => {
beforeEach(() => {
cy.mount(TabsPage, {
providers: [provideRouter([])],
});
});
it('should display correct text for tab 1 (Clients)', () => {
cy.get('ion-tab-button[tab="tab1"] ion-label').should('contain.text', 'Clients');
});
it('should display correct icon for tab 1 (Clients)', () => {
cy.get('ion-tab-button[tab="tab1"] ion-icon').should('have.attr', 'name', 'people');
});
it('should display correct text for tab 2 (Reservations)', () => {
cy.get('ion-tab-button[tab="tab2"] ion-label').should('contain.text', 'Reservations');
});
it('should display correct icon for tab 2 (Reservations)', () => {
cy.get('ion-tab-button[tab="tab2"] ion-icon').should('have.attr', 'name', 'calendar');
});
it('should display correct text for tab 3 (Products)', () => {
cy.get('ion-tab-button[tab="tab3"] ion-label').should('contain.text', 'Products');
});
it('should display correct icon for tab 3 (Products)', () => {
cy.get('ion-tab-button[tab="tab3"] ion-icon').should('have.attr', 'name', 'cube');
});
});
  • Verifica acceso al detalle de cliente y mostrar ID
  • Verifica botón atrás desde detalle de cliente
  • Verifica acceso a crear reserva
  • Verifica botón de cerrar sesión que redirige a login
cypress/e2e/actividad5.cy.ts
describe('Actividad 5 E2E Tests', () => {
beforeEach(() => {
cy.visit('/tabs/tab1');
});
it('should verify client detail access and client ID display', () => {
cy.url().should('include', '/tabs/tab1');
cy.get('ion-item').first().click();
cy.url().should('include', '/tabs/client/');
cy.get('.detail-container h2').should('contain.text', 'Cliente ID:');
});
it('should verify client back button works when accessed via tabs', () => {
cy.get('ion-item').first().click();
cy.url().should('include', '/tabs/client/');
cy.wait(500);
cy.get('ion-back-button').filter(':visible').first().click({ force: true });
cy.url().should('include', '/tabs/tab1');
});
it('should verify client back button defaultHref when accessed directly', () => {
cy.visit('/tabs/client/1');
cy.get('.detail-container h2').should('contain.text', 'Cliente ID: 1');
cy.get('ion-back-button').click();
cy.url().should('include', '/tabs/tab1');
});
it('should verify new reservation page access and back button works via tabs', () => {
cy.url().should('include', '/tabs/tab1');
cy.get('ion-tab-button[tab="tab2"]').click();
cy.url().should('include', '/tabs/tab2');
cy.get('ion-button.create-btn').click();
cy.url().should('include', '/tabs/reservations/create');
cy.wait(500);
cy.get('ion-back-button').filter(':visible').first().click({ force: true });
cy.url().should('include', '/tabs/tab2');
});
it('should verify new reservation back button defaultHref when accessed directly', () => {
cy.visit('/tabs/reservations/create');
cy.get('ion-back-button').click();
cy.url().should('include', '/tabs/tab2');
});
it('should verify Cerrar Sesión redirects to Login', () => {
cy.get('ion-tab-button[tab="tab3"]').click();
cy.url().should('include', '/tabs/tab3');
cy.get('ion-button.logout-btn').click();
cy.url().should('include', '/login');
});
});
  1. Instalar dependencias

    Terminal window
    npm install
  2. Ejecutar pruebas unitarias con Jasmine/Karma

    Terminal window
    npm test
  3. Ejecutar Cypress para pruebas de componentes

    Terminal window
    npx cypress open

    Seleccionar “Component Testing” y elegir el navegador.

  4. Ejecutar Cypress para pruebas E2E

    Terminal window
    npx cypress open

    Seleccionar “E2E Testing” y elegir el navegador.

  5. La aplicación se abrirá en http://localhost:8100 para pruebas E2E.