Skip to content

Commit db430e7

Browse files
initial commit 🚀
0 parents  commit db430e7

File tree

11 files changed

+434
-0
lines changed

11 files changed

+434
-0
lines changed

.github/workflows/playwright.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Playwright Tests
2+
on:
3+
push:
4+
branches: [ main, master ]
5+
pull_request:
6+
branches: [ main, master ]
7+
jobs:
8+
test:
9+
timeout-minutes: 60
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
- uses: actions/setup-node@v4
14+
with:
15+
node-version: lts/*
16+
- name: Install dependencies
17+
run: npm ci
18+
- name: Install Playwright Browsers
19+
run: npx playwright install --with-deps
20+
- name: Run Playwright tests
21+
run: npx playwright test
22+
- uses: actions/upload-artifact@v4
23+
if: ${{ !cancelled() }}
24+
with:
25+
name: playwright-report
26+
path: playwright-report/
27+
retention-days: 30

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
# Playwright
3+
node_modules/
4+
/test-results/
5+
/playwright-report/
6+
/blob-report/
7+
/playwright/.cache/

README.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Test Automation Facade Pattern
2+
3+
Este projeto é uma suíte de testes automatizados utilizando [Playwright](https://playwright.dev/) para validar fluxos de autenticação e cadastro em uma aplicação web. O projeto adota o **Facade Pattern** para organizar e simplificar a interação com as páginas, tornando os testes mais legíveis, reutilizáveis e de fácil manutenção.
4+
5+
## Contexto
6+
7+
O objetivo deste repositório é demonstrar como estruturar testes automatizados de ponta a ponta (E2E) utilizando o padrão de projeto **Facade**. Esse padrão encapsula operações complexas de páginas em classes de fachada, expondo métodos de alto nível para os testes, sem que eles precisem conhecer detalhes de implementação dos elementos da interface.
8+
9+
## Sobre o Facade Pattern
10+
11+
O **Facade Pattern** (Padrão Fachada) é utilizado para fornecer uma interface simplificada para um conjunto de interfaces em um subsistema. No contexto deste projeto, cada fluxo de negócio (ex: autenticação, cadastro) possui uma fachada (`AuthFacade`, `RegisterFacade`) que abstrai as interações com os elementos da página, facilitando a escrita e manutenção dos testes.
12+
13+
**Exemplo:**
14+
```typescript
15+
const register = new RegisterFacade(page);
16+
await register.registerAs("[email protected]", "Nome", "senha", "senha");
17+
```
18+
19+
## Estrutura do Projeto
20+
21+
- `ui/pages/`: Page Objects com os elementos e ações de cada página.
22+
- `ui/facade/`: Facades que encapsulam fluxos completos de negócio.
23+
- `tests/`: Arquivos de teste automatizados.
24+
- `playwright.config.ts`: Configuração do Playwright (incluindo baseURL).
25+
26+
## Comandos Essenciais
27+
28+
- **Executar todos os testes:**
29+
```
30+
npx playwright test
31+
```
32+
33+
- **Executar testes em modo UI interativo:**
34+
```
35+
npx playwright test --ui
36+
```
37+
38+
- **Executar testes em um navegador específico:**
39+
```
40+
npx playwright test --project=chromium
41+
```
42+
43+
- **Executar um arquivo de teste específico:**
44+
```
45+
npx playwright test tests/login.test.ts
46+
```
47+
48+
- **Executar em modo debug:**
49+
```
50+
npx playwright test --debug
51+
```
52+
53+
- **Gerar testes automaticamente com Codegen:**
54+
```
55+
npx playwright codegen
56+
```
57+
58+
## Requisitos
59+
60+
- Node.js instalado
61+
- Dependências instaladas com:
62+
```
63+
npm install
64+
```
65+
66+
## Observações
67+
68+
- O projeto utiliza `baseURL` configurado no `playwright.config.ts`, permitindo o uso de caminhos relativos nos testes.
69+
- Como a aplicação de exemplo não possui banco de dados persistente, os dados criados existem apenas durante a sessão.

constants/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
const BASE_URL = "https://bugbank.netlify.app/";

package-lock.json

Lines changed: 97 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"name": "automation-patterns",
3+
"version": "1.0.0",
4+
"description": "automation test patterns",
5+
"main": "index.js",
6+
"scripts": {},
7+
"author": "Alex Alexandre Alves",
8+
"license": "ISC",
9+
"devDependencies": {
10+
"@playwright/test": "^1.54.0",
11+
"@types/node": "^24.0.13"
12+
}
13+
}

playwright.config.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { defineConfig, devices } from '@playwright/test';
2+
3+
/**
4+
* Read environment variables from file.
5+
* https://github.com/motdotla/dotenv
6+
*/
7+
// import dotenv from 'dotenv';
8+
// import path from 'path';
9+
// dotenv.config({ path: path.resolve(__dirname, '.env') });
10+
11+
/**
12+
* See https://playwright.dev/docs/test-configuration.
13+
*/
14+
export default defineConfig({
15+
testDir: './tests',
16+
/* Run tests in files in parallel */
17+
fullyParallel: false,
18+
/* Fail the build on CI if you accidentally left test.only in the source code. */
19+
forbidOnly: !!process.env.CI,
20+
/* Retry on CI only */
21+
retries: process.env.CI ? 2 : 0,
22+
/* Opt out of parallel tests on CI. */
23+
workers: process.env.CI ? 1 : undefined,
24+
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
25+
reporter: 'html',
26+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
27+
use: {
28+
/* Base URL to use in actions like `await page.goto('/')`. */
29+
baseURL: 'https://bugbank.netlify.app/',
30+
31+
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
32+
trace: 'on-first-retry',
33+
},
34+
35+
/* Configure projects for major browsers */
36+
projects: [
37+
{
38+
name: 'chromium',
39+
use: { ...devices['Desktop Chrome'] },
40+
},
41+
42+
{
43+
name: 'firefox',
44+
use: { ...devices['Desktop Firefox'] },
45+
},
46+
47+
// {
48+
// name: 'webkit',
49+
// use: { ...devices['Desktop Safari'] },
50+
// },
51+
52+
/* Test against mobile viewports. */
53+
// {
54+
// name: 'Mobile Chrome',
55+
// use: { ...devices['Pixel 5'] },
56+
// },
57+
// {
58+
// name: 'Mobile Safari',
59+
// use: { ...devices['iPhone 12'] },
60+
// },
61+
62+
/* Test against branded browsers. */
63+
// {
64+
// name: 'Microsoft Edge',
65+
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
66+
// },
67+
// {
68+
// name: 'Google Chrome',
69+
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
70+
// },
71+
],
72+
73+
/* Run your local dev server before starting the tests */
74+
// webServer: {
75+
// command: 'npm run start',
76+
// url: 'http://localhost:3000',
77+
// reuseExistingServer: !process.env.CI,
78+
// },
79+
});

