Um expect() padrão para o teste na primeira falha. Um formulário com quatro mensagens de validação quebradas precisa de quatro execuções de teste para diagnosticar completamente. expect.soft() coleta todas as falhas e as reporta juntas no final, mas o teste ainda falha se alguma soft assertion falhou: ele continua rodando, não passando.

Como as soft assertions funcionam

import { test, expect } from '@playwright/test';

test('página de perfil do usuário tem todos os elementos obrigatórios', async ({ page }) => {
  await page.goto('/profile');

  // Soft assertions — todas rodam mesmo que algumas falhem
  await expect.soft(page.getByLabel('Full name')).toBeVisible();
  await expect.soft(page.getByLabel('Email')).toBeVisible();
  await expect.soft(page.getByLabel('Phone number')).toBeVisible();
  await expect.soft(page.getByRole('button', { name: 'Save changes' })).toBeEnabled();
  await expect.soft(page.getByRole('img', { name: 'Profile photo' })).toBeVisible();

  // É aqui que o teste realmente falha — se alguma soft assertion acima falhou
  expect(test.info().errors).toHaveLength(0);
});

Cada expect.soft() roda. As falhas são coletadas. O teste continua. No final (ou quando você verifica test.info().errors), todas as falhas são reportadas de uma vez.

Assertions hard vs. soft

Use assertions hard (expect) quando:

  • Uma falha torna o resto do teste sem sentido (ex.: login falhou, nada mais funciona)
  • Você está verificando uma pré-condição, não um resultado
  • Uma falha implica logicamente outras (navegação falhou, nada na página importa)

Use soft assertions (expect.soft) quando:

  • Você está verificando múltiplas propriedades independentes da mesma página
  • Cada falha é informação de debug independentemente útil
  • Você está verificando que um formulário, linha de tabela ou card tem todos os seus campos

test('confirmação de pedido exibe todos os detalhes', async ({ page }) => {
  await page.goto('/orders/12345');

  // Assertion hard — se isso falhar, nada mais importa
  await expect(page.getByRole('heading', { name: 'Order #12345' })).toBeVisible();

  // Soft assertions — verificações independentes, todas úteis
  await expect.soft(page.getByText('Status: Confirmed')).toBeVisible();
  await expect.soft(page.getByText('Delivery: 2–5 business days')).toBeVisible();
  await expect.soft(page.getByText('Total: $149.99')).toBeVisible();
  await expect.soft(page.getByRole('button', { name: 'Track order' })).toBeEnabled();
  await expect.soft(page.getByRole('button', { name: 'Cancel order' })).toBeEnabled();
});

Lendo falhas de soft assertions

Quando uma soft assertion falha, o Playwright reporta todas as falhas juntas:

Error: 2 soft assertion(s) failed.

  1) Soft assertion failed: expect(locator).toBeVisible()

    Call log:
      - waiting for page.getByText('Status: Confirmed')

    Error: expect(locator).toBeVisible() with timeout 5000ms
    Received: hidden

  2) Soft assertion failed: expect(locator).toBeEnabled()

    Call log:
      - waiting for page.getByRole('button', { name: 'Cancel order' })

    Error: expect(locator).toBeEnabled() with timeout 5000ms
    Received: disabled

Dois problemas em uma execução, não um problema por execução.

Soft assertions em testes de validação de formulário

Validação de formulário é um caso de uso clássico: muitos estados de erro para verificar, todos independentes.

test('formulário mostra todos os erros de validação ao submeter vazio', async ({ page }) => {
  await page.goto('/register');
  await page.getByRole('button', { name: 'Create account' }).click();

  // Verifica que todas as mensagens de validação aparecem
  await expect.soft(page.getByText('Email is required')).toBeVisible();
  await expect.soft(page.getByText('Password is required')).toBeVisible();
  await expect.soft(page.getByText('First name is required')).toBeVisible();
  await expect.soft(page.getByText('Last name is required')).toBeVisible();

  // Verifica que o botão de submit ainda está disponível (não desabilitado após falha)
  await expect.soft(page.getByRole('button', { name: 'Create account' })).toBeEnabled();
});

Sem soft assertions, você saberia da primeira mensagem faltando e teria que rodar o teste mais três vezes para encontrar todos os quatro problemas.

Verificando erros explicitamente

Você pode verificar falhas de soft assertions em qualquer ponto do teste:

test('verificação de completude da página de produto', async ({ page }) => {
  await page.goto('/products/laptop-pro');

  // Seção 1: Seção hero
  await expect.soft(page.getByRole('heading', { level: 1 })).toBeVisible();
  await expect.soft(page.getByRole('img', { name: /product/i })).toBeVisible();
  await expect.soft(page.getByText(/\$\d+\.\d{2}/)).toBeVisible(); // Preço

  // Se a seção hero tem falhas, para aqui — não faz sentido verificar o resto
  if (test.info().errors.length > 0) {
    test.fail();
    return;
  }

  // Seção 2: Só roda se a hero passou
  await expect.soft(page.getByRole('button', { name: 'Add to cart' })).toBeEnabled();
  await expect.soft(page.getByRole('tab', { name: 'Reviews' })).toBeVisible();
  await expect.soft(page.getByRole('tab', { name: 'Specifications' })).toBeVisible();
});

Misturando assertions hard e soft

O padrão mais eficaz: assertions hard para pré-condições e estado crítico, soft assertions para propriedades individuais:

test('dashboard carrega todos os widgets', async ({ page }) => {
  await page.goto('/dashboard');

  // Hard — se isso falhar, a página não carregou de forma alguma
  await expect(page).toHaveTitle(/Dashboard/);
  await expect(page.getByRole('main')).toBeVisible();

  // Soft — cada widget é independente
  await expect.soft(page.getByTestId('revenue-widget')).toBeVisible();
  await expect.soft(page.getByTestId('orders-widget')).toBeVisible();
  await expect.soft(page.getByTestId('users-widget')).toBeVisible();
  await expect.soft(page.getByTestId('activity-feed')).toBeVisible();

  // Soft — cada métrica é independente
  await expect.soft(page.getByTestId('revenue-amount')).toContainText('$');
  await expect.soft(page.getByTestId('orders-count')).toContainText(/\d+/);
});

Quando não usar soft assertions

Soft assertions coletam falhas mas deixam o teste continuar. Isso pode mascarar problemas de estado:

// Perigoso — se o clique não funcionou, as assertions abaixo testam o estado errado
await expect.soft(page.getByRole('button', { name: 'Submit' })).toBeEnabled();
await page.getByRole('button', { name: 'Submit' }).click();
await expect.soft(page.getByText('Order confirmed')).toBeVisible(); // pode passar acidentalmente

Se ações dependem de assertions anteriores passando, use assertions hard. Soft assertions são para observação (verificar o que está na página), não para controle de fluxo.

→ Veja também: Assertions no Playwright: O Guia Completo | Estrutura de Testes no Playwright: describe, beforeEach, afterEach e Hooks | Como Ler Mensagens de Erro do Playwright