Spread e rest compartilham a mesma sintaxe ..., mas fazem coisas opostas: spread expande um array ou objeto no lugar, rest coleta múltiplos valores em um só. O ganho prático em automação de testes são as factories de dados: um objeto base espalhado com overrides cria todas as variantes sem repetir todos os campos.

Operador spread: expandindo coisas

O operador spread (...) expande um iterável (array ou objeto) no lugar.

Espalhando arrays

const parte1 = [1, 2, 3];
const parte2 = [4, 5, 6];

const combinado = [...parte1, ...parte2];
// [1, 2, 3, 4, 5, 6]

// Adicionar itens antes ou depois
const comExtras = [0, ...parte1, ...parte2, 7];
// [0, 1, 2, 3, 4, 5, 6, 7]

Copiando um array

const original = ['alice', 'bob', 'charlie'];
const copia = [...original];

copia.push('dave'); // Modifica só a cópia
console.log(original); // ['alice', 'bob', 'charlie'] — inalterado

Espalhando objetos

const configBase = { timeout: 30000, headless: true };
const configCi = { ...configBase, timeout: 60000 };
// { timeout: 60000, headless: true }
// Nota: timeout foi sobrescrito pelo valor posterior

A chave posterior vence em caso de conflito.

Spread em dados de teste: o grande caso de uso

O padrão mais valioso para engenheiros de QA: criar variantes de objeto a partir de uma base:

const usuarioPadrao = {
  email: 'teste@exemplo.com',
  password: 'SenhaValida1',
  role: 'member',
  ativo: true,
  emailVerificado: true,
};

// Criar variantes sem repetir todos os campos
const usuarioAdmin    = { ...usuarioPadrao, role: 'admin' };
const usuarioInativo  = { ...usuarioPadrao, ativo: false };
const naoVerificado   = { ...usuarioPadrao, emailVerificado: false };
const emailCustomizado = { ...usuarioPadrao, email: 'custom@teste.com' };

Essa é a base das factories de dados de teste. Defina o estado do happy path uma vez e crie todos os edge cases a partir dele.

Mesclando configs de teste

const configPlaywrightBase = {
  use: {
    baseURL: 'https://lab.becomeqa.com',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
  },
  timeout: 30_000,
};

// Overrides do ambiente de CI
const overridesCi = {
  timeout: 60_000,
  retries: 2,
};

const configFinal = { ...configPlaywrightBase, ...overridesCi };

Construindo listas de casos de teste

const casoHappyPath = {
  email: 'valido@exemplo.com',
  password: 'SenhaValida1',
  resultadoEsperado: 'sucesso',
  statusEsperado: 200,
};

const casosDeTeste = [
  casoHappyPath,
  { ...casoHappyPath, email: 'outro@teste.com' },
  { ...casoHappyPath, password: 'OutraSenhaValida2' },
  { ...casoHappyPath, email: 'invalido', resultadoEsperado: 'erro', statusEsperado: 422 },
];

Muito mais limpo do que repetir todos os campos para cada caso de teste.

Parâmetros rest: coletando coisas

Parâmetros rest coletam múltiplos itens em um único parâmetro. Usa a mesma sintaxe ..., mas na definição da função, não na chamada:

// REST: coleta múltiplos argumentos em um array
function registrarResultados(nomeTeste: string, ...resultados: string[]) {
  console.log(`Teste: ${nomeTeste}`);
  resultados.forEach(r => console.log(`  - ${r}`));
}

registrarResultados('Teste de login', 'e-mail validado', 'redirect funcionou', 'sessão criada');
// Teste: Teste de login
//   - e-mail validado
//   - redirect funcionou
//   - sessão criada

O ...resultados coleta todos os argumentos após nomeTeste em um array.

Rest em destructuring

Rest também pode ser usado em destructuring para coletar "todo o resto":

const [primeiro, segundo, ...resto] = [1, 2, 3, 4, 5];
// primeiro = 1, segundo = 2, resto = [3, 4, 5]

const { email, password, ...outrosCampos } = usuario;
// email e password são extraídos
// outrosCampos = { role: 'member', ativo: true, ... }

Útil quando você precisa de campos específicos e quer passar o resto adiante:

async function criarUsuarioEObterToken({ email, password, ...dadosPerfil }: DadosCriacaoUsuario) {
  // Usa email e password para autenticação
  const token = await auth.login(email, password);
  
  // Usa o resto para configurar o perfil (sem os campos de auth)
  await api.atualizarPerfil(token, dadosPerfil);
  
  return token;
}

