@dile/utils 3.3.5 → 3.3.7

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.
Files changed (21) hide show
  1. package/package.json +4 -4
  2. package/components/country-select/country-select.spec.js +0 -35
  3. package/components/datepicker/calendar.spec.js +0 -136
  4. package/components/datepicker/datepicker.spec.js +0 -45
  5. package/components/datepicker/datetimepicker.spec.js +0 -55
  6. package/components/graph/graph.spec.js +0 -38
  7. package/components/html-transform/html-transform.spec.js +0 -25
  8. package/components/input-phone/__screenshots__/input-phone.spec.js/dile-input-phone-Rendering-preselects-the-prefix-of-the-country-attribute-1.png +0 -0
  9. package/components/input-phone/__screenshots__/input-phone.spec.js/dile-input-phone-Value-set-from-outside-keeps-the-country-when-it-shares-the-prefix-of-the-value-1.png +0 -0
  10. package/components/input-phone/__screenshots__/input-phone.spec.js/dile-input-phone-Value-with-prefix-does-not-let-the-prefix-selector-events-escape-as-the-field-own-events-1.png +0 -0
  11. package/components/input-phone/__screenshots__/input-phone.spec.js/dile-input-phone-Value-with-prefix-updates-the-value-when-the-user-chooses-a-prefix-1.png +0 -0
  12. package/components/input-phone/input-phone.spec.js +0 -345
  13. package/components/local-time/local-time.spec.js +0 -25
  14. package/components/media-query/media-query.spec.js +0 -34
  15. package/components/network/network.spec.js +0 -33
  16. package/components/phone-prefix-select/__screenshots__/phone-prefix-select.spec.js/dile-phone-prefix-select-Initial-value-and-country-ignores-a-country-that-does-not-match-the-prefix-1.png +0 -0
  17. package/components/phone-prefix-select/__screenshots__/phone-prefix-select.spec.js/dile-phone-prefix-select-Searching-compact-gives-the-selected-field-an-accessible-name-with-the-country-1.png +0 -0
  18. package/components/phone-prefix-select/phone-prefix-select.spec.js +0 -257
  19. package/components/qr-code/qr-code.spec.js +0 -164
  20. package/components/smooth-scroll/smooth-scroll.spec.js +0 -26
  21. package/components/time-duration/time-duration.spec.js +0 -68
