mtrl 0.3.0 → 0.3.1
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/CLAUDE.md +33 -0
- package/index.ts +0 -2
- package/package.json +3 -1
- package/src/components/navigation/index.ts +4 -1
- package/src/components/navigation/types.ts +33 -0
- package/src/components/snackbar/index.ts +7 -1
- package/src/components/snackbar/types.ts +25 -0
- package/src/components/switch/index.ts +5 -1
- package/src/components/switch/types.ts +13 -0
- package/src/components/textfield/index.ts +7 -1
- package/src/components/textfield/types.ts +36 -0
- package/test/components/badge.test.ts +545 -0
- package/test/components/bottom-app-bar.test.ts +303 -0
- package/test/components/button.test.ts +233 -0
- package/test/components/card.test.ts +560 -0
- package/test/components/carousel.test.ts +951 -0
- package/test/components/checkbox.test.ts +462 -0
- package/test/components/chip.test.ts +692 -0
- package/test/components/datepicker.test.ts +1124 -0
- package/test/components/dialog.test.ts +990 -0
- package/test/components/divider.test.ts +412 -0
- package/test/components/extended-fab.test.ts +672 -0
- package/test/components/fab.test.ts +561 -0
- package/test/components/list.test.ts +365 -0
- package/test/components/menu.test.ts +718 -0
- package/test/components/navigation.test.ts +186 -0
- package/test/components/progress.test.ts +567 -0
- package/test/components/radios.test.ts +699 -0
- package/test/components/search.test.ts +1135 -0
- package/test/components/segmented-button.test.ts +732 -0
- package/test/components/sheet.test.ts +641 -0
- package/test/components/slider.test.ts +1220 -0
- package/test/components/snackbar.test.ts +461 -0
- package/test/components/switch.test.ts +452 -0
- package/test/components/tabs.test.ts +1369 -0
- package/test/components/textfield.test.ts +400 -0
- package/test/components/timepicker.test.ts +592 -0
- package/test/components/tooltip.test.ts +630 -0
- package/test/components/top-app-bar.test.ts +566 -0
- package/test/core/dom.attributes.test.ts +148 -0
- package/test/core/dom.classes.test.ts +152 -0
- package/test/core/dom.events.test.ts +243 -0
- package/test/core/emitter.test.ts +141 -0
- package/test/core/ripple.test.ts +99 -0
- package/test/core/state.store.test.ts +189 -0
- package/test/core/utils.normalize.test.ts +61 -0
- package/test/core/utils.object.test.ts +120 -0
- package/test/setup.ts +451 -0
- package/tsconfig.json +2 -2
- package/src/components/snackbar/constants.ts +0 -26
- package/test/components/button.test.js +0 -170
- package/test/components/checkbox.test.js +0 -238
- package/test/components/list.test.js +0 -105
- package/test/components/menu.test.js +0 -385
- package/test/components/navigation.test.js +0 -227
- package/test/components/snackbar.test.js +0 -234
- package/test/components/switch.test.js +0 -186
- package/test/components/textfield.test.js +0 -314
- package/test/core/emitter.test.js +0 -141
- package/test/core/ripple.test.js +0 -66
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
// test/components/badge.test.ts
|
|
2
|
+
import { describe, test, expect, mock } from 'bun:test';
|
|
3
|
+
import { JSDOM } from 'jsdom';
|
|
4
|
+
|
|
5
|
+
// Set up JSDOM
|
|
6
|
+
const dom = new JSDOM(`<!DOCTYPE html><html><body></body></html>`);
|
|
7
|
+
global.document = dom.window.document;
|
|
8
|
+
global.window = dom.window;
|
|
9
|
+
global.Element = dom.window.Element;
|
|
10
|
+
global.HTMLElement = dom.window.HTMLElement;
|
|
11
|
+
global.Event = dom.window.Event;
|
|
12
|
+
global.CustomEvent = dom.window.CustomEvent;
|
|
13
|
+
|
|
14
|
+
// Import types directly to avoid circular dependencies
|
|
15
|
+
import type {
|
|
16
|
+
BadgeComponent,
|
|
17
|
+
BadgeConfig,
|
|
18
|
+
BadgeVariant,
|
|
19
|
+
BadgeColor,
|
|
20
|
+
BadgePosition
|
|
21
|
+
} from '../../src/components/badge/types';
|
|
22
|
+
|
|
23
|
+
// Define constants here to avoid circular dependencies
|
|
24
|
+
const BADGE_VARIANTS = {
|
|
25
|
+
SMALL: 'small',
|
|
26
|
+
LARGE: 'large'
|
|
27
|
+
} as const;
|
|
28
|
+
|
|
29
|
+
const BADGE_COLORS = {
|
|
30
|
+
ERROR: 'error',
|
|
31
|
+
PRIMARY: 'primary',
|
|
32
|
+
SECONDARY: 'secondary',
|
|
33
|
+
TERTIARY: 'tertiary',
|
|
34
|
+
SUCCESS: 'success',
|
|
35
|
+
WARNING: 'warning',
|
|
36
|
+
INFO: 'info'
|
|
37
|
+
} as const;
|
|
38
|
+
|
|
39
|
+
const BADGE_POSITIONS = {
|
|
40
|
+
TOP_RIGHT: 'top-right',
|
|
41
|
+
TOP_LEFT: 'top-left',
|
|
42
|
+
BOTTOM_RIGHT: 'bottom-right',
|
|
43
|
+
BOTTOM_LEFT: 'bottom-left'
|
|
44
|
+
} as const;
|
|
45
|
+
|
|
46
|
+
const BADGE_MAX_CHARACTERS = 4;
|
|
47
|
+
|
|
48
|
+
// Create a mock badge implementation
|
|
49
|
+
const createMockBadge = (config: BadgeConfig = {}): BadgeComponent => {
|
|
50
|
+
// Default configuration
|
|
51
|
+
const defaultConfig: BadgeConfig = {
|
|
52
|
+
variant: BADGE_VARIANTS.LARGE,
|
|
53
|
+
color: BADGE_COLORS.ERROR,
|
|
54
|
+
position: BADGE_POSITIONS.TOP_RIGHT,
|
|
55
|
+
visible: true,
|
|
56
|
+
prefix: 'mtrl'
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// Merge with user configuration
|
|
60
|
+
const mergedConfig = {
|
|
61
|
+
...defaultConfig,
|
|
62
|
+
...config
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Create main element
|
|
66
|
+
const element = document.createElement('div');
|
|
67
|
+
element.className = `${mergedConfig.prefix}-badge`;
|
|
68
|
+
|
|
69
|
+
// Add custom class if provided
|
|
70
|
+
if (mergedConfig.class) {
|
|
71
|
+
element.className += ` ${mergedConfig.class}`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Add variant class
|
|
75
|
+
element.className += ` ${mergedConfig.prefix}-badge--${mergedConfig.variant}`;
|
|
76
|
+
|
|
77
|
+
// Add color class
|
|
78
|
+
element.className += ` ${mergedConfig.prefix}-badge--${mergedConfig.color}`;
|
|
79
|
+
|
|
80
|
+
// Add position class
|
|
81
|
+
element.className += ` ${mergedConfig.prefix}-badge--${mergedConfig.position}`;
|
|
82
|
+
|
|
83
|
+
// Set visibility
|
|
84
|
+
if (!mergedConfig.visible) {
|
|
85
|
+
element.style.display = 'none';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Set label content
|
|
89
|
+
if (mergedConfig.variant === BADGE_VARIANTS.LARGE && mergedConfig.label) {
|
|
90
|
+
element.textContent = String(mergedConfig.label);
|
|
91
|
+
|
|
92
|
+
// Apply max if needed
|
|
93
|
+
if (mergedConfig.max && typeof mergedConfig.label === 'number' && mergedConfig.label > mergedConfig.max) {
|
|
94
|
+
element.textContent = `${mergedConfig.max}+`;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Create wrapper if there's a target
|
|
99
|
+
let wrapper: HTMLElement | undefined;
|
|
100
|
+
if (mergedConfig.target) {
|
|
101
|
+
wrapper = document.createElement('div');
|
|
102
|
+
wrapper.className = `${mergedConfig.prefix}-badge-wrapper`;
|
|
103
|
+
wrapper.appendChild(mergedConfig.target.cloneNode(true));
|
|
104
|
+
wrapper.appendChild(element);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Event handlers
|
|
108
|
+
const eventHandlers: Record<string, Function[]> = {};
|
|
109
|
+
|
|
110
|
+
// Create the badge instance
|
|
111
|
+
const badge: BadgeComponent = {
|
|
112
|
+
element,
|
|
113
|
+
wrapper,
|
|
114
|
+
|
|
115
|
+
getClass: (name: string) => `${mergedConfig.prefix}-badge${name ? '--' + name : ''}`,
|
|
116
|
+
|
|
117
|
+
setLabel: (label: string | number) => {
|
|
118
|
+
if (mergedConfig.variant !== BADGE_VARIANTS.LARGE) {
|
|
119
|
+
return badge;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
let content = String(label);
|
|
123
|
+
|
|
124
|
+
// Apply max if needed
|
|
125
|
+
if (mergedConfig.max && typeof label === 'number' && label > mergedConfig.max) {
|
|
126
|
+
content = `${mergedConfig.max}+`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
element.textContent = content;
|
|
130
|
+
return badge;
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
getLabel: () => element.textContent || '',
|
|
134
|
+
|
|
135
|
+
show: () => {
|
|
136
|
+
element.style.display = '';
|
|
137
|
+
return badge;
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
hide: () => {
|
|
141
|
+
element.style.display = 'none';
|
|
142
|
+
return badge;
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
toggle: (visible?: boolean) => {
|
|
146
|
+
const shouldBeVisible = visible === undefined ?
|
|
147
|
+
element.style.display === 'none' : visible;
|
|
148
|
+
|
|
149
|
+
if (shouldBeVisible) {
|
|
150
|
+
badge.show();
|
|
151
|
+
} else {
|
|
152
|
+
badge.hide();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return badge;
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
isVisible: () => element.style.display !== 'none',
|
|
159
|
+
|
|
160
|
+
setMax: (max: number) => {
|
|
161
|
+
mergedConfig.max = max;
|
|
162
|
+
|
|
163
|
+
// Update display if needed
|
|
164
|
+
if (mergedConfig.variant === BADGE_VARIANTS.LARGE &&
|
|
165
|
+
element.textContent &&
|
|
166
|
+
!isNaN(Number(element.textContent)) &&
|
|
167
|
+
Number(element.textContent) > max) {
|
|
168
|
+
element.textContent = `${max}+`;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return badge;
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
setColor: (color: BadgeColor | string) => {
|
|
175
|
+
// Remove old color class
|
|
176
|
+
element.classList.remove(`${mergedConfig.prefix}-badge--${mergedConfig.color}`);
|
|
177
|
+
|
|
178
|
+
// Update config
|
|
179
|
+
mergedConfig.color = color;
|
|
180
|
+
|
|
181
|
+
// Add new color class
|
|
182
|
+
element.classList.add(`${mergedConfig.prefix}-badge--${color}`);
|
|
183
|
+
|
|
184
|
+
return badge;
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
setVariant: (variant: BadgeVariant | string) => {
|
|
188
|
+
// Remove old variant class
|
|
189
|
+
element.classList.remove(`${mergedConfig.prefix}-badge--${mergedConfig.variant}`);
|
|
190
|
+
|
|
191
|
+
// Update config
|
|
192
|
+
mergedConfig.variant = variant;
|
|
193
|
+
|
|
194
|
+
// Add new variant class
|
|
195
|
+
element.classList.add(`${mergedConfig.prefix}-badge--${variant}`);
|
|
196
|
+
|
|
197
|
+
// Clear content if switching to small variant
|
|
198
|
+
if (variant === BADGE_VARIANTS.SMALL) {
|
|
199
|
+
element.textContent = '';
|
|
200
|
+
} else if (mergedConfig.label) {
|
|
201
|
+
badge.setLabel(mergedConfig.label);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return badge;
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
setPosition: (position: BadgePosition | string) => {
|
|
208
|
+
// Remove old position class
|
|
209
|
+
element.classList.remove(`${mergedConfig.prefix}-badge--${mergedConfig.position}`);
|
|
210
|
+
|
|
211
|
+
// Update config
|
|
212
|
+
mergedConfig.position = position;
|
|
213
|
+
|
|
214
|
+
// Add new position class
|
|
215
|
+
element.classList.add(`${mergedConfig.prefix}-badge--${position}`);
|
|
216
|
+
|
|
217
|
+
return badge;
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
attachTo: (target: HTMLElement) => {
|
|
221
|
+
// Detach first if already attached
|
|
222
|
+
if (wrapper) {
|
|
223
|
+
badge.detach();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Create wrapper
|
|
227
|
+
wrapper = document.createElement('div');
|
|
228
|
+
wrapper.className = `${mergedConfig.prefix}-badge-wrapper`;
|
|
229
|
+
|
|
230
|
+
// Clone target's style and parent connections
|
|
231
|
+
const parent = target.parentNode;
|
|
232
|
+
const nextSibling = target.nextSibling;
|
|
233
|
+
|
|
234
|
+
// Add target and badge to wrapper
|
|
235
|
+
wrapper.appendChild(target);
|
|
236
|
+
wrapper.appendChild(element);
|
|
237
|
+
|
|
238
|
+
// Insert wrapper where target was
|
|
239
|
+
if (parent) {
|
|
240
|
+
parent.insertBefore(wrapper, nextSibling);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return badge;
|
|
244
|
+
},
|
|
245
|
+
|
|
246
|
+
detach: () => {
|
|
247
|
+
if (!wrapper) {
|
|
248
|
+
return badge;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Find the target (first child of wrapper)
|
|
252
|
+
const target = wrapper.childNodes[0] as HTMLElement;
|
|
253
|
+
|
|
254
|
+
// Get wrapper's position in DOM
|
|
255
|
+
const parent = wrapper.parentNode;
|
|
256
|
+
const nextSibling = wrapper.nextSibling;
|
|
257
|
+
|
|
258
|
+
if (parent) {
|
|
259
|
+
// Move badge element to document body (or keep as-is)
|
|
260
|
+
document.body.appendChild(element);
|
|
261
|
+
|
|
262
|
+
// Move target back to original position
|
|
263
|
+
parent.insertBefore(target, nextSibling);
|
|
264
|
+
|
|
265
|
+
// Remove wrapper
|
|
266
|
+
wrapper.remove();
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
wrapper = undefined;
|
|
270
|
+
return badge;
|
|
271
|
+
},
|
|
272
|
+
|
|
273
|
+
addClass: (...classes: string[]) => {
|
|
274
|
+
element.classList.add(...classes);
|
|
275
|
+
return badge;
|
|
276
|
+
},
|
|
277
|
+
|
|
278
|
+
removeClass: (...classes: string[]) => {
|
|
279
|
+
element.classList.remove(...classes);
|
|
280
|
+
return badge;
|
|
281
|
+
},
|
|
282
|
+
|
|
283
|
+
on: (event: string, handler: Function) => {
|
|
284
|
+
if (!eventHandlers[event]) {
|
|
285
|
+
eventHandlers[event] = [];
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
eventHandlers[event].push(handler);
|
|
289
|
+
return badge;
|
|
290
|
+
},
|
|
291
|
+
|
|
292
|
+
off: (event: string, handler: Function) => {
|
|
293
|
+
if (!eventHandlers[event]) return badge;
|
|
294
|
+
|
|
295
|
+
eventHandlers[event] = eventHandlers[event].filter(h => h !== handler);
|
|
296
|
+
return badge;
|
|
297
|
+
},
|
|
298
|
+
|
|
299
|
+
destroy: () => {
|
|
300
|
+
// Clear event handlers
|
|
301
|
+
Object.keys(eventHandlers).forEach(key => {
|
|
302
|
+
eventHandlers[key] = [];
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// Remove elements
|
|
306
|
+
if (wrapper && wrapper.parentNode) {
|
|
307
|
+
wrapper.parentNode.removeChild(wrapper);
|
|
308
|
+
} else if (element.parentNode) {
|
|
309
|
+
element.parentNode.removeChild(element);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
return badge;
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
describe('Badge Component', () => {
|
|
318
|
+
test('should create a badge element', () => {
|
|
319
|
+
const badge = createMockBadge();
|
|
320
|
+
expect(badge.element).toBeDefined();
|
|
321
|
+
expect(badge.element.tagName).toBe('DIV');
|
|
322
|
+
expect(badge.element.className).toContain('mtrl-badge');
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
test('should apply variant class', () => {
|
|
326
|
+
// Test small variant
|
|
327
|
+
const smallBadge = createMockBadge({
|
|
328
|
+
variant: BADGE_VARIANTS.SMALL
|
|
329
|
+
});
|
|
330
|
+
expect(smallBadge.element.className).toContain('mtrl-badge--small');
|
|
331
|
+
|
|
332
|
+
// Test large variant
|
|
333
|
+
const largeBadge = createMockBadge({
|
|
334
|
+
variant: BADGE_VARIANTS.LARGE
|
|
335
|
+
});
|
|
336
|
+
expect(largeBadge.element.className).toContain('mtrl-badge--large');
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
test('should apply color class', () => {
|
|
340
|
+
// Test primary color
|
|
341
|
+
const primaryBadge = createMockBadge({
|
|
342
|
+
color: BADGE_COLORS.PRIMARY
|
|
343
|
+
});
|
|
344
|
+
expect(primaryBadge.element.className).toContain('mtrl-badge--primary');
|
|
345
|
+
|
|
346
|
+
// Test error color
|
|
347
|
+
const errorBadge = createMockBadge({
|
|
348
|
+
color: BADGE_COLORS.ERROR
|
|
349
|
+
});
|
|
350
|
+
expect(errorBadge.element.className).toContain('mtrl-badge--error');
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
test('should apply position class', () => {
|
|
354
|
+
// Test top-right position
|
|
355
|
+
const topRightBadge = createMockBadge({
|
|
356
|
+
position: BADGE_POSITIONS.TOP_RIGHT
|
|
357
|
+
});
|
|
358
|
+
expect(topRightBadge.element.className).toContain('mtrl-badge--top-right');
|
|
359
|
+
|
|
360
|
+
// Test bottom-left position
|
|
361
|
+
const bottomLeftBadge = createMockBadge({
|
|
362
|
+
position: BADGE_POSITIONS.BOTTOM_LEFT
|
|
363
|
+
});
|
|
364
|
+
expect(bottomLeftBadge.element.className).toContain('mtrl-badge--bottom-left');
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
test('should set label text for large badges', () => {
|
|
368
|
+
const label = '42';
|
|
369
|
+
const badge = createMockBadge({
|
|
370
|
+
variant: BADGE_VARIANTS.LARGE,
|
|
371
|
+
label
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
expect(badge.getLabel()).toBe(label);
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
test('should not set label text for small badges', () => {
|
|
378
|
+
const label = '42';
|
|
379
|
+
const badge = createMockBadge({
|
|
380
|
+
variant: BADGE_VARIANTS.SMALL,
|
|
381
|
+
label
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
expect(badge.getLabel()).toBe('');
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
test('should update badge label', () => {
|
|
388
|
+
const badge = createMockBadge({
|
|
389
|
+
variant: BADGE_VARIANTS.LARGE
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
const newLabel = '99';
|
|
393
|
+
badge.setLabel(newLabel);
|
|
394
|
+
expect(badge.getLabel()).toBe(newLabel);
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
test('should handle visibility', () => {
|
|
398
|
+
// Default is visible
|
|
399
|
+
const badge = createMockBadge();
|
|
400
|
+
expect(badge.isVisible()).toBe(true);
|
|
401
|
+
|
|
402
|
+
// Hide badge
|
|
403
|
+
badge.hide();
|
|
404
|
+
expect(badge.isVisible()).toBe(false);
|
|
405
|
+
|
|
406
|
+
// Show badge
|
|
407
|
+
badge.show();
|
|
408
|
+
expect(badge.isVisible()).toBe(true);
|
|
409
|
+
|
|
410
|
+
// Toggle badge
|
|
411
|
+
badge.toggle();
|
|
412
|
+
expect(badge.isVisible()).toBe(false);
|
|
413
|
+
|
|
414
|
+
badge.toggle();
|
|
415
|
+
expect(badge.isVisible()).toBe(true);
|
|
416
|
+
|
|
417
|
+
// Explicit toggle
|
|
418
|
+
badge.toggle(false);
|
|
419
|
+
expect(badge.isVisible()).toBe(false);
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
test('should respect max value', () => {
|
|
423
|
+
const max = 99;
|
|
424
|
+
const badge = createMockBadge({
|
|
425
|
+
variant: BADGE_VARIANTS.LARGE,
|
|
426
|
+
max,
|
|
427
|
+
label: max + 1
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
expect(badge.getLabel()).toBe('99+');
|
|
431
|
+
|
|
432
|
+
// Set a lower label
|
|
433
|
+
badge.setLabel(50);
|
|
434
|
+
expect(badge.getLabel()).toBe('50');
|
|
435
|
+
|
|
436
|
+
// Set a higher label
|
|
437
|
+
badge.setLabel(100);
|
|
438
|
+
expect(badge.getLabel()).toBe('99+');
|
|
439
|
+
|
|
440
|
+
// Change max
|
|
441
|
+
badge.setMax(999);
|
|
442
|
+
badge.setLabel(100);
|
|
443
|
+
expect(badge.getLabel()).toBe('100');
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
test('should change color', () => {
|
|
447
|
+
const badge = createMockBadge({
|
|
448
|
+
color: BADGE_COLORS.ERROR
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
expect(badge.element.className).toContain('mtrl-badge--error');
|
|
452
|
+
|
|
453
|
+
badge.setColor(BADGE_COLORS.SUCCESS);
|
|
454
|
+
expect(badge.element.className).toContain('mtrl-badge--success');
|
|
455
|
+
expect(badge.element.className).not.toContain('mtrl-badge--error');
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
test('should change variant', () => {
|
|
459
|
+
const badge = createMockBadge({
|
|
460
|
+
variant: BADGE_VARIANTS.LARGE,
|
|
461
|
+
label: '42'
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
expect(badge.element.className).toContain('mtrl-badge--large');
|
|
465
|
+
expect(badge.getLabel()).toBe('42');
|
|
466
|
+
|
|
467
|
+
badge.setVariant(BADGE_VARIANTS.SMALL);
|
|
468
|
+
expect(badge.element.className).toContain('mtrl-badge--small');
|
|
469
|
+
expect(badge.element.className).not.toContain('mtrl-badge--large');
|
|
470
|
+
expect(badge.getLabel()).toBe('');
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
test('should change position', () => {
|
|
474
|
+
const badge = createMockBadge({
|
|
475
|
+
position: BADGE_POSITIONS.TOP_RIGHT
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
expect(badge.element.className).toContain('mtrl-badge--top-right');
|
|
479
|
+
|
|
480
|
+
badge.setPosition(BADGE_POSITIONS.BOTTOM_LEFT);
|
|
481
|
+
expect(badge.element.className).toContain('mtrl-badge--bottom-left');
|
|
482
|
+
expect(badge.element.className).not.toContain('mtrl-badge--top-right');
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
test('should have attachment methods', () => {
|
|
486
|
+
const badge = createMockBadge();
|
|
487
|
+
const target = document.createElement('button');
|
|
488
|
+
|
|
489
|
+
// Check if methods exist
|
|
490
|
+
expect(typeof badge.attachTo).toBe('function');
|
|
491
|
+
expect(typeof badge.detach).toBe('function');
|
|
492
|
+
|
|
493
|
+
// Test that methods can be called without errors
|
|
494
|
+
badge.attachTo(target);
|
|
495
|
+
badge.detach();
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
test('should support wrapping with attachTo', () => {
|
|
499
|
+
const badge = createMockBadge({
|
|
500
|
+
target: document.createElement('button')
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
// A badge created with a target should have a wrapper
|
|
504
|
+
expect(badge.wrapper).toBeDefined();
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
test('should add and remove CSS classes', () => {
|
|
508
|
+
const badge = createMockBadge();
|
|
509
|
+
const customClass = 'custom-badge';
|
|
510
|
+
|
|
511
|
+
badge.addClass(customClass);
|
|
512
|
+
expect(badge.element.className).toContain(customClass);
|
|
513
|
+
|
|
514
|
+
badge.removeClass(customClass);
|
|
515
|
+
expect(badge.element.className).not.toContain(customClass);
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
test('should register event handlers', () => {
|
|
519
|
+
const badge = createMockBadge();
|
|
520
|
+
const handler = mock(() => {});
|
|
521
|
+
|
|
522
|
+
badge.on('click', handler);
|
|
523
|
+
// We don't actually trigger events in this mock implementation
|
|
524
|
+
// In a real implementation, we would test event handling here
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
test('should properly clean up resources on destroy', () => {
|
|
528
|
+
const badge = createMockBadge();
|
|
529
|
+
const parent = document.createElement('div');
|
|
530
|
+
parent.appendChild(badge.element);
|
|
531
|
+
|
|
532
|
+
badge.destroy();
|
|
533
|
+
|
|
534
|
+
expect(parent.children.length).toBe(0);
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
test('should apply custom class', () => {
|
|
538
|
+
const customClass = 'custom-badge';
|
|
539
|
+
const badge = createMockBadge({
|
|
540
|
+
class: customClass
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
expect(badge.element.className).toContain(customClass);
|
|
544
|
+
});
|
|
545
|
+
});
|