L'arte del test di layout con Galen Framework
Pubblicato: 2022-03-10Quando si progetta un'interfaccia utente grafica, c'è sempre una domanda aperta: come automatizzare i test per essa? E come ci assicuriamo che il layout del sito Web rimanga reattivo e venga visualizzato correttamente su tutti i tipi di dispositivi con varie risoluzioni? Se a ciò si aggiungono le complicazioni derivanti da contenuti dinamici, requisiti di internazionalizzazione e localizzazione, diventa una vera sfida.
In questo articolo, ti guiderò attraverso un'interessante nuova tecnica di test del layout. Utilizzando Galen Framework, fornirò un tutorial dettagliato per scrivere test di layout generalizzati significativi, che possono essere eseguiti in qualsiasi browser e su qualsiasi dispositivo e allo stesso tempo utilizzati come un'unica fonte di verità nella documentazione di progettazione.
Ulteriori letture su SmashingMag:
- Sviluppo basato su test visivi per la progettazione di interfacce reattive
- Le basi dell'automazione dei test per app, giochi e Web mobile
- Diversi framework di automazione dei test per le app React Native
Dimostrerò anche come sono arrivato a un test ottimizzato per una pagina di messaggistica sul nostro sito Web di annunci, Marktplaats. Impareremo come estendere la sintassi di Galen con il nostro linguaggio, come migliorare il codice di test e come trasformare una routine di test del layout in arte.
Introduzione al quadro di Galeno
Galen Framework è stato trattato un anno fa in "Visual Test-Driven Development for Responsive Interface Design". A quel tempo, la sua sintassi era limitata. Da allora è migliorato molto e ha ottenuto molte nuove funzionalità, che esamineremo qui.
Nel caso non abbiate familiarità con Galen Framework, è uno strumento per test di layout reattivi e cross-browser e test funzionali, con un proprio linguaggio di test, chiamato Galen Specs. È basato su Selenium WebDriver e ha anche una ricca API JavaScript che ti consente di lavorare direttamente con WebDriver. Poiché hai il controllo su WebDriver, puoi eseguire test in qualsiasi browser, nel cloud (SauceLabs, BrowserStack, PerfectoMobile, ecc.) o su dispositivi mobili reali utilizzando Appium.
Installazione ed esecuzione
Configurare Galen Framework è facile. Basta eseguire il seguente comando per installarlo tramite npm:
npm install -g galenframework-cli
Se non utilizzi npm, scarica l'ultimo archivio di Galen Framework, estrai il pacchetto e segui le istruzioni di installazione.
Una volta installato, Galen Framework può essere avviato in vari modi. Ad esempio, puoi utilizzare il comando check
per avviare un rapido test di una singola pagina. Per questo comando, devi fornire un file .gspec
con le convalide del layout, quindi puoi invocarlo in questo modo:
galen check loginPage.gspec --url https://example.com --size 1024x768 --include desktop --htmlreport reports
Questo comando avvierà un browser, aprirà l'URL specificato, ridimensionerà la finestra del browser a 1024 × 768 pixel ed eseguirà tutte le convalide dichiarate nel file loginPage.gspec
. Di conseguenza, otterrai un rapporto HTML dettagliato.
Gestione delle suite di test
Nel mondo reale, una vera applicazione web non è costituita esclusivamente da pagine statiche. Molto spesso dovrai eseguire alcune azioni per raggiungere il luogo che desideri controllare. In questo caso, Galen offre suite di test JavaScript e l'API JavaScript GalenPages per l'implementazione del modello a oggetti della pagina. Ecco un semplice esempio di un test di Galen JavaScript:
test("Home page", function() { var driver = createDriver("https://galenframework.com", "1024x768"); checkLayout(driver, "homePage.gspec", ["desktop"]); });
Ed ecco un'implementazione del modello a oggetti della pagina per una pagina di accesso, tratta da un progetto reale.
WelcomePage = $page("Welcome page", { loginButton: "#welcome-page .button-login" }); LoginPage = $page("Login page", { username: "input[name='login.username']", password: "input[name='login.password']", loginButton: "button.button-login" loginAs: loggedFunction ("Log in as ${_1.username} with password ${_1.password}", function(user) { this.username.typeText(user.username); this.password.typeText(user.password); this.loginButton.click(); }) }); test("Login page", function() { var driver = createDriver("https://testapp.galenframework.com", "1024x768"); var welcomePage = new WelcomePage(driver).waitForIt(); welcomePage.loginButton.click(); new LoginPage(driver).waitForIt(); checkLayout(driver, "loginPage.gspec", ["desktop"]); });
Per un utilizzo avanzato, ti consiglio di guardare il progetto Galen Bootstrap. È un'estensione JavaScript creata appositamente per Galen. Fornisce alcune funzionalità extra per i test dell'interfaccia utente e un modo più semplice per configurare i browser ed eseguire suite di test complesse.
Prova di layout semplice
Vorrei iniziare introducendo un semplice test di layout in Galen Framework. Quindi, passerò ai casi d'uso avanzati e dimostrerò come estendere la sintassi di Galen Specs. Per questo, esamineremo un'intestazione con un'icona e una didascalia:

