Skip to content

Commit 9077845

Browse files
guguclaude
andcommitted
Fix turnstile component tests for Vitest compatibility
Replace Jasmine syntax with Vitest (vi.fn) and use async/await with real delays instead of fakeAsync/tick which conflicts with Zone.js. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 8dd5937 commit 9077845

1 file changed

Lines changed: 57 additions & 47 deletions

File tree

Lines changed: 57 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
1-
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
22
import { TurnstileComponent } from './turnstile.component';
33

44
describe('TurnstileComponent', () => {
55
let component: TurnstileComponent;
66
let fixture: ComponentFixture<TurnstileComponent>;
77
let mockWidgetId: string;
88

9+
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
10+
911
beforeEach(async () => {
1012
mockWidgetId = 'mock-widget-id';
1113

12-
window.turnstile = {
13-
render: jasmine.createSpy('render').and.returnValue(mockWidgetId),
14-
reset: jasmine.createSpy('reset'),
15-
getResponse: jasmine.createSpy('getResponse'),
16-
remove: jasmine.createSpy('remove'),
14+
(window as any).turnstile = {
15+
render: vi.fn().mockReturnValue(mockWidgetId),
16+
reset: vi.fn(),
17+
getResponse: vi.fn(),
18+
remove: vi.fn(),
1719
};
1820

1921
await TestBed.configureTestingModule({
@@ -25,99 +27,107 @@ describe('TurnstileComponent', () => {
2527
});
2628

2729
afterEach(() => {
28-
delete window.turnstile;
30+
component.ngOnDestroy();
31+
delete (window as any).turnstile;
2932
});
3033

3134
it('should create', () => {
3235
expect(component).toBeTruthy();
3336
});
3437

35-
it('should render turnstile widget on init', fakeAsync(() => {
38+
it('should render turnstile widget on init', async () => {
3639
fixture.detectChanges();
37-
tick(100);
40+
await delay(150);
3841

39-
expect(window.turnstile?.render).toHaveBeenCalled();
40-
}));
42+
expect((window as any).turnstile?.render).toHaveBeenCalled();
43+
});
4144

42-
it('should emit tokenReceived when callback is triggered', fakeAsync(() => {
45+
it('should emit tokenReceived when callback is triggered', async () => {
4346
let receivedToken: string | null = null;
4447
component.tokenReceived.subscribe((token: string) => {
4548
receivedToken = token;
4649
});
4750

48-
(window.turnstile?.render as jasmine.Spy).and.callFake((_container: any, options: any) => {
49-
options.callback('test-token');
50-
return mockWidgetId;
51-
});
51+
((window as any).turnstile?.render as ReturnType<typeof vi.fn>).mockImplementation(
52+
(_container: any, options: any) => {
53+
options.callback('test-token');
54+
return mockWidgetId;
55+
},
56+
);
5257

5358
fixture.detectChanges();
54-
tick(100);
59+
await delay(150);
5560

5661
expect(receivedToken).toBe('test-token');
57-
}));
62+
});
5863

59-
it('should emit tokenError when error-callback is triggered', fakeAsync(() => {
64+
it('should emit tokenError when error-callback is triggered', async () => {
6065
let errorEmitted = false;
6166
component.tokenError.subscribe(() => {
6267
errorEmitted = true;
6368
});
6469

65-
(window.turnstile?.render as jasmine.Spy).and.callFake((_container: any, options: any) => {
66-
options['error-callback']();
67-
return mockWidgetId;
68-
});
70+
((window as any).turnstile?.render as ReturnType<typeof vi.fn>).mockImplementation(
71+
(_container: any, options: any) => {
72+
options['error-callback']();
73+
return mockWidgetId;
74+
},
75+
);
6976

7077
fixture.detectChanges();
71-
tick(100);
78+
await delay(150);
7279

73-
expect(errorEmitted).toBeTrue();
74-
}));
80+
expect(errorEmitted).toBe(true);
81+
});
7582

76-
it('should emit tokenExpired when expired-callback is triggered', fakeAsync(() => {
83+
it('should emit tokenExpired when expired-callback is triggered', async () => {
7784
let expiredEmitted = false;
7885
component.tokenExpired.subscribe(() => {
7986
expiredEmitted = true;
8087
});
8188

82-
(window.turnstile?.render as jasmine.Spy).and.callFake((_container: any, options: any) => {
83-
options['expired-callback']();
84-
return mockWidgetId;
85-
});
89+
((window as any).turnstile?.render as ReturnType<typeof vi.fn>).mockImplementation(
90+
(_container: any, options: any) => {
91+
options['expired-callback']();
92+
return mockWidgetId;
93+
},
94+
);
8695

8796
fixture.detectChanges();
88-
tick(100);
97+
await delay(150);
8998

90-
expect(expiredEmitted).toBeTrue();
91-
}));
99+
expect(expiredEmitted).toBe(true);
100+
});
92101

93-
it('should reset the widget when reset() is called', fakeAsync(() => {
102+
it('should reset the widget when reset() is called', async () => {
94103
fixture.detectChanges();
95-
tick(100);
104+
await delay(150);
96105

97106
component.reset();
98107

99-
expect(window.turnstile?.reset).toHaveBeenCalledWith(mockWidgetId);
100-
}));
108+
expect((window as any).turnstile?.reset).toHaveBeenCalledWith(mockWidgetId);
109+
});
101110

102-
it('should remove widget on destroy', fakeAsync(() => {
111+
it('should remove widget on destroy', async () => {
103112
fixture.detectChanges();
104-
tick(100);
113+
await delay(150);
105114

106115
component.ngOnDestroy();
107116

108-
expect(window.turnstile?.remove).toHaveBeenCalledWith(mockWidgetId);
109-
}));
117+
expect((window as any).turnstile?.remove).toHaveBeenCalledWith(mockWidgetId);
118+
});
110119

111-
it('should emit error if turnstile fails to load', fakeAsync(() => {
112-
delete window.turnstile;
120+
it('should emit error if turnstile fails to load', async () => {
121+
delete (window as any).turnstile;
113122
let errorEmitted = false;
114123
component.tokenError.subscribe(() => {
115124
errorEmitted = true;
116125
});
117126

118127
fixture.detectChanges();
119-
tick(5100);
128+
// MAX_POLL_ATTEMPTS (50) * POLL_INTERVAL_MS (100) = 5000ms
129+
await delay(5200);
120130

121-
expect(errorEmitted).toBeTrue();
122-
}));
131+
expect(errorEmitted).toBe(true);
132+
}, 10000);
123133
});

0 commit comments

Comments
 (0)