test(modal): cover image viewer behavior

This commit is contained in:
ncoronel 2026-09-02 14:13:45 -03:00
parent f3d446d012
commit 0910d90363
2 changed files with 137 additions and 0 deletions

View File

@ -7,6 +7,7 @@ import { firstValueFrom } from 'rxjs';
import { ConfirmDeleteModalComponent } from '../../shared/components/confirm-delete-modal/confirm-delete-modal.component';
import { ConfirmModalComponent } from '../../shared/components/confirm-modal/confirm-modal.component';
import { ImageModalComponent } from '../../shared/components/image-modal/image-modal.component';
import { QrModalComponent } from '../../shared/components/qr-modal/qr-modal.component';
import { SimpleModalComponent } from '../../shared/components/simple-modal/simple-modal.component';
import { MODAL_DATA, ModalRef, ModalService } from './modal.service';
@ -258,6 +259,36 @@ describe('ModalService', () => {
showCloseButton: true,
});
});
it('opens the image viewer fullscreen with normalized zoom limits', () => {
service.openImage({
title: 'Producto',
src: '/images/producto.webp',
alt: 'Producto visto de frente',
initialZoom: 8,
minZoom: 0,
maxZoom: 3,
});
const activeModal = service.activeModal();
expect(activeModal?.component).toBe(ImageModalComponent);
expect(activeModal?.config).toEqual({
title: 'Producto',
size: 'full',
presentation: 'fullscreen-media',
data: {
src: '/images/producto.webp',
alt: 'Producto visto de frente',
initialZoom: 3,
minZoom: 0.1,
maxZoom: 3,
},
closeOnBackdrop: true,
closeOnEscape: true,
showCloseButton: true,
});
});
});
@Component({

View File

@ -0,0 +1,106 @@
import '@angular/compiler';
import { ComponentFixture, TestBed, getTestBed } from '@angular/core/testing';
import { BrowserTestingModule, platformBrowserTesting } from '@angular/platform-browser/testing';
import { afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest';
import { ImageModalData, MODAL_DATA } from '../../../core/services/modal.service';
import { ImageModalComponent } from './image-modal.component';
describe('ImageModalComponent', () => {
let fixture: ComponentFixture<ImageModalComponent>;
const data: ImageModalData = {
src: '/images/producto.webp',
alt: 'Vista frontal del producto',
initialZoom: 1,
minZoom: 1,
maxZoom: 2,
};
beforeAll(() => {
try {
getTestBed().initTestEnvironment(BrowserTestingModule, platformBrowserTesting());
} catch {
// Test environment may already be initialized by another setup entrypoint.
}
});
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ImageModalComponent],
providers: [{ provide: MODAL_DATA, useValue: data }],
}).compileComponents();
fixture = TestBed.createComponent(ImageModalComponent);
fixture.detectChanges();
});
afterEach(() => {
fixture.destroy();
TestBed.resetTestingModule();
});
it('renders the image and accessible zoom controls', () => {
const element = fixture.nativeElement as HTMLElement;
const image = element.querySelector('img') as HTMLImageElement;
expect(image.getAttribute('src')).toBe('/images/producto.webp');
expect(image.alt).toBe('Vista frontal del producto');
expect(element.querySelector('[aria-label="Acercar"]')).not.toBeNull();
expect(element.querySelector('[aria-label="Alejar"]')).not.toBeNull();
});
it('zooms with controls, respects limits, and resets', () => {
const element = fixture.nativeElement as HTMLElement;
const zoomIn = element.querySelector('[aria-label="Acercar"]') as HTMLButtonElement;
const zoomOut = element.querySelector('[aria-label="Alejar"]') as HTMLButtonElement;
const reset = element.querySelector('[aria-label="Restablecer zoom"]') as HTMLButtonElement;
zoomIn.click();
fixture.detectChanges();
expect(reset.textContent).toContain('150%');
expect(zoomOut.disabled).toBe(false);
zoomIn.click();
fixture.detectChanges();
expect(reset.textContent).toContain('200%');
expect(zoomIn.disabled).toBe(true);
reset.click();
fixture.detectChanges();
expect(reset.textContent).toContain('100%');
expect(zoomOut.disabled).toBe(true);
});
it('supports pinch zoom through touch pointer events', () => {
const viewport = fixture.nativeElement.querySelector('.image-modal__viewport') as HTMLElement;
const zoom = fixture.nativeElement.querySelector(
'[aria-label="Restablecer zoom"]',
) as HTMLButtonElement;
viewport.dispatchEvent(pointerEvent('pointerdown', 1, 100, 100));
viewport.dispatchEvent(pointerEvent('pointerdown', 2, 200, 100));
viewport.dispatchEvent(pointerEvent('pointermove', 2, 250, 100));
fixture.detectChanges();
expect(zoom.textContent).toContain('150%');
});
it('shows a fallback when the image cannot be loaded', () => {
const image = fixture.nativeElement.querySelector('img') as HTMLImageElement;
image.dispatchEvent(new Event('error'));
fixture.detectChanges();
expect(fixture.nativeElement.querySelector('[role="alert"]')?.textContent).toContain(
'No se pudo cargar la imagen',
);
});
});
function pointerEvent(type: string, pointerId: number, clientX: number, clientY: number): Event {
const event = new MouseEvent(type, { bubbles: true, clientX, clientY });
Object.defineProperties(event, {
pointerId: { value: pointerId },
pointerType: { value: 'touch' },
});
return event;
}