wuic-framework-lib 1.7.12 → 1.7.13
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/fesm2022/{wuic-framework-lib-chart-list.component-C9rj-6-8.mjs → wuic-framework-lib-chart-list.component-BIpu6QY3.mjs} +4 -2
- package/fesm2022/{wuic-framework-lib-code-editor.component-CTI_gqvB.mjs → wuic-framework-lib-code-editor.component-P181nIU9.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-designer.component-67PCnDYC.mjs → wuic-framework-lib-designer.component-DZ7C9ygB.mjs} +4 -2
- package/fesm2022/{wuic-framework-lib-first-run-wizard.component-Bg41Xfht.mjs → wuic-framework-lib-first-run-wizard.component-CGCBKpdv.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-framework-docs.component-BLxQmoDZ.mjs → wuic-framework-lib-framework-docs.component-CX4DuW-Q.mjs} +484 -3
- package/fesm2022/{wuic-framework-lib-pivot-builder.component-Dg-xWzxO.mjs → wuic-framework-lib-pivot-builder.component-CrJUJDxX.mjs} +5 -2
- package/fesm2022/{wuic-framework-lib-prompt-dialog-fallback-host.component-BB0AhnsE.mjs → wuic-framework-lib-prompt-dialog-fallback-host.component-fk_u2CFB.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-report-designer.component-9_M4MA2p.mjs → wuic-framework-lib-report-designer.component-urOz2Pq8.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-report-scaffold-dialog.component-BsKSP1Dk.mjs → wuic-framework-lib-report-scaffold-dialog.component-okexsstE.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-report-viewer.component-C5EAoGOx.mjs → wuic-framework-lib-report-viewer.component-CCpUOyb4.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-scene3d-designer.component-CkoU_J5j.mjs → wuic-framework-lib-scene3d-designer.component-DLcruDYB.mjs} +3 -3
- package/fesm2022/{wuic-framework-lib-scene3d-light-baker-gpu-CjTKHG3s.mjs → wuic-framework-lib-scene3d-light-baker-gpu-Dj22rwPQ.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-scene3d-viewer.component-Dt0fvwFX.mjs → wuic-framework-lib-scene3d-viewer.component-DA47y9vo.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-scheduler-list.component-CEMQJrsN.mjs → wuic-framework-lib-scheduler-list.component-BXx84Cc7.mjs} +24 -16
- package/fesm2022/{wuic-framework-lib-spreadsheet-list-sf.component-Cgmf9tb1.mjs → wuic-framework-lib-spreadsheet-list-sf.component-v7rE3WW_.mjs} +4 -2
- package/fesm2022/{wuic-framework-lib-timeline-list.component-B_bRKY_H.mjs → wuic-framework-lib-timeline-list.component-CP9PpRQB.mjs} +6 -4
- package/fesm2022/{wuic-framework-lib-workflow-designer.component-DVEL_aHg.mjs → wuic-framework-lib-workflow-designer.component-CETZSZzu.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-wuic-framework-lib-Ds_oD2In.mjs → wuic-framework-lib-wuic-framework-lib-CRUM1gc_.mjs} +284 -34
- package/fesm2022/wuic-framework-lib.mjs +1 -1
- package/package.json +1 -1
- package/types/wuic-framework-lib.d.ts +87 -2
|
@@ -16,12 +16,12 @@ import * as i1$3 from 'primeng/image';
|
|
|
16
16
|
import { ImageModule } from 'primeng/image';
|
|
17
17
|
import * as i8$1 from '@ngx-translate/core';
|
|
18
18
|
import { TranslateService, TranslateModule } from '@ngx-translate/core';
|
|
19
|
-
import {
|
|
19
|
+
import { w as getThemeOptions, T as TranslationManagerService, U as UserInfoService } from './wuic-framework-lib-wuic-framework-lib-CRUM1gc_.mjs';
|
|
20
20
|
import * as i1 from '@angular/router';
|
|
21
21
|
|
|
22
22
|
const frameworkDocsContent = {
|
|
23
23
|
"version": "1.0.0",
|
|
24
|
-
"generatedAt": "2026-09-
|
|
24
|
+
"generatedAt": "2026-09-22T17:51:34.428Z",
|
|
25
25
|
"groups": [
|
|
26
26
|
{
|
|
27
27
|
"id": "primi-passi",
|
|
@@ -1096,6 +1096,22 @@ const frameworkDocsContent = {
|
|
|
1096
1096
|
"developer",
|
|
1097
1097
|
"integration"
|
|
1098
1098
|
]
|
|
1099
|
+
},
|
|
1100
|
+
{
|
|
1101
|
+
"slug": "testabilita-e2e",
|
|
1102
|
+
"title": "Testabilità e hook e2e",
|
|
1103
|
+
"titles": {
|
|
1104
|
+
"en-US": "Testability and e2e hooks",
|
|
1105
|
+
"fr-FR": "Testabilité et hooks e2e",
|
|
1106
|
+
"es-ES": "Testabilidad y hooks e2e",
|
|
1107
|
+
"de-DE": "Testbarkeit und e2e-Hooks"
|
|
1108
|
+
},
|
|
1109
|
+
"icon": "pi-check-square",
|
|
1110
|
+
"status": "stable",
|
|
1111
|
+
"audience": [
|
|
1112
|
+
"developer",
|
|
1113
|
+
"integration"
|
|
1114
|
+
]
|
|
1099
1115
|
}
|
|
1100
1116
|
]
|
|
1101
1117
|
},
|
|
@@ -7805,6 +7821,99 @@ const frameworkDocsContent = {
|
|
|
7805
7821
|
],
|
|
7806
7822
|
"images": []
|
|
7807
7823
|
},
|
|
7824
|
+
{
|
|
7825
|
+
"slug": "testabilita-e2e",
|
|
7826
|
+
"lang": "it-IT",
|
|
7827
|
+
"title": "Testabilità e hook e2e",
|
|
7828
|
+
"description": "Testabilità e hook e2e - documentazione operativa e tecnica",
|
|
7829
|
+
"audience": [
|
|
7830
|
+
"developer",
|
|
7831
|
+
"integration"
|
|
7832
|
+
],
|
|
7833
|
+
"status": "stable",
|
|
7834
|
+
"tags": [
|
|
7835
|
+
"advanced"
|
|
7836
|
+
],
|
|
7837
|
+
"keywords": [
|
|
7838
|
+
"Testabilità e hook e2e"
|
|
7839
|
+
],
|
|
7840
|
+
"toc": [
|
|
7841
|
+
{
|
|
7842
|
+
"id": "sec_1",
|
|
7843
|
+
"title": "Scope"
|
|
7844
|
+
},
|
|
7845
|
+
{
|
|
7846
|
+
"id": "sec_2",
|
|
7847
|
+
"title": "Attributi DOM del field editor"
|
|
7848
|
+
},
|
|
7849
|
+
{
|
|
7850
|
+
"id": "sec_3",
|
|
7851
|
+
"title": "Quando il record è davvero caricato"
|
|
7852
|
+
},
|
|
7853
|
+
{
|
|
7854
|
+
"id": "sec_4",
|
|
7855
|
+
"title": "Ispezione del componente: `__wuicCmp`"
|
|
7856
|
+
},
|
|
7857
|
+
{
|
|
7858
|
+
"id": "sec_5",
|
|
7859
|
+
"title": "L'overlay di caricamento"
|
|
7860
|
+
},
|
|
7861
|
+
{
|
|
7862
|
+
"id": "sec_6",
|
|
7863
|
+
"title": "Cosa non usare come selettore"
|
|
7864
|
+
},
|
|
7865
|
+
{
|
|
7866
|
+
"id": "sec_7",
|
|
7867
|
+
"title": "Note operative"
|
|
7868
|
+
}
|
|
7869
|
+
],
|
|
7870
|
+
"sections": [
|
|
7871
|
+
{
|
|
7872
|
+
"id": "overview",
|
|
7873
|
+
"title": "Overview",
|
|
7874
|
+
"html": "<h1>Testabilità e hook e2e</h1><p>Il framework genera l'interfaccia dai metadati: non ci sono <code>id</code> scritti a mano su cui un test possa appoggiarsi, e le etichette visibili passano dalle traduzioni, quindi cambiano con la lingua dell'utente. Per rendere l'applicazione verificabile dall'esterno, i componenti runtime espongono un contratto stabile fatto di <strong>attributi DOM</strong> e di un <strong>handle di ispezione</strong> del componente. Questa pagina elenca quel contratto e i segnali di "pronto" da attendere prima di interagire.</p><h2>Scope</h2><ul><li>Attributi DOM esposti da <code>wuic-field-editor</code> e da <code>wuic-parametric-dialog</code>.</li><li>Handle <code>__wuicCmp</code> per leggere lo stato runtime di un componente anche in build di produzione.</li><li>Segnali di completamento (record caricato, overlay di caricamento chiuso).</li><li>Selettori e pratiche da evitare.</li></ul><h2>Attributi DOM del field editor</h2><p>Ogni campo renderizzato nella form è ospitato da un <code>wuic-field-editor</code> che scrive sul proprio elemento host:</p><table><thead><tr><th>Attributo</th><th>Contenuto</th></tr></thead><tbody><tr><td><code>data-field-name</code></td><td>nome logico della colonna (<code>mc_nome_colonna</code>)</td></tr><tr><td><code>data-field-id</code></td><td><code>mc_id</code> della colonna, vuoto se non disponibile</td></tr><tr><td><code>data-widget-type</code></td><td>tipo di widget risolto (<code>mc_ui_column_type</code>)</td></tr><tr><td><code>data-editable</code></td><td><code>true</code>/<code>false</code> secondo i metadati e lo stato della form</td></tr><tr><td><code>data-hide-in-edit</code></td><td><code>true</code>/<code>false</code> (<code>mc_hide_in_edit</code>)</td></tr><tr><td><code>data-is-edit-form</code></td><td><code>true</code> in edit form, <code>false</code> in filtro/vista</td></tr><tr><td><code>data-has-record</code></td><td><code>true</code> quando l'<strong>oggetto</strong> record è assegnato</td></tr><tr><td><code>data-field-value</code></td><td>valore corrente del campo, serializzato</td></tr></tbody></table><p>Il selettore di riferimento è quindi il nome del campo, non la posizione:</p><p>Snippet 1:</p><p><code>data-field-value</code> è una stringa: per i lookup espone il <code>value</code> annidato, per gli oggetti il JSON, per tutto il resto la conversione a stringa. Un test che vuole un numero o un booleano fa il cast (<code>Number(v)</code>, <code>v === 'true'</code>).</p><p>Gli attributi sono scritti con <code>setAttribute</code> imperativo dentro <code>syncDomAttrs()</code>, invocato da <code>ngOnChanges</code> e <code>ngDoCheck</code>, <strong>non</strong> con <code>@HostBinding</code>: in Angular zoneless i getter dei binding vengono rivalutati solo quando il change detection tocca quel componente, e il primo read di un test arrivava prima.</p><h2>Quando il record è davvero caricato</h2><p><code>data-has-record</code> dice che l'oggetto record <strong>esiste</strong>, non che i valori siano arrivati: la form costruisce lo scheletro e lo riempie quando risponde <code>getFlatRecordData</code>. Il segnale di "valori arrivati" sta sul dialogo:</p><table><thead><tr><th>Segnale</th><th>Significato</th></tr></thead><tbody><tr><td><code>wuic-field-editor[data-has-record="true"]</code></td><td>scheletro pronto, valori non garantiti</td></tr><tr><td><code>wuic-parametric-dialog[data-record-loaded="true"]</code></td><td>la risposta dei dati è arrivata ed è stata applicata</td></tr></tbody></table><p>I widget lazy — code editor, lookup — propagano il proprio valore un tick più tardi del dialogo. Un'attesa robusta concede quindi una finestra breve dopo <code>data-record-loaded</code> perché il valore compaia, senza bloccarsi sui campi legittimamente vuoti:</p><p>Snippet 2:</p><h2>Ispezione del componente: <code>__wuicCmp</code></h2><p><code>window.ng.getComponent()</code> è il debug tooling di Angular e <strong>non esiste nelle build di produzione</strong>: un test che lo usa come unica via non fallisce per un difetto, fallisce perché lo strumento non c'è proprio sull'installazione che usano i clienti.</p><p>Per questo i componenti che i test devono poter interrogare espongono la propria istanza sull'elemento host come <code>__wuicCmp</code>:</p><p>Snippet 3:</p><p>L'handle <strong>non è sempre attaccato</strong>. Esporre l'istanza di un componente la rende raggiungibile da qualunque script della pagina, e in un'installazione di produzione non serve a nessuno:</p><ul><li>in sviluppo (<code>isDevMode()</code>) è sempre attivo, dove peraltro c'è anche <code>window.ng</code>;</li><li>in produzione solo se la pagina ha dichiarato <code>globalThis.__wuicE2E = true</code> <strong>prima</strong> dell'avvio dell'applicazione.</li></ul><p>Il bootstrap dei test lo fa con uno script di init, non il prodotto:</p><p>Snippet 4:</p><p>Quando il flag è spento il costo è un confronto booleano per istanza; quando è acceso, un assegnamento di proprietà più una callback di pulizia alla distruzione del componente.</p><p>Espongono <code>__wuicCmp</code>: <code>list-grid</code>, <code>chart-list</code>, <code>kanban-list</code>, <code>scheduler-list</code>, <code>timeline-list</code>, <code>tree-list</code>, <code>carousel-list</code>, <code>spreadsheet-list-sf</code>, <code>map-list</code>, <code>designer</code>, <code>parametric-dialog</code>, <code>field-editor</code> e i dodici editor di campo, <code>meta-menu</code>, <code>notification-bell</code>, <code>bounded-repeater</code>, <code>pivot-builder</code>, <code>report-designer</code>, <code>workflow-designer</code>, <code>data-source</code>, <code>code-editor</code>, <code>app-settings-editor</code>.</p><p>Per rendere introspezionabile un componente nuovo basta una riga nella classe:</p><p>Snippet 5:</p><h2>L'overlay di caricamento</h2><p>Mentre carica, la shell copre la pagina con <code><div class="busy-indicator"></code>. Un click inviato in quel momento <strong>finisce sull'overlay</strong>, e con Playwright <code>click({ force: true })</code> non fallisce: salta il controllo di raggiungibilità ma consegna comunque l'evento all'elemento sovrapposto. Il click sparisce senza errore e il test fallisce molto più avanti — su un dialogo che non si è mai aperto, una card che non si è mossa, un salvataggio che sembra non essere mai partito.</p><p>Prima di qualunque interazione a coordinate (click forzati, drag, <code>mouse.down</code>) si attende che la pagina sia libera:</p><p>Snippet 6:</p><p>Un controllo utile in diagnosi: <code>document.elementFromPoint(x, y)</code> sul bersaglio dice chi riceverebbe davvero il click.</p><h2>Cosa non usare come selettore</h2><ul><li><strong>Gli `id` generati da Angular</strong> (<code>_ngcontent-*</code>, <code>ng-reflect-*</code>): cambiano a ogni build e spariscono in produzione.</li><li><strong>Il testo visibile delle etichette</strong>: passa da <code>_wuic_translations</code> e cambia con la lingua dell'utente. Su un'installazione con traduzioni non ancora caricate si legge la chiave grezza (<code>menu.root.administration</code>), non l'etichetta.</li><li><strong>La posizione in tabella</strong> (<code>nth-child</code>): l'ordine delle colonne è metadato, e un <code>mcordine</code> diverso cambia il test.</li><li><strong>`window.ng.getComponent` come unica strada</strong>: vale solo in sviluppo (vedi sopra).</li></ul><h2>Note operative</h2><ul><li>Il flag <code>__wuicE2E</code> è un interruttore dei test: il prodotto non lo imposta mai, e nessuna funzionalità dipende dalla sua presenza.</li><li>Gli attributi DOM sono contratto pubblico: se un test si appoggia a un attributo nuovo, quell'attributo va aggiunto al componente e documentato qui, non dedotto da una struttura interna.</li><li>Un <code>cmp</code> nullo restituito da <code>getComponent</code> significa "non ispezionabile", non "senza dati": distinguere i due casi nei messaggi d'errore evita diagnosi che partono nella direzione sbagliata.</li></ul>",
|
|
7875
|
+
"codeSamples": [
|
|
7876
|
+
{
|
|
7877
|
+
"id": "code_1",
|
|
7878
|
+
"title": "Snippet 1",
|
|
7879
|
+
"language": "js",
|
|
7880
|
+
"code": "const host = document.querySelector('wuic-field-editor[data-field-name=\"StateProvinceID\"]');\nconst valore = host.getAttribute('data-field-value');"
|
|
7881
|
+
},
|
|
7882
|
+
{
|
|
7883
|
+
"id": "code_2",
|
|
7884
|
+
"title": "Snippet 2",
|
|
7885
|
+
"language": "js",
|
|
7886
|
+
"code": "await page.waitForFunction((campo) => {\n const host = document.querySelector(`wuic-field-editor[data-field-name=\"${campo}\"]`);\n if (!host || host.getAttribute('data-has-record') !== 'true') return false;\n const dialogo = host.closest('wuic-parametric-dialog, .edit-form-content');\n if (dialogo?.getAttribute('data-record-loaded') !== 'true') return false;\n const valore = host.getAttribute('data-field-value');\n return valore !== null && valore !== '';\n}, 'StateProvinceID', { timeout: 30000 });"
|
|
7887
|
+
},
|
|
7888
|
+
{
|
|
7889
|
+
"id": "code_3",
|
|
7890
|
+
"title": "Snippet 3",
|
|
7891
|
+
"language": "js",
|
|
7892
|
+
"code": "const host = document.querySelector('wuic-chart-list');\nconst cmp = host.__wuicCmp || window.ng?.getComponent?.(host);\nconst tipo = cmp?.chartRef?.chart?.config?.type;"
|
|
7893
|
+
},
|
|
7894
|
+
{
|
|
7895
|
+
"id": "code_4",
|
|
7896
|
+
"title": "Snippet 4",
|
|
7897
|
+
"language": "js",
|
|
7898
|
+
"code": "await page.addInitScript(() => { globalThis.__wuicE2E = true; });"
|
|
7899
|
+
},
|
|
7900
|
+
{
|
|
7901
|
+
"id": "code_5",
|
|
7902
|
+
"title": "Snippet 5",
|
|
7903
|
+
"language": "ts",
|
|
7904
|
+
"code": "import { exposeWuicCmpOnHost } from '../../helpers/wuic-cmp-handle';\n\nexport class MioComponente {\n private readonly wuicCmpHandle = exposeWuicCmpOnHost(this);\n}"
|
|
7905
|
+
},
|
|
7906
|
+
{
|
|
7907
|
+
"id": "code_6",
|
|
7908
|
+
"title": "Snippet 6",
|
|
7909
|
+
"language": "js",
|
|
7910
|
+
"code": "await page.waitForFunction(() => {\n const visibile = (n) => {\n const s = getComputedStyle(n);\n if (s.display === 'none' || s.visibility === 'hidden' || s.opacity === '0') return false;\n const r = n.getBoundingClientRect();\n return r.width > 0 && r.height > 0;\n };\n return !Array.from(document.querySelectorAll('.busy-indicator')).some(visibile);\n}, null, { timeout: 20000 });"
|
|
7911
|
+
}
|
|
7912
|
+
]
|
|
7913
|
+
}
|
|
7914
|
+
],
|
|
7915
|
+
"images": []
|
|
7916
|
+
},
|
|
7808
7917
|
{
|
|
7809
7918
|
"slug": "troubleshooting",
|
|
7810
7919
|
"lang": "it-IT",
|
|
@@ -14537,6 +14646,99 @@ const frameworkDocsContent = {
|
|
|
14537
14646
|
],
|
|
14538
14647
|
"images": []
|
|
14539
14648
|
},
|
|
14649
|
+
{
|
|
14650
|
+
"slug": "testabilita-e2e",
|
|
14651
|
+
"lang": "en-US",
|
|
14652
|
+
"title": "Testability and e2e hooks",
|
|
14653
|
+
"description": "Testability and e2e hooks - documentazione operativa e tecnica",
|
|
14654
|
+
"audience": [
|
|
14655
|
+
"developer",
|
|
14656
|
+
"integration"
|
|
14657
|
+
],
|
|
14658
|
+
"status": "stable",
|
|
14659
|
+
"tags": [
|
|
14660
|
+
"advanced"
|
|
14661
|
+
],
|
|
14662
|
+
"keywords": [
|
|
14663
|
+
"Testability and e2e hooks"
|
|
14664
|
+
],
|
|
14665
|
+
"toc": [
|
|
14666
|
+
{
|
|
14667
|
+
"id": "sec_1",
|
|
14668
|
+
"title": "Scope"
|
|
14669
|
+
},
|
|
14670
|
+
{
|
|
14671
|
+
"id": "sec_2",
|
|
14672
|
+
"title": "Field editor DOM attributes"
|
|
14673
|
+
},
|
|
14674
|
+
{
|
|
14675
|
+
"id": "sec_3",
|
|
14676
|
+
"title": "When the record is really loaded"
|
|
14677
|
+
},
|
|
14678
|
+
{
|
|
14679
|
+
"id": "sec_4",
|
|
14680
|
+
"title": "Component inspection: `__wuicCmp`"
|
|
14681
|
+
},
|
|
14682
|
+
{
|
|
14683
|
+
"id": "sec_5",
|
|
14684
|
+
"title": "The loading overlay"
|
|
14685
|
+
},
|
|
14686
|
+
{
|
|
14687
|
+
"id": "sec_6",
|
|
14688
|
+
"title": "What not to use as a selector"
|
|
14689
|
+
},
|
|
14690
|
+
{
|
|
14691
|
+
"id": "sec_7",
|
|
14692
|
+
"title": "Operational notes"
|
|
14693
|
+
}
|
|
14694
|
+
],
|
|
14695
|
+
"sections": [
|
|
14696
|
+
{
|
|
14697
|
+
"id": "overview",
|
|
14698
|
+
"title": "Overview",
|
|
14699
|
+
"html": "<h1>Testability and e2e hooks</h1><p>The framework generates the UI from metadata: there are no hand-written <code>id</code>s for a test to hold on to, and the visible labels come from the translations, so they change with the user's language. To make the application verifiable from the outside, the runtime components expose a stable contract made of <strong>DOM attributes</strong> and a <strong>component inspection handle</strong>. This page lists that contract and the readiness signals to wait for before interacting.</p><h2>Scope</h2><ul><li>DOM attributes exposed by <code>wuic-field-editor</code> and <code>wuic-parametric-dialog</code>.</li><li>The <code>__wuicCmp</code> handle, to read a component's runtime state even in production builds.</li><li>Completion signals (record loaded, loading overlay gone).</li><li>Selectors and practices to avoid.</li></ul><h2>Field editor DOM attributes</h2><p>Every field rendered in the form is hosted by a <code>wuic-field-editor</code> that writes onto its own host element:</p><table><thead><tr><th>Attribute</th><th>Content</th></tr></thead><tbody><tr><td><code>data-field-name</code></td><td>logical column name (<code>mc_nome_colonna</code>)</td></tr><tr><td><code>data-field-id</code></td><td>the column's <code>mc_id</code>, empty when unavailable</td></tr><tr><td><code>data-widget-type</code></td><td>resolved widget type (<code>mc_ui_column_type</code>)</td></tr><tr><td><code>data-editable</code></td><td><code>true</code>/<code>false</code> per metadata and form state</td></tr><tr><td><code>data-hide-in-edit</code></td><td><code>true</code>/<code>false</code> (<code>mc_hide_in_edit</code>)</td></tr><tr><td><code>data-is-edit-form</code></td><td><code>true</code> in an edit form, <code>false</code> in filter/view</td></tr><tr><td><code>data-has-record</code></td><td><code>true</code> once the record <strong>object</strong> is assigned</td></tr><tr><td><code>data-field-value</code></td><td>the field's current value, serialized</td></tr></tbody></table><p>The anchor is therefore the field name, not the position:</p><p>Snippet 1:</p><p><code>data-field-value</code> is a string: for lookups it exposes the nested <code>value</code>, for objects the JSON, for everything else the string conversion. A test that needs a number or a boolean casts it (<code>Number(v)</code>, <code>v === 'true'</code>).</p><p>The attributes are written with an imperative <code>setAttribute</code> inside <code>syncDomAttrs()</code>, called from <code>ngOnChanges</code> and <code>ngDoCheck</code>, <strong>not</strong> with <code>@HostBinding</code>: in zoneless Angular the binding getters are re-evaluated only when change detection touches that component, and a test's first read arrived earlier than that.</p><h2>When the record is really loaded</h2><p><code>data-has-record</code> says the record object <strong>exists</strong>, not that the values have arrived: the form builds the skeleton and fills it when <code>getFlatRecordData</code> responds. The "values are in" signal lives on the dialog:</p><table><thead><tr><th>Signal</th><th>Meaning</th></tr></thead><tbody><tr><td><code>wuic-field-editor[data-has-record="true"]</code></td><td>skeleton ready, values not guaranteed</td></tr><tr><td><code>wuic-parametric-dialog[data-record-loaded="true"]</code></td><td>the data response arrived and was applied</td></tr></tbody></table><p>Lazy widgets — code editor, lookup — propagate their value one tick after the dialog. A robust wait therefore allows a short window after <code>data-record-loaded</code> for the value to show up, without hanging on fields that are legitimately empty:</p><p>Snippet 2:</p><h2>Component inspection: <code>__wuicCmp</code></h2><p><code>window.ng.getComponent()</code> is Angular's debug tooling and <strong>does not exist in production builds</strong>: a test that relies on it as its only route does not fail because of a defect, it fails because the tool simply isn't there on the installation customers actually run.</p><p>That is why the components tests need to interrogate expose their own instance on the host element as <code>__wuicCmp</code>:</p><p>Snippet 3:</p><p>The handle is <strong>not always attached</strong>. Exposing a component instance makes it reachable from any script on the page, and on a production installation that serves nobody:</p><ul><li>in development (<code>isDevMode()</code>) it is always on, where <code>window.ng</code> exists anyway;</li><li>in production only if the page declared <code>globalThis.__wuicE2E = true</code> <strong>before</strong> the application booted.</li></ul><p>The test bootstrap does that with an init script, not the product:</p><p>Snippet 4:</p><p>With the flag off the cost is one boolean check per instance; with it on, one property assignment plus a cleanup callback when the component is destroyed.</p><p>Components exposing <code>__wuicCmp</code>: <code>list-grid</code>, <code>chart-list</code>, <code>kanban-list</code>, <code>scheduler-list</code>, <code>timeline-list</code>, <code>tree-list</code>, <code>carousel-list</code>, <code>spreadsheet-list-sf</code>, <code>map-list</code>, <code>designer</code>, <code>parametric-dialog</code>, <code>field-editor</code> and the twelve field editors, <code>meta-menu</code>, <code>notification-bell</code>, <code>bounded-repeater</code>, <code>pivot-builder</code>, <code>report-designer</code>, <code>workflow-designer</code>, <code>data-source</code>, <code>code-editor</code>, <code>app-settings-editor</code>.</p><p>Making a new component inspectable takes one line in the class:</p><p>Snippet 5:</p><h2>The loading overlay</h2><p>While loading, the shell covers the page with <code><div class="busy-indicator"></code>. A click sent at that moment <strong>lands on the overlay</strong>, and with Playwright <code>click({ force: true })</code> does not fail: it skips the actionability check but still delivers the event to whatever sits on top. The click vanishes without an error and the test fails much later — on a dialog that never opened, a card that never moved, a save that seems never to have started.</p><p>Before any coordinate-based interaction (forced clicks, drags, <code>mouse.down</code>) wait for the page to be free:</p><p>Snippet 6:</p><p>A useful diagnostic: <code>document.elementFromPoint(x, y)</code> over the target tells you who would actually receive the click.</p><h2>What not to use as a selector</h2><ul><li><strong>Angular-generated `id`s</strong> (<code>_ngcontent-*</code>, <code>ng-reflect-*</code>): they change with every build and disappear in production.</li><li><strong>The visible label text</strong>: it comes from <code>_wuic_translations</code> and changes with the user's language. On an installation whose translations have not loaded you read the raw key (<code>menu.root.administration</code>), not the label.</li><li><strong>Position in a table</strong> (<code>nth-child</code>): column order is metadata, and a different <code>mcordine</code> changes the test.</li><li><strong>`window.ng.getComponent` as the only route</strong>: development only (see above).</li></ul><h2>Operational notes</h2><ul><li>The <code>__wuicE2E</code> flag is a test switch: the product never sets it, and no feature depends on its presence.</li><li>The DOM attributes are a public contract: if a test relies on a new attribute, that attribute is added to the component and documented here, not inferred from an internal structure.</li><li>A null <code>cmp</code> returned by <code>getComponent</code> means "not inspectable", not "no data": telling the two apart in error messages keeps a diagnosis from starting in the wrong direction.</li></ul>",
|
|
14700
|
+
"codeSamples": [
|
|
14701
|
+
{
|
|
14702
|
+
"id": "code_1",
|
|
14703
|
+
"title": "Snippet 1",
|
|
14704
|
+
"language": "js",
|
|
14705
|
+
"code": "const host = document.querySelector('wuic-field-editor[data-field-name=\"StateProvinceID\"]');\nconst valore = host.getAttribute('data-field-value');"
|
|
14706
|
+
},
|
|
14707
|
+
{
|
|
14708
|
+
"id": "code_2",
|
|
14709
|
+
"title": "Snippet 2",
|
|
14710
|
+
"language": "js",
|
|
14711
|
+
"code": "await page.waitForFunction((campo) => {\n const host = document.querySelector(`wuic-field-editor[data-field-name=\"${campo}\"]`);\n if (!host || host.getAttribute('data-has-record') !== 'true') return false;\n const dialogo = host.closest('wuic-parametric-dialog, .edit-form-content');\n if (dialogo?.getAttribute('data-record-loaded') !== 'true') return false;\n const valore = host.getAttribute('data-field-value');\n return valore !== null && valore !== '';\n}, 'StateProvinceID', { timeout: 30000 });"
|
|
14712
|
+
},
|
|
14713
|
+
{
|
|
14714
|
+
"id": "code_3",
|
|
14715
|
+
"title": "Snippet 3",
|
|
14716
|
+
"language": "js",
|
|
14717
|
+
"code": "const host = document.querySelector('wuic-chart-list');\nconst cmp = host.__wuicCmp || window.ng?.getComponent?.(host);\nconst tipo = cmp?.chartRef?.chart?.config?.type;"
|
|
14718
|
+
},
|
|
14719
|
+
{
|
|
14720
|
+
"id": "code_4",
|
|
14721
|
+
"title": "Snippet 4",
|
|
14722
|
+
"language": "js",
|
|
14723
|
+
"code": "await page.addInitScript(() => { globalThis.__wuicE2E = true; });"
|
|
14724
|
+
},
|
|
14725
|
+
{
|
|
14726
|
+
"id": "code_5",
|
|
14727
|
+
"title": "Snippet 5",
|
|
14728
|
+
"language": "ts",
|
|
14729
|
+
"code": "import { exposeWuicCmpOnHost } from '../../helpers/wuic-cmp-handle';\n\nexport class MioComponente {\n private readonly wuicCmpHandle = exposeWuicCmpOnHost(this);\n}"
|
|
14730
|
+
},
|
|
14731
|
+
{
|
|
14732
|
+
"id": "code_6",
|
|
14733
|
+
"title": "Snippet 6",
|
|
14734
|
+
"language": "js",
|
|
14735
|
+
"code": "await page.waitForFunction(() => {\n const visibile = (n) => {\n const s = getComputedStyle(n);\n if (s.display === 'none' || s.visibility === 'hidden' || s.opacity === '0') return false;\n const r = n.getBoundingClientRect();\n return r.width > 0 && r.height > 0;\n };\n return !Array.from(document.querySelectorAll('.busy-indicator')).some(visibile);\n}, null, { timeout: 20000 });"
|
|
14736
|
+
}
|
|
14737
|
+
]
|
|
14738
|
+
}
|
|
14739
|
+
],
|
|
14740
|
+
"images": []
|
|
14741
|
+
},
|
|
14540
14742
|
{
|
|
14541
14743
|
"slug": "troubleshooting",
|
|
14542
14744
|
"lang": "en-US",
|
|
@@ -21269,6 +21471,99 @@ const frameworkDocsContent = {
|
|
|
21269
21471
|
],
|
|
21270
21472
|
"images": []
|
|
21271
21473
|
},
|
|
21474
|
+
{
|
|
21475
|
+
"slug": "testabilita-e2e",
|
|
21476
|
+
"lang": "fr-FR",
|
|
21477
|
+
"title": "Testabilité et hooks e2e",
|
|
21478
|
+
"description": "Testabilité et hooks e2e - documentazione operativa e tecnica",
|
|
21479
|
+
"audience": [
|
|
21480
|
+
"developer",
|
|
21481
|
+
"integration"
|
|
21482
|
+
],
|
|
21483
|
+
"status": "stable",
|
|
21484
|
+
"tags": [
|
|
21485
|
+
"advanced"
|
|
21486
|
+
],
|
|
21487
|
+
"keywords": [
|
|
21488
|
+
"Testabilité et hooks e2e"
|
|
21489
|
+
],
|
|
21490
|
+
"toc": [
|
|
21491
|
+
{
|
|
21492
|
+
"id": "sec_1",
|
|
21493
|
+
"title": "Scope"
|
|
21494
|
+
},
|
|
21495
|
+
{
|
|
21496
|
+
"id": "sec_2",
|
|
21497
|
+
"title": "Attributs DOM du field editor"
|
|
21498
|
+
},
|
|
21499
|
+
{
|
|
21500
|
+
"id": "sec_3",
|
|
21501
|
+
"title": "Quand l'enregistrement est vraiment chargé"
|
|
21502
|
+
},
|
|
21503
|
+
{
|
|
21504
|
+
"id": "sec_4",
|
|
21505
|
+
"title": "Inspection du composant : `__wuicCmp`"
|
|
21506
|
+
},
|
|
21507
|
+
{
|
|
21508
|
+
"id": "sec_5",
|
|
21509
|
+
"title": "L'overlay de chargement"
|
|
21510
|
+
},
|
|
21511
|
+
{
|
|
21512
|
+
"id": "sec_6",
|
|
21513
|
+
"title": "Ce qu'il ne faut pas utiliser comme sélecteur"
|
|
21514
|
+
},
|
|
21515
|
+
{
|
|
21516
|
+
"id": "sec_7",
|
|
21517
|
+
"title": "Notes opérationnelles"
|
|
21518
|
+
}
|
|
21519
|
+
],
|
|
21520
|
+
"sections": [
|
|
21521
|
+
{
|
|
21522
|
+
"id": "overview",
|
|
21523
|
+
"title": "Overview",
|
|
21524
|
+
"html": "<h1>Testabilité et hooks e2e</h1><p>Le framework génère l'interface à partir des métadonnées : il n'y a pas d'<code>id</code> écrits à la main sur lesquels un test pourrait s'appuyer, et les libellés visibles proviennent des traductions, donc ils changent avec la langue de l'utilisateur. Pour rendre l'application vérifiable de l'extérieur, les composants runtime exposent un contrat stable fait d'<strong>attributs DOM</strong> et d'un <strong>handle d'inspection</strong> du composant. Cette page liste ce contrat et les signaux de disponibilité à attendre avant d'interagir.</p><h2>Scope</h2><ul><li>Attributs DOM exposés par <code>wuic-field-editor</code> et <code>wuic-parametric-dialog</code>.</li><li>Handle <code>__wuicCmp</code> pour lire l'état runtime d'un composant même en build de production.</li><li>Signaux d'achèvement (enregistrement chargé, overlay de chargement disparu).</li><li>Sélecteurs et pratiques à éviter.</li></ul><h2>Attributs DOM du field editor</h2><p>Chaque champ rendu dans le formulaire est hébergé par un <code>wuic-field-editor</code> qui écrit sur son propre élément hôte :</p><table><thead><tr><th>Attribut</th><th>Contenu</th></tr></thead><tbody><tr><td><code>data-field-name</code></td><td>nom logique de la colonne (<code>mc_nome_colonna</code>)</td></tr><tr><td><code>data-field-id</code></td><td><code>mc_id</code> de la colonne, vide si indisponible</td></tr><tr><td><code>data-widget-type</code></td><td>type de widget résolu (<code>mc_ui_column_type</code>)</td></tr><tr><td><code>data-editable</code></td><td><code>true</code>/<code>false</code> selon les métadonnées et l'état du formulaire</td></tr><tr><td><code>data-hide-in-edit</code></td><td><code>true</code>/<code>false</code> (<code>mc_hide_in_edit</code>)</td></tr><tr><td><code>data-is-edit-form</code></td><td><code>true</code> en formulaire d'édition, <code>false</code> en filtre/vue</td></tr><tr><td><code>data-has-record</code></td><td><code>true</code> dès que l'<strong>objet</strong> enregistrement est assigné</td></tr><tr><td><code>data-field-value</code></td><td>valeur courante du champ, sérialisée</td></tr></tbody></table><p>Le point d'ancrage est donc le nom du champ, pas la position :</p><p>Snippet 1:</p><p><code>data-field-value</code> est une chaîne : pour les lookups elle expose le <code>value</code> imbriqué, pour les objets le JSON, pour tout le reste la conversion en chaîne. Un test qui attend un nombre ou un booléen fait le cast (<code>Number(v)</code>, <code>v === 'true'</code>).</p><p>Les attributs sont écrits avec un <code>setAttribute</code> impératif dans <code>syncDomAttrs()</code>, appelé par <code>ngOnChanges</code> et <code>ngDoCheck</code>, et <strong>non</strong> avec <code>@HostBinding</code> : en Angular zoneless les getters des bindings ne sont réévalués que lorsque la détection de changements touche ce composant, et la première lecture d'un test arrivait avant.</p><h2>Quand l'enregistrement est vraiment chargé</h2><p><code>data-has-record</code> dit que l'objet enregistrement <strong>existe</strong>, pas que les valeurs sont arrivées : le formulaire construit le squelette et le remplit quand <code>getFlatRecordData</code> répond. Le signal « valeurs arrivées » se trouve sur le dialogue :</p><table><thead><tr><th>Signal</th><th>Signification</th></tr></thead><tbody><tr><td><code>wuic-field-editor[data-has-record="true"]</code></td><td>squelette prêt, valeurs non garanties</td></tr><tr><td><code>wuic-parametric-dialog[data-record-loaded="true"]</code></td><td>la réponse des données est arrivée et a été appliquée</td></tr></tbody></table><p>Les widgets lazy — code editor, lookup — propagent leur valeur un tick après le dialogue. Une attente robuste accorde donc une courte fenêtre après <code>data-record-loaded</code> pour que la valeur apparaisse, sans se bloquer sur les champs légitimement vides :</p><p>Snippet 2:</p><h2>Inspection du composant : <code>__wuicCmp</code></h2><p><code>window.ng.getComponent()</code> est l'outillage de debug d'Angular et <strong>n'existe pas dans les builds de production</strong> : un test qui s'y fie comme unique voie n'échoue pas à cause d'un défaut, il échoue parce que l'outil n'est tout simplement pas là sur l'installation que les clients utilisent.</p><p>C'est pourquoi les composants que les tests doivent pouvoir interroger exposent leur instance sur l'élément hôte sous le nom <code>__wuicCmp</code> :</p><p>Snippet 3:</p><p>Le handle n'est <strong>pas toujours attaché</strong>. Exposer l'instance d'un composant la rend accessible depuis n'importe quel script de la page, et sur une installation de production cela ne sert à personne :</p><ul><li>en développement (<code>isDevMode()</code>) il est toujours actif, là où <code>window.ng</code> existe de toute façon ;</li><li>en production uniquement si la page a déclaré <code>globalThis.__wuicE2E = true</code> <strong>avant</strong> le démarrage de l'application.</li></ul><p>C'est le bootstrap des tests qui le fait, via un script d'init, pas le produit :</p><p>Snippet 4:</p><p>Quand le drapeau est éteint, le coût est une comparaison booléenne par instance ; quand il est allumé, une affectation de propriété plus un callback de nettoyage à la destruction du composant.</p><p>Composants exposant <code>__wuicCmp</code> : <code>list-grid</code>, <code>chart-list</code>, <code>kanban-list</code>, <code>scheduler-list</code>, <code>timeline-list</code>, <code>tree-list</code>, <code>carousel-list</code>, <code>spreadsheet-list-sf</code>, <code>map-list</code>, <code>designer</code>, <code>parametric-dialog</code>, <code>field-editor</code> et les douze éditeurs de champ, <code>meta-menu</code>, <code>notification-bell</code>, <code>bounded-repeater</code>, <code>pivot-builder</code>, <code>report-designer</code>, <code>workflow-designer</code>, <code>data-source</code>, <code>code-editor</code>, <code>app-settings-editor</code>.</p><p>Rendre inspectable un nouveau composant tient en une ligne dans la classe :</p><p>Snippet 5:</p><h2>L'overlay de chargement</h2><p>Pendant le chargement, le shell recouvre la page avec <code><div class="busy-indicator"></code>. Un clic envoyé à ce moment-là <strong>atterrit sur l'overlay</strong>, et avec Playwright <code>click({ force: true })</code> n'échoue pas : il saute le contrôle d'actionabilité mais livre quand même l'événement à l'élément superposé. Le clic disparaît sans erreur et le test échoue bien plus loin — sur un dialogue qui ne s'est jamais ouvert, une carte qui n'a pas bougé, un enregistrement qui semble n'être jamais parti.</p><p>Avant toute interaction par coordonnées (clics forcés, drags, <code>mouse.down</code>), on attend que la page soit libre :</p><p>Snippet 6:</p><p>Un contrôle utile en diagnostic : <code>document.elementFromPoint(x, y)</code> sur la cible indique qui recevrait réellement le clic.</p><h2>Ce qu'il ne faut pas utiliser comme sélecteur</h2><ul><li><strong>Les `id` générés par Angular</strong> (<code>_ngcontent-*</code>, <code>ng-reflect-*</code>) : ils changent à chaque build et disparaissent en production.</li><li><strong>Le texte visible des libellés</strong> : il provient de <code>_wuic_translations</code> et change avec la langue de l'utilisateur. Sur une installation dont les traductions ne sont pas chargées, on lit la clé brute (<code>menu.root.administration</code>), pas le libellé.</li><li><strong>La position dans un tableau</strong> (<code>nth-child</code>) : l'ordre des colonnes est une métadonnée, et un <code>mcordine</code> différent change le test.</li><li><strong>`window.ng.getComponent` comme seule voie</strong> : valable en développement uniquement (voir ci-dessus).</li></ul><h2>Notes opérationnelles</h2><ul><li>Le drapeau <code>__wuicE2E</code> est un interrupteur des tests : le produit ne le positionne jamais, et aucune fonctionnalité ne dépend de sa présence.</li><li>Les attributs DOM sont un contrat public : si un test s'appuie sur un nouvel attribut, cet attribut est ajouté au composant et documenté ici, pas déduit d'une structure interne.</li><li>Un <code>cmp</code> nul renvoyé par <code>getComponent</code> signifie « non inspectable », pas « sans données » : distinguer les deux cas dans les messages d'erreur évite qu'un diagnostic parte dans la mauvaise direction.</li></ul>",
|
|
21525
|
+
"codeSamples": [
|
|
21526
|
+
{
|
|
21527
|
+
"id": "code_1",
|
|
21528
|
+
"title": "Snippet 1",
|
|
21529
|
+
"language": "js",
|
|
21530
|
+
"code": "const host = document.querySelector('wuic-field-editor[data-field-name=\"StateProvinceID\"]');\nconst valore = host.getAttribute('data-field-value');"
|
|
21531
|
+
},
|
|
21532
|
+
{
|
|
21533
|
+
"id": "code_2",
|
|
21534
|
+
"title": "Snippet 2",
|
|
21535
|
+
"language": "js",
|
|
21536
|
+
"code": "await page.waitForFunction((campo) => {\n const host = document.querySelector(`wuic-field-editor[data-field-name=\"${campo}\"]`);\n if (!host || host.getAttribute('data-has-record') !== 'true') return false;\n const dialogo = host.closest('wuic-parametric-dialog, .edit-form-content');\n if (dialogo?.getAttribute('data-record-loaded') !== 'true') return false;\n const valore = host.getAttribute('data-field-value');\n return valore !== null && valore !== '';\n}, 'StateProvinceID', { timeout: 30000 });"
|
|
21537
|
+
},
|
|
21538
|
+
{
|
|
21539
|
+
"id": "code_3",
|
|
21540
|
+
"title": "Snippet 3",
|
|
21541
|
+
"language": "js",
|
|
21542
|
+
"code": "const host = document.querySelector('wuic-chart-list');\nconst cmp = host.__wuicCmp || window.ng?.getComponent?.(host);\nconst tipo = cmp?.chartRef?.chart?.config?.type;"
|
|
21543
|
+
},
|
|
21544
|
+
{
|
|
21545
|
+
"id": "code_4",
|
|
21546
|
+
"title": "Snippet 4",
|
|
21547
|
+
"language": "js",
|
|
21548
|
+
"code": "await page.addInitScript(() => { globalThis.__wuicE2E = true; });"
|
|
21549
|
+
},
|
|
21550
|
+
{
|
|
21551
|
+
"id": "code_5",
|
|
21552
|
+
"title": "Snippet 5",
|
|
21553
|
+
"language": "ts",
|
|
21554
|
+
"code": "import { exposeWuicCmpOnHost } from '../../helpers/wuic-cmp-handle';\n\nexport class MioComponente {\n private readonly wuicCmpHandle = exposeWuicCmpOnHost(this);\n}"
|
|
21555
|
+
},
|
|
21556
|
+
{
|
|
21557
|
+
"id": "code_6",
|
|
21558
|
+
"title": "Snippet 6",
|
|
21559
|
+
"language": "js",
|
|
21560
|
+
"code": "await page.waitForFunction(() => {\n const visibile = (n) => {\n const s = getComputedStyle(n);\n if (s.display === 'none' || s.visibility === 'hidden' || s.opacity === '0') return false;\n const r = n.getBoundingClientRect();\n return r.width > 0 && r.height > 0;\n };\n return !Array.from(document.querySelectorAll('.busy-indicator')).some(visibile);\n}, null, { timeout: 20000 });"
|
|
21561
|
+
}
|
|
21562
|
+
]
|
|
21563
|
+
}
|
|
21564
|
+
],
|
|
21565
|
+
"images": []
|
|
21566
|
+
},
|
|
21272
21567
|
{
|
|
21273
21568
|
"slug": "troubleshooting",
|
|
21274
21569
|
"lang": "fr-FR",
|
|
@@ -28001,6 +28296,99 @@ const frameworkDocsContent = {
|
|
|
28001
28296
|
],
|
|
28002
28297
|
"images": []
|
|
28003
28298
|
},
|
|
28299
|
+
{
|
|
28300
|
+
"slug": "testabilita-e2e",
|
|
28301
|
+
"lang": "es-ES",
|
|
28302
|
+
"title": "Testabilidad y hooks e2e",
|
|
28303
|
+
"description": "Testabilidad y hooks e2e - documentazione operativa e tecnica",
|
|
28304
|
+
"audience": [
|
|
28305
|
+
"developer",
|
|
28306
|
+
"integration"
|
|
28307
|
+
],
|
|
28308
|
+
"status": "stable",
|
|
28309
|
+
"tags": [
|
|
28310
|
+
"advanced"
|
|
28311
|
+
],
|
|
28312
|
+
"keywords": [
|
|
28313
|
+
"Testabilidad y hooks e2e"
|
|
28314
|
+
],
|
|
28315
|
+
"toc": [
|
|
28316
|
+
{
|
|
28317
|
+
"id": "sec_1",
|
|
28318
|
+
"title": "Scope"
|
|
28319
|
+
},
|
|
28320
|
+
{
|
|
28321
|
+
"id": "sec_2",
|
|
28322
|
+
"title": "Atributos DOM del field editor"
|
|
28323
|
+
},
|
|
28324
|
+
{
|
|
28325
|
+
"id": "sec_3",
|
|
28326
|
+
"title": "Cuándo está realmente cargado el registro"
|
|
28327
|
+
},
|
|
28328
|
+
{
|
|
28329
|
+
"id": "sec_4",
|
|
28330
|
+
"title": "Inspección del componente: `__wuicCmp`"
|
|
28331
|
+
},
|
|
28332
|
+
{
|
|
28333
|
+
"id": "sec_5",
|
|
28334
|
+
"title": "El overlay de carga"
|
|
28335
|
+
},
|
|
28336
|
+
{
|
|
28337
|
+
"id": "sec_6",
|
|
28338
|
+
"title": "Qué no usar como selector"
|
|
28339
|
+
},
|
|
28340
|
+
{
|
|
28341
|
+
"id": "sec_7",
|
|
28342
|
+
"title": "Notas operativas"
|
|
28343
|
+
}
|
|
28344
|
+
],
|
|
28345
|
+
"sections": [
|
|
28346
|
+
{
|
|
28347
|
+
"id": "overview",
|
|
28348
|
+
"title": "Overview",
|
|
28349
|
+
"html": "<h1>Testabilidad y hooks e2e</h1><p>El framework genera la interfaz a partir de los metadatos: no hay <code>id</code> escritos a mano en los que un test pueda apoyarse, y las etiquetas visibles vienen de las traducciones, así que cambian con el idioma del usuario. Para que la aplicación sea verificable desde fuera, los componentes de runtime exponen un contrato estable formado por <strong>atributos DOM</strong> y un <strong>handle de inspección</strong> del componente. Esta página enumera ese contrato y las señales de "listo" que hay que esperar antes de interactuar.</p><h2>Scope</h2><ul><li>Atributos DOM expuestos por <code>wuic-field-editor</code> y <code>wuic-parametric-dialog</code>.</li><li>Handle <code>__wuicCmp</code> para leer el estado de runtime de un componente incluso en builds de producción.</li><li>Señales de finalización (registro cargado, overlay de carga cerrado).</li><li>Selectores y prácticas que conviene evitar.</li></ul><h2>Atributos DOM del field editor</h2><p>Cada campo renderizado en el formulario está alojado en un <code>wuic-field-editor</code> que escribe sobre su propio elemento host:</p><table><thead><tr><th>Atributo</th><th>Contenido</th></tr></thead><tbody><tr><td><code>data-field-name</code></td><td>nombre lógico de la columna (<code>mc_nome_colonna</code>)</td></tr><tr><td><code>data-field-id</code></td><td><code>mc_id</code> de la columna, vacío si no está disponible</td></tr><tr><td><code>data-widget-type</code></td><td>tipo de widget resuelto (<code>mc_ui_column_type</code>)</td></tr><tr><td><code>data-editable</code></td><td><code>true</code>/<code>false</code> según metadatos y estado del formulario</td></tr><tr><td><code>data-hide-in-edit</code></td><td><code>true</code>/<code>false</code> (<code>mc_hide_in_edit</code>)</td></tr><tr><td><code>data-is-edit-form</code></td><td><code>true</code> en formulario de edición, <code>false</code> en filtro/vista</td></tr><tr><td><code>data-has-record</code></td><td><code>true</code> cuando el <strong>objeto</strong> registro está asignado</td></tr><tr><td><code>data-field-value</code></td><td>valor actual del campo, serializado</td></tr></tbody></table><p>El ancla es por tanto el nombre del campo, no la posición:</p><p>Snippet 1:</p><p><code>data-field-value</code> es una cadena: para los lookups expone el <code>value</code> anidado, para los objetos el JSON, y para todo lo demás la conversión a cadena. Un test que necesita un número o un booleano hace el cast (<code>Number(v)</code>, <code>v === 'true'</code>).</p><p>Los atributos se escriben con un <code>setAttribute</code> imperativo dentro de <code>syncDomAttrs()</code>, invocado desde <code>ngOnChanges</code> y <code>ngDoCheck</code>, y <strong>no</strong> con <code>@HostBinding</code>: en Angular zoneless los getters de los bindings se reevalúan solo cuando la detección de cambios toca ese componente, y la primera lectura de un test llegaba antes.</p><h2>Cuándo está realmente cargado el registro</h2><p><code>data-has-record</code> dice que el objeto registro <strong>existe</strong>, no que hayan llegado los valores: el formulario construye el esqueleto y lo rellena cuando responde <code>getFlatRecordData</code>. La señal de "valores llegados" está en el diálogo:</p><table><thead><tr><th>Señal</th><th>Significado</th></tr></thead><tbody><tr><td><code>wuic-field-editor[data-has-record="true"]</code></td><td>esqueleto listo, valores no garantizados</td></tr><tr><td><code>wuic-parametric-dialog[data-record-loaded="true"]</code></td><td>la respuesta de datos llegó y se aplicó</td></tr></tbody></table><p>Los widgets lazy — code editor, lookup — propagan su valor un tick después del diálogo. Una espera robusta concede por tanto una ventana breve tras <code>data-record-loaded</code> para que el valor aparezca, sin bloquearse en los campos legítimamente vacíos:</p><p>Snippet 2:</p><h2>Inspección del componente: <code>__wuicCmp</code></h2><p><code>window.ng.getComponent()</code> es el debug tooling de Angular y <strong>no existe en las builds de producción</strong>: un test que lo usa como única vía no falla por un defecto, falla porque la herramienta sencillamente no está en la instalación que usan los clientes.</p><p>Por eso los componentes que los tests deben poder interrogar exponen su propia instancia en el elemento host como <code>__wuicCmp</code>:</p><p>Snippet 3:</p><p>El handle <strong>no siempre está adjunto</strong>. Exponer la instancia de un componente la hace alcanzable desde cualquier script de la página, y en una instalación de producción eso no le sirve a nadie:</p><ul><li>en desarrollo (<code>isDevMode()</code>) está siempre activo, donde además existe <code>window.ng</code>;</li><li>en producción solo si la página declaró <code>globalThis.__wuicE2E = true</code> <strong>antes</strong> del arranque de la aplicación.</li></ul><p>Lo hace el bootstrap de los tests con un script de init, no el producto:</p><p>Snippet 4:</p><p>Con el flag apagado el coste es una comparación booleana por instancia; encendido, una asignación de propiedad más un callback de limpieza al destruir el componente.</p><p>Exponen <code>__wuicCmp</code>: <code>list-grid</code>, <code>chart-list</code>, <code>kanban-list</code>, <code>scheduler-list</code>, <code>timeline-list</code>, <code>tree-list</code>, <code>carousel-list</code>, <code>spreadsheet-list-sf</code>, <code>map-list</code>, <code>designer</code>, <code>parametric-dialog</code>, <code>field-editor</code> y los doce editores de campo, <code>meta-menu</code>, <code>notification-bell</code>, <code>bounded-repeater</code>, <code>pivot-builder</code>, <code>report-designer</code>, <code>workflow-designer</code>, <code>data-source</code>, <code>code-editor</code>, <code>app-settings-editor</code>.</p><p>Hacer inspeccionable un componente nuevo es una línea en la clase:</p><p>Snippet 5:</p><h2>El overlay de carga</h2><p>Mientras carga, el shell cubre la página con <code><div class="busy-indicator"></code>. Un clic enviado en ese momento <strong>acaba en el overlay</strong>, y con Playwright <code>click({ force: true })</code> no falla: salta la comprobación de actionability pero entrega igualmente el evento al elemento superpuesto. El clic desaparece sin error y el test falla mucho más adelante — en un diálogo que nunca se abrió, una tarjeta que no se movió, un guardado que parece no haber salido nunca.</p><p>Antes de cualquier interacción por coordenadas (clics forzados, drags, <code>mouse.down</code>) se espera a que la página esté libre:</p><p>Snippet 6:</p><p>Una comprobación útil en diagnóstico: <code>document.elementFromPoint(x, y)</code> sobre el objetivo dice quién recibiría realmente el clic.</p><h2>Qué no usar como selector</h2><ul><li><strong>Los `id` generados por Angular</strong> (<code>_ngcontent-*</code>, <code>ng-reflect-*</code>): cambian en cada build y desaparecen en producción.</li><li><strong>El texto visible de las etiquetas</strong>: viene de <code>_wuic_translations</code> y cambia con el idioma del usuario. En una instalación cuyas traducciones no se han cargado se lee la clave en bruto (<code>menu.root.administration</code>), no la etiqueta.</li><li><strong>La posición en una tabla</strong> (<code>nth-child</code>): el orden de las columnas es metadato, y un <code>mcordine</code> distinto cambia el test.</li><li><strong>`window.ng.getComponent` como única vía</strong>: solo vale en desarrollo (ver arriba).</li></ul><h2>Notas operativas</h2><ul><li>El flag <code>__wuicE2E</code> es un interruptor de los tests: el producto no lo establece nunca, y ninguna funcionalidad depende de su presencia.</li><li>Los atributos DOM son contrato público: si un test se apoya en un atributo nuevo, ese atributo se añade al componente y se documenta aquí, no se deduce de una estructura interna.</li><li>Un <code>cmp</code> nulo devuelto por <code>getComponent</code> significa "no inspeccionable", no "sin datos": distinguir ambos casos en los mensajes de error evita que un diagnóstico arranque en la dirección equivocada.</li></ul>",
|
|
28350
|
+
"codeSamples": [
|
|
28351
|
+
{
|
|
28352
|
+
"id": "code_1",
|
|
28353
|
+
"title": "Snippet 1",
|
|
28354
|
+
"language": "js",
|
|
28355
|
+
"code": "const host = document.querySelector('wuic-field-editor[data-field-name=\"StateProvinceID\"]');\nconst valore = host.getAttribute('data-field-value');"
|
|
28356
|
+
},
|
|
28357
|
+
{
|
|
28358
|
+
"id": "code_2",
|
|
28359
|
+
"title": "Snippet 2",
|
|
28360
|
+
"language": "js",
|
|
28361
|
+
"code": "await page.waitForFunction((campo) => {\n const host = document.querySelector(`wuic-field-editor[data-field-name=\"${campo}\"]`);\n if (!host || host.getAttribute('data-has-record') !== 'true') return false;\n const dialogo = host.closest('wuic-parametric-dialog, .edit-form-content');\n if (dialogo?.getAttribute('data-record-loaded') !== 'true') return false;\n const valore = host.getAttribute('data-field-value');\n return valore !== null && valore !== '';\n}, 'StateProvinceID', { timeout: 30000 });"
|
|
28362
|
+
},
|
|
28363
|
+
{
|
|
28364
|
+
"id": "code_3",
|
|
28365
|
+
"title": "Snippet 3",
|
|
28366
|
+
"language": "js",
|
|
28367
|
+
"code": "const host = document.querySelector('wuic-chart-list');\nconst cmp = host.__wuicCmp || window.ng?.getComponent?.(host);\nconst tipo = cmp?.chartRef?.chart?.config?.type;"
|
|
28368
|
+
},
|
|
28369
|
+
{
|
|
28370
|
+
"id": "code_4",
|
|
28371
|
+
"title": "Snippet 4",
|
|
28372
|
+
"language": "js",
|
|
28373
|
+
"code": "await page.addInitScript(() => { globalThis.__wuicE2E = true; });"
|
|
28374
|
+
},
|
|
28375
|
+
{
|
|
28376
|
+
"id": "code_5",
|
|
28377
|
+
"title": "Snippet 5",
|
|
28378
|
+
"language": "ts",
|
|
28379
|
+
"code": "import { exposeWuicCmpOnHost } from '../../helpers/wuic-cmp-handle';\n\nexport class MioComponente {\n private readonly wuicCmpHandle = exposeWuicCmpOnHost(this);\n}"
|
|
28380
|
+
},
|
|
28381
|
+
{
|
|
28382
|
+
"id": "code_6",
|
|
28383
|
+
"title": "Snippet 6",
|
|
28384
|
+
"language": "js",
|
|
28385
|
+
"code": "await page.waitForFunction(() => {\n const visibile = (n) => {\n const s = getComputedStyle(n);\n if (s.display === 'none' || s.visibility === 'hidden' || s.opacity === '0') return false;\n const r = n.getBoundingClientRect();\n return r.width > 0 && r.height > 0;\n };\n return !Array.from(document.querySelectorAll('.busy-indicator')).some(visibile);\n}, null, { timeout: 20000 });"
|
|
28386
|
+
}
|
|
28387
|
+
]
|
|
28388
|
+
}
|
|
28389
|
+
],
|
|
28390
|
+
"images": []
|
|
28391
|
+
},
|
|
28004
28392
|
{
|
|
28005
28393
|
"slug": "troubleshooting",
|
|
28006
28394
|
"lang": "es-ES",
|
|
@@ -34733,6 +35121,99 @@ const frameworkDocsContent = {
|
|
|
34733
35121
|
],
|
|
34734
35122
|
"images": []
|
|
34735
35123
|
},
|
|
35124
|
+
{
|
|
35125
|
+
"slug": "testabilita-e2e",
|
|
35126
|
+
"lang": "de-DE",
|
|
35127
|
+
"title": "Testbarkeit und e2e-Hooks",
|
|
35128
|
+
"description": "Testbarkeit und e2e-Hooks - documentazione operativa e tecnica",
|
|
35129
|
+
"audience": [
|
|
35130
|
+
"developer",
|
|
35131
|
+
"integration"
|
|
35132
|
+
],
|
|
35133
|
+
"status": "stable",
|
|
35134
|
+
"tags": [
|
|
35135
|
+
"advanced"
|
|
35136
|
+
],
|
|
35137
|
+
"keywords": [
|
|
35138
|
+
"Testbarkeit und e2e-Hooks"
|
|
35139
|
+
],
|
|
35140
|
+
"toc": [
|
|
35141
|
+
{
|
|
35142
|
+
"id": "sec_1",
|
|
35143
|
+
"title": "Geltungsbereich"
|
|
35144
|
+
},
|
|
35145
|
+
{
|
|
35146
|
+
"id": "sec_2",
|
|
35147
|
+
"title": "DOM-Attribute des Field Editors"
|
|
35148
|
+
},
|
|
35149
|
+
{
|
|
35150
|
+
"id": "sec_3",
|
|
35151
|
+
"title": "Wann der Datensatz wirklich geladen ist"
|
|
35152
|
+
},
|
|
35153
|
+
{
|
|
35154
|
+
"id": "sec_4",
|
|
35155
|
+
"title": "Komponenten-Inspektion: `__wuicCmp`"
|
|
35156
|
+
},
|
|
35157
|
+
{
|
|
35158
|
+
"id": "sec_5",
|
|
35159
|
+
"title": "Das Lade-Overlay"
|
|
35160
|
+
},
|
|
35161
|
+
{
|
|
35162
|
+
"id": "sec_6",
|
|
35163
|
+
"title": "Was nicht als Selektor taugt"
|
|
35164
|
+
},
|
|
35165
|
+
{
|
|
35166
|
+
"id": "sec_7",
|
|
35167
|
+
"title": "Betriebshinweise"
|
|
35168
|
+
}
|
|
35169
|
+
],
|
|
35170
|
+
"sections": [
|
|
35171
|
+
{
|
|
35172
|
+
"id": "overview",
|
|
35173
|
+
"title": "Overview",
|
|
35174
|
+
"html": "<h1>Testbarkeit und e2e-Hooks</h1><p>Das Framework erzeugt die Oberfläche aus Metadaten: Es gibt keine handgeschriebenen <code>id</code>s, an denen sich ein Test festhalten könnte, und die sichtbaren Beschriftungen kommen aus den Übersetzungen, ändern sich also mit der Sprache des Benutzers. Damit die Anwendung von außen prüfbar ist, stellen die Runtime-Komponenten einen stabilen Vertrag bereit: <strong>DOM-Attribute</strong> und ein <strong>Inspektions-Handle</strong> der Komponente. Diese Seite listet diesen Vertrag und die Bereitschaftssignale auf, die vor jeder Interaktion abzuwarten sind.</p><h2>Geltungsbereich</h2><ul><li>DOM-Attribute von <code>wuic-field-editor</code> und <code>wuic-parametric-dialog</code>.</li><li>Handle <code>__wuicCmp</code>, um den Laufzeitzustand einer Komponente auch in Production-Builds zu lesen.</li><li>Abschlusssignale (Datensatz geladen, Lade-Overlay verschwunden).</li><li>Selektoren und Praktiken, die zu vermeiden sind.</li></ul><h2>DOM-Attribute des Field Editors</h2><p>Jedes im Formular gerenderte Feld sitzt in einem <code>wuic-field-editor</code>, der auf sein eigenes Host-Element schreibt:</p><table><thead><tr><th>Attribut</th><th>Inhalt</th></tr></thead><tbody><tr><td><code>data-field-name</code></td><td>logischer Spaltenname (<code>mc_nome_colonna</code>)</td></tr><tr><td><code>data-field-id</code></td><td><code>mc_id</code> der Spalte, leer wenn nicht verfügbar</td></tr><tr><td><code>data-widget-type</code></td><td>aufgelöster Widget-Typ (<code>mc_ui_column_type</code>)</td></tr><tr><td><code>data-editable</code></td><td><code>true</code>/<code>false</code> gemäß Metadaten und Formularzustand</td></tr><tr><td><code>data-hide-in-edit</code></td><td><code>true</code>/<code>false</code> (<code>mc_hide_in_edit</code>)</td></tr><tr><td><code>data-is-edit-form</code></td><td><code>true</code> im Bearbeitungsformular, <code>false</code> in Filter/Ansicht</td></tr><tr><td><code>data-has-record</code></td><td><code>true</code>, sobald das Datensatz-<strong>Objekt</strong> zugewiesen ist</td></tr><tr><td><code>data-field-value</code></td><td>aktueller Feldwert, serialisiert</td></tr></tbody></table><p>Der Anker ist also der Feldname, nicht die Position:</p><p>Snippet 1:</p><p><code>data-field-value</code> ist ein String: bei Lookups wird der verschachtelte <code>value</code> ausgegeben, bei Objekten das JSON, sonst die String-Konvertierung. Ein Test, der eine Zahl oder einen Boolean braucht, castet selbst (<code>Number(v)</code>, <code>v === 'true'</code>).</p><p>Die Attribute werden mit einem imperativen <code>setAttribute</code> in <code>syncDomAttrs()</code> geschrieben, aufgerufen von <code>ngOnChanges</code> und <code>ngDoCheck</code>, und <strong>nicht</strong> über <code>@HostBinding</code>: in zoneless Angular werden Binding-Getter nur dann neu ausgewertet, wenn die Change Detection diese Komponente berührt — und der erste Lesezugriff eines Tests kam früher.</p><h2>Wann der Datensatz wirklich geladen ist</h2><p><code>data-has-record</code> sagt, dass das Datensatz-Objekt <strong>existiert</strong>, nicht dass die Werte angekommen sind: Das Formular baut das Gerüst und füllt es, sobald <code>getFlatRecordData</code> antwortet. Das Signal „Werte da" sitzt am Dialog:</p><table><thead><tr><th>Signal</th><th>Bedeutung</th></tr></thead><tbody><tr><td><code>wuic-field-editor[data-has-record="true"]</code></td><td>Gerüst bereit, Werte nicht garantiert</td></tr><tr><td><code>wuic-parametric-dialog[data-record-loaded="true"]</code></td><td>die Datenantwort ist angekommen und wurde angewendet</td></tr></tbody></table><p>Lazy-Widgets — Code Editor, Lookup — propagieren ihren Wert einen Tick nach dem Dialog. Ein robustes Warten gewährt deshalb nach <code>data-record-loaded</code> ein kurzes Fenster, in dem der Wert erscheinen darf, ohne bei legitim leeren Feldern hängen zu bleiben:</p><p>Snippet 2:</p><h2>Komponenten-Inspektion: <code>__wuicCmp</code></h2><p><code>window.ng.getComponent()</code> ist das Debug-Tooling von Angular und <strong>existiert in Production-Builds nicht</strong>: Ein Test, der sich allein darauf stützt, scheitert nicht an einem Defekt, sondern daran, dass das Werkzeug auf der Installation, die Kunden tatsächlich betreiben, schlicht fehlt.</p><p>Deshalb legen die Komponenten, die Tests abfragen müssen, ihre eigene Instanz als <code>__wuicCmp</code> auf das Host-Element:</p><p>Snippet 3:</p><p>Das Handle ist <strong>nicht immer gesetzt</strong>. Eine Komponenteninstanz offenzulegen macht sie für jedes Skript der Seite erreichbar, und auf einer Produktionsinstallation nützt das niemandem:</p><ul><li>in der Entwicklung (<code>isDevMode()</code>) immer, dort gibt es <code>window.ng</code> ohnehin;</li><li>in Produktion nur, wenn die Seite <code>globalThis.__wuicE2E = true</code> <strong>vor</strong> dem Start der Anwendung gesetzt hat.</li></ul><p>Das erledigt der Test-Bootstrap über ein Init-Skript, nicht das Produkt:</p><p>Snippet 4:</p><p>Ist das Flag aus, kostet es einen booleschen Vergleich pro Instanz; ist es an, eine Property-Zuweisung plus einen Aufräum-Callback beim Zerstören der Komponente.</p><p><code>__wuicCmp</code> stellen bereit: <code>list-grid</code>, <code>chart-list</code>, <code>kanban-list</code>, <code>scheduler-list</code>, <code>timeline-list</code>, <code>tree-list</code>, <code>carousel-list</code>, <code>spreadsheet-list-sf</code>, <code>map-list</code>, <code>designer</code>, <code>parametric-dialog</code>, <code>field-editor</code> und die zwölf Feldeditoren, <code>meta-menu</code>, <code>notification-bell</code>, <code>bounded-repeater</code>, <code>pivot-builder</code>, <code>report-designer</code>, <code>workflow-designer</code>, <code>data-source</code>, <code>code-editor</code>, <code>app-settings-editor</code>.</p><p>Eine neue Komponente inspizierbar zu machen ist eine Zeile in der Klasse:</p><p>Snippet 5:</p><h2>Das Lade-Overlay</h2><p>Während des Ladens legt die Shell <code><div class="busy-indicator"></code> über die ganze Seite. Ein in diesem Moment gesendeter Klick <strong>landet auf dem Overlay</strong>, und mit Playwright scheitert <code>click({ force: true })</code> nicht: Es überspringt die Actionability-Prüfung, liefert das Event aber trotzdem an das darüberliegende Element aus. Der Klick verschwindet ohne Fehler, und der Test scheitert viel später — an einem Dialog, der nie aufging, einer Karte, die sich nie bewegte, einem Speichern, das nie gestartet zu sein scheint.</p><p>Vor jeder koordinatenbasierten Interaktion (erzwungene Klicks, Drags, <code>mouse.down</code>) wird abgewartet, bis die Seite frei ist:</p><p>Snippet 6:</p><p>Nützlich in der Diagnose: <code>document.elementFromPoint(x, y)</code> über dem Ziel sagt, wer den Klick tatsächlich bekäme.</p><h2>Was nicht als Selektor taugt</h2><ul><li><strong>Von Angular erzeugte `id`s</strong> (<code>_ngcontent-*</code>, <code>ng-reflect-*</code>): Sie ändern sich mit jedem Build und verschwinden in Produktion.</li><li><strong>Der sichtbare Text der Beschriftungen</strong>: Er kommt aus <code>_wuic_translations</code> und ändert sich mit der Sprache des Benutzers. Auf einer Installation mit nicht geladenen Übersetzungen liest man den rohen Schlüssel (<code>menu.root.administration</code>), nicht die Beschriftung.</li><li><strong>Die Position in einer Tabelle</strong> (<code>nth-child</code>): Die Spaltenreihenfolge ist Metadatum, und ein anderes <code>mcordine</code> verändert den Test.</li><li><strong>`window.ng.getComponent` als einziger Weg</strong>: gilt nur in der Entwicklung (siehe oben).</li></ul><h2>Betriebshinweise</h2><ul><li>Das Flag <code>__wuicE2E</code> ist ein Schalter der Tests: Das Produkt setzt es nie, und keine Funktion hängt von seiner Anwesenheit ab.</li><li>Die DOM-Attribute sind ein öffentlicher Vertrag: Stützt sich ein Test auf ein neues Attribut, wird dieses Attribut der Komponente hinzugefügt und hier dokumentiert — nicht aus einer internen Struktur abgeleitet.</li><li>Ein von <code>getComponent</code> zurückgegebenes <code>null</code> bedeutet „nicht inspizierbar", nicht „keine Daten": Beides in Fehlermeldungen zu unterscheiden verhindert, dass eine Diagnose in die falsche Richtung startet.</li></ul>",
|
|
35175
|
+
"codeSamples": [
|
|
35176
|
+
{
|
|
35177
|
+
"id": "code_1",
|
|
35178
|
+
"title": "Snippet 1",
|
|
35179
|
+
"language": "js",
|
|
35180
|
+
"code": "const host = document.querySelector('wuic-field-editor[data-field-name=\"StateProvinceID\"]');\nconst valore = host.getAttribute('data-field-value');"
|
|
35181
|
+
},
|
|
35182
|
+
{
|
|
35183
|
+
"id": "code_2",
|
|
35184
|
+
"title": "Snippet 2",
|
|
35185
|
+
"language": "js",
|
|
35186
|
+
"code": "await page.waitForFunction((campo) => {\n const host = document.querySelector(`wuic-field-editor[data-field-name=\"${campo}\"]`);\n if (!host || host.getAttribute('data-has-record') !== 'true') return false;\n const dialogo = host.closest('wuic-parametric-dialog, .edit-form-content');\n if (dialogo?.getAttribute('data-record-loaded') !== 'true') return false;\n const valore = host.getAttribute('data-field-value');\n return valore !== null && valore !== '';\n}, 'StateProvinceID', { timeout: 30000 });"
|
|
35187
|
+
},
|
|
35188
|
+
{
|
|
35189
|
+
"id": "code_3",
|
|
35190
|
+
"title": "Snippet 3",
|
|
35191
|
+
"language": "js",
|
|
35192
|
+
"code": "const host = document.querySelector('wuic-chart-list');\nconst cmp = host.__wuicCmp || window.ng?.getComponent?.(host);\nconst tipo = cmp?.chartRef?.chart?.config?.type;"
|
|
35193
|
+
},
|
|
35194
|
+
{
|
|
35195
|
+
"id": "code_4",
|
|
35196
|
+
"title": "Snippet 4",
|
|
35197
|
+
"language": "js",
|
|
35198
|
+
"code": "await page.addInitScript(() => { globalThis.__wuicE2E = true; });"
|
|
35199
|
+
},
|
|
35200
|
+
{
|
|
35201
|
+
"id": "code_5",
|
|
35202
|
+
"title": "Snippet 5",
|
|
35203
|
+
"language": "ts",
|
|
35204
|
+
"code": "import { exposeWuicCmpOnHost } from '../../helpers/wuic-cmp-handle';\n\nexport class MioComponente {\n private readonly wuicCmpHandle = exposeWuicCmpOnHost(this);\n}"
|
|
35205
|
+
},
|
|
35206
|
+
{
|
|
35207
|
+
"id": "code_6",
|
|
35208
|
+
"title": "Snippet 6",
|
|
35209
|
+
"language": "js",
|
|
35210
|
+
"code": "await page.waitForFunction(() => {\n const visibile = (n) => {\n const s = getComputedStyle(n);\n if (s.display === 'none' || s.visibility === 'hidden' || s.opacity === '0') return false;\n const r = n.getBoundingClientRect();\n return r.width > 0 && r.height > 0;\n };\n return !Array.from(document.querySelectorAll('.busy-indicator')).some(visibile);\n}, null, { timeout: 20000 });"
|
|
35211
|
+
}
|
|
35212
|
+
]
|
|
35213
|
+
}
|
|
35214
|
+
],
|
|
35215
|
+
"images": []
|
|
35216
|
+
},
|
|
34736
35217
|
{
|
|
34737
35218
|
"slug": "troubleshooting",
|
|
34738
35219
|
"lang": "de-DE",
|
|
@@ -35288,4 +35769,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
35288
35769
|
}] } });
|
|
35289
35770
|
|
|
35290
35771
|
export { FrameworkDocsComponent };
|
|
35291
|
-
//# sourceMappingURL=wuic-framework-lib-framework-docs.component-
|
|
35772
|
+
//# sourceMappingURL=wuic-framework-lib-framework-docs.component-CX4DuW-Q.mjs.map
|