O AppsQuality Lab é um laboratório público para praticar testes de interface e de API. A QA Store é uma loja fictícia com API REST documentada e a mesma jornada de compra construída de cinco jeitos diferentes, para você comparar como cada tecnologia muda a forma de localizar elementos e escrever esperas.
Ambiente público de testes. Todos os dados são fictícios, ficam isolados por token e expiram em 1 hora. Nunca use dados pessoais reais (nome, CPF, e-mail, telefone ou cartão).
Variantes da loja
Todas fazem o mesmo fluxo: login → lista com busca, filtro e ordenação → detalhe → carrinho → checkout em 2 passos → confirmação → sair.
| Variante | Nível | O que treina |
|---|---|---|
| HTML + JS puro | Iniciante | Seletores estáveis: data-testid em tudo e ids fixos. Ideal para o primeiro script. |
| React | Intermediário | Ids e classes que mudam a cada carregamento (ex.: id="btn-a8f3k"). Localize por texto, papel (role) e aria-label; data-test só no botão de login, no contador do carrinho e no número do pedido. |
| Vue 3 | Intermediário | Sem ids nem data-testid: só classes semânticas e textos. A lista usa rolagem infinita (6 produtos por vez). |
| Legado | Avançado | Layout em tabelas, campos como name="txtNome", navegação com recarga de página, nenhum atributo de teste e checkout dentro de iframe. |
| Shadow DOM | Avançado | Web Components com Shadow DOM aberto nos cards de produto, no carrinho e no menu da conta. |
| Elementos difíceis | Todos | Esperas, botão que se move, alertas nativos, nova aba, upload e download, arrastar e soltar, menu hover, tabela, datepicker, select dependente, toast, iframe aninhado, Shadow DOM aninhado, spinner, rolagem infinita, máscaras, tooltip, modal, abas e acordeão, cada um com o que treinar. |
Usuários de teste
Senha de todos: qa@12345
| Usuário | Comportamento |
|---|---|
standard_user | Tudo funciona como esperado. |
locked_user | O login sempre responde 423 (conta bloqueada). |
slow_user | Login e todas as requisições autenticadas demoram cerca de 3 segundos. |
problem_user | Bugs de propósito: todas as imagens são a mesma figura quebrada; a ordenação price_desc é ignorada; adicionar o produto 7 coloca o 8 no carrinho; o sobrenome some do pedido. |
error_user | O checkout falha com 500 nas tentativas ímpares (1ª, 3ª…) e funciona nas pares. |
API REST
Base: https://appsquality.com.br/wp-json/aq-lab/v1 · documentação legível · OpenAPI 3.0 (JSON) · status
Envie o token como Authorization: Bearer <token>. Se algum proxy remover esse cabeçalho, use X-Lab-Token: <token>, que funciona igual.
curl
TOKEN=$(curl -s -X POST 'https://appsquality.com.br/wp-json/aq-lab/v1/auth/login' \
-H 'Content-Type: application/json' \
-d '{"username":"standard_user","password":"qa@12345"}' | jq -r .token)
curl -s 'https://appsquality.com.br/wp-json/aq-lab/v1/products?sort=price_asc&per_page=5' -H "Authorization: Bearer $TOKEN" -i
Cypress (cy.request)
const api = 'https://appsquality.com.br/wp-json/aq-lab/v1';
it('adiciona ao carrinho', () => {
cy.request('POST', `${api}/auth/login`, { username: 'standard_user', password: 'qa@12345' })
.its('body.token')
.then((token) => {
const auth = { Authorization: `Bearer ${token}` };
cy.request({ method: 'POST', url: `${api}/cart`, headers: auth, body: { productId: 1, qty: 2 } })
.its('status').should('eq', 201);
});
});
Playwright (request)
import { test, expect } from '@playwright/test';
const api = 'https://appsquality.com.br/wp-json/aq-lab/v1';
test('login bloqueado devolve 423', async ({ request }) => {
const res = await request.post(`${api}/auth/login`, {
data: { username: 'locked_user', password: 'qa@12345' },
});
expect(res.status()).toBe(423);
expect((await res.json()).code).toBe('user_locked');
});
Postman
Importe a URL do OpenAPI (Import → Link) e crie uma variável de coleção token. No login, na aba Scripts → Post-response:
pm.test('login 200', () => pm.response.to.have.status(200));
pm.collectionVariables.set('token', pm.response.json().token);
Nas demais requisições use Authorization → Bearer Token com {{token}}.
Regras de uso
- Limite de 120 requisições por minuto por IP; acima disso a API responde
429comRetry-After. - Cada token tem sua própria cópia de carrinho, pedidos, contatos e reservas;
POST /resetvolta ao estado inicial. - Corpos de requisição têm limite de 16 KB e cada coleção aceita até 50 registros por token.
- Não faça testes de carga, varreduras de segurança ou ataques de negação de serviço. Para isso, rode o plugin no seu próprio WordPress local.
- Bugs propositais (como os do
problem_user) estão documentados; se achar um que não esteja, conte pela página de contato.
