@block-auth.io/angular 0.2.10 → 0.3.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.
@@ -1,10 +1,11 @@
1
- import { describe, it, expect, afterEach } from 'vitest';
1
+ import { describe, it, expect, afterEach, vi } from 'vitest';
2
2
  import { Component } from '@angular/core';
3
3
  import { render, screen, fireEvent } from '@testing-library/angular';
4
- import { setLocale } from '@block-auth.io/core';
4
+ import { setLocale, type TxnDataParam } from '@block-auth.io/core';
5
5
  import {
6
6
  SolicitedDataModalComponent,
7
7
  type ParamChange,
8
+ type ShareChange,
8
9
  } from './solicited-data-modal.component';
9
10
 
10
11
  // Port de packages/react/src/components/txns/internals/SolicitedDataModal.test.tsx
@@ -45,6 +46,30 @@ describe('SolicitedDataModal', () => {
45
46
  expect(screen.getByText('Opcional')).toBeDefined();
46
47
  });
47
48
 
49
+ it('marca los obligatorios y los opcionales con texto discreto en lugar del asterisco', async () => {
50
+ @Component({
51
+ standalone: true,
52
+ imports: [SolicitedDataModalComponent],
53
+ template: `<ba-solicited-data-modal
54
+ [requiredParams]="['users-email']"
55
+ [optionalParams]="['users-phone']"
56
+ />`,
57
+ })
58
+ class Host {}
59
+ await render(Host);
60
+ const emailLabel = document.querySelector(
61
+ 'label[for="solicited-data-users-email"]'
62
+ ) as HTMLLabelElement;
63
+ const phoneLabel = document.querySelector(
64
+ 'label[for="solicited-data-users-phone"]'
65
+ ) as HTMLLabelElement;
66
+ expect(emailLabel.querySelector('.bal-ba-glass-label-required')?.textContent).toBe('Required');
67
+ expect(phoneLabel.querySelector('.bal-ba-glass-label-optional')?.textContent).toBe('Optional');
68
+ expect(screen.queryByText('*')).toBeNull();
69
+ expect(screen.getByLabelText(/Email\s*Required/)).toBe(fieldInput('users-email'));
70
+ expect(document.querySelector('.bal-ba-glass-badge')).toBeNull();
71
+ });
72
+
48
73
  it('emite paramChange al escribir y validationChange según validez', async () => {
49
74
  const paramChanges: ParamChange[] = [];
50
75
  const validationChanges: boolean[] = [];
@@ -97,8 +122,540 @@ describe('SolicitedDataModal', () => {
97
122
  await render(Host);
98
123
  const input = screen.getByRole('textbox');
99
124
  await fireEvent.blur(input);
125
+ expect(screen.getByText('Enter a valid email (e.g. name@domain.com)')).toBeDefined();
126
+ });
127
+ });
128
+
129
+ const serverParams: TxnDataParam[] = [
130
+ { slug: 'users-firstname', mode: 'required', status: 'shared', value: 'Ana' },
131
+ {
132
+ slug: 'users-lastname',
133
+ mode: 'optional',
134
+ status: 'granted',
135
+ value: 'Pérez',
136
+ },
137
+ {
138
+ slug: 'users-email',
139
+ mode: 'required',
140
+ status: 'consent',
141
+ value: 'ana@block-auth.io',
142
+ },
143
+ { slug: 'users-phone', mode: 'required', status: 'missing', value: null },
144
+ ];
145
+
146
+ const fieldInput = (slug: string) =>
147
+ document.getElementById(`solicited-data-${slug}`) as HTMLInputElement;
148
+ const shareSwitch = (slug: string) =>
149
+ document.getElementById(`solicited-data-share-${slug}`) as HTMLButtonElement;
150
+ const isShared = (slug: string) => shareSwitch(slug).getAttribute('aria-checked') === 'true';
151
+
152
+ describe('SolicitedDataModal con los datos pedidos por el servidor', () => {
153
+ afterEach(() => setLocale('en'));
154
+
155
+ it('muestra todos los datos con su valor de perfil y el interruptor Ceder', async () => {
156
+ @Component({
157
+ standalone: true,
158
+ imports: [SolicitedDataModalComponent],
159
+ template: `<ba-solicited-data-modal [params]="params" />`,
160
+ })
161
+ class Host {
162
+ params = serverParams;
163
+ }
164
+ await render(Host);
165
+ expect(screen.getByText('First Name')).toBeDefined();
166
+ expect(screen.getByText('Last Name')).toBeDefined();
167
+ expect(fieldInput('users-firstname').value).toBe('Ana');
168
+ expect(fieldInput('users-lastname').value).toBe('Pérez');
169
+ expect(fieldInput('users-email').value).toBe('ana@block-auth.io');
170
+ expect(fieldInput('users-phone').value).toBe('');
171
+ expect(fieldInput('users-phone').type).toBe('tel');
172
+ expect(shareSwitch('users-email').getAttribute('role')).toBe('switch');
173
+ expect(isShared('users-firstname')).toBe(true);
174
+ expect(shareSwitch('users-firstname').disabled).toBe(false);
175
+ expect(isShared('users-lastname')).toBe(true);
176
+ expect(isShared('users-email')).toBe(false);
177
+ expect(isShared('users-phone')).toBe(false);
178
+ expect(fieldInput('users-firstname').readOnly).toBe(false);
179
+ expect(screen.getByLabelText('Clear field First Name')).toBeDefined();
180
+ });
181
+
182
+ it('emite shareChange al activar Ceder', async () => {
183
+ const shareChanges: ShareChange[] = [];
184
+ @Component({
185
+ standalone: true,
186
+ imports: [SolicitedDataModalComponent],
187
+ template: `<ba-solicited-data-modal [params]="params" (shareChange)="sc($event)" />`,
188
+ })
189
+ class Host {
190
+ params = serverParams;
191
+ sc = (e: ShareChange) => shareChanges.push(e);
192
+ }
193
+ await render(Host);
194
+ await fireEvent.click(screen.getByRole('switch', { name: 'Share Email' }));
195
+ expect(shareChanges[shareChanges.length - 1]).toEqual({
196
+ slug: 'users-email',
197
+ shared: true,
198
+ });
199
+ });
200
+
201
+ it('emite shareChange al desactivar Ceder', async () => {
202
+ const shareChanges: ShareChange[] = [];
203
+ @Component({
204
+ standalone: true,
205
+ imports: [SolicitedDataModalComponent],
206
+ template: `<ba-solicited-data-modal [params]="params" (shareChange)="sc($event)" />`,
207
+ })
208
+ class Host {
209
+ params = serverParams;
210
+ sc = (e: ShareChange) => shareChanges.push(e);
211
+ }
212
+ await render(Host);
213
+ await fireEvent.click(screen.getByRole('switch', { name: 'Share Last Name' }));
214
+ expect(shareChanges[shareChanges.length - 1]).toEqual({
215
+ slug: 'users-lastname',
216
+ shared: false,
217
+ });
218
+ });
219
+
220
+ it('muestra la x para limpiar solo si el campo tiene contenido', async () => {
221
+ const paramChanges: ParamChange[] = [];
222
+ @Component({
223
+ standalone: true,
224
+ imports: [SolicitedDataModalComponent],
225
+ template: `<ba-solicited-data-modal [params]="params" (paramChange)="pc($event)" />`,
226
+ })
227
+ class Host {
228
+ params = serverParams;
229
+ pc = (e: ParamChange) => paramChanges.push(e);
230
+ }
231
+ await render(Host);
232
+ expect(screen.queryByLabelText('Clear field Phone')).toBeNull();
233
+ await fireEvent.click(screen.getByLabelText('Clear field Email'));
234
+ expect(paramChanges[paramChanges.length - 1]).toEqual({
235
+ slug: 'users-email',
236
+ value: '',
237
+ });
238
+ expect(document.activeElement).toBe(fieldInput('users-email'));
239
+ });
240
+
241
+ it('ofrece Guardar y Deshacer cuando el valor cambia', async () => {
242
+ const saved: string[] = [];
243
+ const undone: string[] = [];
244
+ @Component({
245
+ standalone: true,
246
+ imports: [SolicitedDataModalComponent],
247
+ template: `<ba-solicited-data-modal
248
+ [params]="params"
249
+ [userParamValues]="{ 'users-email': 'otra@block-auth.io' }"
250
+ [sharedParams]="{ 'users-email': true }"
251
+ (saveParam)="sp($event)"
252
+ (undoParam)="up($event)"
253
+ />`,
254
+ })
255
+ class Host {
256
+ params = serverParams;
257
+ sp = (slug: string) => saved.push(slug);
258
+ up = (slug: string) => undone.push(slug);
259
+ }
260
+ await render(Host);
261
+ expect(screen.getByText('Save or undo the change')).toBeDefined();
262
+ await fireEvent.click(screen.getByText('Save'));
263
+ expect(saved).toEqual(['users-email']);
264
+ await fireEvent.click(screen.getByText('Undo'));
265
+ expect(undone).toEqual(['users-email']);
266
+ });
267
+
268
+ it('indica que el valor guardado irá al perfil y no permite guardar uno inválido', async () => {
269
+ @Component({
270
+ standalone: true,
271
+ imports: [SolicitedDataModalComponent],
272
+ template: `<ba-solicited-data-modal
273
+ [params]="params"
274
+ [userParamValues]="{
275
+ 'users-email': 'otra@block-auth.io',
276
+ 'users-phone': 'abc'
277
+ }"
278
+ [savedParams]="{ 'users-email': 'otra@block-auth.io' }"
279
+ [sharedParams]="{ 'users-email': true }"
280
+ />`,
281
+ })
282
+ class Host {
283
+ params = serverParams;
284
+ }
285
+ await render(Host);
286
+ expect(screen.getByText('It will be saved to your profile on accept')).toBeDefined();
100
287
  expect(
101
- screen.getByText('Enter a valid email (e.g. name@domain.com)'),
102
- ).toBeDefined();
288
+ (document.getElementById('solicited-data-save-users-phone') as HTMLButtonElement).disabled
289
+ ).toBe(true);
290
+ await fireEvent.blur(fieldInput('users-phone'));
291
+ expect(screen.getByText(/valid phone/i)).toBeDefined();
292
+ expect(fieldInput('users-phone').getAttribute('aria-invalid')).toBe('true');
293
+ expect(fieldInput('users-phone').getAttribute('aria-describedby')).toBe(
294
+ 'solicited-data-users-phone-error'
295
+ );
296
+ });
297
+
298
+ it('avisa mientras falte un obligatorio y muestra el error del servidor', async () => {
299
+ const validationChanges: boolean[] = [];
300
+ @Component({
301
+ standalone: true,
302
+ imports: [SolicitedDataModalComponent],
303
+ template: `<ba-solicited-data-modal
304
+ [params]="params"
305
+ [sharedParams]="{ 'users-email': true }"
306
+ errorTxt="Server error"
307
+ (validationChange)="vc($event)"
308
+ />`,
309
+ })
310
+ class Host {
311
+ params = serverParams;
312
+ vc = (v: boolean) => validationChanges.push(v);
313
+ }
314
+ await render(Host);
315
+ const notice = document.getElementById('solicited-data-notice')!;
316
+ expect(notice.textContent?.trim()).toBe('Authorize or fill in the required data to continue');
317
+ expect(notice.querySelector('.bal-ba-glass-notice-icon')?.getAttribute('aria-hidden')).toBe(
318
+ 'true'
319
+ );
320
+ expect(validationChanges[validationChanges.length - 1]).toBe(false);
321
+ expect(screen.getByRole('alert').textContent?.trim()).toBe('Server error');
322
+ });
323
+
324
+ it('oculta el aviso cuando no falta ningún obligatorio', async () => {
325
+ @Component({
326
+ standalone: true,
327
+ imports: [SolicitedDataModalComponent],
328
+ template: `<ba-solicited-data-modal
329
+ [requiredParams]="['users-email']"
330
+ [userParamValues]="{ 'users-email': 'user@test.com' }"
331
+ />`,
332
+ })
333
+ class Host {}
334
+ await render(Host);
335
+ expect(document.getElementById('solicited-data-notice')).toBeNull();
336
+ });
337
+ });
338
+
339
+ const card = (slug: string) => fieldInput(slug).closest('.bal-ba-glass-field') as HTMLElement;
340
+ const isPending = (slug: string) => card(slug).classList.contains('bal-ba-glass-field-pending');
341
+
342
+ describe('SolicitedDataModal campos vacíos y pendientes', () => {
343
+ afterEach(() => setLocale('en'));
344
+
345
+ it('destaca solo las tarjetas obligatorias pendientes', async () => {
346
+ @Component({
347
+ standalone: true,
348
+ imports: [SolicitedDataModalComponent],
349
+ template: `<ba-solicited-data-modal
350
+ [params]="params"
351
+ [userParamValues]="{ 'users-lastname': '' }"
352
+ />`,
353
+ })
354
+ class Host {
355
+ params = serverParams;
356
+ }
357
+ await render(Host);
358
+ expect(isPending('users-email')).toBe(true);
359
+ expect(isPending('users-phone')).toBe(true);
360
+ expect(isPending('users-firstname')).toBe(false);
361
+ expect(isPending('users-lastname')).toBe(false);
362
+ });
363
+
364
+ it('deja de destacar la tarjeta al resolverse', async () => {
365
+ @Component({
366
+ standalone: true,
367
+ imports: [SolicitedDataModalComponent],
368
+ template: `<ba-solicited-data-modal [params]="params" [sharedParams]="shared" />`,
369
+ })
370
+ class Host {
371
+ params = serverParams;
372
+ shared: Record<string, boolean> = {};
373
+ }
374
+ const { fixture } = await render(Host);
375
+ expect(isPending('users-email')).toBe(true);
376
+ fixture.componentInstance.shared = { 'users-email': true };
377
+ fixture.detectChanges();
378
+ expect(isPending('users-email')).toBe(false);
379
+ });
380
+
381
+ it('deshabilita y desmarca Ceder si el campo está vacío', async () => {
382
+ const shareChanges: ShareChange[] = [];
383
+ @Component({
384
+ standalone: true,
385
+ imports: [SolicitedDataModalComponent],
386
+ template: `<ba-solicited-data-modal
387
+ [params]="params"
388
+ [userParamValues]="{ 'users-lastname': ' ' }"
389
+ (shareChange)="sc($event)"
390
+ />`,
391
+ })
392
+ class Host {
393
+ params = serverParams;
394
+ sc = (e: ShareChange) => shareChanges.push(e);
395
+ }
396
+ await render(Host);
397
+ expect(shareSwitch('users-phone').disabled).toBe(true);
398
+ expect(isShared('users-lastname')).toBe(false);
399
+ expect(shareSwitch('users-lastname').disabled).toBe(true);
400
+ await fireEvent.click(shareSwitch('users-lastname'));
401
+ expect(shareChanges).toEqual([]);
402
+ expect(shareSwitch('users-email').disabled).toBe(false);
403
+ });
404
+
405
+ it('permite guardar un campo vaciado y avisa de que no se cederá', async () => {
406
+ const saved: string[] = [];
407
+ @Component({
408
+ standalone: true,
409
+ imports: [SolicitedDataModalComponent],
410
+ template: `<ba-solicited-data-modal
411
+ [params]="params"
412
+ [userParamValues]="{ 'users-lastname': '' }"
413
+ [savedParams]="savedParams"
414
+ (saveParam)="sp($event)"
415
+ />`,
416
+ })
417
+ class Host {
418
+ params = serverParams;
419
+ savedParams: Record<string, string> = {};
420
+ sp = (slug: string) => saved.push(slug);
421
+ }
422
+ const { fixture } = await render(Host);
423
+ const save = document.getElementById('solicited-data-save-users-lastname') as HTMLButtonElement;
424
+ expect(save.disabled).toBe(false);
425
+ await fireEvent.click(save);
426
+ expect(saved).toEqual(['users-lastname']);
427
+ fixture.componentInstance.savedParams = { 'users-lastname': '' };
428
+ fixture.detectChanges();
429
+ expect(screen.getByText('This data will not be shared')).toBeDefined();
430
+ expect(
431
+ screen
432
+ .getByText('This data will not be shared')
433
+ .classList.contains('bal-ba-glass-hint-success')
434
+ ).toBe(false);
435
+ expect(isShared('users-lastname')).toBe(false);
436
+ expect(shareSwitch('users-lastname').disabled).toBe(true);
437
+ expect(document.getElementById('solicited-data-save-users-lastname')).toBeNull();
438
+ });
439
+
440
+ it('coloca Deshacer a la izquierda y Guardar a la derecha', async () => {
441
+ @Component({
442
+ standalone: true,
443
+ imports: [SolicitedDataModalComponent],
444
+ template: `<ba-solicited-data-modal
445
+ [params]="params"
446
+ [userParamValues]="{ 'users-email': 'otra@block-auth.io' }"
447
+ />`,
448
+ })
449
+ class Host {
450
+ params = serverParams;
451
+ }
452
+ await render(Host);
453
+ const buttons = Array.from(
454
+ document.querySelectorAll('.bal-ba-glass-decision-actions button')
455
+ ).map((button) => button.id);
456
+ expect(buttons).toEqual(['solicited-data-undo-users-email', 'solicited-data-save-users-email']);
457
+ });
458
+
459
+ it('traduce el aviso de dato no cedido', async () => {
460
+ setLocale('es');
461
+ @Component({
462
+ standalone: true,
463
+ imports: [SolicitedDataModalComponent],
464
+ template: `<ba-solicited-data-modal
465
+ [params]="params"
466
+ [userParamValues]="{ 'users-lastname': '' }"
467
+ [savedParams]="{ 'users-lastname': '' }"
468
+ />`,
469
+ })
470
+ class Host {
471
+ params = serverParams;
472
+ }
473
+ await render(Host);
474
+ expect(screen.getByText('Este dato no se cederá')).toBeDefined();
475
+ });
476
+ });
477
+
478
+ describe('SolicitedDataModal scroll de la lista', () => {
479
+ afterEach(() => vi.restoreAllMocks());
480
+
481
+ const scrollArea = () => document.querySelector('.bal-ba-glass-scroll') as HTMLElement;
482
+
483
+ @Component({
484
+ standalone: true,
485
+ imports: [SolicitedDataModalComponent],
486
+ template: `<ba-solicited-data-modal [params]="params" />`,
487
+ })
488
+ class Host {
489
+ params = serverParams;
490
+ }
491
+
492
+ it('no difumina los bordes si el contenido cabe', async () => {
493
+ await render(Host);
494
+ expect(scrollArea().classList.contains('bal-ba-glass-scroll-overflow')).toBe(false);
495
+ });
496
+
497
+ it('difumina los bordes solo cuando hay desbordamiento', async () => {
498
+ vi.spyOn(HTMLElement.prototype, 'scrollHeight', 'get').mockReturnValue(600);
499
+ vi.spyOn(HTMLElement.prototype, 'clientHeight', 'get').mockReturnValue(400);
500
+ const { fixture } = await render(Host);
501
+ fixture.detectChanges();
502
+ expect(scrollArea().classList.contains('bal-ba-glass-scroll-overflow')).toBe(true);
503
+ });
504
+ });
505
+
506
+ describe('SolicitedDataModal botón de cerrar', () => {
507
+ afterEach(() => setLocale('en'));
508
+
509
+ it('emite closed al pulsar el botón de cerrar', async () => {
510
+ let closes = 0;
511
+ @Component({
512
+ standalone: true,
513
+ imports: [SolicitedDataModalComponent],
514
+ template: `<ba-solicited-data-modal
515
+ [requiredParams]="['users-email']"
516
+ [closable]="true"
517
+ (closed)="onClosed()"
518
+ />`,
519
+ })
520
+ class Host {
521
+ onClosed = () => closes++;
522
+ }
523
+ await render(Host);
524
+ await fireEvent.click(screen.getByRole('button', { name: 'Close' }));
525
+ expect(closes).toBe(1);
526
+ });
527
+
528
+ it('traduce el botón de cerrar', async () => {
529
+ setLocale('es');
530
+ @Component({
531
+ standalone: true,
532
+ imports: [SolicitedDataModalComponent],
533
+ template: `<ba-solicited-data-modal [requiredParams]="['users-email']" [closable]="true" />`,
534
+ })
535
+ class Host {}
536
+ await render(Host);
537
+ expect(screen.getByRole('button', { name: 'Cerrar' })).toBeDefined();
538
+ });
539
+
540
+ it('Aceptar abajo emite accepted sin aceptar el login', async () => {
541
+ let accepts = 0;
542
+ @Component({
543
+ standalone: true,
544
+ imports: [SolicitedDataModalComponent],
545
+ template: `<ba-solicited-data-modal
546
+ [requiredParams]="['users-email']"
547
+ [closable]="true"
548
+ [acceptable]="true"
549
+ (accepted)="onAccepted()"
550
+ />`,
551
+ })
552
+ class Host {
553
+ onAccepted = () => accepts++;
554
+ }
555
+ await render(Host);
556
+ const accept = screen.getByRole('button', { name: 'Accept' });
557
+ expect(accept.id).toBe('solicited-data-accept');
558
+ expect(accept.closest('.bal-ba-glass-scroll')).toBeNull();
559
+ expect(accept.parentElement?.lastElementChild).toBe(accept);
560
+ await fireEvent.click(accept);
561
+ expect(accepts).toBe(1);
562
+ });
563
+
564
+ it('traduce el botón Aceptar', async () => {
565
+ setLocale('es');
566
+ @Component({
567
+ standalone: true,
568
+ imports: [SolicitedDataModalComponent],
569
+ template: `<ba-solicited-data-modal
570
+ [requiredParams]="['users-email']"
571
+ [acceptable]="true"
572
+ />`,
573
+ })
574
+ class Host {}
575
+ await render(Host);
576
+ expect(screen.getByRole('button', { name: 'Aceptar' })).toBeDefined();
577
+ });
578
+
579
+ it('no muestra Aceptar si no es aceptable', async () => {
580
+ @Component({
581
+ standalone: true,
582
+ imports: [SolicitedDataModalComponent],
583
+ template: `<ba-solicited-data-modal [requiredParams]="['users-email']" />`,
584
+ })
585
+ class Host {}
586
+ await render(Host);
587
+ expect(document.getElementById('solicited-data-accept')).toBeNull();
588
+ });
589
+
590
+ it('no muestra el botón de cerrar si no es cerrable', async () => {
591
+ @Component({
592
+ standalone: true,
593
+ imports: [SolicitedDataModalComponent],
594
+ template: `<ba-solicited-data-modal [requiredParams]="['users-email']" />`,
595
+ })
596
+ class Host {}
597
+ await render(Host);
598
+ expect(screen.queryByRole('button', { name: 'Close' })).toBeNull();
599
+ });
600
+ });
601
+
602
+ describe('SolicitedDataModal sin respuesta del servidor', () => {
603
+ it('muestra los campos de uiConfig sin Ceder ni Guardar', async () => {
604
+ @Component({
605
+ standalone: true,
606
+ imports: [SolicitedDataModalComponent],
607
+ template: `<ba-solicited-data-modal
608
+ [requiredParams]="['users-email']"
609
+ [userParamValues]="{ 'users-email': 'ana@block-auth.io' }"
610
+ />`,
611
+ })
612
+ class Host {}
613
+ await render(Host);
614
+ expect(fieldInput('users-email').value).toBe('ana@block-auth.io');
615
+ expect(shareSwitch('users-email')).toBeNull();
616
+ expect(screen.queryByText('Save')).toBeNull();
617
+ expect(screen.getByLabelText('Clear field Email')).toBeDefined();
618
+ });
619
+ });
620
+
621
+ describe('SolicitedDataModal teléfono', () => {
622
+ const phoneParams = (status: 'shared' | 'consent'): TxnDataParam[] => [
623
+ { slug: 'users-phone', mode: 'required', status, value: '+34634343343' },
624
+ ];
625
+
626
+ it('el teléfono shared se edita con el selector de país', async () => {
627
+ await render(SolicitedDataModalComponent, {
628
+ componentInputs: { params: phoneParams('shared') },
629
+ });
630
+ const phone = document.getElementById('solicited-data-users-phone') as HTMLInputElement;
631
+ expect(phone.value).toBe('634 34 33 43');
632
+ expect(phone.readOnly).toBe(false);
633
+ expect(document.getElementById('solicited-data-users-phone-country')).not.toBeNull();
634
+ expect(screen.getByLabelText('Clear field Phone')).toBeDefined();
635
+ });
636
+
637
+ it('separa país y número y emite el valor en E.164', async () => {
638
+ const paramChanges: ParamChange[] = [];
639
+ await render(SolicitedDataModalComponent, {
640
+ componentInputs: { params: phoneParams('consent') },
641
+ on: { paramChange: (change: ParamChange) => paramChanges.push(change) },
642
+ });
643
+ const country = document.getElementById(
644
+ 'solicited-data-users-phone-country'
645
+ ) as HTMLButtonElement;
646
+ const phone = document.getElementById('solicited-data-users-phone') as HTMLInputElement;
647
+ expect(country.textContent).toContain('+34');
648
+ expect(phone.value).toBe('634 34 33 43');
649
+ expect((screen.getByText('Phone').closest('label') as HTMLLabelElement).htmlFor).toBe(
650
+ 'solicited-data-users-phone'
651
+ );
652
+ await fireEvent.input(phone, { target: { value: '634 34 33 44' } });
653
+ expect(paramChanges[paramChanges.length - 1]).toEqual({
654
+ slug: 'users-phone',
655
+ value: '+34634343344',
656
+ });
657
+ await fireEvent.click(screen.getByLabelText('Clear field Phone'));
658
+ expect(paramChanges[paramChanges.length - 1]).toEqual({ slug: 'users-phone', value: '' });
659
+ expect(document.activeElement).toBe(phone);
103
660
  });
104
661
  });