Selenium logo Selenium

WebDriver 4 + Mocha + Chai

Instalação, E2E, API, Page Objects e testflow-selenium

Chrome · JavaScript · Allure · GitHub Actions

O que é o Selenium WebDriver 4?

Padrão W3C WebDriver para automação de browsers — controla Chrome, Firefox e Safari via protocolo HTTP, com bindings em várias linguagens.

  • Selenium 4 — API unificada, Selenium Manager gerencia drivers
  • Pacote npm selenium-webdriver — cliente oficial para Node.js
  • Neste projeto: Chrome headless via Builder().forBrowser('chrome')
  • TestFlow na porta 5050 — mesma app dos suites Cypress/Playwright
  • Screenshots on failure, Allure report, tags Mocha (@smoke, @regression)

Por que Mocha + Chai?

Runner maduro

describe / it, hooks globais, timeout configurável e grep por tag.

Assertions legíveis

expect(x).to.equal(y) — BDD style, familiar para quem vem de Jest/Mocha.

Stack enxuta

Sem framework extra — WebDriver direto + helpers próprios (getByTestId).

Relatórios

allure-mocha no CI · mochawesome local — HTML rico com screenshots.

Pré-requisitos

Ambiente

  • Node.js 20+ (CI usa 24)
  • npm — instala deps e roda Mocha
  • Google Chrome — browser padrão
  • Docker — TestFlow na porta 5050
  • App TestFlow (qaschool/testflow)
$ node --version
v20.x.x

$ docker run -p 5050:5050 qaschool/testflow:latest
# curl http://localhost:5050/health

Instalação do ambiente por SO

Antes de clonar: Node 20+, Git e Docker (TestFlow na porta 5050).

macOS

Homebrew (recomendado)

brew install node@20 git
brew link --overwrite node@20
brew install --cask google-chrome docker

node --version   # v20+
git --version

TestFlow

docker run --rm -p 5050:5050 qaschool/testflow:latest

# alternativa: nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
nvm install 20 && nvm use 20

Windows

winget (Windows 10/11)

winget install OpenJS.NodeJS.LTS
winget install Git.Git
winget install Google.Chrome
winget install Docker.DockerDesktop

node --version
git --version

TestFlow + npm

docker run --rm -p 5050:5050 qaschool/testflow:latest

git clone https://github.com/lflucasferreira/testflow-selenium.git
cd testflow-selenium && npm install

Use PowerShell ou Git Bash para os comandos npm.

Linux (CI e local)

Debian / Ubuntu

curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs git

# Chrome headless (CI pattern)
sudo apt-get install -y google-chrome-stable

Docker + suite

sudo apt-get install -y docker.io
sudo usermod -aG docker $USER   # relogar depois

docker run --rm -p 5050:5050 qaschool/testflow:latest
npm ci && npm run test:smoke

Selenium Manager baixa o ChromeDriver compatível automaticamente.

Instalação — testflow-selenium

  1. Clone e instale
    git clone https://github.com/lflucasferreira/testflow-selenium.git
    cd testflow-selenium && npm install
  2. Configure env (opcional)
    cp .env.example .env — BASE_URL, HEADLESS, credenciais demo
  3. Suba TestFlow
    docker run -p 5050:5050 qaschool/testflow:latest
  4. Rode os testes
    npm test · npm run test:smoke · npm run test:api

Estrutura do projeto

testflow-selenium/
├── .mocharc.cjs          # Mocha + Allure/mochawesome
├── config/env.js         # BASE_URL, headless, credenciais
├── support/
│   ├── driver.js         # Builder + Chrome options
│   ├── helpers.js        # getByTestId, waits, screenshots
│   ├── auth.js           # loginViaApi, visitWithSession
│   └── api.js            # fetch + publicRequest
├── pages/                # Page Object Model
├── tests/                # 11 arquivos *.test.js
│   └── hooks.js          # beforeAll/afterEach global
└── scripts/              # wd-run.sh, Allure, Pages
  • pages/ — ações e assertions por tela
  • support/auth.js — seed de sessão via API
  • tests/**/*.test.js — Mocha + Chai
  • Tags: @smoke · @regression · @api · @critical
  • 11 arquivos — E2E + API (sem a11y, visual ou component testing isolado)