Nel codice HTML, potrebbe assomigliare a questo:
<body> <!-- … --> <div> <img class="header-logo" src="/imgs/header-logo.png"/> <h1>My Blog</h1> </div> <!-- … --> </body>
La forma più semplice di un test di layout di Galen sarebbe simile alla seguente. Innanzitutto, dobbiamo dichiarare gli oggetti con i selettori CSS.
@objects header #header icon #header img caption #header h1
Quindi, dichiariamo una sezione di test con un nome significativo e inseriamo tutte le nostre convalide sotto di essa.
= Icon and Caption = icon: left-of caption 10 to 15px width 32px height 32px inside header 10px top caption: aligned horizontally all header inside header
Qui abbiamo testato due elementi di intestazione: l'icona e la didascalia. Tutte le convalide elencate sotto l'icona e gli elementi della didascalia sono in realtà specifiche Galen standard. Queste specifiche sono gli elementi costitutivi fondamentali con cui puoi assemblare la tua soluzione di test del layout. Ogni specifica verifica una singola proprietà (come larghezza, altezza, testo), posizionamento relativo (come all'interno, a sinistra di, sopra) o pixel nello screenshot (come combinazione di colori, immagine).
Testare più elementi usando forEach Loops
L'esempio precedente mostra uno scenario semplice. Vediamo come possiamo affrontare una situazione più complicata: un menu orizzontale. Per prima cosa, proviamo una semplice tecnica di test del layout.

Inizia abbinando più elementi sulla pagina. Con il codice seguente, stiamo dicendo a Galen di cercare elementi che corrispondono al selettore #menu ul li
CSS.
@objects menu #menu item-* ul li
Successivamente, possiamo fare riferimento a queste voci con nomi come menu.item-1
e menu.item-2
e scorrere tutte le voci di menu utilizzando un ciclo @forEach
.
= Menu = menu.item-1: inside menu 0px top left bottom @forEach [menu.item-*] as menuItem, next as nextItem ${menuItem}: left-of ${nextItem} 0px aligned horizontally all ${nextItem}
Come puoi vedere, anche se il controllo vero e proprio non è così complesso, il codice è già diventato meno intuitivo. Immagina se avessimo un codice più simile nei nostri test. Ad un certo punto, diventerebbe un pasticcio ingestibile. Dovrebbe esserci un modo per migliorarlo.
Ripensare i test di layout
Se pensi all'esempio precedente, sembra che potremmo esprimere il layout in una o due frasi. Ad esempio, potremmo dire qualcosa del tipo: "Tutte le voci di menu devono essere allineate orizzontalmente, senza margini intermedi. La prima voce di menu dovrebbe trovarsi sul lato sinistro del menu, senza margini". Poiché abbiamo formulato delle frasi per spiegare il layout che vogliamo, perché non possiamo semplicemente usarle nel nostro codice? Immagina se potessimo scrivere il codice in questo modo:
= Menu = |first menu.item-* is in top left corner of menu |menu.item-* are aligned horizontally next to each other
In effetti, questo è un vero codice funzionante, copiato dal mio progetto. In queste ultime due righe (che iniziano con la pipe, |
), stiamo invocando funzioni personalizzate che raccolgono i loro argomenti analizzando queste due istruzioni. Naturalmente, l'esempio sopra non funzionerà così com'è. Affinché venga compilato, è necessario implementare i gestori per queste due istruzioni. Torneremo su questa implementazione in seguito.
Il punto chiave dell'esempio sopra è che il test del layout è passato dal test guidato dagli oggetti al test basato sull'espressione . Potrebbe non essere ovvio da un esempio così piccolo, ma è sicuramente evidente su scala più ampia. Allora, perché questo è significativo? La risposta breve è che questo cambia la nostra mentalità e influisce sul modo in cui progettiamo il nostro software e scriviamo i test per esso.
Usando questa tecnica, non trattiamo la nostra pagina come un insieme di oggetti con relazioni specifiche tra loro. Non testiamo le proprietà CSS dei singoli elementi. Ed evitiamo di scrivere codice complicato non banale. Invece, stiamo cercando di pensare a schemi di layout comuni e affermazioni significative. Invece di testare separatamente la voce di menu 1, la voce di menu 2 e così via, applichiamo affermazioni generiche che:
- sono riproducibili su altri elementi;
- non contengono valori di pixel codificati;
- si applicano alle astrazioni e non agli oggetti concreti;
- e, ultimo ma non meno importante, hanno effettivamente un senso quando li leggiamo.
Come funziona
Lascia che ti spieghi il meccanismo delle espressioni di layout personalizzate usando questo semplice esempio:

In questo esempio, dovremmo controllare che il pulsante si estenda al pannello, senza margini sul lato sinistro o destro. Senza regole personalizzate, possiamo affrontarlo in diversi modi, ma io preferisco la seguente soluzione:
button: inside some_panel 0px left right
Il codice sopra ci dà la flessibilità di dichiarare un margine personalizzato sui lati e verifica anche implicitamente che il pulsante sia contenuto completamente all'interno del pannello. Lo svantaggio è che non è molto leggibile, motivo per cui inserirò questa convalida dietro il button stretches to some_panel
. Affinché funzioni, dobbiamo scrivere una regola personalizzata come questa:
@rule %{elementName} stretches to %{parentName} ${elementName}: inside ${parentName} 0px left right
Questo è tutto. Ora possiamo metterlo nel nostro test in una sola riga:
| button stretches to some_panel
Come puoi vedere, questa regola accetta due argomenti: elementName
e parentName
. Questo ci permette di applicarlo anche ad altri elementi. Basta sostituire i nomi di questi due oggetti.
| login_panel stretches to main_container | header stretches to screen | footer stretches to screen # etc.
Implementazione del proprio linguaggio di prova
Torniamo agli esempi iniziali di espressioni di layout per il menu orizzontale.
= Menu = | first menu.item-* is in top left corner of menu | menu.item-* are aligned horizontally next to each other
Possiamo implementare la prima regola nel modo seguente:
@rule first %{itemPattern} is in %{cornerSides} corner of %{parentElement} @if ${count(itemPattern) > 0} ${first(itemPattern).name}: inside ${parentElement} 0px ${cornerSides}
Se utilizzato nel nostro esempio, analizzerebbe gli argomenti come segue:
-
itemPattern
=menu.item-*
-
cornerSides
= intop left
-
parentElement
=menu
Poiché abbiamo finito con la nostra prima espressione, possiamo passare a quella successiva. Nella seconda espressione, dovremmo testare l'allineamento orizzontale di tutte le voci di menu. Propongo tre semplici passaggi:
- Trova tutte le voci di menu.
- Esegui l'iterazione su tutti fino al penultimo elemento.
- Verificare che l'elemento
n
si trovi a sinistra dell'elementon+1
e che i loro bordi superiore e inferiore siano allineati.
Per farlo funzionare, dobbiamo prendere un ciclo @forEach
e le specifiche left-of
e aligned
. Fortunatamente, in Galeno puoi fare riferimento all'elemento precedente o successivo in un ciclo. Nel caso in cui tu abbia dichiarato un riferimento all'elemento successivo, itererà solo fino al penultimo elemento, che è esattamente ciò di cui abbiamo bisogno.
@rule %{itemPattern} are aligned horizontally next to each other @forEach [${itemPattern}] as item, next as nextItem ${item}: left-of ${nextItem} 0px aligned horizontally all ${nextItem}
Potresti chiedere, e se dovessimo specificare un margine nel nostro test (come ~ 20px
o 10 to 20px
)? Quindi, suggerisco di implementare una regola separata o di estendere quella esistente per supportare un argomento %{margin}
.
@rule %{itemPattern} are aligned horizontally next to each other with %{margin} margin @forEach [${itemPattern}] as item, next as nextItem ${item}: left-of ${nextItem} ${margin} aligned horizontally all ${nextItem}
Questo è tutto! Abbiamo creato un'espressione generica che ci aiuta a convalidare il menu orizzontale. Tuttavia, grazie alla sua flessibilità, possiamo fare molto di più. Possiamo usarlo per testare qualsiasi altro elemento nella pagina. Possiamo anche usarlo per testare l'allineamento di due pulsanti:

| menu.item-* are aligned horizontally next to each other with 0px margin | submit_button, cancel_button are aligned horizontally next to each other with 20px margin
Potresti notare in questi due esempi che abbiamo dichiarato il primo argomento in due modi diversi. Nella prima espressione, il primo argomento è “menu.item-*”
e nella seconda espressione è dichiarato come “submit_button, cancel_button”
. Ciò è possibile perché il ciclo @forEach
ci consente di utilizzare un elenco di oggetti separati da virgole insieme all'operatore stella. Ma non abbiamo ancora finito con il refactoring. Potremmo migliorare ulteriormente il codice e renderlo più leggibile. Se creiamo gruppi per le voci di menu e i pulsanti del modulo di accesso, potremmo ottenere qualcosa del genere:

@groups menu_items menu_item-* login_form_buttons submit_button, cancel_button = Testing login page = | &menu_items are aligned horizontally next to each other with 0px margin | &login_form_buttons are aligned horizontally next to each other with 20px margin
In questo caso, dobbiamo usare il simbolo &
, che sta per una dichiarazione di gruppo. Questo è già un buon test. Innanzitutto, funziona e siamo in grado di testare ciò di cui abbiamo bisogno. Inoltre, il codice è chiaro e leggibile. Se un'altra persona dovesse chiederti come dovrebbe essere la pagina di accesso e quali sono i requisiti di progettazione, potresti dirgli di guardare il test.
Come puoi vedere, l'implementazione di espressioni personalizzate per modelli di layout complessi non è un grosso problema. Potrebbe essere una sfida all'inizio, ma ricorda comunque qualcosa di un'attività creativa.
Margini dinamici
Diamo un'occhiata a un altro raro modello di layout che potresti trovare a volte su vari siti Web. E se volessimo testare che gli elementi hanno una distanza uguale tra loro? Proviamo a implementare un'altra regola per questo, ma questa volta utilizzando un'implementazione JavaScript. Propongo una tale affermazione: “box_item-* are aligned horizontally next to each other with equal distance”
. Sarà un po' complicato perché non conosciamo il margine tra gli elementi e non possiamo semplicemente codificare i valori dei pixel. Pertanto, la prima cosa che dobbiamo fare è recuperare il margine effettivo tra il primo e l'ultimo elemento.

Una volta ottenuto quel margine, possiamo dichiararlo in un ciclo @forEach
simile a come facevamo prima. Propongo di implementare questa regola utilizzando l'API JavaScript perché la logica richiesta è un po' più complessa rispetto a tutti i nostri esempi precedenti. Creiamo un file chiamato my-rules.js
e digitiamo questo codice:
rule("%{objectPattern} are aligned horizontally next to each other with equal margin", function (objectName, parameters) { var allItems = findAll(parameters.objectPattern), distance = Math.round(Math.abs(allItems[1].left() - allItems[0].right())), expectedMargin = (distance - 1) + " to " + (distance + 1) + "px"; if (allItems.length > 0) { for (var i = 0; i < allItems.length - 1; i += 1) { var nextElementName = allItems[i + 1].name; this.addObjectSpecs(allItems[i].name, [ "aligned horizontally all " + nextElementName, "left-of " + nextElementName + " " + expectedMargin ]); } } });
Nel nostro codice di prova, lo useremo in questo modo:
@script my-rules.js # … = Boxes = | box_item-* are aligned horizontally next to each other with equal distance
Come puoi vedere, in Galen Framework possiamo scegliere tra due linguaggi durante l'implementazione delle regole: Galen Specs e JavaScript. Per le espressioni semplici, Galen Specs è più facile da usare, ma per quelle complesse scelgo sempre JavaScript. Se vuoi saperne di più sulle regole JavaScript, fai riferimento alla documentazione.
Galeno Extra
Avendo giocato abbastanza con vari schemi di layout, mi sono reso conto che tutte queste regole di Galeno potevano essere facilmente applicate in qualsiasi altro progetto di prova. Questo mi ha dato l'idea di compilare le espressioni di layout più comuni nella propria libreria. È così che sono arrivato a creare il progetto Galen Extras. Di seguito sono riportati alcuni esempi di ciò che questa libreria è in grado di fare:
| header.icon should be squared | amount of &menu_items should be > 3 | &menu_items are aligned horizontally next to each other | &list_items are aligned vertically above each other with equal distance | every &menu_item is inside menu 0px top and has width > 50px | first &menu_item is inside menu 0px top left | &menu_items are rendered in 2 column table | &menu_items are rendered in 2 column table, with 0 to 1px vertical and 10px horizontal margin | &login_form_elements sides are vertically inside content_container with 20px margin login_panel: | located on the left side of panel and takes 70 % of its width # etc …
La libreria Galen Extras contiene molti degli schemi di layout che si trovano comunemente sui siti Web e continuo ad aggiornarla non appena scopro uno schema utile. Una volta configurata questa libreria, ho deciso di provarla su un vero progetto di test.
Testare l'app di messaggistica
Attualmente lavoro come ingegnere del software presso Marktplaats. Ad un certo punto, ho deciso di applicare tutta l'esperienza maturata in un progetto reale. Avevo bisogno di testare la pagina di messaggistica sul nostro sito web. Ecco come appare:

Ad essere onesti, l'implementazione di test per tali pagine mi è sempre sembrata un po' spaventosa, in particolare i test di layout. Ma con la libreria Galen Extras in atto, in realtà è andato abbastanza bene e presto sono stato in grado di trovare questo codice:
@import ../selected-conversation.gspec @groups (message, messages) messenger.message-* first_two_messages messenger.message-1,messenger.message-2 first_message messenger.message-1 second_message messenger.message-2 third_message messenger.message-3 (message_date_label, message_date_labels) messenger.date_label-* first_date_label messenger.date_label-1 second_date_label messenger.date_label-2 = Messages panel = = Messages and Date labels = |amount of visible &message_date_labels should be 1 |first &message_date_label has text is "17 november 2015" |amount of visible &messages should be 3 |&first_two_messages should be located at the left inside messenger with ~ 20px margin |&third_message should be located at the right inside messenger with ~ 20px margin |&messages are placed above each other with 10 to 15px margin |text of all &messages should be ["Hi there!", "I want to buy something", "Hello! Sure, it's gonna be 100 euros"] = Styling = |&first_two_messages should be styled as others message |&third_message should be styled as own message
Estrazione di intervalli di pixel
Il test sembrava a posto: era compatto e leggibile ma ancora lontano dall'essere perfetto. Non mi sono piaciute molto tutte quelle definizioni di margine ( ~ 20px
, 10 to 15px
). Alcuni di loro sono stati ripetuti ed era difficile capire cosa rappresentassero ciascuno di loro. Ecco perché ho deciso di nascondere ogni margine dietro una variabile significativa.
# ... @set messages_side_margin ~ 20px messages_vertical_margin 10 to 15px = Messages panel = = Messages and Date labels = |amount of visible &message_date_labels should be 1 |first &message_date_label has text is "17 november 2015" |amount of visible &messages should be 3 |&first_two_messages should be located at the left inside messenger with ${messages_side_margin} margin |&third_message should be located at the right inside messenger with ${messages_side_margin} margin |&messages are placed above each other with ${messages_vertical_margin} margin # ...
Come puoi vedere, ho spostato i margini in messages_vertical_margin
e messages_side_margin
. Ho anche dichiarato un margine minimal
, che è un intervallo compreso tra 0 e 1 pixel.
# ... @set minimal 0 to 1px = Conversations Panel = | &conversations are aligned above each other with ${minimal} margin # ...
Convalida basata su immagini ed espressioni personalizzate
Dopo aver coperto il posizionamento di tutti gli elementi principali nella pagina, ho deciso di testare anche lo styling. Volevo verificare che ogni messaggio avesse un colore di sfondo specifico per il ruolo dell'utente. Quando gli utenti hanno effettuato l'accesso, i messaggi avranno uno sfondo azzurro. I messaggi per altri utenti avrebbero uno sfondo bianco. Nel caso in cui non sia stato inviato un messaggio, l'avviso di errore avrà uno sfondo rosa. Ecco la regola che mi ha aiutato a convalidare questi stili:
@set OWN_MESSAGE_COLOR #E1E8F5 OTHERS_MESSAGE_COLOR white ERROR_MESSAGE_COLOR #FFE6E6 @rule %{item} should be styled as %{style} message ${item}: @if ${style === "own"} color-scheme > 60% ${OWN_MESSAGE_COLOR}, 0.2 to 20 % ${MAJOR_TEXT_MESSAGE_COLOR} @elseif ${style === "error"} color-scheme > 60% ${ERROR_MESSAGE_COLOR}, 0.2 to 20 % ${MAJOR_TEXT_MESSAGE_COLOR} @else color-scheme > 60% ${OTHERS_MESSAGE_COLOR}, 0.2 to 20 % ${MAJOR_TEXT_MESSAGE_COLOR}
La specifica della combinazione di color-scheme
verifica la distribuzione proporzionale dei colori all'interno di un elemento. Ritaglia uno screenshot della pagina e analizza la distribuzione del colore. Quindi, per verificare il colore di sfondo di un elemento, controlliamo semplicemente che la sua distribuzione sia maggiore del 60% della gamma cromatica totale. Nel test, questa regola viene invocata in questo modo:
= Styling = |&first_two_messages should be styled as others message |&third_message should be styled as own message
Configurazione delle suite di test
L'app di messaggistica è un'applicazione dinamica che funziona insieme all'API di messaggistica RESTful. Pertanto, per testare i suoi layout in tutti i diversi stati, dobbiamo preparare i dati di prova. Ho deciso di simulare l'API di messaggistica in modo da poter configurare tutti i miei messaggi di prova nella suite di test. Ecco un frammento della mia suite di test che mostra come sono strutturati i nostri test.
// ... testOnAllDevices("Unselected 2 conversations", "/", function (driver, device) { mock.onGetMyConversationsReturn(sampleConversations); refresh(driver); new MessageAppPage(driver).waitForIt(); checkLayout(driver, "specs/tests/unselected-conversations.gspec", device.tags); }); testOnAllDevices("When clicking a conversation it should reveal messages", "/", function (driver, device) { mock.onGetMyConversationsReturn(sampleConversations); mock.onGetSingleConversationReturn(sampleMessages); refresh(driver); var page = new MessageAppPage(driver).waitForIt(); page.clickFirstConversation(); checkLayout({ driver: driver, spec: "specs/tests/three-simple-messages-test.gspec", tags: device.tags, vars: { expectedTextProvider: textProvider({ "messenger.message-1": "Hi there!\n11:02", "messenger.message-2": "I want to buy something\n12:02", "messenger.message-3": "Hello! Sure, it's gonna be 100 euros\n13:02" }) } }); }); // ...
Cattura insetti
L'implementazione di queste semplici espressioni ripaga abbastanza rapidamente. Esaminiamo il tipo di bug che possiamo rilevare con la nostra suite di test.
Problema di stile
Ecco un esempio di quando qualcosa va storto nella nostra base di codice CSS e, di conseguenza, tutti i messaggi vengono visualizzati con lo stesso sfondo.

