Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 177 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -164,3 +164,180 @@ jobs:
- run: npm run build:storage:lite
- run: npm run test:sync
- run: npm run test:sync:schematics

# Detecta quais arquivos mudaram para decidir se roda testes visuais
changes:
name: Detect changes
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
outputs:
visual: ${{ steps.filter.outputs.visual }}
steps:
- uses: actions/checkout@v3
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
visual:
- 'e2e/visual/**'
- 'projects/ui/src/lib/**'
- 'package.json'
- 'playwright.config.ts'
- 'angular.json'
- '.github/workflows/ci.yml'

test-visual:
name: Test visual regression
needs: changes
# Roda sempre em push (master/development) e em PRs apenas se arquivos relevantes mudaram
# Usa always() para garantir que roda em push mesmo quando o job 'changes' foi skipped
if: always() && !cancelled() && (github.event_name == 'push' || needs.changes.outputs.visual == 'true')

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v3

- uses: actions/setup-node@v3
with:
node-version: 24

# Cache de node_modules para evitar npm install do zero a cada execucao
- name: Cache node_modules
id: cache-node-modules
uses: actions/cache@v4
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ hashFiles('package.json') }}
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.

# Cache dos browsers do Playwright para evitar download a cada execucao
- name: Cache Playwright browsers
id: cache-playwright
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('package.json') }}

# Detecta o nome da branch atual
- name: Get branch name
id: branch
env:
HEAD_REF: ${{ github.head_ref }}
REF_NAME: ${{ github.ref_name }}
EVENT_NAME: ${{ github.event_name }}
run: |
if [ "$EVENT_NAME" = "pull_request" ]; then
BRANCH_NAME="$HEAD_REF"
else
BRANCH_NAME="$REF_NAME"
fi
echo "name=$BRANCH_NAME" >> $GITHUB_OUTPUT
echo "Branch name: $BRANCH_NAME"

# Verifica se existe uma branch de mesmo nome no po-style
- name: Check for matching po-style branch
id: po_style
env:
BRANCH_NAME: ${{ steps.branch.outputs.name }}
run: |
ENCODED_BRANCH=$(echo "$BRANCH_NAME" | sed 's|/|%2F|g')
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
"https://api.github.com/repos/po-ui/po-style/branches/$ENCODED_BRANCH")
if [ "$HTTP_STATUS" = "200" ]; then
echo "found=true" >> $GITHUB_OUTPUT
echo "Branch '$BRANCH_NAME' encontrada no po-style"
else
echo "found=false" >> $GITHUB_OUTPUT
echo "Branch '$BRANCH_NAME' nao encontrada no po-style (HTTP $HTTP_STATUS), usando @po-ui/style do npm"
fi

# Se encontrou a branch, clona po-style, builda e gera o tgz
- name: Build po-style from matching branch
if: steps.po_style.outputs.found == 'true'
env:
BRANCH_NAME: ${{ steps.branch.outputs.name }}
run: |
git clone --branch "$BRANCH_NAME" --depth 1 https://github.com/po-ui/po-style.git /tmp/po-style
cd /tmp/po-style
npm ci
npm run build
npm run pack:style
echo "TGZ gerado:"
ls -la dist/style/*.tgz

# Instala dependencias do po-angular (skip se cache hit)
- name: Install dependencies
if: steps.cache-node-modules.outputs.cache-hit != 'true'
run: npm i

# Se o cache de node_modules foi restaurado mas NAO existe branch po-style,
# reinstala @po-ui/style do npm para evitar versao stale de um tgz anterior
- name: Ensure clean po-style from npm
if: steps.cache-node-modules.outputs.cache-hit == 'true' && steps.po_style.outputs.found != 'true'
run: npm install @po-ui/style@$(node -p "require('./package.json').dependencies['@po-ui/style']")

# Se tiver o tgz do po-style, instala por cima da versao do npm
- name: Install po-style from tgz
if: steps.po_style.outputs.found == 'true'
run: |
TGZ_PATH=$(ls /tmp/po-style/dist/style/*.tgz)
echo "Instalando @po-ui/style a partir de: $TGZ_PATH"
npm install "$TGZ_PATH"

# Cache do build da lib UI para evitar rebuild a cada execucao
- name: Cache UI build
id: cache-ui-build
uses: actions/cache@v4
with:
path: dist/ng-components
key: ui-build-${{ runner.os }}-${{ hashFiles('projects/ui/src/**', 'package.json') }}

- name: Build UI library
if: steps.cache-ui-build.outputs.cache-hit != 'true'
run: npm run build:ui:lite

# Instala dependencias de sistema do Playwright (sempre necessario, mesmo com cache de browsers)
- name: Install Playwright system deps
run: npx playwright install-deps chromium

# Instala browsers do Playwright (skip se cache hit)
- name: Install Playwright browsers
if: steps.cache-playwright.outputs.cache-hit != 'true'
run: npx playwright install chromium

# Cache de baselines geradas no ambiente CI (sem restore-keys para evitar matches parciais stale)
- name: Restore visual regression baselines from cache
id: baselines-cache
uses: actions/cache@v4
with:
path: e2e/visual/__snapshots__
key: visual-baselines-${{ runner.os }}-${{ hashFiles('e2e/visual/**/*.visual.spec.ts', 'e2e/visual/**/*.component.html') }}

# Se nao encontrou baselines no cache, regenera todas para o ambiente CI (Linux)
# Usa --update-snapshots para sobrescrever baselines commitadas (geradas em outro OS)
- name: Generate baselines for CI environment
if: steps.baselines-cache.outputs.cache-hit != 'true'
run: npx playwright test --update-snapshots --reporter=list

# Executa os testes visuais comparando com as baselines
- name: Run visual regression tests
run: npx playwright test

# Disponibiliza o relatorio HTML do Playwright como artefato
- name: Upload visual regression report
uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: visual-regression-report
path: e2e/visual/playwright-report/
retention-days: 15

# Disponibiliza os resultados de teste (diffs, screenshots) como artefato
- name: Upload visual regression test results
uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: visual-regression-test-results
path: e2e/visual/test-results/
retention-days: 15
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ testem.log
.scannerwork
.env

# Playwright
/e2e/visual/test-results/
/e2e/visual/playwright-report/

# System Files
.DS_Store
Thumbs.db
Expand Down
40 changes: 40 additions & 0 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,46 @@
}
}
},
"visual-app": {
"projectType": "application",
"schematics": {},
"root": "e2e/visual",
"sourceRoot": "e2e/visual",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"outputPath": {
"base": "dist/visual-app"
},
"index": "e2e/visual/app/index.html",
"polyfills": ["e2e/visual/app/polyfills.ts"],
"tsConfig": "e2e/visual/tsconfig.visual.json",
"assets": [
{
"glob": "**/*",
"input": "node_modules/@po-ui/style/images",
"output": "/assets/images"
}
],
"styles": ["./node_modules/@po-ui/style/css/po-theme-default.min.css"],
"scripts": [],
"extractLicenses": false,
"sourceMap": true,
"optimization": false,
"namedChunks": true,
"browser": "e2e/visual/app/main.ts"
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"buildTarget": "visual-app:build"
}
}
}
},
"portal": {
"projectType": "application",
"schematics": {},
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading