136 lines
5.1 KiB
TypeScript
136 lines
5.1 KiB
TypeScript
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);
|
|
});
|
|
});
|