Se confronti questo screenshot con l'originale, noterai che l'ultimo messaggio ha uno sfondo bianco, mentre dovrebbe essere azzurro. Vediamo come Galeno segnala questo problema:

Per l'oggetto evidenziato, viene visualizzato il color #e1e8f5 on “messenger.message-3” is 0% but it should be greater than 60%
. Ad essere onesti, questo messaggio di errore non sembra molto chiaro, ma poiché questo controllo è stato generato da una regola personalizzata, possiamo sempre cercare il suo nome originale in un ramo del rapporto:

Se scorri verso l'alto, vedrai che l'istruzione originale è &third_message should be styled as own message
. Questo è un altro vantaggio dell'utilizzo di espressioni personalizzate: aiutano a comprendere l'errore e descrivono bene tutte le convalide generate.
Problema di posizionamento
Ecco un altro esempio di quando il layout va storto a causa di un allineamento errato di un elemento. Nella schermata seguente, puoi vedere che l'ultimo messaggio è posizionato sul lato sinistro della finestra di messaggistica, invece che a destra.

Esaminiamo nuovamente lo screenshot con il messaggio di errore:

Lo screenshot evidenzia il contenitore di messaggistica e l'ultimo elemento del messaggio. Insieme a ciò, mostra il seguente messaggio di errore: “messenger.message-3” is 285px right which is not in range of 22 to 28px
. Potrebbe non essere chiaro a uno sviluppatore web il motivo per cui è previsto un margine da 22 a 28 pixel sul lato destro. Ancora una volta, dovresti cercare una dichiarazione di convalida nel ramo del rapporto:

