Localizzatori
Un localizzatore identifica un elemento o un insieme di elementi. Ogni localizzatore è definito da una stringa, detta selettore. Vitest astrae questo concetto fornendo metodi pratici che generano automaticamente tali selettori.
L'API dei localizzatori si basa su una derivazione dei localizzatori di Playwright chiamata Ivya. Tuttavia, Vitest rende questa API disponibile per ogni provider, non solo per Playwright.
TIP
Questa pagina illustra l'utilizzo dell'API. Per una comprensione più approfondita dei localizzatori e del loro impiego, si consiglia di consultare la documentazione "Locators" di Playwright.
getByRole
function getByRole(
role: ARIARole | string,
options?: LocatorByRoleOptions
): Locator;
Crea un localizzatore per individuare un elemento tramite il suo ruolo ARIA, gli attributi ARIA e il nome accessibile.
TIP
Se si cerca un singolo elemento con getByText('Il nome')
, è spesso preferibile utilizzare getByRole(expectedRole, { name: 'Il nome' })
. La query basata sul nome accessibile non sostituisce altre query come *ByAltText
o *ByTitle
. Sebbene il nome accessibile possa coincidere con questi attributi, non ne replica la funzionalità.
Considera la seguente struttura DOM:
<h3>Sign up</h3>
<label>
Login
<input type="text" />
</label>
<label>
Password
<input type="password" />
</label>
<br />
<button>Submit</button>
Puoi localizzare ciascun elemento in base al suo ruolo implicito:
await expect
.element(page.getByRole('heading', { name: 'Sign up' }))
.toBeVisible();
await page.getByRole('textbox', { name: 'Login' }).fill('admin');
await page.getByRole('textbox', { name: 'Password' }).fill('admin');
await page.getByRole('button', { name: /submit/i }).click();
WARNING
I ruoli vengono confrontati per uguaglianza di stringa, senza ereditare dalla gerarchia dei ruoli ARIA. Di conseguenza, una query su un ruolo di superclasse come checkbox
non includerà elementi con un ruolo di sottoclasse come switch
.
Per impostazione predefinita, molti elementi semantici in HTML possiedono un ruolo; ad esempio, <input type="radio">
ha il ruolo "radio". Gli elementi non semantici in HTML non hanno un ruolo; <div>
e <span>
senza semantica aggiunta restituiscono null
. L'attributo role
può fornire semantica.
Fornire ruoli tramite attributi role
o aria-*
a elementi incorporati che possiedono già un ruolo implicito è fortemente sconsigliato dalle linee guida ARIA.
Opzioni
exact: boolean
Indica se il
name
deve corrispondere esattamente: con distinzione tra maiuscole e minuscole e considerando l'intera stringa. Disabilitato per impostazione predefinita. Questa opzione viene ignorata sename
è un'espressione regolare. Si noti che la corrispondenza esatta esegue comunque il trimming degli spazi bianchi.tsx<button>Hello World</button>; page.getByRole('button', { name: 'hello world' }); // ✅ page.getByRole('button', { name: 'hello world', exact: true }); // ❌ page.getByRole('button', { name: 'Hello World', exact: true }); // ✅
checked: boolean
Determina se gli elementi selezionati (impostati da
aria-checked
o<input type="checkbox"/>
) devono essere inclusi. Per impostazione predefinita, il filtro non viene applicato.Vedi
aria-checked
per maggiori informazioni.tsx<> <button role="checkbox" aria-checked="true" /> <input type="checkbox" checked /> </>; page.getByRole('checkbox', { checked: true }); // ✅ page.getByRole('checkbox', { checked: false }); // ❌
disabled: boolean
Indica se gli elementi disabilitati devono essere inclusi. Per impostazione predefinita, il filtro non viene applicato. Si noti che, a differenza di altri attributi, lo stato
disabled
è ereditato.Vedi
aria-disabled
per maggiori informazioni.tsx<input type="text" disabled />; page.getByRole('textbox', { disabled: true }); // ✅ page.getByRole('textbox', { disabled: false }); // ❌
expanded: boolean
Indica se gli elementi espansi devono essere inclusi. Per impostazione predefinita, il filtro non viene applicato.
Vedi
aria-expanded
per maggiori informazioni.tsx<a aria-expanded="true" href="example.com"> Link </a>; page.getByRole('link', { expanded: true }); // ✅ page.getByRole('link', { expanded: false }); // ❌
includeHidden: boolean
Indica se gli elementi che sono normalmente esclusi dall'albero di accessibilità devono essere interrogati. Per impostazione predefinita, solo gli elementi non nascosti vengono abbinati dal selettore di ruolo.
Si noti che i ruoli
none
epresentation
sono sempre inclusi.tsx<button style="display: none" />; page.getByRole('button'); // ❌ page.getByRole('button', { includeHidden: false }); // ❌ page.getByRole('button', { includeHidden: true }); // ✅
level: number
Un attributo numerico solitamente presente per i ruoli
heading
,listitem
,row
,treeitem
, con valori predefiniti per gli elementi<h1>-<h6>
. Per impostazione predefinita, il filtro non viene applicato.Vedi
aria-level
per maggiori informazioni.tsx<> <h1>Heading Level One</h1> <div role="heading" aria-level="1"> Second Heading Level One </div> </>; page.getByRole('heading', { level: 1 }); // ✅ page.getByRole('heading', { level: 2 }); // ❌
name: string | RegExp
Nome accessibile. Per impostazione predefinita, la corrispondenza non distingue tra maiuscole e minuscole e cerca la presenza di una sottostringa. Usa l'opzione
exact
per controllare questo comportamento.tsx<button>Click Me!</button>; page.getByRole('button', { name: 'Click Me!' }); // ✅ page.getByRole('button', { name: 'click me!' }); // ✅ page.getByRole('button', { name: 'Click Me?' }); // ❌
pressed: boolean
Indica se gli elementi premuti devono essere inclusi. Per impostazione predefinita, il filtro non viene applicato.
Vedi
aria-pressed
per maggiori informazioni.tsx<button aria-pressed="true">👍</button>; page.getByRole('button', { pressed: true }); // ✅ page.getByRole('button', { pressed: false }); // ❌
selected: boolean
Indica se gli elementi selezionati devono essere inclusi. Per impostazione predefinita, il filtro non viene applicato.
Vedi
aria-selected
per maggiori informazioni.tsx<button role="tab" aria-selected="true"> Vue </button>; page.getByRole('button', { selected: true }); // ✅ page.getByRole('button', { selected: false }); // ❌
Vedi anche
getByAltText
function getByAltText(text: string | RegExp, options?: LocatorOptions): Locator;
Crea un localizzatore in grado di trovare un elemento con un attributo alt
che corrisponde al testo. A differenza dell'implementazione di testing-library, Vitest troverà la corrispondenza con qualsiasi elemento che abbia un attributo alt
corrispondente.
<img alt="Incredibles 2 Poster" src="/incredibles-2.png" />;
page.getByAltText(/incredibles.*? poster/i); // ✅
page.getByAltText('non existing alt text'); // ❌
Opzioni
exact: boolean
Indica se il
text
deve corrispondere esattamente: con distinzione tra maiuscole e minuscole e considerando l'intera stringa. Disabilitato per impostazione predefinita. Questa opzione viene ignorata setext
è un'espressione regolare. Si noti che la corrispondenza esatta esegue comunque il trimming degli spazi bianchi.
Vedi anche
getByLabelText
function getByLabelText(
text: string | RegExp,
options?: LocatorOptions
): Locator;
Crea un localizzatore in grado di trovare un elemento che ha un'etichetta associata.
Il localizzatore page.getByLabelText('Username')
troverà tutti gli input nell'esempio seguente:
// relazione `for`/`htmlFor` tra label e id dell'elemento del form
<label for="username-input">Username</label>
<input id="username-input" />
// L'attributo aria-labelledby con elementi del form
<label id="username-label">Username</label>
<input aria-labelledby="username-label" />
// Etichette wrapper
<label>Username <input /></label>
// Etichette wrapper dove il testo dell'etichetta è in un altro elemento figlio
<label>
<span>Username</span>
<input />
</label>
// attributi aria-label
// Attenzione: questa non è un'etichetta visibile agli utenti sulla pagina, quindi la funzione del tuo input deve essere chiara per gli utenti visivi.
<input aria-label="Username" />
Opzioni
exact: boolean
Indica se il
text
deve corrispondere esattamente: con distinzione tra maiuscole e minuscole e considerando l'intera stringa. Disabilitato per impostazione predefinita. Questa opzione viene ignorata setext
è un'espressione regolare. Si noti che la corrispondenza esatta esegue comunque il trimming degli spazi bianchi.
Vedi anche
getByPlaceholder
function getByPlaceholder(
text: string | RegExp,
options?: LocatorOptions
): Locator;
Crea un localizzatore in grado di trovare un elemento che ha l'attributo placeholder
specificato. Vitest troverà la corrispondenza con qualsiasi elemento che abbia un attributo placeholder
corrispondente, non solo input
.
<input placeholder="Username" />;
page.getByPlaceholder('Username'); // ✅
page.getByPlaceholder('not found'); // ❌
WARNING
È generalmente preferibile affidarsi a un'etichetta usando getByLabelText
piuttosto che a un placeholder.
Opzioni
exact: boolean
Indica se il
text
deve corrispondere esattamente: con distinzione tra maiuscole e minuscole e considerando l'intera stringa. Disabilitato per impostazione predefinita. Questa opzione viene ignorata setext
è un'espressione regolare. Si noti che la corrispondenza esatta esegue comunque il trimming degli spazi bianchi.
Vedi anche
getByText
function getByText(text: string | RegExp, options?: LocatorOptions): Locator;
Crea un localizzatore in grado di trovare un elemento che contiene il testo specificato. Il testo verrà confrontato con il nodeValue
di TextNode o con il valore dell'input se il tipo è button
o reset
. La ricerca testuale normalizza sempre gli spazi bianchi, anche con corrispondenza esatta. Ad esempio, trasforma più spazi in uno, trasforma le interruzioni di riga in spazi e ignora gli spazi bianchi iniziali e finali.
<a href="/about">About ℹ️</a>;
page.getByText(/about/i); // ✅
page.getByText('about', { exact: true }); // ❌
TIP
Questo localizzatore è utile per individuare elementi non interattivi. Se hai bisogno di localizzare un elemento interattivo, come un pulsante o un input, preferisci getByRole
.
Opzioni
exact: boolean
Indica se il
text
deve corrispondere esattamente: con distinzione tra maiuscole e minuscole e considerando l'intera stringa. Disabilitato per impostazione predefinita. Questa opzione viene ignorata setext
è un'espressione regolare. Si noti che la corrispondenza esatta esegue comunque il trimming degli spazi bianchi.
Vedi anche
getByTitle
function getByTitle(text: string | RegExp, options?: LocatorOptions): Locator;
Crea un localizzatore in grado di trovare un elemento con l'attributo title
specificato. A differenza di getByTitle
di testing-library, Vitest non è in grado di trovare elementi title
all'interno di un SVG.
<span title="Delete" id="2"></span>;
page.getByTitle('Delete'); // ✅
page.getByTitle('Create'); // ❌
Opzioni
exact: boolean
Indica se il
text
deve corrispondere esattamente: con distinzione tra maiuscole e minuscole e considerando l'intera stringa. Disabilitato per impostazione predefinita. Questa opzione viene ignorata setext
è un'espressione regolare. Si noti che la corrispondenza esatta esegue comunque il trimming degli spazi bianchi.
Vedi anche
getByTestId
function getByTestId(text: string | RegExp): Locator;
Crea un localizzatore in grado di trovare un elemento che corrisponde all'attributo ID di test specificato. Puoi configurare il nome dell'attributo con browser.locators.testIdAttribute
.
<div data-testid="custom-element" />;
page.getByTestId('custom-element'); // ✅
page.getByTestId('non-existing-element'); // ❌
WARNING
Si consiglia di utilizzare questo metodo solo quando gli altri localizzatori non sono sufficienti per il tuo caso d'uso. L'utilizzo degli attributi data-testid
non riflette il modo in cui il tuo software viene utilizzato dagli utenti e dovrebbe essere evitato se possibile.
Opzioni
exact: boolean
Indica se il
text
deve corrispondere esattamente: con distinzione tra maiuscole e minuscole e considerando l'intera stringa. Disabilitato per impostazione predefinita. Questa opzione viene ignorata setext
è un'espressione regolare. Si noti che la corrispondenza esatta esegue comunque il trimming degli spazi bianchi.
Vedi anche
nth
function nth(index: number): Locator;
Questo metodo restituisce un nuovo localizzatore che corrisponde solo a un indice specifico in un risultato di query multi-elemento. L'indicizzazione è a base zero; nth(0)
seleziona il primo elemento. A differenza di elements()[n]
, il localizzatore nth
verrà riprovato finché l'elemento non sarà presente.
<div aria-label="one"><input /><input /><input /></div>
<div aria-label="two"><input /></div>
page.getByRole('textbox').nth(0); // ✅
page.getByRole('textbox').nth(4); // ❌
TIP
Prima di ricorrere a nth
, potresti trovare utile usare localizzatori concatenati per restringere la tua ricerca. A volte non c'è un modo migliore per distinguere gli elementi se non tramite la loro posizione; anche se questo può portare a test "flaky" (instabili), è meglio di niente.
page.getByLabel('two').getByRole('input'); // ✅ alternativa migliore a page.getByRole('textbox').nth(3)
page.getByLabel('one').getByRole('input'); // ❌ troppo ambiguo
page.getByLabel('one').getByRole('input').nth(1); // ✅ compromesso pragmatico
first
function first(): Locator;
Questo metodo restituisce un nuovo localizzatore che corrisponde solo al primo indice di un risultato di query multi-elemento. È una scorciatoia per nth(0)
.
<input /> <input /> <input />
page.getByRole('textbox').first(); // ✅
last
function last(): Locator;
Questo metodo restituisce un nuovo localizzatore che corrisponde solo all'ultimo indice di un risultato di query multi-elemento. È una scorciatoia per nth(-1)
.
<input /> <input /> <input />
page.getByRole('textbox').last(); // ✅
and
function and(locator: Locator): Locator;
Questo metodo crea un nuovo localizzatore che corrisponde sia al localizzatore su cui è chiamato che a quello fornito. L'esempio seguente trova un pulsante con un titolo specifico:
page.getByRole('button').and(page.getByTitle('Subscribe'));
or
function or(locator: Locator): Locator;
Questo metodo crea un nuovo localizzatore che corrisponde a uno o a entrambi i localizzatori.
WARNING
Si noti che se il localizzatore corrisponde a più di un singolo elemento, l'invocazione di un altro metodo potrebbe generare un errore se si aspetta un singolo elemento:
<>
<button>Click me</button>
<a href="https://vitest.dev">Error happened!</a>
</>;
page.getByRole('button').or(page.getByRole('link')).click(); // ❌ corrisponde a più elementi
filter
function filter(options: LocatorOptions): Locator;
Questo metodo affina il localizzatore in base alle opzioni, come il filtraggio per testo. Può essere concatenato per applicare più filtri.
has
- Tipo:
Locator
Questa opzione restringe il selettore per trovare la corrispondenza con gli elementi che contengono altri elementi che corrispondono al localizzatore fornito. Ad esempio, con questo HTML:
<article>
<div>Vitest</div>
</article>
<article>
<div>Rolldown</div>
</article>
Possiamo restringere il localizzatore per trovare solo l'article
con il testo Vitest
al suo interno:
page.getByRole('article').filter({ has: page.getByText('Vitest') }); // ✅
WARNING
Il localizzatore fornito (page.getByText('Vitest')
nell'esempio) deve essere relativo al localizzatore padre (page.getByRole('article')
nell'esempio). Verrà eseguita una query a partire dal localizzatore padre, non dalla radice del documento.
Ciò significa che non puoi passare un localizzatore che esegue una query sull'elemento al di fuori del localizzatore padre:
page.getByText('Vitest').filter({ has: page.getByRole('article') }); // ❌
Questo esempio fallirà perché l'elemento article
è al di fuori dell'elemento con il testo Vitest
.
TIP
Questo metodo può essere concatenato per affinare ulteriormente l'elemento:
page
.getByRole('article')
.filter({ has: page.getByRole('button', { name: 'delete row' }) })
.filter({ has: page.getByText('Vitest') });
hasNot
- Tipo:
Locator
Questa opzione restringe il selettore per trovare la corrispondenza con gli elementi che non contengono altri elementi che corrispondono al localizzatore fornito. Ad esempio, con questo HTML:
<article>
<div>Vitest</div>
</article>
<article>
<div>Rolldown</div>
</article>
Possiamo restringere il localizzatore per trovare solo l'article
che non ha Rolldown
al suo interno.
page.getByRole('article').filter({ hasNot: page.getByText('Rolldown') }); // ✅
page.getByRole('article').filter({ hasNot: page.getByText('Vitest') }); // ❌
WARNING
Si noti che il localizzatore fornito viene sottoposto a query rispetto al padre, non alla radice del documento, proprio come l'opzione has
.
hasText
- Tipo:
string | RegExp
Questa opzione restringe il selettore per abbinare solo gli elementi che contengono il testo fornito da qualche parte al loro interno. Quando viene passata la string
, la corrispondenza non distingue tra maiuscole e minuscole e cerca la presenza di una sottostringa.
<article>
<div>Vitest</div>
</article>
<article>
<div>Rolldown</div>
</article>
Entrambi i localizzatori troveranno lo stesso elemento perché la ricerca non distingue tra maiuscole e minuscole:
page.getByRole('article').filter({ hasText: 'Vitest' }); // ✅
page.getByRole('article').filter({ hasText: 'Vite' }); // ✅
hasNotText
- Tipo:
string | RegExp
Questa opzione restringe il selettore per abbinare solo gli elementi che non contengono il testo fornito da qualche parte al loro interno. Quando viene passata la string
, la corrispondenza non distingue tra maiuscole e minuscole e cerca la presenza di una sottostringa.
Metodi
Tutti i metodi sono asincroni e devono essere preceduti da await
. A partire da Vitest 3, i test falliranno se un metodo non viene atteso.
click
function click(options?: UserEventClickOptions): Promise<void>;
Clicca su un elemento. Puoi usare le opzioni per impostare la posizione del cursore.
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).click();
dblClick
function dblClick(options?: UserEventDoubleClickOptions): Promise<void>;
Simula un evento di doppio clic su un elemento. Puoi usare le opzioni per impostare la posizione del cursore.
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).dblClick();
tripleClick
function tripleClick(options?: UserEventTripleClickOptions): Promise<void>;
Simula un evento di triplo clic su un elemento. Poiché non esiste un tripleclick
nell'API del browser, questo metodo attiverà tre eventi di clic consecutivamente.
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).tripleClick();
clear
function clear(options?: UserEventClearOptions): Promise<void>;
Cancella il contenuto del campo di input.
import { page } from '@vitest/browser/context';
await page.getByRole('textbox', { name: 'Full Name' }).clear();
hover
function hover(options?: UserEventHoverOptions): Promise<void>;
Sposta la posizione del cursore sull'elemento corrispondente al localizzatore.
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).hover();
unhover
function unhover(options?: UserEventHoverOptions): Promise<void>;
Questo funziona allo stesso modo di locator.hover
, ma sposta il cursore sull'elemento document.body
anziché sull'elemento selezionato.
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).unhover();
fill
function fill(text: string, options?: UserEventFillOptions): Promise<void>;
Imposta il valore dell'elemento input
, textarea
o contenteditable
corrente.
import { page } from '@vitest/browser/context';
await page.getByRole('input', { name: 'Full Name' }).fill('Mr. Bean');
dropTo
function dropTo(
target: Locator,
options?: UserEventDragAndDropOptions
): Promise<void>;
Trascina l'elemento corrispondente al localizzatore nella posizione di destinazione.
import { page } from '@vitest/browser/context';
const paris = page.getByText('Paris');
const france = page.getByText('France');
await paris.dropTo(france);
selectOptions
function selectOptions(
values: HTMLElement | HTMLElement[] | Locator | Locator[] | string | string[],
options?: UserEventSelectOptions
): Promise<void>;
Seleziona uno o più valori da un elemento <select>
.
import { page } from '@vitest/browser/context';
const languages = page.getByRole('select', { name: 'Languages' });
await languages.selectOptions('EN');
await languages.selectOptions(['ES', 'FR']);
await languages.selectOptions([
languages.getByRole('option', { name: 'Spanish' }),
languages.getByRole('option', { name: 'French' }),
]);
screenshot
function screenshot(
options: LocatorScreenshotOptions & { save: false }
): Promise<string>;
function screenshot(
options: LocatorScreenshotOptions & { base64: true }
): Promise<{
path: string;
base64: string;
}>;
function screenshot(
options?: LocatorScreenshotOptions & { base64?: false }
): Promise<string>;
Crea uno screenshot dell'elemento individuato dal localizzatore.
Puoi specificare la posizione di salvataggio dello screenshot usando l'opzione path
, che è relativa al file di test corrente. Se l'opzione path
non è impostata, Vitest adotterà come predefinito browser.screenshotDirectory
(__screenshot__
per impostazione predefinita), insieme ai nomi del file e del test per determinare il percorso del file dello screenshot.
Se hai bisogno anche del contenuto dello screenshot, puoi specificare base64: true
per restituirlo in formato base64, oltre al percorso di salvataggio.
import { page } from '@vitest/browser/context';
const button = page.getByRole('button', { name: 'Click Me!' });
const path = await button.screenshot();
const { path, base64 } = await button.screenshot({
path: './button-click-me.png',
base64: true, // restituisce anche la stringa base64
});
// path - percorso completo dello screenshot
// base64 - stringa codificata in base64 dello screenshot
WARNING 3.2.0+
Si noti che screenshot
restituirà sempre il contenuto in formato base64 se save
è impostato su false
. Il path
viene ignorato in quel caso.
query
function query(): Element | null;
Questo metodo restituisce un singolo elemento individuato dal localizzatore o null
se non viene trovato alcun elemento.
Se più elementi corrispondono al selettore, questo metodo genererà un errore. Usa .elements()
quando hai bisogno di tutti gli elementi DOM corrispondenti o .all()
se hai bisogno di un array di localizzatori che lo individuano.
Considera la seguente struttura DOM:
<div>Hello <span>World</span></div>
<div>Hello</div>
Questi localizzatori non genereranno un errore:
page.getByText('Hello World').query(); // ✅ HTMLDivElement
page.getByText('Hello Germany').query(); // ✅ null
page.getByText('World').query(); // ✅ HTMLSpanElement
page.getByText('Hello', { exact: true }).query(); // ✅ HTMLSpanElement
Questi localizzatori genereranno un errore:
// matches multiple elements
page.getByText('Hello').query(); // ❌
page.getByText(/^Hello/).query(); // ❌
element
function element(): Element;
Questo metodo restituisce un singolo elemento individuato dal localizzatore.
Se nessun elemento corrisponde al selettore, viene sollevato un errore. Considera l'utilizzo di .query()
quando hai solo bisogno di verificare se l'elemento esiste.
Se più elementi corrispondono al selettore, viene sollevato un errore. Usa .elements()
quando hai bisogno di tutti gli elementi DOM corrispondenti o .all()
se hai bisogno di un array di localizzatori che lo individuano.
TIP
Questo metodo può essere utile se devi passarlo come argomento a una libreria esterna. Viene chiamato automaticamente quando il localizzatore viene utilizzato con expect.element
ogni volta che l'asserzione viene rieseguita:
await expect.element(page.getByRole('button')).toBeDisabled();
Considera la seguente struttura DOM:
<div>Hello <span>World</span></div>
<div>Hello Germany</div>
<div>Hello</div>
Questi localizzatori non genereranno un errore:
page.getByText('Hello World').element(); // ✅
page.getByText('Hello Germany').element(); // ✅
page.getByText('World').element(); // ✅
page.getByText('Hello', { exact: true }).element(); // ✅
Questi localizzatori genereranno un errore:
// matches multiple elements
page.getByText('Hello').element(); // ❌
page.getByText(/^Hello/).element(); // ❌
// returns no elements
page.getByText('Hello USA').element(); // ❌
elements
function elements(): Element[];
Questo metodo restituisce un array di elementi che corrispondono al selettore del localizzatore.
Questa funzione non solleva mai un errore. Se non ci sono elementi che corrispondono al selettore, questo metodo restituirà un array vuoto.
Considera la seguente struttura DOM:
<div>Hello <span>World</span></div>
<div>Hello</div>
Questi localizzatori funzioneranno sempre correttamente:
page.getByText('Hello World').elements(); // ✅ [HTMLElement]
page.getByText('World').elements(); // ✅ [HTMLElement]
page.getByText('Hello', { exact: true }).elements(); // ✅ [HTMLElement]
page.getByText('Hello').elements(); // ✅ [HTMLElement, HTMLElement]
page.getByText('Hello USA').elements(); // ✅ []
all
function all(): Locator[];
Questo metodo restituisce un array di nuovi localizzatori individuati dal selettore.
Internamente, questo metodo chiama .elements
e incapsula ogni elemento usando page.elementLocator
.
Proprietà
selector
Il selector
è una stringa che verrà utilizzata per individuare l'elemento tramite il provider del browser. Playwright utilizzerà una sintassi di localizzatore playwright
mentre preview
e webdriverio
utilizzeranno CSS.
DANGER
Si sconsiglia di utilizzare questa stringa nel tuo codice di test. La stringa selector
dovrebbe essere usata solo quando si lavora con l'API dei comandi:
import type { BrowserCommand } from 'vitest/node';
const test: BrowserCommand<string> = function test(context, selector) {
// playwright
await context.iframe.locator(selector).click();
// webdriverio
await context.browser.$(selector).click();
};
import { test } from 'vitest';
import { commands, page } from '@vitest/browser/context';
test('works correctly', async () => {
await commands.test(page.getByText('Hello').selector); // ✅
// vitest lo convertirà automaticamente in una stringa
await commands.test(page.getByText('Hello')); // ✅
});
Localizzatori personalizzati 3.2.0+ advanced
Puoi estendere l'API dei localizzatori integrati definendo un oggetto di funzioni factory per localizzatori. Questi metodi saranno disponibili sull'oggetto page
e su qualsiasi localizzatore creato.
Questi localizzatori possono essere utili se quelli integrati non sono sufficienti. Ad esempio, quando usi un framework personalizzato per la tua UI.
La factory del localizzatore deve restituire una stringa selettore o il localizzatore stesso.
TIP
La sintassi del selettore è identica ai localizzatori di Playwright. Si prega di leggere la loro guida per comprendere meglio come utilizzarli.
import { locators } from '@vitest/browser/context';
locators.extend({
getByArticleTitle(title) {
return `[data-title="${title}"]`;
},
getByArticleCommentsCount(count) {
return `.comments :text("${count} comments")`;
},
async previewComments() {
// si noti che se il metodo è stato chiamato su `page`, `this` sarà `page`,
// non il localizzatore!
if (this !== page) {
await this.click();
}
// ...
},
});
// se stai usando typescript, puoi estendere l'interfaccia LocatorSelectors
// per abilitare l'autocompletamento nei metodi locators.extend, page.* e locator.*
declare module '@vitest/browser/context' {
interface LocatorSelectors {
// se il metodo personalizzato restituisce una stringa, verrà convertito in un localizzatore
// se restituisce qualcos'altro, verrà restituito direttamente
getByArticleTitle(title: string): Locator;
getByArticleCommentsCount(count: number): Locator;
// Vitest restituirà una promessa e non cercherà di convertirla in un localizzatore
previewComments(this: Locator): Promise<void>;
}
}
Se il metodo viene chiamato sull'oggetto page
globale, il selettore sarà applicato all'intera pagina. Nell'esempio seguente, getByArticleTitle
troverà tutti gli elementi con un attributo data-title
con il valore di title
. Tuttavia, se il metodo viene chiamato sul localizzatore, sarà ristretto a quel localizzatore.
<article data-title="Hello, World!">
Hello, World!
<button id="comments">2 comments</button>
</article>
<article data-title="Hello, Vitest!">
Hello, Vitest!
<button id="comments">0 comments</button>
</article>
const articles = page.getByRole('article');
const worldArticle = page.getByArticleTitle('Hello, World!'); // ✅
const commentsElement = worldArticle.getByArticleCommentsCount(2); // ✅
const wrongCommentsElement = worldArticle.getByArticleCommentsCount(0); // ❌
const wrongElement = page.getByArticleTitle('No Article!'); // ❌
await commentsElement.previewComments(); // ✅
await wrongCommentsElement.previewComments(); // ❌