Padrões práticos no Playwright

Padrão 1: Helper de teste flexível

type OpcaoClique = {
  timeout?: number;
  force?: boolean;
};

async function clicarEAguardar(
  page: Page,
  selector: string,
  { timeout = 5000, force = false, ...opcoes }: OpcaoClique = {}
) {
  await page.locator(selector).click({ timeout, force, ...opcoes });
  await page.waitForLoadState('networkidle');
}

Padrão 2: Construindo headers de requisição

const headersPadrao = {
  'Content-Type': 'application/json',
  'Accept': 'application/json',
};

const headersAuth = {
  ...headersPadrao,
  'Authorization': `Bearer ${token}`,
};

const headersAdmin = {
  ...headersAuth,
  'X-Admin-Key': process.env.ADMIN_KEY,
};

Padrão 3: Combinando dados de teste de múltiplas fontes

const dadosBase = await lerArquivoFixture('usuario-base.json');
const especificoAmbiente = await lerArquivoFixture(`${process.env.ENV}-overrides.json`);

const dadosTeste = { ...dadosBase, ...especificoAmbiente };
// Valores específicos do ambiente sobrescrevem os valores base

Padrão 4: Coletando casos com falha

async function rodarTodosCasos(casos: CasoTeste[]): Promise<string[]> {
  const falhas: string[] = [];
  
  for (const caso of casos) {
    try {
      await rodarCaso(caso);
    } catch (error) {
      falhas.push(`${caso.nome}: ${error.message}`);
    }
  }
  
  return falhas;
}

// No ponto de chamada:
const [primeiraFalha, ...outrasFalhas] = await rodarTodosCasos(casosDeTeste);
if (primeiraFalha) {
  console.log('Primeira falha:', primeiraFalha);
  console.log('Falhas adicionais:', outrasFalhas);
}

Spread vs. rest: como distinguir

Spread — você está colocando coisas dentro (expandindo em um array/objeto literal):

const arr = [...itens];         // expandindo itens para o array
const obj = { ...config };      // expandindo config para o objeto
func(...args);                   // expandindo args como argumentos de função

Rest — você está coletando coisas de (reunindo em um parâmetro):

function fn(...args) {}          // coletando argumentos da chamada
const [a, ...resto] = array;    // coletando o restante do array
const { x, ...outros } = obj;   // coletando o restante do objeto

Mesmo símbolo .... O contexto determina o significado.

Um erro comum: cópia rasa

O spread cria uma cópia rasa: objetos aninhados ainda são referências compartilhadas.

const usuario = { nome: 'Alice', endereco: { cidade: 'São Paulo' } };
const copia = { ...usuario };

copia.nome = 'Bob';                      // Muda só a cópia
copia.endereco.cidade = 'Rio de Janeiro'; // Muda TANTO usuario quanto copia

console.log(usuario.endereco.cidade); // 'Rio de Janeiro' — ops

Se precisar de uma cópia profunda (objetos aninhados também independentes), use uma abordagem diferente:

// Cópia profunda simples (funciona para dados serializáveis em JSON)
const copiaFunda = JSON.parse(JSON.stringify(usuario));

// Ou use structuredClone (JS moderno)
const copiaFunda2 = structuredClone(usuario);

Para a maioria dos objetos de dados de teste que são pares simples chave-valor sem objetos mutáveis aninhados, spread está ótimo. Mas conheça a limitação.

Resumo

| Sintaxe | Contexto | O que faz |

|---------|---------|-----------|

| [...arr] | Array literal | Expande arr no novo array |

| {...obj} | Object literal | Copia todas as propriedades de obj |

| fn(...args) | Chamada de função | Passa elementos do array como argumentos separados |

| function fn(...params) | Definição de função | Coleta múltiplos argumentos em array |

| const [a, ...resto] = arr | Destructuring de array | Coleta itens restantes |

| const {x, ...resto} = obj | Destructuring de objeto | Coleta propriedades restantes |

Quando o padrão fizer sentido, você vai reconhecê-lo em todo lugar. Aparece no use() do Playwright, em fixtures de teste, em arquivos de config e em toda factory de dados de teste que você vai ler.

→ Veja também: Objetos JavaScript e Desestruturação para Engenheiros QA | JavaScript para QA Engineers: O Mínimo para Começar a Automatizar | TypeScript para QA: Por que os Tipos Estáticos Melhoram Seus Testes