Skip to content

Commit

Permalink
Merge pull request #24 from brunomachadors/23-add-automated-tests-and…
Browse files Browse the repository at this point in the history
…-test-ids-for-about-page

feat(tests): Improve About Page tests and update validation steps
  • Loading branch information
brunomachadors authored Jan 5, 2025
2 parents 7b7aade + c7bc4e4 commit 0dadc8e
Show file tree
Hide file tree
Showing 10 changed files with 268 additions and 49 deletions.
6 changes: 5 additions & 1 deletion playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ export default defineConfig({
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,

reporter: [['line'], ['github']],
reporter: [
['line'],
['github'],
['html', { outputFolder: 'playwright-report', open: 'always' }],
],
expect: {
timeout: 10_000,
},
Expand Down
36 changes: 26 additions & 10 deletions src/app/about/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,45 @@ import LinkButton from '../components/Button/LinkButton';

export default function About() {
return (
<div className="flex flex-col items-center justify-center min-h-[85vh] p-8">
<div className="flex flex-col sm:flex-row items-stretch border border-yellow-500 rounded-xl shadow-lg overflow-hidden w-full max-w-7xl">
{/* Foto */}
<div className="flex items-center justify-center bg-transparent w-full sm:w-1/2 p-4">
<main
className="flex flex-col items-center justify-center min-h-[85vh] p-8"
data-test-id="about-page"
aria-labelledby="about-page-title"
>
<div
className="flex flex-col sm:flex-row items-stretch border border-yellow-500 rounded-xl shadow-lg overflow-hidden w-full max-w-7xl"
data-test-id="about-container"
>
<div
className="flex items-center justify-center bg-transparent w-full sm:w-1/2 p-4"
data-test-id="about-photo"
>
<Image
src="https://res.cloudinary.com/dtglidvcw/image/upload/v1735730755/Portifolio/capalinguacinza.png"
alt="Bruno Machado"
width={600}
height={600}
className="rounded-lg shadow-lg object-cover"
aria-label="Photo of Bruno Machado"
/>
</div>

{/* Conteúdo */}
<div className="flex flex-col flex-1 p-8 rounded-lg">
<div
className="flex flex-col flex-1 p-8 rounded-lg"
data-test-id="about-content"
>
<AboutSections />
</div>
</div>

{/* Botão Centralizado Abaixo */}
<div className="mt-8">
<LinkButton text="Go to Resume" href="/resume" />
<div className="mt-8" data-test-id="resume-button-container">
<LinkButton
text="Go to Resume"
href="/resume"
data-test-id="resume-button"
aria-label="Navigate to Resume page"
/>
</div>
</div>
</main>
);
}
55 changes: 44 additions & 11 deletions src/app/components/AboutSections/AboutSections.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
'use client';
import React from 'react';
import { useState } from 'react';

const sections = [
Expand Down Expand Up @@ -43,41 +44,73 @@ export default function AboutSections() {
};

return (
<div className="flex flex-col items-start gap-6">
{/* Título */}
<h1 className="text-4xl sm:text-5xl font-bold text-yellow-500 text-center sm:text-left mb-4">
<div
className="flex flex-col items-start gap-6"
data-test-id="about-sections"
>
<h1
className="text-4xl sm:text-5xl font-bold text-yellow-500 text-center sm:text-left mb-4"
data-test-id="about-title"
>
About Me
</h1>

{/* Descrição Inicial */}
<p className="text-lg sm:text-xl text-gray-300 mb-4">
<p
className="text-lg sm:text-xl text-gray-300 mb-4"
data-test-id="about-description"
>
I&apos;m Bruno Machado, a QA Engineer passionate about software
development, test automation, accessibility, and Shift Left practices.
</p>

{/* Sessões Expansíveis */}
{sections.map((section, index) => (
<div
key={index}
onClick={() => toggleSection(index)}
className="w-full pb-4 border-b border-yellow-500 cursor-pointer last:border-none px-0 mx-0"
id={`section${index}`}
data-test-id={`section-${index}`}
>
<div className="flex justify-between items-center">
<span className="text-lg sm:text-xl font-bold text-yellow-500">
<span
className="text-lg sm:text-xl font-bold text-yellow-500"
data-test-id={`section-title-${index}`}
>
{section.title}
</span>
<span
className={`transform transition-transform duration-300 ${
openSection === index ? 'rotate-180' : ''
}`}
data-test-id={`toggle-icon-${index}`}
onClick={() => toggleSection(index)}
role="button" // Semântica de acessibilidade
aria-expanded={openSection === index}
>
</span>
</div>
{openSection === index && (
<div className="mt-2 text-gray-300 text-base sm:text-lg">
{section.content}
<div
className="mt-2 text-gray-300 text-base sm:text-lg"
data-test-id={`section-content-${index}`}
>
{typeof section.content === 'string' ? (
<span data-test-id={`section-text-${index}`}>
{section.content}
</span>
) : (
<div>
{React.Children.map(
section.content.props.children,
(child, childIndex) => (
<p
data-test-id={`section-content-${index}-line-${childIndex}`}
>
{child}
</p>
)
)}
</div>
)}
</div>
)}
</div>
Expand Down
40 changes: 40 additions & 0 deletions tests/about.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { test } from '@playwright/test';
import { AboutPage } from './pages/AboutPage';
import { ABOUT_DATA } from './data/test-data';

test.describe('About Page', () => {
test('Content', async ({ page }) => {
const aboutPage = new AboutPage(page);

await test.step('Navigate', async () => {
await aboutPage.navigateToAbout();
await aboutPage.validatePageLoaded();
});

await test.step('Container', async () => {
await aboutPage.validateAboutContainer();
});

await test.step('Title', async () => {
await aboutPage.validateAboutTitle(ABOUT_DATA.aboutTitle);
});

await test.step('Description', async () => {
await aboutPage.validateAboutDescription(ABOUT_DATA.aboutDescription);
});

await test.step('Resume Button', async () => {
await aboutPage.validateResumeButton('Go to Resume');
});

for (let i = 0; i < ABOUT_DATA.sections.length; i++) {
const { title, content } = ABOUT_DATA.sections[i];

await test.step(`Section ${i}: ${title}`, async () => {
await aboutPage.clickToggleIcon(i);
await aboutPage.validateSectionTitleVisible(i, title);
await aboutPage.validateSectionContentVisible(i, content);
});
}
});
});
24 changes: 0 additions & 24 deletions tests/data/index.ts

This file was deleted.

55 changes: 55 additions & 0 deletions tests/data/test-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Home Page Data
export const HOME_DATA = {
title: 'Welcome to my Portfolio',
subtitle: 'Explore my skills, experience, and projects as a QA Engineer.',
startButtonText: 'Start here',
};

// Footer Data
export const FOOTER_DATA = {
links: ['instagram', 'linkedin', 'github', 'medium', 'email'],
};

// Header Data
export const HEADER_DATA = {
menuOptions: [
'home',
'about',
'resume',
'skills',
'projects',
'posts',
'contacts',
],
};

export const ABOUT_DATA = {
aboutTitle: 'About Me',
aboutDescription:
"I'm Bruno Machado, a QA Engineer passionate about software development, test automation, accessibility, and Shift Left practices.",
sections: [
{
title: 'Personal Information',
content: [
'Location: Porto, Portugal',
'Nationality: Brazilian',
'Year of Birth: 1986',
],
},
{
title: 'My Journey into QA',
content:
'I started working in QA by chance and quickly realized that I have a strong aptitude for it. With over 17 years of experience in testing, I have specialized in test automation since 2017.',
},
{
title: 'Focus on Shift Left Practices',
content:
'I actively promote early involvement of QA in the development process, collaborating with developers to implement test frameworks and identify potential issues before they arise.',
},
{
title: 'Collaboration and Mentoring',
content:
'I value building strong relationships with colleagues, fostering a collaborative work environment, and mentoring professionals in the testing field.',
},
],
};
2 changes: 1 addition & 1 deletion tests/footer.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { test } from '@playwright/test';
import { FooterPage } from './pages/FooterPage';
import { FOOTER_DATA } from './data';
import { FOOTER_DATA } from './data/test-data';

test.describe('Footer', () => {
test('Links and Visibility', async ({ page }) => {
Expand Down
2 changes: 1 addition & 1 deletion tests/menu.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { test } from '@playwright/test';
import { MenuPage } from './pages/MenuPage';
import { HEADER_DATA } from './data';
import { HEADER_DATA } from './data/test-data';

test.describe('Menu', () => {
test('Navigation Validation', async ({ page, isMobile }) => {
Expand Down
95 changes: 95 additions & 0 deletions tests/pages/AboutPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { Page, expect } from '@playwright/test';

export class AboutPage {
readonly page: Page;

constructor(page: Page) {
this.page = page;
}

async navigateToAbout() {
await this.page.goto('/about', { waitUntil: 'commit' });
}

async validatePageLoaded() {
const imageLocator = this.page.getByRole('img', { name: 'Bruno Machado' });
await expect(imageLocator).toBeVisible();
}

async validateAboutTitle(expectedTitle: string) {
const titleLocator = this.page.locator('[data-test-id="about-title"]');
await expect(titleLocator).toBeVisible();
await expect(titleLocator).toHaveText(expectedTitle);
}

async validateAboutDescription(expectedDescription: string) {
const descriptionLocator = this.page.locator(
'[data-test-id="about-description"]'
);
await expect(descriptionLocator).toBeVisible();
await expect(descriptionLocator).toHaveText(expectedDescription);
}

async validateResumeButton(expectedText: string) {
const buttonLocator = this.page.locator('[data-test-id="resume-button"]');
await expect(buttonLocator).toBeVisible({ timeout: 5000 });
await expect(buttonLocator).toHaveText(expectedText);
}

async validateAboutContainer() {
const containerLocator = this.page.locator(
'[data-test-id="about-container"]'
);
await expect(containerLocator).toBeVisible();
}

async clickToggleIcon(index: number) {
const toggleIcon = this.page.locator(
`[data-test-id="toggle-icon-${index}"]`
);
await toggleIcon.click();

const contentLocator = this.page.locator(
`[data-test-id="section-content-${index}"]`
);
await this.page.waitForTimeout(300);
if (!(await contentLocator.isVisible())) {
await toggleIcon.click();
await this.page.waitForTimeout(300);
}
}

async validateSectionTitleVisible(index: number, expectedTitle: string) {
const titleLocator = this.page.locator(
`[data-test-id="section-title-${index}"]`
);
await expect(titleLocator).toBeVisible();
await expect(titleLocator).toHaveText(expectedTitle);
}

async validateSectionContentVisible(
index: number,
expectedContent: string | string[]
) {
const contentLocator = this.page.locator(
`[data-test-id="section-content-${index}"]`
);

if (!(await contentLocator.isVisible())) {
await this.clickToggleIcon(index);
}

await expect(contentLocator).toBeVisible();

if (Array.isArray(expectedContent)) {
for (let i = 0; i < expectedContent.length; i++) {
const lineLocator = contentLocator.locator(
`[data-test-id="section-content-${index}-line-${i}"]`
);
await expect(lineLocator).toHaveText(expectedContent[i]);
}
} else {
await expect(contentLocator).toHaveText(expectedContent);
}
}
}
Loading

0 comments on commit 0dadc8e

Please sign in to comment.