tests/login.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { test } from '@playwright/test';
2+
import { OauthFlow } from '../ui/flows/oauth-flow';
3+
4+
5+
test.beforeEach(async ({ page }) => {
6+
await page.goto('/')
7+
})
8+
9+
test.describe('Register and Authentication tests', () => {
10+
11+
test('CT001 - Should be able to register and do login with a new user with success', async ({ page }) => {
12+
// Start the selected flow
13+
const oauthFlow = new OauthFlow(page);
14+
// Do the test
15+
oauthFlow.login("Testezinho da silva", "[email protected]", "12345", "12345");
16+
});
17+
});

ui/flows/oauth-flow.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { expect, Page } from '@playwright/test';
2+
import { LoginPage } from '../pages/login-page';
3+
import { RegisterPage } from '../pages/register-page';
4+
5+
export class OauthFlow {
6+
constructor(private page: Page) { }
7+
8+
async login(name: string, email: string, password: string, confirmationPassword: string) {
9+
10+
const loginPage = new LoginPage(this.page);
11+
const registerPage = new RegisterPage(this.page);
12+
13+
// Registration
14+
await loginPage.clickRegisterButton();
15+
await registerPage.fillEmail(email);
16+
await registerPage.fillName(name);
17+
await registerPage.fillPassword(password);
18+
await registerPage.fillPasswordConfirmation(confirmationPassword);
19+
await registerPage.clickRegisterButton();
20+
21+
// // Registration assert
22+
// await expect(registerPage.confirmationMessage).toBeVisible();
23+
// await expect(registerPage.confirmationIcon).toBeVisible();
24+
// await registerPage.closeButton.click();
25+
26+
// // Do login
27+
// await loginPage.fillEmail(email);
28+
// await loginPage.fillPassword(password);
29+
// await loginPage.clickLoginButton();
30+
// await this.page.waitForURL("https://bugbank.netlify.app/home");
31+
// await expect(this.page).toHaveURL("https://bugbank.netlify.app/home");
32+
}
33+
}

ui/pages/login-page.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { Page, Locator } from "@playwright/test";
2+
3+
4+
export class LoginPage {
5+
6+
readonly page: Page;
7+
readonly emailInput: Locator;
8+
readonly passwordInput: Locator;
9+
readonly loginButton: Locator;
10+
readonly registerButton: Locator;
11+
12+
constructor(page: Page) {
13+
this.page = page;
14+
this.emailInput = page.locator('form').filter({ hasText: 'E-mailSenhaAcessarRegistrarConheça nossos requisitosA aplicação não conta com' }).getByPlaceholder('Informe seu e-mail');
15+
this.passwordInput = page.locator('form').filter({ hasText: 'E-mailSenhaAcessarRegistrarConheça nossos requisitosA aplicação não conta com' }).getByPlaceholder('Informe sua senha');
16+
this.loginButton = page.getByRole('button', { name: 'Acessar' });
17+
this.registerButton = page.getByRole('button', { name: 'Registrar' });
18+
}
19+
20+
async fillEmail(email: string) {
21+
await this.emailInput.fill(email);
22+
}
23+
24+
async fillPassword(password: string) {
25+
await this.passwordInput.fill(password);
26+
}
27+
28+
async clickLoginButton() {
29+
await this.loginButton.click();
30+
}
31+
32+
async clickRegisterButton() {
33+
await this.registerButton.click();
34+
}
35+
36+
}

0 commit comments

Comments
 (0)