import { Component, signal } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ShippingModeService } from '@africanies/africanies-core'; import type { ShippingMode } from '@africanies/africanies-models'; import { ButtonComponent, type ButtonSize, type ButtonVariant, } from './button.component'; @Component({ standalone: true, imports: [ButtonComponent], template: ` `, }) class ButtonHostComponent { readonly variant = signal('primary'); readonly size = signal('md'); readonly disabled = signal(false); readonly loading = signal(false); } describe('ButtonComponent', () => { let fixture: ComponentFixture; let host: ButtonHostComponent; let button: HTMLButtonElement; let mode: ReturnType>; beforeEach(async () => { mode = signal('sfn'); await TestBed.configureTestingModule({ imports: [ButtonHostComponent], providers: [ { provide: ShippingModeService, useValue: { mode: mode.asReadonly(), setMode: (next: ShippingMode) => mode.set(next), }, }, ], }).compileComponents(); fixture = TestBed.createComponent(ButtonHostComponent); host = fixture.componentInstance; fixture.detectChanges(); button = fixture.nativeElement.querySelector('button[africanies-button]'); }); it('should render projected content', () => { expect(button.textContent?.trim()).toBe('Label'); }); it('should apply primary variant classes by default (SFN / export)', () => { const tokens = button.className.split(/\s+/); expect(tokens).toContain('bg-export'); expect(tokens).toContain('text-white'); expect(tokens).not.toContain('bg-export-strong'); }); it('should switch primary to import orange when mode is STN', () => { mode.set('stn'); fixture.detectChanges(); const tokens = button.className.split(/\s+/); expect(tokens).toContain('bg-import-strong'); expect(tokens).not.toContain('bg-export'); }); it('should switch ghost-primary text accent with shipping mode', () => { host.variant.set('ghost-primary'); fixture.detectChanges(); let tokens = button.className.split(/\s+/); expect(tokens).toContain('text-export'); expect(tokens).toContain('bg-transparent'); mode.set('stn'); fixture.detectChanges(); tokens = button.className.split(/\s+/); expect(tokens).toContain('text-import-strong'); expect(tokens).not.toContain('text-export'); }); it('should switch variant and size classes', () => { host.variant.set('danger'); host.size.set('sm'); fixture.detectChanges(); expect(button.className).toContain('bg-danger-dark'); expect(button.className).toContain('h-8'); }); it('should expose disabled and aria-disabled for a11y', () => { host.disabled.set(true); fixture.detectChanges(); expect(button.disabled).toBe(true); expect(button.getAttribute('aria-disabled')).toBe('true'); expect(button.getAttribute('tabindex')).toBe('-1'); }); it('should keep a native button type for keyboard activation', () => { expect(button.tagName).toBe('BUTTON'); expect(button.getAttribute('type')).toBe('button'); }); it('should show a circular spinner and treat the host as busy while loading', () => { host.loading.set(true); fixture.detectChanges(); expect(button.getAttribute('aria-busy')).toBe('true'); expect(button.disabled).toBe(true); expect(button.querySelector('.animate-spin')).not.toBeNull(); expect(button.textContent?.trim()).toBe('Label'); }); });