wip: snapshot das alterações não commitadas (2026-10-20)
Origem: D:/Documents/Github/dev-workflows Arquivos omitidos (segredos, bancos de dados, logs, >50 MB): 0
This commit is contained in:
1 parent
c17192c9fe
commit
2ef6f6be10
61 files changed
+7892
No files matched your search
@@ -0,0 +1,91 @@
|
||||
# Checagens de frontend para o `.dev-workflows.toml`
|
||||
|
||||
Estas checagens precisam do app de pé ou de configuração do projeto, por isso entram como
|
||||
`[[check]]`. O gate só roda as do nível pedido ou abaixo.
|
||||
|
||||
```toml
|
||||
[[check]]
|
||||
name = "lighthouse"
|
||||
cmd = "npx lhci autorun"
|
||||
tier = 2
|
||||
|
||||
[[check]]
|
||||
name = "a11y"
|
||||
cmd = "npx playwright test e2e/a11y.spec.ts"
|
||||
tier = 2
|
||||
|
||||
[[check]]
|
||||
name = "bundle"
|
||||
cmd = "npx size-limit"
|
||||
tier = 2
|
||||
|
||||
[[check]]
|
||||
name = "visual"
|
||||
cmd = "npx playwright test e2e/visual.spec.ts"
|
||||
tier = 3
|
||||
```
|
||||
|
||||
## Lighthouse CI com orçamento (`lighthouserc.json`)
|
||||
|
||||
```json
|
||||
{
|
||||
"ci": {
|
||||
"collect": { "startServerCommand": "npm run start", "url": ["http://localhost:3000/"], "numberOfRuns": 3 },
|
||||
"assert": {
|
||||
"assertions": {
|
||||
"largest-contentful-paint": ["error", { "maxNumericValue": 2500 }],
|
||||
"total-blocking-time": ["error", { "maxNumericValue": 200 }],
|
||||
"cumulative-layout-shift": ["error", { "maxNumericValue": 0.1 }],
|
||||
"categories:accessibility": ["error", { "minScore": 0.9 }]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
INP só existe com usuário real; em laboratório, TBT é o proxy.
|
||||
|
||||
## Acessibilidade com Playwright + axe (`e2e/a11y.spec.ts`)
|
||||
|
||||
```ts
|
||||
import { test, expect } from "@playwright/test";
|
||||
import AxeBuilder from "@axe-core/playwright";
|
||||
|
||||
for (const path of ["/", "/login"]) {
|
||||
test(`a11y ${path}`, async ({ page }) => {
|
||||
await page.goto(path);
|
||||
const { violations } = await new AxeBuilder({ page }).analyze();
|
||||
const graves = violations.filter(v => v.impact === "serious" || v.impact === "critical");
|
||||
expect(graves).toEqual([]);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Regressão visual (`e2e/visual.spec.ts`)
|
||||
|
||||
```ts
|
||||
import { test, expect } from "@playwright/test";
|
||||
|
||||
for (const width of [375, 1280]) {
|
||||
test(`home ${width}px`, async ({ page }) => {
|
||||
await page.setViewportSize({ width, height: 900 });
|
||||
await page.goto("/");
|
||||
await expect(page).toHaveScreenshot(`home-${width}.png`, { fullPage: true });
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
A primeira execução grava a referência (`--update-snapshots`); as seguintes comparam.
|
||||
|
||||
## Bundle (`size-limit` no `package.json`)
|
||||
|
||||
```json
|
||||
"size-limit": [{ "path": "dist/**/*.js", "limit": "200 KB" }]
|
||||
```
|
||||
|
||||
## Screenshot rápida para o `ui-critic`
|
||||
|
||||
```bash
|
||||
npx playwright screenshot --viewport-size=375,812 http://localhost:3000 /tmp/ui-375.png
|
||||
npx playwright screenshot --viewport-size=1280,800 http://localhost:3000 /tmp/ui-1280.png
|
||||
```
|
||||
@@ -0,0 +1,49 @@
|
||||
# PDF e documento visual: HTML + CSS + Playwright
|
||||
|
||||
Todo PDF passa por aqui: design primeiro, depois render, depois inspeção visual das páginas.
|
||||
|
||||
## Por que não reportlab direto
|
||||
|
||||
`platypus` com tabela longa estoura margem e corta linhas entre páginas. HTML + CSS de impressão
|
||||
resolve quebra de página, cabeçalho repetido e margens com regras declarativas.
|
||||
|
||||
## 1. HTML com CSS de impressão
|
||||
|
||||
```css
|
||||
@page { size: A4; margin: 18mm 16mm; }
|
||||
table { width: 100%; border-collapse: collapse; }
|
||||
thead { display: table-header-group; } /* repete o cabeçalho em cada página */
|
||||
tr, img, figure { break-inside: avoid; }
|
||||
h1, h2 { break-after: avoid; }
|
||||
td { overflow-wrap: anywhere; } /* texto longo não empurra a margem */
|
||||
```
|
||||
|
||||
## 2. Render com Playwright
|
||||
|
||||
```python
|
||||
from playwright.sync_api import sync_playwright
|
||||
|
||||
with sync_playwright() as p:
|
||||
page = p.chromium.launch().new_page()
|
||||
page.goto("file:///caminho/relatorio.html")
|
||||
page.pdf(path="relatorio.pdf", format="A4", print_background=True, prefer_css_page_size=True)
|
||||
```
|
||||
|
||||
## 3. Inspeção visual obrigatória
|
||||
|
||||
Converta cada página em PNG e abra com Read:
|
||||
|
||||
```bash
|
||||
pdftoppm -png -r 110 relatorio.pdf /tmp/qa/pagina
|
||||
ls /tmp/qa/pagina-*.png
|
||||
```
|
||||
|
||||
Em cada imagem, confira:
|
||||
|
||||
- nada cortado nas bordas (texto, tabela, imagem);
|
||||
- tabela longa quebra entre páginas com o cabeçalho repetido;
|
||||
- nenhuma linha órfã de título no pé da página;
|
||||
- fontes carregadas (sem fallback inesperado).
|
||||
|
||||
Achou problema: ajuste o CSS, renderize de novo e inspecione de novo. Só entregue depois de todas as
|
||||
páginas passarem.
|
||||
Reference in new issue
Block a user