Skip to content

Commit 21e4b3a

Browse files
test(button): adiciona testes e2e com cypress para os samples do po-button
Configura Cypress no projeto e cria testes e2e para os três samples do componente po-button: basic, labs e social-network. Cria componentes wrapper no app que replicam os samples usando caminhos relativos ao invés do pacote @po-ui/ng-components. Testes cobrem: - Renderização e estado inicial dos componentes - Interações de clique e eventos - Alteração de propriedades (label, kind, size, disabled, loading, danger) - Fluxo completo do sample social-network - Funcionalidade de restore no labs Co-Authored-By: aline.lariguet <alinecbgmoreira@gmail.com>
1 parent 68a14bd commit 21e4b3a

15 files changed

Lines changed: 553 additions & 2 deletions

cypress.config.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { defineConfig } from 'cypress';
2+
3+
export default defineConfig({
4+
e2e: {
5+
baseUrl: 'http://localhost:4200',
6+
supportFile: 'cypress/support/e2e.ts',
7+
specPattern: 'cypress/e2e/**/*.cy.ts',
8+
video: false,
9+
screenshotOnRunFailure: true,
10+
viewportWidth: 1280,
11+
viewportHeight: 720,
12+
defaultCommandTimeout: 10000
13+
}
14+
});
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
describe('PO Button Basic Sample', () => {
2+
beforeEach(() => {
3+
cy.visit('/button/basic');
4+
});
5+
6+
it('deve renderizar o botão com o label "PO Button"', () => {
7+
cy.get('po-button').should('exist');
8+
cy.get('po-button button.po-button').should('be.visible');
9+
cy.get('po-button .po-button-label').should('contain.text', 'PO Button');
10+
});
11+
12+
it('deve exibir um alerta ao clicar no botão', () => {
13+
const stub = cy.stub();
14+
cy.on('window:alert', stub);
15+
16+
cy.get('po-button button.po-button')
17+
.click()
18+
.then(() => {
19+
expect(stub).to.have.been.calledWith('Po Button!');
20+
});
21+
});
22+
23+
it('deve possuir o atributo p-kind padrão secondary', () => {
24+
cy.get('po-button').should('have.attr', 'p-kind', 'secondary');
25+
});
26+
27+
it('não deve estar desabilitado', () => {
28+
cy.get('po-button button.po-button').should('not.be.disabled');
29+
});
30+
31+
it('deve ter a classe po-button no elemento button', () => {
32+
cy.get('po-button button').should('have.class', 'po-button');
33+
});
34+
});
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
describe('PO Button Labs Sample', () => {
2+
beforeEach(() => {
3+
cy.visit('/button/labs');
4+
});
5+
6+
describe('Estado inicial', () => {
7+
it('deve renderizar o botão principal', () => {
8+
cy.get('app-button-labs po-button').first().find('button.po-button').should('be.visible');
9+
});
10+
11+
it('deve iniciar com kind secondary', () => {
12+
cy.get('app-button-labs po-button').first().should('have.attr', 'p-kind', 'secondary');
13+
});
14+
15+
it('deve renderizar o formulário de configuração', () => {
16+
cy.get('app-button-labs form').should('exist');
17+
});
18+
19+
it('deve exibir o campo de input para Label', () => {
20+
cy.get('app-button-labs po-input').should('exist');
21+
});
22+
23+
it('deve exibir o checkbox group de Properties', () => {
24+
cy.get('app-button-labs po-checkbox-group').should('exist');
25+
});
26+
27+
it('deve exibir os radio groups de configuração', () => {
28+
cy.get('app-button-labs po-radio-group').should('have.length', 4);
29+
});
30+
31+
it('deve exibir o botão Sample Restore', () => {
32+
cy.get('app-button-labs po-button').last().find('.po-button-label').should('contain.text', 'Sample Restore');
33+
});
34+
});
35+
36+
describe('Alteração de Label', () => {
37+
it('deve atualizar o label do botão ao digitar no campo Label', () => {
38+
cy.get('app-button-labs po-input input').clear().type('Meu Botão');
39+
cy.get('app-button-labs po-button').first().find('.po-button-label').should('contain.text', 'Meu Botão');
40+
});
41+
});
42+
43+
describe('Propriedade Disabled', () => {
44+
it('deve desabilitar o botão ao marcar a opção Disabled', () => {
45+
cy.get('app-button-labs po-checkbox-group').contains('Disabled').click();
46+
cy.get('app-button-labs po-button').first().find('button.po-button').should('be.disabled');
47+
});
48+
});
49+
50+
describe('Propriedade Loading', () => {
51+
it('deve exibir o ícone de loading ao marcar a opção Loading', () => {
52+
cy.get('app-button-labs po-checkbox-group').contains('Loading').click();
53+
cy.get('app-button-labs po-button').first().find('button.po-button').should('be.disabled');
54+
cy.get('app-button-labs po-button').first().find('.po-button-loading-icon').should('exist');
55+
});
56+
});
57+
58+
describe('Propriedade Danger', () => {
59+
it('deve aplicar o atributo danger ao marcar a opção Danger', () => {
60+
cy.get('app-button-labs po-checkbox-group').contains('Danger').click();
61+
cy.get('app-button-labs po-button').first().should('have.attr', 'p-danger', 'true');
62+
});
63+
});
64+
65+
describe('Alteração de Kind', () => {
66+
it('deve alterar o kind para primary', () => {
67+
cy.get('app-button-labs po-radio-group[name="kind"]').contains('primary').click();
68+
cy.get('app-button-labs po-button').first().should('have.attr', 'p-kind', 'primary');
69+
});
70+
71+
it('deve alterar o kind para tertiary', () => {
72+
cy.get('app-button-labs po-radio-group[name="kind"]').contains('tertiary').click();
73+
cy.get('app-button-labs po-button').first().should('have.attr', 'p-kind', 'tertiary');
74+
});
75+
});
76+
77+
describe('Alteração de Size', () => {
78+
it('deve alterar o tamanho para large', () => {
79+
cy.get('app-button-labs po-radio-group[name="size"]').contains('large').click();
80+
cy.get('app-button-labs po-button').first().find('button.po-button').should('have.class', 'po-button-large');
81+
});
82+
});
83+
84+
describe('Botão Click', () => {
85+
it('deve exibir um diálogo ao clicar no botão principal', () => {
86+
cy.get('app-button-labs po-button').first().find('button.po-button').click();
87+
cy.get('po-modal').should('be.visible');
88+
cy.get('po-modal').should('contain.text', 'Hello PO World!!!');
89+
});
90+
});
91+
92+
describe('Restore', () => {
93+
it('deve restaurar o estado inicial ao clicar em Sample Restore', () => {
94+
// Altera o label
95+
cy.get('app-button-labs po-input input').clear().type('Teste');
96+
cy.get('app-button-labs po-button').first().find('.po-button-label').should('contain.text', 'Teste');
97+
98+
// Clica em restaurar
99+
cy.get('app-button-labs po-button').last().find('button.po-button').click();
100+
101+
// Verifica que o kind voltou para secondary
102+
cy.get('app-button-labs po-button').first().should('have.attr', 'p-kind', 'secondary');
103+
});
104+
});
105+
});
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
describe('PO Button Social Network Sample', () => {
2+
beforeEach(() => {
3+
cy.visit('/button/social-network');
4+
});
5+
6+
it('deve renderizar o widget de Friend Request', () => {
7+
cy.get('po-widget').should('exist');
8+
cy.get('po-widget').should('contain.text', 'Friend Request');
9+
});
10+
11+
it('deve exibir o primeiro amigo (Mr. Dev PO)', () => {
12+
cy.get('app-button-social-network').should('contain.text', 'Mr. Dev PO');
13+
cy.get('app-button-social-network').should('contain.text', '7 mutual friends');
14+
cy.get('app-button-social-network').should('contain.text', 'Mountain View, CA');
15+
});
16+
17+
it('deve renderizar os três botões de ação', () => {
18+
cy.get('app-button-social-network po-button').should('have.length', 3);
19+
cy.get('app-button-social-network po-button').eq(0).find('.po-button-label').should('contain.text', 'Confirm');
20+
cy.get('app-button-social-network po-button').eq(1).find('.po-button-label').should('contain.text', 'Ignore');
21+
cy.get('app-button-social-network po-button').eq(2).find('.po-button-label').should('contain.text', 'Block');
22+
});
23+
24+
it('deve avançar para o próximo amigo ao clicar em Confirm', () => {
25+
cy.get('app-button-social-network po-button').eq(0).find('button.po-button').click();
26+
27+
// Verifica notificação de sucesso
28+
cy.get('po-toaster').should('contain.text', 'User added successfully!');
29+
30+
// Verifica que o segundo amigo é exibido
31+
cy.get('app-button-social-network').should('contain.text', 'Mr. AI PO');
32+
cy.get('app-button-social-network').should('contain.text', '99+ mutual friends');
33+
cy.get('app-button-social-network').should('contain.text', 'New York City, NY');
34+
});
35+
36+
it('deve avançar para o próximo amigo ao clicar em Ignore', () => {
37+
cy.get('app-button-social-network po-button').eq(1).find('button.po-button').click();
38+
39+
// Verifica notificação de warning
40+
cy.get('po-toaster').should('contain.text', 'User ignored successfully!');
41+
42+
// Verifica que o segundo amigo é exibido
43+
cy.get('app-button-social-network').should('contain.text', 'Mr. AI PO');
44+
});
45+
46+
it('deve avançar para o próximo amigo ao clicar em Block', () => {
47+
cy.get('app-button-social-network po-button').eq(2).find('button.po-button').click();
48+
49+
// Verifica notificação de informação
50+
cy.get('po-toaster').should('contain.text', 'User blocked successfully!');
51+
52+
// Verifica que o segundo amigo é exibido
53+
cy.get('app-button-social-network').should('contain.text', 'Mr. AI PO');
54+
});
55+
56+
it('deve exibir mensagem final após interagir com todos os amigos', () => {
57+
// Primeiro amigo - Confirm
58+
cy.get('app-button-social-network po-button').eq(0).find('button.po-button').click();
59+
cy.get('app-button-social-network').should('contain.text', 'Mr. AI PO');
60+
61+
// Segundo amigo - Ignore
62+
cy.get('app-button-social-network po-button').eq(1).find('button.po-button').click();
63+
cy.get('app-button-social-network').should('contain.text', 'Mr. UX PO');
64+
65+
// Terceiro amigo - Block
66+
cy.get('app-button-social-network po-button').eq(2).find('button.po-button').click();
67+
68+
// Verifica mensagem final
69+
cy.get('app-button-social-network').should('contain.text', 'Congratulations TOTVS, no more requests!');
70+
});
71+
72+
it('não deve exibir botões após interagir com todos os amigos', () => {
73+
// Interage com os três amigos
74+
cy.get('app-button-social-network po-button').eq(0).find('button.po-button').click();
75+
cy.get('app-button-social-network po-button').eq(0).find('button.po-button').click();
76+
cy.get('app-button-social-network po-button').eq(0).find('button.po-button').click();
77+
78+
// Verifica que não há mais botões de ação
79+
cy.get('app-button-social-network po-button').should('have.length', 0);
80+
});
81+
82+
it('deve exibir o avatar do usuário', () => {
83+
cy.get('po-avatar').should('exist');
84+
});
85+
});

