Skip to content

Commit 78e1603

Browse files
committed
feat: refactor NgxSpinnerComponent to use input() for properties and simplify initialization
1 parent 1554343 commit 78e1603

File tree

3 files changed

+234
-216
lines changed

3 files changed

+234
-216
lines changed

angular.json

Lines changed: 0 additions & 133 deletions
This file was deleted.
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import { ChangeDetectorRef } from '@angular/core';
2+
import { ComponentFixture, TestBed } from '@angular/core/testing';
3+
import { provideAnimations } from '@angular/platform-browser/animations';
4+
import { BehaviorSubject } from 'rxjs';
5+
import { NgxSpinnerComponent } from './ngx-spinner.component';
6+
import { DEFAULTS, NgxSpinner, PRIMARY_SPINNER } from './ngx-spinner.enum';
7+
import { NgxSpinnerService } from './ngx-spinner.service';
8+
9+
describe('NgxSpinnerComponent', () => {
10+
let component: NgxSpinnerComponent;
11+
let fixture: ComponentFixture<NgxSpinnerComponent>;
12+
let spinnerService: jasmine.SpyObj<NgxSpinnerService>;
13+
let changeDetectorRef: jasmine.SpyObj<ChangeDetectorRef>;
14+
15+
const mockSpinnerSubject = new BehaviorSubject<NgxSpinner>(new NgxSpinner());
16+
17+
// Helper function to create a keyboard event with spies
18+
const createKeyboardEvent = (type: string = 'keydown'): KeyboardEvent => {
19+
const event = new KeyboardEvent(type);
20+
spyOn(event, 'preventDefault');
21+
Object.defineProperty(event, 'returnValue', {
22+
set: jasmine.createSpy('set returnValue'),
23+
get: jasmine.createSpy('get returnValue').and.returnValue(false),
24+
});
25+
return event;
26+
};
27+
28+
beforeEach(async () => {
29+
const spySpinnerService = jasmine.createSpyObj('NgxSpinnerService', ['getSpinner', 'show', 'hide']);
30+
const spyChangeDetectorRef = jasmine.createSpyObj('ChangeDetectorRef', ['detectChanges']);
31+
32+
spySpinnerService.getSpinner.and.returnValue(mockSpinnerSubject.asObservable());
33+
34+
await TestBed.configureTestingModule({
35+
imports: [NgxSpinnerComponent],
36+
providers: [
37+
{ provide: NgxSpinnerService, useValue: spySpinnerService },
38+
{ provide: ChangeDetectorRef, useValue: spyChangeDetectorRef },
39+
provideAnimations(),
40+
],
41+
}).compileComponents();
42+
43+
spinnerService = TestBed.inject(NgxSpinnerService) as jasmine.SpyObj<NgxSpinnerService>;
44+
changeDetectorRef = TestBed.inject(ChangeDetectorRef) as jasmine.SpyObj<ChangeDetectorRef>;
45+
});
46+
47+
beforeEach(() => {
48+
fixture = TestBed.createComponent(NgxSpinnerComponent);
49+
component = fixture.componentInstance;
50+
fixture.detectChanges();
51+
});
52+
53+
it('should create', () => {
54+
expect(component).toBeTruthy();
55+
});
56+
57+
it('should initialize with default values', () => {
58+
expect(component.bdColor()).toBe(DEFAULTS.BD_COLOR);
59+
expect(component.size()).toBe('large');
60+
expect(component.color()).toBe(DEFAULTS.SPINNER_COLOR);
61+
expect(component.type()).toBe(DEFAULTS.SPINNER_TYPE);
62+
expect(component.fullScreen()).toBe(true);
63+
expect(component.name()).toBe(PRIMARY_SPINNER);
64+
expect(component.zIndex()).toBe(DEFAULTS.Z_INDEX);
65+
expect(component.template()).toBeUndefined();
66+
expect(component.showSpinner()).toBe(false);
67+
expect(component.disableAnimation()).toBe(false);
68+
});
69+
70+
it('should update spinner when service emits new value', () => {
71+
const newSpinner = new NgxSpinner({
72+
name: 'test-spinner',
73+
bdColor: 'rgba(0,0,0,0.8)',
74+
size: 'medium',
75+
color: '#ffffff',
76+
type: 'ball-spin',
77+
fullScreen: false,
78+
show: true,
79+
});
80+
81+
mockSpinnerSubject.next(newSpinner);
82+
83+
expect(component.spinner.name).toBe('test-spinner');
84+
expect(component.spinner.bdColor).toBe('rgba(0,0,0,0.8)');
85+
expect(component.spinner.size).toBe('medium');
86+
expect(component.spinner.color).toBe('#ffffff');
87+
expect(component.spinner.type).toBe('ball-spin');
88+
expect(component.spinner.fullScreen).toBe(false);
89+
expect(component.spinner.show).toBe(true);
90+
});
91+
92+
describe('Keyboard Event Handling', () => {
93+
it('should handle keydown event when spinner is visible', () => {
94+
const event = createKeyboardEvent();
95+
component.spinnerDOM = { nativeElement: document.createElement('div') };
96+
97+
component.handleKeyboardEvent(event);
98+
99+
expect(event.preventDefault).toHaveBeenCalled();
100+
expect(event.returnValue).toBe(false);
101+
});
102+
103+
it('should handle keyup event when spinner is visible', () => {
104+
const event = createKeyboardEvent('keyup');
105+
component.spinnerDOM = { nativeElement: document.createElement('div') };
106+
107+
component.handleKeyboardEvent(event);
108+
109+
expect(event.preventDefault).toHaveBeenCalled();
110+
expect(event.returnValue).toBe(false);
111+
});
112+
113+
it('should not handle keyboard events when spinner is not visible', () => {
114+
const event = createKeyboardEvent();
115+
component.spinnerDOM = null;
116+
117+
component.handleKeyboardEvent(event);
118+
119+
expect(event.preventDefault).not.toHaveBeenCalled();
120+
});
121+
122+
it('should not handle keyboard events when spinner DOM is not initialized', () => {
123+
const event = createKeyboardEvent();
124+
component.spinnerDOM = undefined;
125+
126+
component.handleKeyboardEvent(event);
127+
128+
expect(event.preventDefault).not.toHaveBeenCalled();
129+
});
130+
});
131+
132+
describe('Spinner Class Generation', () => {
133+
it('should generate correct class name for large spinner', () => {
134+
const type = 'ball-spin';
135+
const size = 'large';
136+
const className = component.getClass(type, size);
137+
expect(className).toBe('la-ball-spin la-3x');
138+
});
139+
140+
it('should generate correct class name for medium spinner', () => {
141+
const type = 'ball-spin';
142+
const size = 'medium';
143+
const className = component.getClass(type, size);
144+
expect(className).toBe('la-ball-spin la-2x');
145+
});
146+
147+
it('should generate correct class name for small spinner', () => {
148+
const type = 'ball-spin';
149+
const size = 'small';
150+
const className = component.getClass(type, size);
151+
expect(className).toBe('la-ball-spin la-sm');
152+
});
153+
154+
it('should update spinner class on input change', () => {
155+
component.spinner.type = 'ball-spin';
156+
component.spinner.size = 'large';
157+
component.onInputChange();
158+
expect(component.spinner.class).toBe('la-ball-spin la-3x');
159+
});
160+
161+
it('should use default values when type or size is undefined', () => {
162+
component.spinner.type = undefined;
163+
component.spinner.size = undefined;
164+
component.onInputChange();
165+
expect(component.spinner.class).toBe(`la-${DEFAULTS.SPINNER_TYPE} `);
166+
});
167+
});
168+
169+
describe('Component Lifecycle', () => {
170+
it('should clean up subscription on destroy', () => {
171+
spyOn(component.ngUnsubscribe, 'next');
172+
spyOn(component.ngUnsubscribe, 'complete');
173+
174+
component.ngOnDestroy();
175+
176+
expect(component.ngUnsubscribe.next).toHaveBeenCalled();
177+
expect(component.ngUnsubscribe.complete).toHaveBeenCalled();
178+
});
179+
180+
it('should set default options on init', () => {
181+
spyOn(component, 'setDefaultOptions');
182+
component.ngOnInit();
183+
expect(component.setDefaultOptions).toHaveBeenCalled();
184+
});
185+
});
186+
});

0 commit comments

Comments
 (0)