bump
This commit is contained in:
135
apps/frontend/src/app/shared/ui/ui-components.spec.ts
Normal file
135
apps/frontend/src/app/shared/ui/ui-components.spec.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
import { Component, ViewChild } from '@angular/core';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import {
|
||||
UiButtonComponent,
|
||||
UiConfirmDialogComponent,
|
||||
UiEmptyStateComponent,
|
||||
UiFormFieldComponent,
|
||||
UiIconButtonComponent,
|
||||
UiPaginationComponent,
|
||||
UiStatusBadgeComponent,
|
||||
UiToastHostComponent,
|
||||
ToastService,
|
||||
} from './index';
|
||||
import { isDesignSystemRouteEnabled } from '../../core/dev-only.guard';
|
||||
import { devRoutes } from '../../core/dev-routes.prod';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
imports: [
|
||||
UiButtonComponent,
|
||||
UiConfirmDialogComponent,
|
||||
UiEmptyStateComponent,
|
||||
UiFormFieldComponent,
|
||||
UiIconButtonComponent,
|
||||
UiPaginationComponent,
|
||||
UiStatusBadgeComponent,
|
||||
UiToastHostComponent,
|
||||
],
|
||||
template: `
|
||||
<button id="trigger" type="button">Trigger</button>
|
||||
<ui-button label="Speichern" [loading]="true" />
|
||||
<ui-icon-button icon="delete" label="Eintrag loeschen" />
|
||||
<ui-form-field label="Name" error="Name ist erforderlich">
|
||||
<input class="ui-control" aria-invalid="true" />
|
||||
</ui-form-field>
|
||||
<ui-status-badge label="Deaktiviert" tone="danger" />
|
||||
<ui-empty-state title="Keine Daten" actionLabel="Neu" (action)="emptyActionCount += 1" />
|
||||
<ui-pagination [page]="2" [pageSize]="10" [total]="35" (pageChange)="page = $event" />
|
||||
<ui-confirm-dialog />
|
||||
<ui-toast-host />
|
||||
`,
|
||||
})
|
||||
class UiTestHostComponent {
|
||||
@ViewChild(UiConfirmDialogComponent) dialog?: UiConfirmDialogComponent;
|
||||
page = 2;
|
||||
emptyActionCount = 0;
|
||||
}
|
||||
|
||||
describe('shared UI components', () => {
|
||||
it('renders button loading and disabled state', async () => {
|
||||
await TestBed.configureTestingModule({ imports: [UiTestHostComponent] }).compileComponents();
|
||||
const fixture = TestBed.createComponent(UiTestHostComponent);
|
||||
fixture.detectChanges();
|
||||
|
||||
const button = (fixture.nativeElement as HTMLElement).querySelector('ui-button button');
|
||||
expect(button?.hasAttribute('disabled')).toBe(true);
|
||||
expect(button?.getAttribute('aria-busy')).toBe('true');
|
||||
});
|
||||
|
||||
it('requires accessible labels for icon buttons', async () => {
|
||||
await TestBed.configureTestingModule({ imports: [UiTestHostComponent] }).compileComponents();
|
||||
const fixture = TestBed.createComponent(UiTestHostComponent);
|
||||
fixture.detectChanges();
|
||||
|
||||
const button = (fixture.nativeElement as HTMLElement).querySelector('ui-icon-button button');
|
||||
expect(button?.getAttribute('aria-label')).toBe('Eintrag loeschen');
|
||||
});
|
||||
|
||||
it('shows form field errors and status text', async () => {
|
||||
await TestBed.configureTestingModule({ imports: [UiTestHostComponent] }).compileComponents();
|
||||
const fixture = TestBed.createComponent(UiTestHostComponent);
|
||||
fixture.detectChanges();
|
||||
const element = fixture.nativeElement as HTMLElement;
|
||||
|
||||
expect(element.textContent).toContain('Name ist erforderlich');
|
||||
expect(element.textContent).toContain('Deaktiviert');
|
||||
});
|
||||
|
||||
it('opens and closes confirm dialog and restores focus', async () => {
|
||||
await TestBed.configureTestingModule({ imports: [UiTestHostComponent] }).compileComponents();
|
||||
const fixture = TestBed.createComponent(UiTestHostComponent);
|
||||
fixture.detectChanges();
|
||||
const trigger = (fixture.nativeElement as HTMLElement).querySelector<HTMLButtonElement>(
|
||||
'#trigger',
|
||||
);
|
||||
trigger?.focus();
|
||||
|
||||
const promise = fixture.componentInstance.dialog?.open({
|
||||
title: 'Loeschen',
|
||||
description: 'Wirklich loeschen?',
|
||||
confirmLabel: 'Loeschen',
|
||||
danger: true,
|
||||
});
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect((fixture.nativeElement as HTMLElement).querySelector('[role="dialog"]')).not.toBeNull();
|
||||
fixture.componentInstance.dialog?.close(true);
|
||||
fixture.detectChanges();
|
||||
|
||||
await expect(promise).resolves.toBe(true);
|
||||
expect(document.activeElement).toBe(trigger);
|
||||
});
|
||||
|
||||
it('shows and closes toasts', async () => {
|
||||
await TestBed.configureTestingModule({ imports: [UiTestHostComponent] }).compileComponents();
|
||||
const fixture = TestBed.createComponent(UiTestHostComponent);
|
||||
const service = TestBed.inject(ToastService);
|
||||
const id = service.show({ tone: 'success', title: 'Gespeichert' });
|
||||
fixture.detectChanges();
|
||||
|
||||
expect((fixture.nativeElement as HTMLElement).textContent).toContain('Gespeichert');
|
||||
service.close(id);
|
||||
fixture.detectChanges();
|
||||
expect((fixture.nativeElement as HTMLElement).textContent).not.toContain('Gespeichert');
|
||||
});
|
||||
|
||||
it('emits empty state and pagination actions', async () => {
|
||||
await TestBed.configureTestingModule({ imports: [UiTestHostComponent] }).compileComponents();
|
||||
const fixture = TestBed.createComponent(UiTestHostComponent);
|
||||
fixture.detectChanges();
|
||||
const element = fixture.nativeElement as HTMLElement;
|
||||
|
||||
element.querySelector<HTMLButtonElement>('ui-empty-state button')?.click();
|
||||
element.querySelectorAll<HTMLButtonElement>('ui-pagination button')[0]?.click();
|
||||
|
||||
expect(fixture.componentInstance.emptyActionCount).toBe(1);
|
||||
expect(fixture.componentInstance.page).toBe(1);
|
||||
});
|
||||
|
||||
it('keeps the design system route disabled outside development mode', () => {
|
||||
expect(isDesignSystemRouteEnabled(false)).toBe(false);
|
||||
expect(devRoutes).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user