cypress/support/e2e.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Arquivo de suporte para testes E2E com Cypress
2+
// Importações e comandos customizados podem ser adicionados aqui
3+
4+
Cypress.on('uncaught:exception', () => {
5+
// Previne falhas de teste por exceções não tratadas da aplicação
6+
return false;
7+
});

cypress/tsconfig.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2020",
4+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
5+
"types": ["cypress", "node"],
6+
"moduleResolution": "node",
7+
"module": "commonjs",
8+
"strict": true,
9+
"esModuleInterop": true,
10+
"skipLibCheck": true,
11+
"forceConsistentCasingInFileNames": true,
12+
"resolveJsonModule": true,
13+
"isolatedModules": true
14+
},
15+
"include": ["**/*.ts"]
16+
}

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
"@animaliads/animalia-icon": "1.0.5",
108108
"@commitlint/cli": "^18.4.3",
109109
"@commitlint/config-angular": "^18.4.3",
110+
"@cypress/schematic": "^5.0.0",
110111
"@po-ui/ng-schematics": "^18.0.0",
111112
"@types/jasmine": "~5.1.4",
112113
"@types/jasminewd2": "~2.0.13",
@@ -115,6 +116,7 @@
115116
"@types/systemjs": "^6.13.5",
116117
"@typescript-eslint/eslint-plugin": "^8.33.1",
117118
"@typescript-eslint/parser": "^8.33.1",
119+
"cypress": "^15.11.0",
118120
"del": "^6.0.0",
119121
"dgeni": "file:libs/dgeni-0.4.15.tgz",
120122
"dgeni-packages": "file:libs/dgeni-packages-0.30.1.tgz",
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<router-outlet></router-outlet>

