O { page, request } em toda função de teste do Playwright é destructuring: ele extrai essas propriedades do objeto de fixture que o framework passa automaticamente. Quando isso fica claro, fixtures customizadas deixam de parecer mágica e começam a parecer o mesmo padrão repetido.
O que é um objeto?
Um objeto é uma coleção de pares chave-valor. Chaves são strings; valores podem ser qualquer coisa:
const usuario = {
id: 1,
email: 'alice@exemplo.com',
role: 'admin',
ativo: true,
};Acesse valores com notação de ponto ou de colchetes:
console.log(usuario.email); // 'alice@exemplo.com'
console.log(usuario['role']); // 'admin'
console.log(usuario.id); // 1Modifique valores da mesma forma:
usuario.email = 'novaalice@exemplo.com';
usuario.role = 'member';Objetos em dados de teste
A maioria dos dados de teste em testes Playwright é expressa como objetos ou arrays de objetos:
const credenciaisLogin = {
email: 'qa_teste@exemplo.com',
password: 'SenhaValida123!',
};
await page.fill('[data-testid="email"]', credenciaisLogin.email);
await page.fill('[data-testid="password"]', credenciaisLogin.password);Coleções de casos de teste:
const EMAILS_INVALIDOS = [
{ input: '', descricao: 'vazio' },
{ input: 'nao-e-email', descricao: 'sem @' },
{ input: 'faltando@', descricao: 'sem domínio' },
{ input: 'a@b', descricao: 'sem TLD' },
];Cada EMAILS_INVALIDOS[0] é um objeto com as propriedades input e descricao.
Destructuring: o que é
Destructuring permite extrair valores de um objeto (ou array) para variáveis individuais em uma linha, em vez de múltiplas linhas.
Sem destructuring:const usuario = { id: 1, nome: 'Alice', email: 'alice@teste.com', role: 'admin' };
const id = usuario.id;
const nome = usuario.nome;
const email = usuario.email;
const role = usuario.role;const { id, nome, email, role } = usuario;Mesmo resultado: quatro variáveis com os mesmos valores, em uma linha em vez de quatro.
Renomear durante o destructuring
Se você quer que a variável tenha um nome diferente da chave:
const config = {
database_host: 'localhost',
database_port: 5432,
};
const { database_host: host, database_port: porta } = config;
console.log(host); // 'localhost'
console.log(porta); // 5432Valores padrão no destructuring
Se uma chave pode não existir, você pode fornecer um padrão:
const produto = { nome: 'Notebook', preco: 999 };
const { nome, preco, desconto = 0 } = produto;
// desconto = 0 (não estava em produto, usa o padrão)Destructuring em parâmetros de função
O lugar mais comum onde você vai ver destructuring no Playwright é nas funções de teste:
// Sem destructuring
test('usuário consegue fazer login', async (args) => {
const page = args.page;
const request = args.request;
// ...
});
// Com destructuring (padrão padrão do Playwright)
test('usuário consegue fazer login', async ({ page, request }) => {
// page e request disponíveis diretamente
});Isso é destructuring de objeto no parâmetro da função. A sintaxe { page, request } extrai essas propriedades do objeto de fixture que o Playwright passa.
É por isso que o código de testes Playwright parece ter "variáveis mágicas": elas estão sendo extraídas por destructuring do objeto de fixture automaticamente.
Fixtures customizadas: destructuring na prática
Quando você cria fixtures customizadas, vai escrever esse padrão:
export const test = base.extend<{ loginPage: LoginPage }>({
loginPage: async ({ page }, use) => {
const loginPage = new LoginPage(page);
await use(loginPage);
},
});
// Então em um teste:
test('login funciona', async ({ page, loginPage }) => {
// ^^^ desestruturado do objeto de fixture
await loginPage.login('user@teste.com', 'senha');
});Entender destructuring faz as fixtures fazerem sentido.
Destructuring aninhado
Objetos podem conter outros objetos. Você pode desestruturar múltiplos níveis de uma vez:
const respostaApi = {
status: 200,
data: {
usuario: {
id: 123,
email: 'alice@teste.com',
},
token: 'eyJhbGciOiJIUzI1NiJ9...',
},
};
// Destructuring aninhado
const { status, data: { usuario: { id, email }, token } } = respostaApi;
console.log(status); // 200
console.log(id); // 123
console.log(email); // 'alice@teste.com'
console.log(token); // 'eyJhbGciOiJIUzI1NiJ9...'Parece complexo no início. Na prática, você raramente vai mais de 2 níveis de profundidade. Se ficar complicado, faça destructuring em etapas:
const { data } = respostaApi;
const { usuario, token } = data;
const { id, email } = usuario;Mesmo resultado, mais fácil de ler.
Destructuring de array (resumo)
Arrays usam [] em vez de {}:
const coordenadas = [-23.5505, -46.6333];
const [latitude, longitude] = coordenadas;
// latitude = -23.5505, longitude = -46.6333Pule elementos com vírgulas:
const [primeiro, , terceiro] = ['a', 'b', 'c'];
// primeiro = 'a', terceiro = 'c'O operador spread com objetos
O operador spread (...) copia todas as propriedades de um objeto para outro:
const usuarioBase = {
role: 'member',
ativo: true,
};
const usuarioAdmin = {
...usuarioBase, // copia role e ativo
email: 'admin@teste.com',
role: 'admin', // sobrescreve o valor do spread
};
// { role: 'admin', ativo: true, email: 'admin@teste.com' }Em dados de teste: criando variantes
const usuarioPadrao = {
email: 'teste@exemplo.com',
password: 'SenhaValida1',
role: 'member',
ativo: true,
};
const usuarioAdmin = { ...usuarioPadrao, role: 'admin' };
const usuarioInativo = { ...usuarioPadrao, ativo: false };
const emailCustomizado = { ...usuarioPadrao, email: 'custom@exemplo.com' };Esse padrão, "objeto base + overrides", é muito comum em factories de dados de teste. Você define o estado válido padrão uma vez e usa spread para criar variantes.
Padrões práticos em testes Playwright
Destructuring do corpo da resposta de API
const response = await request.post('/api/users', {
data: { email: 'novo@teste.com', password: 'SenhaValida1' },
});
const { id, email, role, created_at } = await response.json();
expect(id).toBeTruthy();
expect(email).toBe('novo@teste.com');
expect(role).toBe('member');Passando parâmetros de objeto para helpers
async function preencherFormularioLogin(page: Page, { email, password }: { email: string; password: string }) {
await page.fill('[data-testid="email"]', email);
await page.fill('[data-testid="password"]', password);
}
// No ponto de chamada:
await preencherFormularioLogin(page, { email: 'user@teste.com', password: 'senha' });Mesclando configuração de teste
const configBase = {
baseURL: 'https://lab.becomeqa.com',
timeout: 30000,
};
const configCi = {
...configBase,
timeout: 60000, // mais lento no CI
video: 'retain-on-failure',
};Erros comuns
Destructuring de undefined:const response = await fetch('/api/usuario');
const { id } = await response.json(); // Se a resposta for null/undefined, isso lança erroSempre verifique se o valor existe antes de fazer destructuring de objetos profundamente aninhados.
Modificar cópias com spread não afeta o original... mas em objetos aninhados sim:const original = { nome: 'Alice', dados: { pontuacao: 100 } };
const copia = { ...original };
copia.nome = 'Bob'; // original.nome continua 'Alice'
copia.dados.pontuacao = 200; // original.dados.pontuacao também muda!O spread é uma cópia rasa. Objetos aninhados ainda são referências compartilhadas.
Resumo
| Sintaxe | O que faz |
|---------|-----------|
| const { a, b } = obj | Extrai a e b de obj |
| const { a: x } = obj | Extrai a de obj, nomeia como x |
| const { a = 5 } = obj | Extrai a, padrão 5 se ausente |
| async ({ page, request }) => {} | Desestrutura fixtures do Playwright |
| { ...obj, chave: 'valor' } | Faz spread de obj, sobrescreve ou adiciona chave |
Objetos e destructuring estão em todo lugar no JavaScript e TypeScript modernos. Quando os padrões ficam familiares, o código de testes Playwright fica muito mais fácil de ler e escrever.
→ Veja também: JavaScript para QA Engineers: O Mínimo para Começar a Automatizar | Arrays JavaScript: map, filter, find e forEach — O Guia de Campo do QA | TypeScript para QA: Por que os Tipos Estáticos Melhoram Seus Testes