Skip to content

Commit 9e964d1

Browse files
Copilothotlong
andcommitted
Add test coverage for LazyPluginLoader: preloadPlugin, errorFallback, retries=0, retry-then-succeed
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent 7454ba7 commit 9e964d1

1 file changed

Lines changed: 97 additions & 1 deletion

File tree

packages/react/src/__tests__/LazyPluginLoader.test.tsx

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import { describe, it, expect, vi } from 'vitest';
1010
import { render, screen, waitFor } from '@testing-library/react';
1111
import React from 'react';
12-
import { createLazyPlugin } from '../LazyPluginLoader';
12+
import { createLazyPlugin, preloadPlugin } from '../LazyPluginLoader';
1313

1414
describe('createLazyPlugin', () => {
1515
it('should create a lazy-loaded component', async () => {
@@ -77,4 +77,100 @@ describe('createLazyPlugin', () => {
7777
// Restore console.error
7878
console.error = originalError;
7979
});
80+
81+
it('should preload a plugin without rendering', async () => {
82+
const TestComponent = () => <div>Preloaded</div>;
83+
const importFn = vi.fn(() => Promise.resolve({ default: TestComponent }));
84+
85+
const result = await preloadPlugin(importFn);
86+
87+
expect(importFn).toHaveBeenCalledTimes(1);
88+
expect(result).toEqual({ default: TestComponent });
89+
});
90+
91+
it('should render errorFallback when component fails to load', async () => {
92+
const originalError = console.error;
93+
console.error = vi.fn();
94+
95+
const ErrorFallback = ({ error, retry }: { error: Error; retry: () => void }) => (
96+
<div>
97+
<span>Error: {error.message}</span>
98+
<button onClick={retry}>Retry</button>
99+
</div>
100+
);
101+
102+
const LazyComponent = createLazyPlugin(
103+
() => Promise.reject(new Error('chunk failed')),
104+
{ retries: 0, errorFallback: ErrorFallback }
105+
);
106+
107+
render(<LazyComponent />);
108+
109+
await waitFor(() => {
110+
expect(screen.getByText('Error: chunk failed')).toBeInTheDocument();
111+
});
112+
113+
expect(screen.getByRole('button', { name: 'Retry' })).toBeInTheDocument();
114+
115+
console.error = originalError;
116+
});
117+
118+
it('should not retry when retries=0', async () => {
119+
const originalError = console.error;
120+
console.error = vi.fn();
121+
122+
const importFn = vi.fn(() => Promise.reject(new Error('fail')));
123+
124+
const ErrorFallback = ({ error }: { error: Error; retry: () => void }) => (
125+
<div>Error: {error.message}</div>
126+
);
127+
128+
const LazyComponent = createLazyPlugin(importFn, {
129+
retries: 0,
130+
errorFallback: ErrorFallback,
131+
});
132+
133+
render(<LazyComponent />);
134+
135+
await waitFor(() => {
136+
expect(screen.getByText('Error: fail')).toBeInTheDocument();
137+
});
138+
139+
// Called only once — no retries
140+
expect(importFn).toHaveBeenCalledTimes(1);
141+
142+
console.error = originalError;
143+
});
144+
145+
it('should retry on failure then succeed', async () => {
146+
const originalError = console.error;
147+
console.error = vi.fn();
148+
149+
const TestComponent = () => <div>Success after retry</div>;
150+
151+
let callCount = 0;
152+
const importFn = vi.fn(() => {
153+
callCount++;
154+
if (callCount <= 2) {
155+
return Promise.reject(new Error('transient error'));
156+
}
157+
return Promise.resolve({ default: TestComponent as React.ComponentType });
158+
});
159+
160+
const LazyComponent = createLazyPlugin(importFn, {
161+
retries: 3,
162+
retryDelay: 10,
163+
});
164+
165+
render(<LazyComponent />);
166+
167+
await waitFor(() => {
168+
expect(screen.getByText('Success after retry')).toBeInTheDocument();
169+
}, { timeout: 5000 });
170+
171+
// First call + 2 retries (fails) + 1 success = called 3 times
172+
expect(importFn).toHaveBeenCalledTimes(3);
173+
174+
console.error = originalError;
175+
});
80176
});

0 commit comments

Comments
 (0)