Add input controls and checkbox component

Introduced a new input controls library with a checkbox component.

-  **Feature**: Added input controls library with checkbox component
- 🎨 **Style**: Updated checkbox component styles and structure
- 🧪 **Test**: Added unit tests for checkbox and empty state components
- 🛠️ **Refactor**: Improved checkbox component code and removed unused styles
- 📚 **Docs**: Updated commit message guidelines in VSCode settings
This commit is contained in:
Lorenz Hilpert
2025-03-31 12:29:22 +02:00
parent 3c110efdfa
commit d38fed297d
11 changed files with 282 additions and 25 deletions

View File

@@ -2,13 +2,47 @@
## Unit Testing Requirements
- Test files should end with `.spec.ts`.
- Use Spectator for Component, Directive and Service tests.
- Use Jest as the test runner.
- Follow the Arrange-Act-Assert (AAA) pattern in tests.
- Mock external dependencies to isolate the unit under test.
- Test files should end with `.spec.ts`
- Use Spectator for Component, Directive and Service tests
- Use Jest as the test runner
- Follow the Arrange-Act-Assert (AAA) pattern in tests
- Mock external dependencies to isolate the unit under test
- Mock child components to ensure true unit testing isolation
## Example Test Structure
## Best Practices
### Component Testing
- Use `createComponentFactory` for standalone components
- Use `createHostFactory` when testing components with templates
- Mock child components using `ng-mocks`
- Test component inputs, outputs, and lifecycle hooks
- Verify DOM rendering and component behavior separately
### Mocking Child Components
Always mock child components to:
- Isolate the component under test
- Prevent unintended side effects
- Reduce test complexity
- Improve test performance
```typescript
import { MockComponent } from 'ng-mocks';
import { ChildComponent } from './child.component';
describe('ParentComponent', () => {
const createComponent = createComponentFactory({
component: ParentComponent,
declarations: [MockComponent(ChildComponent)],
});
});
```
## Example Test Structures
### Basic Component Test
```typescript
import { createComponentFactory, Spectator } from '@ngneat/spectator/jest';
@@ -27,9 +61,135 @@ describe('MyComponent', () => {
});
it('should handle action correctly', () => {
// Arrange
spectator.setInput('inputProp', 'testValue');
// Act
spectator.click('button');
// Assert
expect(spectator.component.outputProp).toBe('expectedValue');
});
});
```
### Host Component Test with Child Components
```typescript
import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest';
import { ParentComponent } from './parent.component';
import { ChildComponent } from './child.component';
import { MockComponent } from 'ng-mocks';
describe('ParentComponent', () => {
let spectator: SpectatorHost<ParentComponent>;
const createHost = createHostFactory({
component: ParentComponent,
declarations: [MockComponent(ChildComponent)],
template: `
<app-parent
[input]="inputValue"
(output)="handleOutput($event)">
</app-parent>`,
});
beforeEach(() => {
spectator = createHost(undefined, {
hostProps: {
inputValue: 'test',
handleOutput: jest.fn(),
},
});
});
it('should pass input to child component', () => {
// Arrange
const childComponent = spectator.query(ChildComponent);
// Assert
expect(childComponent.input).toBe('test');
});
});
```
### Testing Events and Outputs
```typescript
it('should emit when button is clicked', () => {
// Arrange
const outputSpy = jest.fn();
spectator.component.outputEvent.subscribe(outputSpy);
// Act
spectator.click('button');
// Assert
expect(outputSpy).toHaveBeenCalledWith(expectedValue);
});
```
## Common Patterns
### Query Elements
```typescript
// By CSS selector
const element = spectator.query('.class-name');
// By directive/component
const child = spectator.query(ChildComponent);
// Multiple elements
const elements = spectator.queryAll('.item');
```
### Trigger Events
```typescript
// Click events
spectator.click('.button');
spectator.click(buttonElement);
// Input events
spectator.typeInElement('value', 'input');
// Custom events
spectator.triggerEventHandler(MyComponent, 'eventName', eventValue);
```
### Test Async Operations
```typescript
it('should handle async operations', async () => {
// Arrange
const response = { data: 'test' };
service.getData.mockResolvedValue(response);
// Act
await spectator.component.loadData();
// Assert
expect(spectator.component.data).toEqual(response);
});
```
## Tips and Tricks
1. **Debugging Tests**
- Use `spectator.debug()` to log the current DOM state
- Use `console.log` sparingly and remove before committing
- Set breakpoints in your IDE for step-by-step debugging
2. **Common Pitfalls**
- Don't test implementation details
- Avoid testing third-party libraries
- Don't test multiple concerns in a single test
- Remember to clean up subscriptions
3. **Performance**
- Mock heavy dependencies
- Keep test setup minimal
- Use `beforeAll` for expensive operations shared across tests