From b0dba2325db8861ff1faced0a2f8a29f25801051 Mon Sep 17 00:00:00 2001 From: Lorenz Hilpert Date: Fri, 28 Mar 2025 14:20:22 +0100 Subject: [PATCH] feat: add unit tests for ButtonComponent using Spectator and Jest --- .github/copilot-instructions.md | 7 ++ .../buttons/src/lib/button.component.spec.ts | 71 +++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 libs/ui/buttons/src/lib/button.component.spec.ts diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 1e1a056a7..0f04eb747 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -14,10 +14,13 @@ You are a mentor with a dual approach: when I make a mistake or my work needs im - Angular (v19+) - TypeScript (v5.x) - Nx.dev (v20+) + - Spectator (v19+) - A Powerful Tool to Simplify Your Angular Tests + - NgRx (v19+) - State Management - You can assist me with writing, debugging, and explaining code using my tech stack: TypeScript, Nx.dev, Bun, Git, GitHub, Angular, Hono, Drizzle, date-fns, MongoDB, SQLite, and NgRx. - You can preview my code or project descriptions and provide feedback on functionality, structure, and readability within this stack. - You can suggest specific improvements, such as better TypeScript type safety, cleaner Angular Signals usage, optimized Nx workspace setups, or efficient Drizzle queries. - If needed, you can search the web or coding resources (e.g., GitHub docs, Angular guides) to provide examples or best practices relevant to my work. +- When generating or reviewing code, include references to imported files to provide a deeper understanding of the context. ## Behavioral Guidelines @@ -50,6 +53,8 @@ You are a mentor with a dual approach: when I make a mistake or my work needs im ## Testing Requirements +- Testing Framework Jest +- Spectator should be used for Unit tests - Unit tests should be included for all components and services - Use the Angular TestBed configuration - Include error case testing @@ -185,3 +190,5 @@ describe('CounterComponent', () => { - [Nx Documentation](https://nx.dev/getting-started/intro) - [TypeScript Handbook](https://www.typescriptlang.org/docs/handbook/intro.html) - [Angular Signals Guide](https://angular.io/guide/signals) +- [Spectator - Documentation](https://ngneat.github.io/spectator/docs/installation) +- [NgRx Documentation](https://ngrx.io/docs) diff --git a/libs/ui/buttons/src/lib/button.component.spec.ts b/libs/ui/buttons/src/lib/button.component.spec.ts new file mode 100644 index 000000000..cc193b97f --- /dev/null +++ b/libs/ui/buttons/src/lib/button.component.spec.ts @@ -0,0 +1,71 @@ +import { createComponentFactory, Spectator } from '@ngneat/spectator/jest'; +import { ButtonComponent } from './button.component'; +import { NgIconComponent } from '@ng-icons/core'; +import { ButtonColor, ButtonSize } from './types'; + +describe('ButtonComponent', () => { + let spectator: Spectator; + const createComponent = createComponentFactory({ + component: ButtonComponent, + imports: [NgIconComponent], + }); + + beforeEach(() => { + spectator = createComponent(); + }); + + it('should create', () => { + expect(spectator.component).toBeTruthy(); + }); + + it('should set default input values', () => { + expect(spectator.component.size()).toBe('medium'); + expect(spectator.component.color()).toBe('primary'); + expect(spectator.component.pending()).toBe(false); + expect(spectator.component.tabIndex()).toBe(0); + }); + + it('should apply correct size classes', () => { + const sizes: ButtonSize[] = ['small', 'medium', 'large']; + + sizes.forEach((size) => { + spectator.setInput('size', size); + expect(spectator.element).toHaveClass(`ui-button__${size}`); + }); + }); + + it('should apply correct color classes', () => { + const colors: ButtonColor[] = ['primary', 'secondary', 'tertiary']; + + colors.forEach((color) => { + spectator.setInput('color', color); + expect(spectator.element).toHaveClass(`ui-button__${color}`); + }); + }); + + it('should update tabIndex in DOM', () => { + spectator.setInput('tabIndex', -1); + expect(spectator.element.tabIndex).toBe(-1); + }); + + it('should show loading icon when pending', () => { + spectator.setInput('pending', true); + const loadingIcon = spectator.query('ng-icon[name="isaLoading"]'); + expect(loadingIcon).toExist(); + }); + + it('should have base button class', () => { + expect(spectator.element).toHaveClass('ui-button'); + }); + + it('should combine all classes correctly', () => { + spectator.setInput({ + size: 'large', + color: 'secondary', + }); + + expect(spectator.element).toHaveClass('ui-button'); + expect(spectator.element).toHaveClass('ui-button__large'); + expect(spectator.element).toHaveClass('ui-button__secondary'); + }); +});