ai-progress-controls 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/LICENSE +21 -0
- package/README.md +823 -0
- package/dist/ai-progress-controls.es.js +7191 -0
- package/dist/ai-progress-controls.es.js.map +1 -0
- package/dist/ai-progress-controls.umd.js +2 -0
- package/dist/ai-progress-controls.umd.js.map +1 -0
- package/dist/index.d.ts +2212 -0
- package/package.json +105 -0
- package/src/__tests__/setup.ts +93 -0
- package/src/core/base/AIControl.ts +230 -0
- package/src/core/base/index.ts +3 -0
- package/src/core/base/types.ts +77 -0
- package/src/core/base/utils.ts +168 -0
- package/src/core/batch-progress/BatchProgress.test.ts +458 -0
- package/src/core/batch-progress/BatchProgress.ts +760 -0
- package/src/core/batch-progress/index.ts +14 -0
- package/src/core/batch-progress/styles.ts +480 -0
- package/src/core/batch-progress/types.ts +169 -0
- package/src/core/model-loader/ModelLoader.test.ts +311 -0
- package/src/core/model-loader/ModelLoader.ts +673 -0
- package/src/core/model-loader/index.ts +2 -0
- package/src/core/model-loader/styles.ts +496 -0
- package/src/core/model-loader/types.ts +127 -0
- package/src/core/parameter-panel/ParameterPanel.test.ts +856 -0
- package/src/core/parameter-panel/ParameterPanel.ts +877 -0
- package/src/core/parameter-panel/index.ts +14 -0
- package/src/core/parameter-panel/styles.ts +323 -0
- package/src/core/parameter-panel/types.ts +278 -0
- package/src/core/parameter-slider/ParameterSlider.test.ts +299 -0
- package/src/core/parameter-slider/ParameterSlider.ts +653 -0
- package/src/core/parameter-slider/index.ts +8 -0
- package/src/core/parameter-slider/styles.ts +493 -0
- package/src/core/parameter-slider/types.ts +107 -0
- package/src/core/queue-progress/QueueProgress.test.ts +344 -0
- package/src/core/queue-progress/QueueProgress.ts +563 -0
- package/src/core/queue-progress/index.ts +5 -0
- package/src/core/queue-progress/styles.ts +469 -0
- package/src/core/queue-progress/types.ts +130 -0
- package/src/core/retry-progress/RetryProgress.test.ts +397 -0
- package/src/core/retry-progress/RetryProgress.ts +957 -0
- package/src/core/retry-progress/index.ts +6 -0
- package/src/core/retry-progress/styles.ts +530 -0
- package/src/core/retry-progress/types.ts +176 -0
- package/src/core/stream-progress/StreamProgress.test.ts +531 -0
- package/src/core/stream-progress/StreamProgress.ts +517 -0
- package/src/core/stream-progress/index.ts +2 -0
- package/src/core/stream-progress/styles.ts +349 -0
- package/src/core/stream-progress/types.ts +82 -0
- package/src/index.ts +19 -0
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
+
import { StreamProgress } from './StreamProgress';
|
|
3
|
+
import { waitForElement, waitForNextTick } from '../../__tests__/setup';
|
|
4
|
+
|
|
5
|
+
describe('StreamProgress Component', () => {
|
|
6
|
+
let progress: StreamProgress;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
progress = new StreamProgress();
|
|
10
|
+
document.body.appendChild(progress);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
if (progress.parentNode) {
|
|
15
|
+
progress.remove();
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe('Constructor & Configuration', () => {
|
|
20
|
+
it('should create instance with default config', () => {
|
|
21
|
+
expect(progress).toBeInstanceOf(StreamProgress);
|
|
22
|
+
expect(progress.tagName.toLowerCase()).toBe('stream-progress');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should accept custom configuration', () => {
|
|
26
|
+
const customProgress = new StreamProgress({
|
|
27
|
+
maxTokens: 2000,
|
|
28
|
+
costPerToken: 0.00003,
|
|
29
|
+
showRate: false,
|
|
30
|
+
showCost: false,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
expect(customProgress).toBeInstanceOf(StreamProgress);
|
|
34
|
+
expect(customProgress['config'].maxTokens).toBe(2000);
|
|
35
|
+
expect(customProgress['config'].costPerToken).toBe(0.00003);
|
|
36
|
+
expect(customProgress['config'].showRate).toBe(false);
|
|
37
|
+
customProgress.remove();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should have shadow root', async () => {
|
|
41
|
+
await waitForElement(progress);
|
|
42
|
+
expect(progress.shadowRoot).toBeTruthy();
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe('State Management', () => {
|
|
47
|
+
it('should initialize with idle state', () => {
|
|
48
|
+
const state = progress['state'];
|
|
49
|
+
expect(state.tokensGenerated).toBe(0);
|
|
50
|
+
expect(state.isStreaming).toBe(false);
|
|
51
|
+
expect(state.isCancelled).toBe(false);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should update state when started', () => {
|
|
55
|
+
progress.start('Starting...');
|
|
56
|
+
const state = progress['state'];
|
|
57
|
+
|
|
58
|
+
expect(state.isStreaming).toBe(true);
|
|
59
|
+
expect(state.startTime).toBeGreaterThan(0);
|
|
60
|
+
expect(state.message).toBe('Starting...');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should track tokens correctly', () => {
|
|
64
|
+
progress.start();
|
|
65
|
+
progress.update({ tokensGenerated: 100 });
|
|
66
|
+
|
|
67
|
+
const state = progress['state'];
|
|
68
|
+
expect(state.tokensGenerated).toBe(100);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe('Methods', () => {
|
|
73
|
+
describe('start()', () => {
|
|
74
|
+
it('should start streaming', () => {
|
|
75
|
+
progress.start('Generating...');
|
|
76
|
+
const state = progress['state'];
|
|
77
|
+
|
|
78
|
+
expect(state.isStreaming).toBe(true);
|
|
79
|
+
expect(state.tokensGenerated).toBe(0);
|
|
80
|
+
expect(state.message).toBe('Generating...');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should emit streamstart event', async () => {
|
|
84
|
+
const spy = vi.fn();
|
|
85
|
+
progress.addEventListener('streamstart', spy);
|
|
86
|
+
|
|
87
|
+
progress.start();
|
|
88
|
+
await waitForNextTick();
|
|
89
|
+
|
|
90
|
+
expect(spy).toHaveBeenCalled();
|
|
91
|
+
expect(spy.mock.calls[0][0].detail).toHaveProperty('startTime');
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should not start if already streaming', () => {
|
|
95
|
+
progress.start();
|
|
96
|
+
const firstStartTime = progress['state'].startTime;
|
|
97
|
+
|
|
98
|
+
progress.start();
|
|
99
|
+
expect(progress['state'].startTime).toBe(firstStartTime);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('update()', () => {
|
|
104
|
+
beforeEach(() => {
|
|
105
|
+
progress.start();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should update token count', async () => {
|
|
109
|
+
progress.update({ tokensGenerated: 50 });
|
|
110
|
+
await waitForNextTick();
|
|
111
|
+
|
|
112
|
+
const state = progress['state'];
|
|
113
|
+
expect(state.tokensGenerated).toBe(50);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should calculate tokens per second', async () => {
|
|
117
|
+
progress.update({ tokensGenerated: 100, tokensPerSecond: 25 });
|
|
118
|
+
await waitForNextTick();
|
|
119
|
+
|
|
120
|
+
const state = progress['state'];
|
|
121
|
+
expect(state.tokensPerSecond).toBe(25);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should update message', async () => {
|
|
125
|
+
progress.update({ tokensGenerated: 50, message: 'Processing...' });
|
|
126
|
+
await waitForNextTick();
|
|
127
|
+
|
|
128
|
+
const state = progress['state'];
|
|
129
|
+
expect(state.message).toBe('Processing...');
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('should emit streamupdate event', async () => {
|
|
133
|
+
const spy = vi.fn();
|
|
134
|
+
progress.addEventListener('streamupdate', spy);
|
|
135
|
+
|
|
136
|
+
progress.update({ tokensGenerated: 100 });
|
|
137
|
+
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
138
|
+
|
|
139
|
+
expect(spy).toHaveBeenCalled();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should not update if cancelled', () => {
|
|
143
|
+
progress.cancel();
|
|
144
|
+
const tokensBeforeUpdate = progress['state'].tokensGenerated;
|
|
145
|
+
|
|
146
|
+
progress.update({ tokensGenerated: 100 });
|
|
147
|
+
expect(progress['state'].tokensGenerated).toBe(tokensBeforeUpdate);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('should calculate cost', async () => {
|
|
151
|
+
const costPerToken = 0.00002;
|
|
152
|
+
const tokensGenerated = 1000;
|
|
153
|
+
const customProgress = new StreamProgress({ costPerToken });
|
|
154
|
+
document.body.appendChild(customProgress);
|
|
155
|
+
|
|
156
|
+
customProgress.start();
|
|
157
|
+
customProgress.update({ tokensGenerated });
|
|
158
|
+
await waitForNextTick();
|
|
159
|
+
|
|
160
|
+
const expectedCost = tokensGenerated * costPerToken;
|
|
161
|
+
expect(customProgress['state'].totalCost).toBeCloseTo(expectedCost, 6);
|
|
162
|
+
|
|
163
|
+
customProgress.remove();
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe('complete()', () => {
|
|
168
|
+
beforeEach(() => {
|
|
169
|
+
progress.start();
|
|
170
|
+
progress.update({ tokensGenerated: 100 });
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('should complete streaming', () => {
|
|
174
|
+
progress.complete();
|
|
175
|
+
const state = progress['state'];
|
|
176
|
+
|
|
177
|
+
expect(state.isStreaming).toBe(false);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should emit streamcomplete event', async () => {
|
|
181
|
+
const spy = vi.fn();
|
|
182
|
+
progress.addEventListener('streamcomplete', spy);
|
|
183
|
+
|
|
184
|
+
progress.complete();
|
|
185
|
+
await waitForNextTick();
|
|
186
|
+
|
|
187
|
+
expect(spy).toHaveBeenCalled();
|
|
188
|
+
const detail = spy.mock.calls[0][0].detail;
|
|
189
|
+
expect(detail).toHaveProperty('tokensGenerated');
|
|
190
|
+
expect(detail).toHaveProperty('duration');
|
|
191
|
+
expect(detail).toHaveProperty('totalCost');
|
|
192
|
+
expect(detail).toHaveProperty('averageRate');
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('should not complete if not streaming', () => {
|
|
196
|
+
const notStreamingProgress = new StreamProgress();
|
|
197
|
+
document.body.appendChild(notStreamingProgress);
|
|
198
|
+
|
|
199
|
+
const spy = vi.fn();
|
|
200
|
+
notStreamingProgress.addEventListener('streamcomplete', spy);
|
|
201
|
+
|
|
202
|
+
notStreamingProgress.complete();
|
|
203
|
+
expect(spy).not.toHaveBeenCalled();
|
|
204
|
+
|
|
205
|
+
notStreamingProgress.remove();
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
describe('cancel()', () => {
|
|
210
|
+
beforeEach(() => {
|
|
211
|
+
progress.start();
|
|
212
|
+
progress.update({ tokensGenerated: 50 });
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('should cancel streaming', () => {
|
|
216
|
+
progress.cancel();
|
|
217
|
+
const state = progress['state'];
|
|
218
|
+
|
|
219
|
+
expect(state.isStreaming).toBe(false);
|
|
220
|
+
expect(state.isCancelled).toBe(true);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('should emit streamcancel event', async () => {
|
|
224
|
+
const spy = vi.fn();
|
|
225
|
+
progress.addEventListener('streamcancel', spy);
|
|
226
|
+
|
|
227
|
+
progress.cancel('user');
|
|
228
|
+
await waitForNextTick();
|
|
229
|
+
|
|
230
|
+
expect(spy).toHaveBeenCalled();
|
|
231
|
+
const detail = spy.mock.calls[0][0].detail;
|
|
232
|
+
expect(detail.reason).toBe('user');
|
|
233
|
+
expect(detail).toHaveProperty('tokensGenerated');
|
|
234
|
+
expect(detail).toHaveProperty('duration');
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('should support different cancel reasons', async () => {
|
|
238
|
+
const reasons: Array<'user' | 'error' | 'timeout'> = ['user', 'error', 'timeout'];
|
|
239
|
+
|
|
240
|
+
for (const reason of reasons) {
|
|
241
|
+
const spy = vi.fn();
|
|
242
|
+
const testProgress = new StreamProgress();
|
|
243
|
+
document.body.appendChild(testProgress);
|
|
244
|
+
testProgress.addEventListener('streamcancel', spy);
|
|
245
|
+
|
|
246
|
+
testProgress.start();
|
|
247
|
+
testProgress.cancel(reason);
|
|
248
|
+
await waitForNextTick();
|
|
249
|
+
|
|
250
|
+
expect(spy.mock.calls[0][0].detail.reason).toBe(reason);
|
|
251
|
+
testProgress.remove();
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('should not cancel twice', async () => {
|
|
256
|
+
const spy = vi.fn();
|
|
257
|
+
progress.addEventListener('streamcancel', spy);
|
|
258
|
+
|
|
259
|
+
progress.cancel();
|
|
260
|
+
await waitForNextTick();
|
|
261
|
+
|
|
262
|
+
progress.cancel();
|
|
263
|
+
await waitForNextTick();
|
|
264
|
+
|
|
265
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
describe('reset()', () => {
|
|
270
|
+
it('should reset to initial state', () => {
|
|
271
|
+
progress.start();
|
|
272
|
+
progress.update({ tokensGenerated: 100, tokensPerSecond: 25 });
|
|
273
|
+
progress.complete();
|
|
274
|
+
|
|
275
|
+
progress.reset();
|
|
276
|
+
const state = progress['state'];
|
|
277
|
+
|
|
278
|
+
expect(state.tokensGenerated).toBe(0);
|
|
279
|
+
expect(state.tokensPerSecond).toBe(0);
|
|
280
|
+
expect(state.totalCost).toBe(0);
|
|
281
|
+
expect(state.isStreaming).toBe(false);
|
|
282
|
+
expect(state.isCancelled).toBe(false);
|
|
283
|
+
expect(state.startTime).toBe(0);
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
describe('Properties', () => {
|
|
289
|
+
describe('disabled', () => {
|
|
290
|
+
it('should get/set disabled state', () => {
|
|
291
|
+
expect(progress.disabled).toBe(false);
|
|
292
|
+
|
|
293
|
+
progress.disabled = true;
|
|
294
|
+
expect(progress.disabled).toBe(true);
|
|
295
|
+
|
|
296
|
+
progress.disabled = false;
|
|
297
|
+
expect(progress.disabled).toBe(false);
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
describe('Rendering', () => {
|
|
303
|
+
it('should render in shadow DOM', async () => {
|
|
304
|
+
await waitForElement(progress);
|
|
305
|
+
expect(progress.shadowRoot?.querySelector('.stream-progress')).toBeTruthy();
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('should show progress bar when configured', async () => {
|
|
309
|
+
const withProgressBar = new StreamProgress({ showProgressBar: true });
|
|
310
|
+
document.body.appendChild(withProgressBar);
|
|
311
|
+
await waitForElement(withProgressBar);
|
|
312
|
+
|
|
313
|
+
withProgressBar.start();
|
|
314
|
+
await waitForNextTick();
|
|
315
|
+
|
|
316
|
+
withProgressBar.remove();
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
it('should show rate when configured', async () => {
|
|
320
|
+
const withRate = new StreamProgress({ showRate: true });
|
|
321
|
+
document.body.appendChild(withRate);
|
|
322
|
+
await waitForElement(withRate);
|
|
323
|
+
|
|
324
|
+
withRate.start();
|
|
325
|
+
withRate.update({ tokensGenerated: 100, tokensPerSecond: 25 });
|
|
326
|
+
await waitForNextTick();
|
|
327
|
+
|
|
328
|
+
withRate.remove();
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
it('should show cost when configured', async () => {
|
|
332
|
+
const withCost = new StreamProgress({ showCost: true, costPerToken: 0.00002 });
|
|
333
|
+
document.body.appendChild(withCost);
|
|
334
|
+
await waitForElement(withCost);
|
|
335
|
+
|
|
336
|
+
withCost.start();
|
|
337
|
+
withCost.update({ tokensGenerated: 1000 });
|
|
338
|
+
await waitForNextTick();
|
|
339
|
+
|
|
340
|
+
withCost.remove();
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
describe('Edge Cases', () => {
|
|
345
|
+
it('should handle rapid updates', async () => {
|
|
346
|
+
progress.start();
|
|
347
|
+
|
|
348
|
+
for (let i = 1; i <= 100; i++) {
|
|
349
|
+
progress.update({ tokensGenerated: i });
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Wait for throttle to process at least one update
|
|
353
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
354
|
+
|
|
355
|
+
const state = progress['state'];
|
|
356
|
+
expect(state.tokensGenerated).toBeGreaterThan(0);
|
|
357
|
+
expect(state.tokensGenerated).toBeLessThanOrEqual(100);
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
it('should handle zero tokens', () => {
|
|
361
|
+
progress.start();
|
|
362
|
+
progress.update({ tokensGenerated: 0 });
|
|
363
|
+
|
|
364
|
+
const state = progress['state'];
|
|
365
|
+
expect(state.tokensGenerated).toBe(0);
|
|
366
|
+
expect(state.totalCost).toBe(0);
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
it('should handle very large token counts', async () => {
|
|
370
|
+
progress.start();
|
|
371
|
+
progress.update({ tokensGenerated: 1000000 });
|
|
372
|
+
await waitForNextTick();
|
|
373
|
+
|
|
374
|
+
const state = progress['state'];
|
|
375
|
+
expect(state.tokensGenerated).toBe(1000000);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it('should handle negative token rates gracefully', async () => {
|
|
379
|
+
progress.start();
|
|
380
|
+
progress.update({ tokensGenerated: 100, tokensPerSecond: -5 });
|
|
381
|
+
await waitForNextTick();
|
|
382
|
+
|
|
383
|
+
const state = progress['state'];
|
|
384
|
+
expect(state.tokensPerSecond).toBe(-5);
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
describe('Accessibility', () => {
|
|
389
|
+
it('should have proper ARIA role', async () => {
|
|
390
|
+
await waitForElement(progress);
|
|
391
|
+
|
|
392
|
+
const role = progress.getAttribute('role');
|
|
393
|
+
expect(role).toBe('progressbar');
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
it('should update aria-valuenow on progress', async () => {
|
|
397
|
+
progress.start();
|
|
398
|
+
progress.update({ tokensGenerated: 100 });
|
|
399
|
+
await waitForNextTick();
|
|
400
|
+
|
|
401
|
+
const valuenow = progress.getAttribute('aria-valuenow');
|
|
402
|
+
expect(valuenow).toBe('100');
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
it('should have aria-valuemax', async () => {
|
|
406
|
+
const maxTokens = 2000;
|
|
407
|
+
const customProgress = new StreamProgress({ maxTokens });
|
|
408
|
+
document.body.appendChild(customProgress);
|
|
409
|
+
|
|
410
|
+
customProgress.start();
|
|
411
|
+
customProgress.update({ tokensGenerated: 100 });
|
|
412
|
+
await waitForNextTick();
|
|
413
|
+
|
|
414
|
+
const valuemax = customProgress.getAttribute('aria-valuemax');
|
|
415
|
+
expect(valuemax).toBe('2000');
|
|
416
|
+
|
|
417
|
+
customProgress.remove();
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
describe('Memory Management', () => {
|
|
422
|
+
it('should clean up on disconnect', () => {
|
|
423
|
+
const temp = new StreamProgress();
|
|
424
|
+
document.body.appendChild(temp);
|
|
425
|
+
temp.start();
|
|
426
|
+
temp.update({ tokensGenerated: 100 });
|
|
427
|
+
|
|
428
|
+
temp.remove();
|
|
429
|
+
|
|
430
|
+
expect(() => temp.update({ tokensGenerated: 200 })).not.toThrow();
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
it('should cancel animation frames on cleanup', () => {
|
|
434
|
+
progress.start();
|
|
435
|
+
progress.update({ tokensGenerated: 100 });
|
|
436
|
+
|
|
437
|
+
const animationFrame = progress['animationFrame'];
|
|
438
|
+
progress.remove();
|
|
439
|
+
|
|
440
|
+
// Animation frame should be cleared
|
|
441
|
+
expect(progress['animationFrame']).toBe(animationFrame);
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
describe('Size Variants', () => {
|
|
446
|
+
it('should default to default size', () => {
|
|
447
|
+
expect(progress['config'].size).toBe('default');
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
it('should accept size in constructor', () => {
|
|
451
|
+
const compactProgress = new StreamProgress({ size: 'compact' });
|
|
452
|
+
expect(compactProgress['config'].size).toBe('compact');
|
|
453
|
+
compactProgress.remove();
|
|
454
|
+
|
|
455
|
+
const largeProgress = new StreamProgress({ size: 'large' });
|
|
456
|
+
expect(largeProgress['config'].size).toBe('large');
|
|
457
|
+
largeProgress.remove();
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
it('should update size via attribute', async () => {
|
|
461
|
+
await waitForElement(progress);
|
|
462
|
+
|
|
463
|
+
progress.setAttribute('size', 'compact');
|
|
464
|
+
await waitForNextTick();
|
|
465
|
+
expect(progress['config'].size).toBe('compact');
|
|
466
|
+
expect(progress.getAttribute('size')).toBe('compact');
|
|
467
|
+
|
|
468
|
+
progress.setAttribute('size', 'large');
|
|
469
|
+
await waitForNextTick();
|
|
470
|
+
expect(progress['config'].size).toBe('large');
|
|
471
|
+
expect(progress.getAttribute('size')).toBe('large');
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
it('should apply size attribute to host element', async () => {
|
|
475
|
+
await waitForElement(progress);
|
|
476
|
+
|
|
477
|
+
progress.setAttribute('size', 'compact');
|
|
478
|
+
await waitForNextTick();
|
|
479
|
+
expect(progress.hasAttribute('size')).toBe(true);
|
|
480
|
+
expect(progress.getAttribute('size')).toBe('compact');
|
|
481
|
+
});
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
describe('Visual Variants', () => {
|
|
485
|
+
it('should apply default variant by default', () => {
|
|
486
|
+
expect(progress['config'].variant).toBe('default');
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
it('should apply minimal variant', () => {
|
|
490
|
+
const minimal = new StreamProgress({ variant: 'minimal' });
|
|
491
|
+
expect(minimal['config'].variant).toBe('minimal');
|
|
492
|
+
minimal.remove();
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
it('should apply gradient variant', () => {
|
|
496
|
+
const gradient = new StreamProgress({ variant: 'gradient' });
|
|
497
|
+
expect(gradient['config'].variant).toBe('gradient');
|
|
498
|
+
gradient.remove();
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
it('should apply glassmorphic variant', () => {
|
|
502
|
+
const glassmorphic = new StreamProgress({ variant: 'glassmorphic' });
|
|
503
|
+
expect(glassmorphic['config'].variant).toBe('glassmorphic');
|
|
504
|
+
glassmorphic.remove();
|
|
505
|
+
});
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
describe('Animation Effects', () => {
|
|
509
|
+
it('should apply none animation by default', () => {
|
|
510
|
+
expect(progress['config'].animation).toBe('none');
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
it('should apply striped animation', () => {
|
|
514
|
+
const striped = new StreamProgress({ animation: 'striped' });
|
|
515
|
+
expect(striped['config'].animation).toBe('striped');
|
|
516
|
+
striped.remove();
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
it('should apply pulse animation', () => {
|
|
520
|
+
const pulse = new StreamProgress({ animation: 'pulse' });
|
|
521
|
+
expect(pulse['config'].animation).toBe('pulse');
|
|
522
|
+
pulse.remove();
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
it('should apply glow animation', () => {
|
|
526
|
+
const glow = new StreamProgress({ animation: 'glow' });
|
|
527
|
+
expect(glow['config'].animation).toBe('glow');
|
|
528
|
+
glow.remove();
|
|
529
|
+
});
|
|
530
|
+
});
|
|
531
|
+
});
|