@@ -1,257 +0,0 @@
1
- import { describe, it, expect, afterEach } from 'vitest';
2
- import './phone-prefix-select.js';
3
-
4
- describe('dile-phone-prefix-select', () => {
5
- afterEach(() => {
6
- document.body.innerHTML = '';
7
- });
8
-
9
- function wait(ms) {
10
- return new Promise((resolve) => setTimeout(resolve, ms));
11
- }
12
-
13
- async function render(attributes = '') {
14
- document.body.innerHTML = `<dile-phone-prefix-select ${attributes}></dile-phone-prefix-select>`;
15
- const el = document.body.querySelector('dile-phone-prefix-select');
16
- await el.updateComplete;
17
- return el;
18
- }
19
-
20
- async function settle(el) {
21
- await wait(20);
22
- await el.updateComplete;
23
- }
24
-
25
- async function typeKeyword(el, keyword) {
26
- const input = el.shadowRoot.getElementById('search');
27
- input.value = keyword;
28
- input.dispatchEvent(new Event('input', { bubbles: true }));
29
- await settle(el);
30
- }
31
-
32
- function visibleOptionTexts(el) {
33
- return Array.from(el.select.shadowRoot.querySelectorAll('[role="option"]')).map(o => o.textContent.trim());
34
- }
35
-
36
- async function selectOptionByText(el, text) {
37
- const option = Array.from(el.select.shadowRoot.querySelectorAll('[role="option"]'))
38
- .find(o => o.textContent.trim() === text);
39
- option.click();
40
- await el.select.updateComplete;
41
- await el.updateComplete;
42
- }
43
-
44
- describe('Rendering', () => {
45
- it('renders the search field without requiring a slotted select', async () => {
46
- const el = await render();
47
- expect(el.shadowRoot.getElementById('search')).toBeTruthy();
48
- expect(el.sourceOptions.length).toBeGreaterThan(200);
49
- });
50
-
51
- it('uses English texts by default and Spanish ones with language="es"', async () => {
52
- const en = await render();
53
- expect(en.shadowRoot.getElementById('search').placeholder).toBe('Search a country or prefix...');
54
-
55
- const es = await render('language="es"');
56
- expect(es.shadowRoot.getElementById('search').placeholder).toBe('Busca un país o prefijo...');
57
- });
58
-
59
- it('labels the clear button of the selected country in the component language', async () => {
60
- for (const [language, expected] of [['en', 'Clear selection'], ['es', 'Borrar selección']]) {
61
- const el = await render(`language="${language}" value="+34"`);
62
- await el.updateComplete;
63
- const result = el.shadowRoot.getElementById('result');
64
- await result.updateComplete;
65
- expect(result.shadowRoot.querySelector('button').getAttribute('aria-label')).toBe(expected);
66
- }
67
- });
68
-
69
- it('keeps a custom placeholder', async () => {
70
- const el = await render('language="es" placeholder="Prefijo"');
71
- expect(el.shadowRoot.getElementById('search').placeholder).toBe('Prefijo');
72
- });
73
- });
74
-
75
- describe('Searching', () => {
76
- it('numeric keywords match the beginning of the prefix', async () => {
77
- const el = await render();
78
-
79
- await typeKeyword(el, '35');
80
-
81
- const texts = visibleOptionTexts(el);
82
- expect(texts).toContain('Portugal (+351)');
83
- expect(texts).toContain('Finland (+358)');
84
- expect(texts.every(t => /\(\+35/.test(t))).toBe(true);
85
- });
86
-
87
- it('accepts the leading "+" in numeric keywords', async () => {
88
- const el = await render();
89
-
90
- await typeKeyword(el, '+34');
91
-
92
- expect(visibleOptionTexts(el)).toEqual(['Spain (+34)']);
93
- });
94
-
95
- it('text keywords match country names ignoring case and accents', async () => {
96
- const el = await render('language="es"');
97
-
98
- await typeKeyword(el, 'MEXICO');
99
-
100
- expect(visibleOptionTexts(el)).toEqual(['México (+52)']);
101
- });
102
-
103
- it('matches alternative names of the same country', async () => {
104
- const el = await render('language="es"');
105
-
106
- await typeKeyword(el, 'myanmar');
107
-
108
- expect(visibleOptionTexts(el)).toEqual(['Birmania (+95)']);
109
- });
110
-
111
- it('prefixFirst shows the prefix before the country name', async () => {
112
- const el = await render('prefixFirst');
113
-
114
- await typeKeyword(el, '+34');
115
-
116
- expect(visibleOptionTexts(el)).toEqual(['+34 Spain']);
117
- });
118
-
119
- it('compact shows only the prefix once selected, keeping full texts in the list', async () => {
120
- const el = await render('compact value="+44"');
121
-
122
- expect(el.selectedText).toBe('+44');
123
- expect(el.sourceOptions.find(o => o.value === 'GB').text).toBe('United Kingdom (+44)');
124
- });
125
-
126
- it('compact gives the selected field an accessible name with the country', async () => {
127
- const el = await render('compact label="Prefix" value="+44"');
128
- await el.updateComplete;
129
- const result = el.shadowRoot.getElementById('result');
130
- await result.updateComplete;
131
- const input = result.shadowRoot.querySelector('input');
132
-
133
- expect(input.value).toBe('+44');
134
- expect(input.getAttribute('aria-label')).toBe('Prefix, United Kingdom (+44)');
135
- });
136
-
137
- it('lists priority countries first', async () => {
138
- const el = await render('priority-countries="US|CA"');
139
-
140
- await typeKeyword(el, '1');
141
-
142
- expect(visibleOptionTexts(el).slice(0, 2)).toEqual(['United States (+1)', 'Canada (+1)']);
143
- });
144
- });
145
-
146
- describe('Selecting', () => {
147
- it('value is the prefix and country is the ISO code of the selected option', async () => {
148
- const el = await render('name="phone_prefix"');
149
- await typeKeyword(el, 'canada');
150
-
151
- let changedDetail = null;
152
- let prefixDetail = null;
153
- el.addEventListener('element-changed', (e) => { changedDetail = e.detail; });
154
- el.addEventListener('dile-phone-prefix-changed', (e) => { prefixDetail = e.detail; });
155
-
156
- await selectOptionByText(el, 'Canada (+1)');
157
-
158
- expect(el.value).toBe('+1');
159
- expect(el.country).toBe('CA');
160
- expect(el.selectedText).toBe('Canada (+1)');
161
- expect(changedDetail).toEqual({ name: 'phone_prefix', value: '+1' });
162
- expect(prefixDetail).toEqual({ value: '+1', country: 'CA' });
163
- });
164
-
165
- it('clearing the selection resets value and country', async () => {
166
- const el = await render();
167
- await typeKeyword(el, 'spain');
168
- await selectOptionByText(el, 'Spain (+34)');
169
-
170
- el.shadowRoot.getElementById('result').dispatchEvent(new CustomEvent('dile-input-search-cleared', { bubbles: true }));
171
- await el.updateComplete;
172
-
173
- expect(el.value).toBeUndefined();
174
- expect(el.country).toBeUndefined();
175
- expect(el.isSelected).toBe(false);
176
- });
177
- });
178
-
179
- describe('Initial value and country', () => {
180
- it('resolves the main country of a shared prefix', async () => {
181
- const el = await render('value="+1"');
182
-
183
- expect(el.country).toBe('US');
184
- expect(el.selectedText).toBe('United States (+1)');
185
- });
186
-
187
- it('uses the given country when it matches the prefix', async () => {
188
- const el = await render('value="+1" country="CA"');
189
-
190
- expect(el.country).toBe('CA');
191
- expect(el.selectedText).toBe('Canada (+1)');
192
- });
193
-
194
- it('ignores a country that does not match the prefix', async () => {
195
- const el = await render('value="+44" country="CA"');
196
-
197
- expect(el.country).toBe('GB');
198
- expect(el.value).toBe('+44');
199
- });
200
-
201
- it('accepts a prefix without "+"', async () => {
202
- const el = await render('value="34"');
203
-
204
- expect(el.country).toBe('ES');
205
- expect(el.selectedText).toBe('Spain (+34)');
206
- });
207
-
208
- it('setting only the country selects its prefix', async () => {
209
- const el = await render('country="MX"');
210
- await el.updateComplete;
211
-
212
- expect(el.value).toBe('+52');
213
- expect(el.isSelected).toBe(true);
214
- expect(el.selectedText).toBe('Mexico (+52)');
215
- });
216
-
217
- it('set() keeps the current country when it shares the new prefix', async () => {
218
- const el = await render('value="+1" country="CA"');
219
-
220
- el.set('+1');
221
- await el.updateComplete;
222
- expect(el.country).toBe('CA');
223
-
224
- el.set('+33');
225
- await el.updateComplete;
226
- expect(el.country).toBe('FR');
227
- });
228
-
229
- it('clear() resets value and country', async () => {
230
- const el = await render('value="+34"');
231
-
232
- el.clear();
233
- await el.updateComplete;
234
-
235
- expect(el.value).toBeUndefined();
236
- expect(el.country).toBeUndefined();
237
- });
238
-
239
- it('updates the selected text when the language changes', async () => {
240
- const el = await render('value="+34"');
241
- expect(el.selectedText).toBe('Spain (+34)');
242
-
243
- el.language = 'es';
244
- await el.updateComplete;
245
-
246
- expect(el.selectedText).toBe('España (+34)');
247
- });
248
-
249
- it('is form-associated with the prefix as form value', async () => {
250
- document.body.innerHTML = '<form><dile-phone-prefix-select name="prefix" value="+34"></dile-phone-prefix-select></form>';
251
- const el = document.body.querySelector('dile-phone-prefix-select');
252
- await el.updateComplete;
253
-
254
- expect(new FormData(document.body.querySelector('form')).get('prefix')).toBe('+34');
255
- });
256
- });
257
- });
@@ -1,164 +0,0 @@
1
- import { describe, it, expect, afterEach } from 'vitest';
2
- import './qr-code.js';
3
-
4
- describe('dile-qr-code', () => {
5
- afterEach(() => {
6
- document.body.innerHTML = '';
7
- });
8
-
9
- async function renderQrCode(html) {
10
- document.body.innerHTML = html;
11
- const el = document.body.querySelector('dile-qr-code');
12
- await el.updateComplete;
13
- return el;
14
- }
15
-
16
- it('renders canvas with default properties', async () => {
17
- const el = await renderQrCode('<dile-qr-code></dile-qr-code>');
18
- const canvas = el.shadowRoot.querySelector('canvas');
19
- expect(canvas).not.toBeNull();
20
- expect(canvas.getAttribute('role')).toBe('img');
21
- expect(canvas.getAttribute('aria-label')).toBe('QR Code');
22
- expect(canvas.width).toBe(128);
23
- expect(canvas.height).toBe(128);
24
- expect(el.value).toBe('');
25
- expect(el.size).toBe(128);
26
- expect(el.fill).toBe('#000000');
27
- expect(el.background).toBe('#ffffff');
28
- expect(el.radius).toBe(0);
29
- expect(el.errorCorrection).toBe('M');
30
- expect(el.logo).toBe('');
31
- expect(el.logoSize).toBe(0);
32
- expect(el.logoRadius).toBe(4);
33
- expect(el.logoBackground).toBe('');
34
- expect(el.logoPadding).toBe(4);
35
- });
36
-
37
- it('sets accessible label from value or custom label attribute', async () => {
38
- const elWithValue = await renderQrCode(
39
- '<dile-qr-code value="https://example.com"></dile-qr-code>'
40
- );
41
- const canvas1 = elWithValue.shadowRoot.querySelector('canvas');
42
- expect(canvas1.getAttribute('aria-label')).toBe('https://example.com');
43
-
44
- const elWithLabel = await renderQrCode(
45
- '<dile-qr-code value="https://example.com" label="QR para pago"></dile-qr-code>'
46
- );
47
- const canvas2 = elWithLabel.shadowRoot.querySelector('canvas');
48
- expect(canvas2.getAttribute('aria-label')).toBe('QR para pago');
49
- });
50
-
51
- it('renders pixels on canvas when value is provided', async () => {
52
- const el = await renderQrCode(
53
- '<dile-qr-code value="https://dile-components.com"></dile-qr-code>'
54
- );
55
- const canvas = el.shadowRoot.querySelector('canvas');
56
- const ctx = canvas.getContext('2d');
57
- const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
58
- const hasDrawnPixels = imageData.data.some((channel) => channel !== 0);
59
- expect(hasDrawnPixels).toBe(true);
60
- });
61
-
62
- it('clears canvas when value is empty or cleared', async () => {
63
- const el = await renderQrCode(
64
- '<dile-qr-code value="https://example.com"></dile-qr-code>'
65
- );
66
- const canvas = el.shadowRoot.querySelector('canvas');
67
- const ctx = canvas.getContext('2d');
68
-
69
- // First check it has pixels
70
- let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
71
- expect(imageData.data.some((channel) => channel !== 0)).toBe(true);
72
-
73
- // Empty the value
74
- el.value = '';
75
- await el.updateComplete;
76
-
77
- imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
78
- const hasDrawnPixels = imageData.data.some((channel) => channel !== 0);
79
- expect(hasDrawnPixels).toBe(false);
80
- });
81
-
82
- it('updates canvas dimensions when size property changes', async () => {
83
- const el = await renderQrCode(
84
- '<dile-qr-code value="test" size="200"></dile-qr-code>'
85
- );
86
- const canvas = el.shadowRoot.querySelector('canvas');
87
- expect(canvas.width).toBe(200);
88
- expect(canvas.height).toBe(200);
89
-
90
- el.size = 256;
91
- await el.updateComplete;
92
- expect(canvas.width).toBe(256);
93
- expect(canvas.height).toBe(256);
94
- });
95
-
96
- it('updates canvas when fill, background, radius, or errorCorrection change', async () => {
97
- const el = await renderQrCode(
98
- '<dile-qr-code value="test" fill="#0000ff" background="#ffff00" radius="0.5" error-correction="H"></dile-qr-code>'
99
- );
100
- const canvas = el.shadowRoot.querySelector('canvas');
101
- const ctx = canvas.getContext('2d');
102
- let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
103
- expect(imageData.data.some((channel) => channel !== 0)).toBe(true);
104
-
105
- // Update fill and radius
106
- el.fill = '#ff0000';
107
- el.radius = 0.2;
108
- el.errorCorrection = 'Q';
109
- await el.updateComplete;
110
-
111
- imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
112
- expect(imageData.data.some((channel) => channel !== 0)).toBe(true);
113
- });
114
-
115
- it('handles transparent background', async () => {
116
- const el = await renderQrCode(
117
- '<dile-qr-code value="test" background="transparent"></dile-qr-code>'
118
- );
119
- const canvas = el.shadowRoot.querySelector('canvas');
120
- expect(canvas).not.toBeNull();
121
- const ctx = canvas.getContext('2d');
122
- const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
123
- expect(imageData.data.some((channel) => channel !== 0)).toBe(true);
124
- });
125
-
126
- it('renders logo on top of QR code and dispatches dile-qr-code-logo-loaded', async () => {
127
- const sampleLogo =
128
- 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20"><rect width="20" height="20" fill="rgb(255,0,0)"/></svg>';
129
-
130
- const el = await renderQrCode(
131
- `<dile-qr-code value="https://dile-components.com" logo="${sampleLogo}" logo-size="24" logo-padding="2"></dile-qr-code>`
132
- );
133
-
134
- // Wait for the logo load event if not already fired
135
- const canvas = el.shadowRoot.querySelector('canvas');
136
- expect(canvas).not.toBeNull();
137
-
138
- // Check center pixel in canvas to verify logo/badge was drawn
139
- const ctx = canvas.getContext('2d');
140
- const centerX = Math.floor(canvas.width / 2);
141
- const centerY = Math.floor(canvas.height / 2);
142
- const centerPixel = ctx.getImageData(centerX, centerY, 1, 1).data;
143
- // Red channel from red svg rect
144
- expect(centerPixel[0]).toBe(255);
145
- });
146
-
147
- it('handles logo load error gracefully and dispatches dile-qr-code-logo-error', async () => {
148
- document.body.innerHTML = '';
149
- const el = document.createElement('dile-qr-code');
150
- el.value = 'https://dile-components.com';
151
-
152
- const errorPromise = new Promise((resolve) => {
153
- el.addEventListener('dile-qr-code-logo-error', resolve, { once: true });
154
- });
155
-
156
- el.logo = 'data:image/invalid;base64,broken';
157
- document.body.appendChild(el);
158
- await el.updateComplete;
159
-
160
- const event = await errorPromise;
161
- expect(event).toBeDefined();
162
- expect(el.shadowRoot.querySelector('canvas')).not.toBeNull();
163
- });
164
- });
@@ -1,26 +0,0 @@
1
- import { describe, it, expect, afterEach } from 'vitest';
2
- import './smooth-scroll.js';
3
-
4
- describe('dile-smooth-scroll', () => {
5
- afterEach(() => {
6
- document.body.innerHTML = '';
7
- });
8
-
9
- async function renderSmoothScroll(html) {
10
- document.body.innerHTML = html;
11
- const el = document.body.querySelector('dile-smooth-scroll');
12
- await el.updateComplete;
13
- return el;
14
- }
15
-
16
- it('renders without throwing', async () => {
17
- const el = await renderSmoothScroll('<dile-smooth-scroll></dile-smooth-scroll>');
18
- expect(el).toBeTruthy();
19
- });
20
-
21
- it('exposes smooth scroll methods without throwing when invoked', async () => {
22
- const el = await renderSmoothScroll('<dile-smooth-scroll></dile-smooth-scroll>');
23
- expect(typeof el.smoothScrollToTop).toBe('function');
24
- expect(() => el.smoothScrollToTop()).not.toThrow();
25
- });
26
- });
@@ -1,68 +0,0 @@
1
- import { describe, it, expect, afterEach } from 'vitest';
2
- import './time-duration.js';
3
-
4
- describe('dile-time-duration', () => {
5
- afterEach(() => {
6
- document.body.innerHTML = '';
7
- });
8
-
9
- async function renderTimeDuration(html) {
10
- document.body.innerHTML = html;
11
- const el = document.body.querySelector('dile-time-duration');
12
- await el.updateComplete;
13
- return el;
14
- }
15
-
16
- it('renders 80 seconds as "1m 20s"', async () => {
17
- const el = await renderTimeDuration('<dile-time-duration seconds="80"></dile-time-duration>');
18
- const timeText = el.shadowRoot.querySelector('.time-text').textContent;
19
- expect(timeText).toContain('1m');
20
- expect(timeText).toContain('20s');
21
- });
22
-
23
- it('renders 3665 seconds as "1h 1m"', async () => {
24
- const el = await renderTimeDuration('<dile-time-duration seconds="3665"></dile-time-duration>');
25
- const timeText = el.shadowRoot.querySelector('.time-text').textContent;
26
- expect(timeText).toContain('1h');
27
- expect(timeText).toContain('1m');
28
- });
29
-
30
- it('renders with extended format', async () => {
31
- const el = await renderTimeDuration('<dile-time-duration seconds="3665" extended></dile-time-duration>');
32
- const timeText = el.shadowRoot.querySelector('.time-text').textContent;
33
- expect(timeText).toContain('hour');
34
- expect(timeText).toContain('minute');
35
- });
36
-
37
- it('renders with Spanish language', async () => {
38
- const el = await renderTimeDuration('<dile-time-duration seconds="3665" extended language="es"></dile-time-duration>');
39
- const timeText = el.shadowRoot.querySelector('.time-text').textContent;
40
- expect(timeText).toContain('hora');
41
- expect(timeText).toContain('minuto');
42
- });
43
-
44
- it('renders with days', async () => {
45
- const el = await renderTimeDuration('<dile-time-duration seconds="90061"></dile-time-duration>');
46
- const timeText = el.shadowRoot.querySelector('.time-text').textContent;
47
- expect(timeText).toContain('1d');
48
- expect(timeText).toContain('1h');
49
- });
50
-
51
- it('respects precision attribute', async () => {
52
- const el = await renderTimeDuration('<dile-time-duration seconds="80" precision="seconds"></dile-time-duration>');
53
- const timeText = el.shadowRoot.querySelector('.time-text').textContent;
54
- expect(timeText).toContain('1m');
55
- expect(timeText).toContain('20s');
56
- });
57
-
58
- it('renders 0 seconds with smallest allowed unit', async () => {
59
- const el = await renderTimeDuration('<dile-time-duration seconds="0"></dile-time-duration>');
60
- const timeText = el.shadowRoot.querySelector('.time-text').textContent;
61
- expect(timeText).toContain('0s');
62
- });
63
-
64
- it('displays custom icon', async () => {
65
- const el = await renderTimeDuration('<dile-time-duration seconds="80" icon="material.timer"></dile-time-duration>');
66
- expect(el.shadowRoot.querySelector('dile-iconlib').getAttribute('icon')).toBe('material.timer');
67
- });
68
- });