projects/app/src/app/app.module.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,26 @@ import { PoModule } from '../../../ui/src/public-api';
88

99
import { AppComponent } from './app.component';
1010

11+
import { ButtonBasicComponent } from './button-basic/button-basic.component';
12+
import { ButtonLabsComponent } from './button-labs/button-labs.component';
13+
import { ButtonSocialNetworkComponent } from './button-social-network/button-social-network.component';
14+
1115
@NgModule({
12-
declarations: [AppComponent],
16+
declarations: [AppComponent, ButtonBasicComponent, ButtonLabsComponent, ButtonSocialNetworkComponent],
1317
bootstrap: [AppComponent],
14-
imports: [BrowserModule, FormsModule, RouterModule.forRoot([], {}), PoModule],
18+
imports: [
19+
BrowserModule,
20+
FormsModule,
21+
RouterModule.forRoot(
22+
[
23+
{ path: 'button/basic', component: ButtonBasicComponent },
24+
{ path: 'button/labs', component: ButtonLabsComponent },
25+
{ path: 'button/social-network', component: ButtonSocialNetworkComponent }
26+
],
27+
{}
28+
),
29+
PoModule
30+
],
1531
providers: [provideHttpClient(withInterceptorsFromDi())]
1632
})
1733
export class AppModule {}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<po-button p-label="PO Button" (p-click)="onClick()"> </po-button>

0 commit comments

Comments
 (0)