Configuração — driver & Mocha

// support/driver.js
const driver = await new Builder()
  .forBrowser('chrome')
  .setChromeOptions(options)  // --headless=new, window-size
  .build()

// .mocharc.cjs
module.exports = {
  require: ['tests/hooks.js'],
  timeout: 120000,
  reporter: process.env.CI ? 'allure-mocha' : 'mochawesome',
  spec: 'tests/**/*.test.js',
}

tests/hooks.js cria o WebDriver uma vez, expõe getHelpers() global e tira screenshot em falha.

Seu primeiro teste

// tests/auth/login.test.js
const LoginPage = require('../../pages/LoginPage')
const { getConfig } = require('../../support/driver')

describe('Authentication @regression', function () {
  beforeEach(async function () {
    const helpers = getHelpers()
    await clearSession(helpers)
    loginPage = new LoginPage(helpers)
    await loginPage.open()
  })

  it('logs in via UI and redirects to dashboard @smoke @critical', async function () {
    const config = getConfig()
    await loginPage.loginWith(config.demoEmail, config.demoPassword)
    await loginPage.shouldRedirectToDashboard()
  })
})

Navegação & browser

APIUso no TestFlow
driver.get(url)Abrir login, dashboard, páginas /web/*.html
driver.getCurrentUrl()Assert redirect pós-login
driver.getTitle()Smoke — título da página
driver.executeScript(fn)sessionStorage, skip onboarding tour
driver.wait(until…)Explicit wait por condição
driver.takeScreenshot()Allure attachment on failure
driver.manage().window()Viewport 1280×800

Elementos — find & interact

APIExemplo TestFlow
By.css('[data-testid="…"]')Locator principal do projeto
findElement / findElementsUm ou múltiplos elementos
.click()Submit, sidebar, nav links
.sendKeys(text)Email, senha, busca
.clear()Limpar campo antes de fill
.getText()KPIs, erros, labels
.getAttribute(name)placeholder, type=password
until.elementIsVisibleWait explícito no helper
Select(element)Dropdowns run-suite, run-env

Assertions — Chai

AssertionExemplo
expect(x).to.equal(y)Status HTTP, contadores
expect(x).to.be.trueBotão submit habilitado
expect(x).to.include(str)URL contém /web/dashboard.html
expect(x).to.be.an('array')Lista de users na API
expect(x).to.match(regex)Formato de email válido
Page Object throwsshouldRedirectToDashboard() — erro descritivo

Helpers — getByTestId

// support/helpers.js
async getByTestId(testId, timeout = TIMEOUTS.DEFAULT) {
  return this.waitForVisible(
    By.css(`[data-testid="${testId}"]`), timeout
  )
}

async clickByTestId(testId) {
  const el = await this.getByTestId(testId)
  await el.click()
}

async typeByTestId(testId, text) {
  const el = await this.getByTestId(testId)
  await el.clear()
  await el.sendKeys(text)
}
getByTestId clickByTestId typeByTestId getTextByTestId countByTestIdPrefix

Auth via API

// support/auth.js
async function loginViaApi(helpers, email, password) {
  const res = await fetch(`${config.baseUrl}/api/auth/login`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ email, password }),
  })
  const body = await res.json()
  cachedAuth = { email, token: body.token, name: body.user?.name }
  return cachedAuth
}

async function visitWithSession(helpers, path) {
  await seedAuthSession(helpers)  // sessionStorage sandbox-auth
  await helpers.driver.get(`${config.baseUrl}${path}`)
}

Evita login UI repetido — specs focam na feature sob teste.

API tests — fetch + Ajv

// tests/api/auth.api.test.js
const { publicRequest } = require('../../support/api')
const { validateWithSchema } = require('../../support/schemaValidator')

describe('API @api @regression — POST /api/auth/login', function () {
  it('returns status 200 @smoke @api', async function () {
    const res = await publicRequest('/api/auth/login', {
      method: 'POST', body: VALID,
    })
    expect(res.status).to.equal(200)
  })

  it('validates response against auth-login schema', function () {
    validateWithSchema(res.body, loadFixture('schemas/auth-login.json'))
  })
})
npm run test:api   # sem browser — só Node.js + fetch

Tags Mocha — @smoke @regression

TagUsoComando
@smokeFluxos críticos rápidosnpm run test:smoke
@regressionCobertura ampla E2Enpm run test:regression
@apiContratos RESTnpm run test:api
@criticalLogin, navegação essencialnpm run test:critical

Tags no título do describe ou it — filtradas via scripts/wd-run.sh --grep '@smoke'.

Page Object Model (POM)

Test (.test.js)

  • describe / it (Mocha)
  • Given / When / Then
  • Sem seletores espalhados
→

Page Object

  • helpers.getByTestId
  • Actions (loginWith)
  • Assertions (shouldRedirect…)

Page Objects do TestFlow

LoginPage.js auth, validação, API toggle
DashboardPage.js KPIs, activity, new run modal
TeamPage.js tabela, invite, inline edit
SettingsPage.js forms, toggles, save
WizardPage.js multi-step, review
BasePage.js helpers + config compartilhados

Cobertura da suíte — 11 arquivos

ÁreaArquivoTag
Smokesmoke/navigation.test.js@smoke
Authauth/login.test.js@regression
Dashboarddashboard/dashboard.test.js@regression
Team / Settingsteam/ · settings/@regression
Wizard / Advancedwizard/ · advanced/@regression
Activity / Statesactivity/ · states/@regression
Components pagecomponents/components.test.js@regression
APIapi/auth.api.test.js@api

Sem suites de a11y (axe), regressão visual ou component testing isolado — foco em E2E browser + API REST.

Comandos npm

ComandoDescrição
Execução principal
npm testSuite E2E completa (Mocha)
npm run test:headedBrowser visível (HEADLESS=false)
npm run test:smokeFiltra @smoke
npm run test:regressionFiltra @regression
npm run test:apiSó tests/api/** — sem browser
npm run test:criticalFiltra @critical

Comandos npm — por feature

ComandoDescrição
Por pasta
npm run test:authtests/auth/**
npm run test:dashboardtests/dashboard/**
npm run test:teamtests/team/**
npm run test:wizardtests/wizard/**
Relatório
npm run report:openAbre mochawesome HTML local
npm run report:allureGera Allure report
npm run test:smoke:reportSmoke + abre relatório

Allure Report

npm run test:smoke
npm run report:allure
npm run report:allure:open

# CI publica em GitHub Pages
npm run pages:prepare-allure
  • Screenshots anexados em falha (afterEach hook)
  • allure-mocha no CI · mochawesome local
  • Resultados mergeados: smoke + regression + full suite
  • GitHub Pages: job publish-allure em push na main

CI — selenium.yml

smoke

@smoke contra TestFlow Docker — gate rápido no PR

regression

@regression — cobertura ampla E2E

selenium-run

Suite completa npm test — Chrome headless Ubuntu

publish-allure

Merge Allure + deploy GitHub Pages com relatório HTML

Service container qaschool/testflow:latest · health check /health · artefatos de screenshot e allure-results em falha.

Boas práticas

  • Page Objects — locators data-testid centralizados em helpers.js
  • visitWithSession no beforeEach — specs focam na feature
  • getByTestId — explicit wait antes de interagir
  • BASE_URL via config/env.js — não hardcode localhost
  • API tests com fetch nativo + validação JSON Schema (Ajv)
  • Smoke, regression e full suite em paralelo no CI
  • Tags Mocha — filtrar @smoke, @api nos scripts npm
  • IDs rastreáveis [TC-xxxx] em support/enums/testCases.js
  • Um cenário por it() — falhas legíveis no Allure

Próximos passos

Você já sabe instalar Selenium WebDriver 4, configurar Mocha + Chai e rodar E2E no TestFlow.

← → slides  |  ↓ ↑ sub-slides  |  F tela cheia  |  ESC overview