@uploadista/react 0.0.20 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/index.d.mts +3 -3
- package/dist/components/index.mjs +1 -1
- package/dist/index.d.mts +4 -548
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -2
- package/dist/upload-zone-CH8B2-hl.mjs +2 -0
- package/dist/upload-zone-CH8B2-hl.mjs.map +1 -0
- package/dist/{uploadista-provider-Cb13AK7Z.d.mts → uploadista-provider-DwKXudoT.d.mts} +558 -15
- package/dist/uploadista-provider-DwKXudoT.d.mts.map +1 -0
- package/dist/use-upload-BgaJmdwF.mjs.map +1 -1
- package/dist/use-uploadista-events-CtDXJYrR.d.mts.map +1 -1
- package/dist/use-uploadista-events-KhJ4knam.mjs.map +1 -1
- package/package.json +12 -9
- package/src/__tests__/event-utils.test.ts +179 -0
- package/src/__tests__/setup.ts +40 -0
- package/src/__tests__/uploadista-provider.test.tsx +316 -0
- package/src/__tests__/use-drag-drop.test.tsx +476 -0
- package/src/__tests__/use-upload.test.tsx +317 -0
- package/src/__tests__/use-uploadista-client.test.tsx +208 -0
- package/src/components/flow-primitives.tsx +3 -8
- package/src/components/index.tsx +37 -6
- package/src/components/upload-primitives.tsx +22 -19
- package/src/components/upload-zone.tsx +1 -2
- package/src/hooks/event-utils.ts +1 -1
- package/src/hooks/use-upload-events.ts +2 -5
- package/src/index.ts +89 -96
- package/vitest.config.ts +16 -0
- package/dist/flow-upload-list-BJSCZ4Ty.mjs +0 -2
- package/dist/flow-upload-list-BJSCZ4Ty.mjs.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/uploadista-provider-Cb13AK7Z.d.mts.map +0 -1
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import { render, renderHook, screen, waitFor } from "@testing-library/react";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
import { describe, expect, it, vi } from "vitest";
|
|
4
|
+
import {
|
|
5
|
+
UploadistaProvider,
|
|
6
|
+
useUploadistaContext,
|
|
7
|
+
} from "../components/uploadista-provider";
|
|
8
|
+
|
|
9
|
+
// Mock dependencies
|
|
10
|
+
vi.mock("@uploadista/client-browser", () => ({
|
|
11
|
+
createUploadistaClient: vi.fn(() => ({
|
|
12
|
+
upload: vi.fn(),
|
|
13
|
+
executeFlow: vi.fn(),
|
|
14
|
+
discoverFlowInputs: vi.fn(),
|
|
15
|
+
uploadWithFlow: vi.fn(),
|
|
16
|
+
multiInputFlowUpload: vi.fn(),
|
|
17
|
+
getChunkingInsights: vi.fn(() => ({
|
|
18
|
+
currentChunkSize: 1024 * 1024,
|
|
19
|
+
recommendedChunkSize: 1024 * 1024,
|
|
20
|
+
networkCondition: "good",
|
|
21
|
+
})),
|
|
22
|
+
exportMetrics: vi.fn(() => ({})),
|
|
23
|
+
getNetworkMetrics: vi.fn(() => ({
|
|
24
|
+
averageSpeed: 1024 * 1024,
|
|
25
|
+
currentSpeed: 1024 * 1024,
|
|
26
|
+
estimatedTimeRemaining: 0,
|
|
27
|
+
})),
|
|
28
|
+
getNetworkCondition: vi.fn(() => "good"),
|
|
29
|
+
resetMetrics: vi.fn(),
|
|
30
|
+
})),
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
vi.mock("@uploadista/client-core", async (importOriginal) => {
|
|
34
|
+
const actual =
|
|
35
|
+
await importOriginal<typeof import("@uploadista/client-core")>();
|
|
36
|
+
return {
|
|
37
|
+
...actual,
|
|
38
|
+
FlowManager: vi.fn().mockImplementation(() => ({
|
|
39
|
+
handleFlowEvent: vi.fn(),
|
|
40
|
+
handleUploadProgress: vi.fn(),
|
|
41
|
+
cleanup: vi.fn(),
|
|
42
|
+
})),
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe("UploadistaProvider", () => {
|
|
47
|
+
describe("context provision", () => {
|
|
48
|
+
it("should render children", () => {
|
|
49
|
+
render(
|
|
50
|
+
<UploadistaProvider
|
|
51
|
+
baseUrl="https://api.example.com"
|
|
52
|
+
storageId="test"
|
|
53
|
+
chunkSize={1024 * 1024}
|
|
54
|
+
storeFingerprintForResuming={true}
|
|
55
|
+
>
|
|
56
|
+
<div data-testid="child">Child content</div>
|
|
57
|
+
</UploadistaProvider>,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
expect(screen.getByTestId("child")).toHaveTextContent("Child content");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("should provide context to children", () => {
|
|
64
|
+
const TestComponent = () => {
|
|
65
|
+
const context = useUploadistaContext();
|
|
66
|
+
return (
|
|
67
|
+
<div data-testid="result">
|
|
68
|
+
{context.client ? "has-client" : "no-client"}
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
render(
|
|
74
|
+
<UploadistaProvider
|
|
75
|
+
baseUrl="https://api.example.com"
|
|
76
|
+
storageId="test"
|
|
77
|
+
chunkSize={1024 * 1024}
|
|
78
|
+
storeFingerprintForResuming={true}
|
|
79
|
+
>
|
|
80
|
+
<TestComponent />
|
|
81
|
+
</UploadistaProvider>,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
expect(screen.getByTestId("result")).toHaveTextContent("has-client");
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("should provide client and config through context", () => {
|
|
88
|
+
const TestComponent = () => {
|
|
89
|
+
const { client, config } = useUploadistaContext();
|
|
90
|
+
return (
|
|
91
|
+
<div>
|
|
92
|
+
<div data-testid="client">{client ? "present" : "missing"}</div>
|
|
93
|
+
<div data-testid="baseUrl">{config.baseUrl}</div>
|
|
94
|
+
<div data-testid="storageId">{config.storageId}</div>
|
|
95
|
+
</div>
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
render(
|
|
100
|
+
<UploadistaProvider
|
|
101
|
+
baseUrl="https://api.example.com"
|
|
102
|
+
storageId="my-storage"
|
|
103
|
+
chunkSize={1024 * 1024}
|
|
104
|
+
storeFingerprintForResuming={true}
|
|
105
|
+
>
|
|
106
|
+
<TestComponent />
|
|
107
|
+
</UploadistaProvider>,
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
expect(screen.getByTestId("client")).toHaveTextContent("present");
|
|
111
|
+
expect(screen.getByTestId("baseUrl")).toHaveTextContent(
|
|
112
|
+
"https://api.example.com",
|
|
113
|
+
);
|
|
114
|
+
expect(screen.getByTestId("storageId")).toHaveTextContent("my-storage");
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe("useUploadistaContext", () => {
|
|
119
|
+
it("should throw error when used outside provider", () => {
|
|
120
|
+
const TestComponent = () => {
|
|
121
|
+
useUploadistaContext();
|
|
122
|
+
return null;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
expect(() => {
|
|
126
|
+
render(<TestComponent />);
|
|
127
|
+
}).toThrow(
|
|
128
|
+
"useUploadistaContext must be used within an UploadistaProvider",
|
|
129
|
+
);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("should return context value when used within provider", () => {
|
|
133
|
+
const wrapper = ({ children }: { children: ReactNode }) => (
|
|
134
|
+
<UploadistaProvider
|
|
135
|
+
baseUrl="https://api.example.com"
|
|
136
|
+
storageId="test"
|
|
137
|
+
chunkSize={1024 * 1024}
|
|
138
|
+
storeFingerprintForResuming={true}
|
|
139
|
+
>
|
|
140
|
+
{children}
|
|
141
|
+
</UploadistaProvider>
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const { result } = renderHook(() => useUploadistaContext(), { wrapper });
|
|
145
|
+
|
|
146
|
+
expect(result.current.client).toBeDefined();
|
|
147
|
+
expect(result.current.config).toBeDefined();
|
|
148
|
+
expect(result.current.subscribeToEvents).toBeDefined();
|
|
149
|
+
expect(typeof result.current.subscribeToEvents).toBe("function");
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
describe("event subscription", () => {
|
|
154
|
+
it("should provide subscribeToEvents function", () => {
|
|
155
|
+
const wrapper = ({ children }: { children: ReactNode }) => (
|
|
156
|
+
<UploadistaProvider
|
|
157
|
+
baseUrl="https://api.example.com"
|
|
158
|
+
storageId="test"
|
|
159
|
+
chunkSize={1024 * 1024}
|
|
160
|
+
storeFingerprintForResuming={true}
|
|
161
|
+
>
|
|
162
|
+
{children}
|
|
163
|
+
</UploadistaProvider>
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const { result } = renderHook(() => useUploadistaContext(), { wrapper });
|
|
167
|
+
|
|
168
|
+
expect(typeof result.current.subscribeToEvents).toBe("function");
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("should allow subscribing to events", () => {
|
|
172
|
+
const wrapper = ({ children }: { children: ReactNode }) => (
|
|
173
|
+
<UploadistaProvider
|
|
174
|
+
baseUrl="https://api.example.com"
|
|
175
|
+
storageId="test"
|
|
176
|
+
chunkSize={1024 * 1024}
|
|
177
|
+
storeFingerprintForResuming={true}
|
|
178
|
+
>
|
|
179
|
+
{children}
|
|
180
|
+
</UploadistaProvider>
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
const { result } = renderHook(() => useUploadistaContext(), { wrapper });
|
|
184
|
+
|
|
185
|
+
const handler = vi.fn();
|
|
186
|
+
const unsubscribe = result.current.subscribeToEvents(handler);
|
|
187
|
+
|
|
188
|
+
expect(typeof unsubscribe).toBe("function");
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("should return unsubscribe function from subscribeToEvents", () => {
|
|
192
|
+
const wrapper = ({ children }: { children: ReactNode }) => (
|
|
193
|
+
<UploadistaProvider
|
|
194
|
+
baseUrl="https://api.example.com"
|
|
195
|
+
storageId="test"
|
|
196
|
+
chunkSize={1024 * 1024}
|
|
197
|
+
storeFingerprintForResuming={true}
|
|
198
|
+
>
|
|
199
|
+
{children}
|
|
200
|
+
</UploadistaProvider>
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
const { result } = renderHook(() => useUploadistaContext(), { wrapper });
|
|
204
|
+
|
|
205
|
+
const handler = vi.fn();
|
|
206
|
+
const unsubscribe = result.current.subscribeToEvents(handler);
|
|
207
|
+
|
|
208
|
+
// Should not throw when called
|
|
209
|
+
expect(() => unsubscribe()).not.toThrow();
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
describe("options passthrough", () => {
|
|
214
|
+
it("should pass all options to the client", () => {
|
|
215
|
+
const TestComponent = () => {
|
|
216
|
+
const { config } = useUploadistaContext();
|
|
217
|
+
return (
|
|
218
|
+
<div>
|
|
219
|
+
<div data-testid="chunkSize">{config.chunkSize}</div>
|
|
220
|
+
<div data-testid="parallelUploads">{config.parallelUploads}</div>
|
|
221
|
+
</div>
|
|
222
|
+
);
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
render(
|
|
226
|
+
<UploadistaProvider
|
|
227
|
+
baseUrl="https://api.example.com"
|
|
228
|
+
storageId="test"
|
|
229
|
+
chunkSize={2 * 1024 * 1024}
|
|
230
|
+
parallelUploads={4}
|
|
231
|
+
storeFingerprintForResuming={true}
|
|
232
|
+
>
|
|
233
|
+
<TestComponent />
|
|
234
|
+
</UploadistaProvider>,
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
expect(screen.getByTestId("chunkSize")).toHaveTextContent(
|
|
238
|
+
String(2 * 1024 * 1024),
|
|
239
|
+
);
|
|
240
|
+
expect(screen.getByTestId("parallelUploads")).toHaveTextContent("4");
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
describe("nested providers", () => {
|
|
245
|
+
it("should allow nested providers with different configs", () => {
|
|
246
|
+
const TestComponent = ({ testId }: { testId: string }) => {
|
|
247
|
+
const { config } = useUploadistaContext();
|
|
248
|
+
return <div data-testid={testId}>{config.storageId}</div>;
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
render(
|
|
252
|
+
<UploadistaProvider
|
|
253
|
+
baseUrl="https://api.example.com"
|
|
254
|
+
storageId="outer-storage"
|
|
255
|
+
chunkSize={1024 * 1024}
|
|
256
|
+
storeFingerprintForResuming={true}
|
|
257
|
+
>
|
|
258
|
+
<TestComponent testId="outer" />
|
|
259
|
+
<UploadistaProvider
|
|
260
|
+
baseUrl="https://api.example.com"
|
|
261
|
+
storageId="inner-storage"
|
|
262
|
+
chunkSize={1024 * 1024}
|
|
263
|
+
storeFingerprintForResuming={true}
|
|
264
|
+
>
|
|
265
|
+
<TestComponent testId="inner" />
|
|
266
|
+
</UploadistaProvider>
|
|
267
|
+
</UploadistaProvider>,
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
expect(screen.getByTestId("outer")).toHaveTextContent("outer-storage");
|
|
271
|
+
expect(screen.getByTestId("inner")).toHaveTextContent("inner-storage");
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
describe("context stability", () => {
|
|
276
|
+
it("should maintain stable context value reference", async () => {
|
|
277
|
+
const contextValues: any[] = [];
|
|
278
|
+
|
|
279
|
+
const TestComponent = () => {
|
|
280
|
+
const context = useUploadistaContext();
|
|
281
|
+
contextValues.push(context);
|
|
282
|
+
return null;
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const { rerender } = render(
|
|
286
|
+
<UploadistaProvider
|
|
287
|
+
baseUrl="https://api.example.com"
|
|
288
|
+
storageId="test"
|
|
289
|
+
chunkSize={1024 * 1024}
|
|
290
|
+
storeFingerprintForResuming={true}
|
|
291
|
+
>
|
|
292
|
+
<TestComponent />
|
|
293
|
+
</UploadistaProvider>,
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
// Re-render with same props
|
|
297
|
+
rerender(
|
|
298
|
+
<UploadistaProvider
|
|
299
|
+
baseUrl="https://api.example.com"
|
|
300
|
+
storageId="test"
|
|
301
|
+
chunkSize={1024 * 1024}
|
|
302
|
+
storeFingerprintForResuming={true}
|
|
303
|
+
>
|
|
304
|
+
<TestComponent />
|
|
305
|
+
</UploadistaProvider>,
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
await waitFor(() => {
|
|
309
|
+
expect(contextValues.length).toBe(2);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
// Both context values should have the same client reference
|
|
313
|
+
expect(contextValues[0].client).toBe(contextValues[1].client);
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
});
|