Files
shopit-front/src/app/shared/components/modal-host/modal-host.component.spec.ts

184 lines
5.7 KiB
TypeScript

import '@angular/compiler';
import { Component, inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { TestBed, getTestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { BrowserTestingModule, platformBrowserTesting } from '@angular/platform-browser/testing';
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
import { MODAL_DATA, ModalRef, ModalService } from '../../../core/services/modal.service';
import { ModalHostComponent } from './modal-host.component';
@Component({
standalone: true,
template: `
<div class="modal-test-content">
<span class="modal-test-title">{{ data?.title }}</span>
<button type="button" class="modal-test-close" (click)="close()">Cerrar</button>
</div>
`,
})
class ModalContentTestComponent {
readonly data = inject<{ title: string } | null>(MODAL_DATA);
readonly modalRef = inject<ModalRef<string>>(ModalRef);
close(): void {
this.modalRef.close('accepted');
}
}
describe('ModalHostComponent', () => {
let service: ModalService;
let doc: Document;
beforeAll(() => {
try {
getTestBed().initTestEnvironment(BrowserTestingModule, platformBrowserTesting());
} catch {
// Test environment may already be initialized by another setup entrypoint.
}
});
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ModalHostComponent],
}).compileComponents();
service = TestBed.inject(ModalService);
doc = TestBed.inject(DOCUMENT);
});
afterEach(() => {
doc.body.style.overflow = '';
doc.body.style.paddingRight = '';
TestBed.resetTestingModule();
});
it('renders nothing when no modal is active', () => {
const fixture = TestBed.createComponent(ModalHostComponent);
fixture.detectChanges();
expect(fixture.nativeElement.textContent?.trim()).toBe('');
expect(doc.body.style.overflow).toBe('');
});
it('opens and renders the requested component with its title and data', () => {
const fixture = TestBed.createComponent(ModalHostComponent);
service.open(ModalContentTestComponent, {
title: 'Editar producto',
data: { title: 'Contenido del modal' },
});
fixture.detectChanges();
const title = fixture.nativeElement.querySelector('.modal-shell__title');
const content = fixture.nativeElement.querySelector('.modal-test-title');
expect(title?.textContent).toContain('Editar producto');
expect(content?.textContent).toContain('Contenido del modal');
expect(doc.body.style.overflow).toBe('hidden');
});
it('closes with a result from the child component', () => {
const fixture = TestBed.createComponent(ModalHostComponent);
const ref = service.open(ModalContentTestComponent, {
data: { title: 'Cerrar' },
});
const closedSpy = vi.fn();
ref.afterClosed$.subscribe(closedSpy);
fixture.detectChanges();
const closeButton = fixture.nativeElement.querySelector(
'.modal-test-close',
) as HTMLButtonElement;
closeButton.click();
fixture.detectChanges();
expect(closedSpy).toHaveBeenCalledWith('accepted');
expect(service.activeModal()).toBeNull();
expect(doc.body.style.overflow).toBe('');
expect(doc.body.style.paddingRight).toBe('');
});
it('closes on backdrop click when enabled', () => {
const fixture = TestBed.createComponent(ModalHostComponent);
const ref = service.open(ModalContentTestComponent, {
data: { title: 'Backdrop' },
closeOnBackdrop: true,
});
fixture.detectChanges();
const backdrop = fixture.nativeElement.querySelector('.modal-shell') as HTMLDivElement;
backdrop.click();
fixture.detectChanges();
expect(service.activeModal()).toBeNull();
expect(ref.dismissReason()).toBe('backdrop');
});
it('does not close on backdrop click when disabled', () => {
const fixture = TestBed.createComponent(ModalHostComponent);
const ref = service.open(ModalContentTestComponent, {
data: { title: 'Persistente' },
closeOnBackdrop: false,
});
fixture.detectChanges();
const backdrop = fixture.nativeElement.querySelector('.modal-shell') as HTMLDivElement;
backdrop.click();
fixture.detectChanges();
expect(service.activeModal()?.ref).toBe(ref);
});
it('closes on Escape when enabled', () => {
const fixture = TestBed.createComponent(ModalHostComponent);
const ref = service.open(ModalContentTestComponent, {
data: { title: 'Escape' },
closeOnEscape: true,
});
fixture.detectChanges();
doc.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
fixture.detectChanges();
expect(service.activeModal()).toBeNull();
expect(ref.dismissReason()).toBe('escape');
});
it('keeps the modal open on Escape when disabled', () => {
const fixture = TestBed.createComponent(ModalHostComponent);
const ref = service.open(ModalContentTestComponent, {
data: { title: 'No Escape' },
closeOnEscape: false,
});
fixture.detectChanges();
doc.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
fixture.detectChanges();
expect(service.activeModal()?.ref).toBe(ref);
});
it('closes from the shell close button with a programmatic dismiss reason', () => {
const fixture = TestBed.createComponent(ModalHostComponent);
const ref = service.open(ModalContentTestComponent, {
title: 'Con cierre',
data: { title: 'Boton' },
});
fixture.detectChanges();
const closeButton = fixture.debugElement.query(By.css('.btn-close'))
.nativeElement as HTMLButtonElement;
closeButton.click();
fixture.detectChanges();
expect(service.activeModal()).toBeNull();
expect(ref.dismissReason()).toBe('programmatic');
});
});