L'istruzione originale per quel controllo è &third_message should be located at the right inside messenger with ~ 25px margin
. Questo ha molto più senso. Inoltre, altri ingegneri front-end capiranno questo rapporto di prova, anche se non hanno scritto i test.
Linee guida per il test del layout
Con tutti questi diversi esperimenti in mente, ho deciso di formalizzare tutto l'apprendimento in linee guida generali per i test di layout. Ecco un rapido elenco di controllo dei passaggi da seguire per facilitare la routine di test.
- Identificare i modelli di layout nel design.
- Generalizzare le dichiarazioni di convalida. Prova a condensare la maggior parte delle convalide in singole frasi.
- Componentizza! È sempre meglio spostare i test di elementi ripetuti in componenti dedicati.
- Usa nomi significativi per sezioni, regole e oggetti.
- Evita i pixel. Prova a sostituire i valori dei pixel (se valori esatti o intervalli) con variabili significative.
- Modifica il codice del tuo sito web per semplificare il test. Questo ti aiuterà a strutturare e mantenere sia il codice di produzione che di test.
Criteri di accettazione in soccorso
Spesso ricevo domande del tipo: "Quindi quanto dovrebbe essere dettagliato un test di layout? E cosa dovremmo testare in particolare?" Una risposta generale è difficile da dare. Il problema è che quando la copertura del test è piccola, perdi i bug. D'altra parte, se hai test troppo dettagliati, potresti ottenere molti falsi positivi e in futuro potresti perderti nella manutenzione del test. Quindi, c'è un compromesso. Ma ho trovato una linea guida generale per me stesso. Se dividi il lavoro in storie utente più piccole, diventa più facile strutturare il design di una pagina sotto forma di criteri di accettazione. Alla fine, potresti inserire proprio questo criterio di accettazione nel tuo codice di test. Ad esempio, alcune di queste istruzioni potrebbero essere definite sotto forma di regole personalizzate, come mostrato in tutti gli esempi di codice precedenti. Un buon esempio di criteri di accettazione potrebbe essere qualcosa del genere:
- I popup devono essere centrati verticalmente e orizzontalmente sullo schermo.
- Dovrebbero essere larghi 400 pixel.
- I pulsanti devono essere allineati orizzontalmente.
- E così via
Una volta descritto il progetto in frasi semplici, diventa più facile convertirli in istruzioni riutilizzabili e organizzare il codice di test.
Conclusione
Come puoi vedere, un esercizio del genere ti aiuta a strutturare un progetto e scoprire schemi di layout generali che possono essere condivisi su più componenti di pagina. Anche se la pagina è complessa e composta da molti elementi, puoi sempre trovare un modo per raggrupparli nelle espressioni di layout. Con questo approccio, il test del layout diventa più uno strumento per lo sviluppo basato su test, aiutandoti a progettare, implementare e fornire software in modo incrementale, il che è particolarmente utile in un ambiente agile.
Risorse
- Galen Framework (sito ufficiale)
- Galen Framework, GitHub
- Galen Extras (biblioteca), GitHub
- Galen Bootstrap, GitHub
- "Esercitazioni sulla struttura di Galeno", YouTube