Skip to content

feat: setup Playwright e2e testing infrastructure#328

Open
DSingh0304 wants to merge 88 commits intokeploy:mainfrom
DSingh0304:main
Open

feat: setup Playwright e2e testing infrastructure#328
DSingh0304 wants to merge 88 commits intokeploy:mainfrom
DSingh0304:main

Conversation

@DSingh0304
Copy link

@DSingh0304 DSingh0304 commented Feb 19, 2026

Related Tickets & Documents

Part of e2e testing initiative

Current Status

Ready for Review - CI/CD issues resolved, workflow passing, ready for merge

Recent Updates

  • ✅ Implemented homepage E2E test (navigation, hero section, core elements)
  • ✅ Fixed CI environment variable configuration (hardcoded public WordPress GraphQL endpoint)
  • ✅ Added workflow permissions for PR comments (pull-requests: write, issues: write)
  • ✅ Resolved fork compatibility issues (CI now works on both main repo and forks)
  • ✅ All Playwright tests passing on Chromium

Description

This PR establishes the foundation for comprehensive end-to-end testing using Playwright. It sets up the testing infrastructure with environment-based configuration, multi-browser support, and GitHub Actions CI integration, along with a working homepage E2E test.

The configuration enables automated testing across different browsers and environments without code changes, provides fast local development feedback, and ensures code quality through automated PR checks.

Changes

  • Added Playwright configuration with environment-driven settings (playwright.config.ts)
  • Created GitHub Actions workflow for automated CI testing (.github/workflows/playwright.yml)
    • Hardcoded WordPress API URL for CI compatibility with forks
    • Added proper permissions for PR comment bot
    • Configured to skip comments on forked PRs (security)
  • Added comprehensive test scripts to package.json
  • Created environment variable template (.env.test.example)
  • Set up tests/e2e directory structure with homepage E2E test
  • Updated .gitignore to exclude test artifacts and secrets
  • Configured 5 browser projects: Chromium, Firefox, WebKit, Mobile Chrome, Mobile Safari
  • Implemented WebServer auto-start for seamless local testing

Type of Change

  • Chore (maintenance, refactoring, tooling updates)
  • Bug fix (non-breaking change that fixes an issue)
  • New feature (change that adds functionality)
  • Breaking Change (may require updates in existing code)
  • UI improvement (visual or design changes)
  • Performance improvement (optimization or efficiency enhancements)
  • Documentation update (changes to README, guides, etc.)
  • CI (updates to continuous integration workflows)
  • Revert (undo a previous commit or merge)

Testing

  • Verified Playwright installation: npx playwright install
  • Created and configured .env.test from template
  • Implemented comprehensive homepage E2E test suite (tests/pages/HomePage.spec.ts):
    • ✅ Page load and title verification
    • ✅ Header with logo display
    • ✅ Navigation links (Technology, Community)
    • ✅ Hero/intro section rendering
    • ✅ Footer display and links
    • ✅ Footer social links (GitHub, Twitter, LinkedIn, Slack)
    • ✅ Search functionality (desktop)
    • ✅ Posts/stories section display
    • ✅ Working navigation to Technology page
    • ✅ Working navigation to Community page
    • ✅ Keyboard navigation support
  • Ran tests locally: npm run test:e2e:chromium - All 11 tests passing ✅
  • Tested Playwright UI mode: npm run test:e2e:ui
  • Verified WebServer auto-start functionality
  • Confirmed test artifacts generate correctly (screenshots, videos, reports)
  • Validated all browser projects are properly configured
  • CI/CD validated: GitHub Actions workflow passing on all commits

Demo

Playwright Test Run Video:

In this video the playwright test is begin run in the CI in chromium browser only but the all the tests have passed in all 3 browsers with 1 test as flaky ( No significant errors or failed tests. )

Screenshot from 2026-03-18 16-54-17

Test Commands Available:

npm run test:e2e              # Run all tests
npm run test:e2e:ui           # Interactive debugging mode
npm run test:e2e:headed       # Watch tests run in browser
npm run test:e2e:chromium     # Fast single-browser testing
npm run test:e2e:codegen      # Generate test code from interactions
npm run test:e2e:report       # View HTML test report

Browser Coverage:

  • Desktop: Chromium, Firefox, WebKit
  • Mobile: Mobile Chrome (Pixel 5), Mobile Safari (iPhone 13)
  • CI: Chromium only initially (expandable to all browsers)

Environment and Dependencies

New Dependencies:

  • @playwright/test (v1.58.2) - Test framework
  • dotenv (v17.3.1) - Environment variable management

Configuration Changes:

  • Create .env.test file from .env.test.example template (optional for local development)
  • Repository secrets required no longer needed - WordPress API URL now hardcoded in workflow
  • Install Playwright browsers: npx playwright install

Work in Progress (WIP)

Current Focus:

  • ✅ Homepage E2E test fully implemented (tests/pages/HomePage.spec.ts)
  • ✅ Core component tests complete: Header/Navbar, HeroPost, MoreStories, Footer, PostHeader, PostBody, ScrollToTop, TableContents
  • 🔄 Next 3 component tests to be pushed: Tag, Testimonials, TopBlogs
  • Following: Page-level tests: Technology, Community, Search, Authors, Tags, 404

Not Included in This PR:

  1. Multi-browser CI testing (Firefox, WebKit) - currently Chromium only
  2. Mobile-specific test scenarios (structure in place, coverage expanding)

TODOs for Follow-up PRs 📋

Component Tests (High Priority)

  • Homepage Component (tests/pages/HomePage.spec.ts)
  • Header/Navigation Component (tests/components/Navigation.spec.ts)
  • Hero Post Component (tests/components/HeroPost.spec.ts)
  • More Stories Component (tests/components/MoreStories.spec.ts)
  • Footer Component (tests/components/Footer.spec.ts)
  • Post Header Component (tests/components/PostHeader.spec.ts)
  • Post Body Component (tests/components/PostBody.spec.ts)
  • Scroll To Top Component (tests/components/ScrollToTop.spec.ts)
  • Table of Contents Component (tests/components/TableContents.spec.ts)
  • Tag Component (tests/components/Tag.spec.ts)
  • Testimonials Component (tests/components/Testimonials.spec.ts)
  • Top Blogs Component (tests/components/TopBlogs.spec.ts)

Page Tests (High Priority)

  • Homepage (tests/pages/HomePage.spec.ts)
  • Technology Index Page (tests/pages/TechnologyPage.spec.ts)
  • Technology Post Page (tests/pages/TechnologyPostPage.spec.ts)
  • Community Index Page (tests/pages/CommunityPage.spec.ts)
  • Community Post Page (tests/pages/CommunityPostPage.spec.ts)
  • Community Search Page (tests/pages/CommunitySearchPage.spec.ts)
  • Search Page (tests/pages/SearchPage.spec.ts)
  • Authors Index Page (tests/pages/AuthorsIndexPage.spec.ts)
  • Author Detail Page (tests/pages/AuthorDetailPage.spec.ts)
  • Tags Index Page (tests/pages/TagsIndexPage.spec.ts)
  • Tag Detail Page (tests/pages/TagDetailPage.spec.ts)
  • 404 Error Page (tests/pages/NotFoundPage.spec.ts)

Medium Priority

  • Mobile Responsiveness (Test on Mobile Chrome/Safari)
  • Expand CI browser matrix to include Firefox and WebKit
  • README documentation (Setup, guidelines, debugging)
  • Test fixtures and utilities (Mock data, helpers, custom assertions)

Low Priority

  • Accessibility testing (axe-core)
  • Link checker and image optimization tests

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation (README update tracked in TODOs)
  • I have added corresponding tests (homepage E2E test included, expanding coverage)
  • I have run the build command to ensure there are no build errors
  • My changes have been tested across relevant browsers/devices
  • For UI changes, I've included visual evidence of my changes (N/A - infrastructure only)

Additional Notes

CI/CD Configuration Details:

  • WordPress GraphQL endpoint (https://wp.keploy.io/graphql) is hardcoded in workflow for security and fork compatibility
  • This is safe because: (1) endpoint is already public in repo, (2) used client-side in Next.js app, (3) read-only access only
  • PR comment bot only runs on same-repo PRs (skipped for forks due to permission restrictions)
  • Test artifacts (reports, screenshots, videos) auto-upload on test failures

Copilot AI review requested due to automatic review settings February 19, 2026 18:11
@kilo-code-bot
Copy link

kilo-code-bot bot commented Feb 19, 2026

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Overview

This PR adds Playwright E2E testing infrastructure to the blog website. The implementation is well-structured and follows best practices:

  • ✅ Proper Playwright configuration with sensible defaults and environment variable overrides
  • ✅ GitHub Actions workflow with proper caching, artifact uploads, and PR commenting
  • ✅ Comprehensive homepage tests covering navigation, footer, search, and accessibility
  • ✅ Environment variable examples provided for local development
  • ✅ Appropriate .gitignore updates for test artifacts
Files Reviewed (7 files)
  • .env.test.example - Test environment configuration template
  • .github/workflows/playwright.yml - CI workflow for E2E tests
  • .gitignore - Updated to exclude test artifacts
  • package-lock.json - Dependency updates
  • package.json - Added test scripts and dev dependencies
  • playwright.config.ts - Playwright test configuration
  • tests/pages/HomePage.spec.ts - Homepage E2E tests
Notes
  • The previous comments on tests/e2e/smoke.spec.ts are no longer applicable as that file has been removed/renamed in this version of the PR.
  • The baseURL parameter in tests at lines 62 and 70 of HomePage.spec.ts is destructured but unused - this is a very minor code quality observation that doesn't affect functionality.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Sets up Playwright-based end-to-end testing for the Next.js blog app, including local developer workflows and CI execution in GitHub Actions.

Changes:

  • Adds Playwright test configuration (multi-browser projects, webServer auto-start, artifact output dirs).
  • Introduces initial e2e test structure with a placeholder smoke test and .env.test template.
  • Adds npm scripts and a GitHub Actions workflow to run Playwright tests in CI.

Reviewed changes

Copilot reviewed 5 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/e2e/smoke.spec.ts Adds initial smoke test exercising homepage load/title.
playwright.config.ts Defines Playwright config (projects, timeouts, reporters, webServer, env loading).
package.json Adds Playwright/dotenv dev deps and e2e scripts; updates Node types.
package-lock.json Locks new dependencies (@playwright/test, playwright, dotenv) and type updates.
.gitignore Updates ignored env/test artifact patterns, adds Playwright output/cache ignores.
.github/workflows/playwright.yml Adds CI workflow to run Playwright tests (Chromium matrix initially).
.env.test.example Provides template env vars for local e2e runs.
Comments suppressed due to low confidence (2)

.github/workflows/playwright.yml:74

  • This workflow creates a new PR comment on every run and doesn’t declare the issues: write / pull-requests: write permissions needed for github.rest.issues.createComment (the repo already uses explicit permissions in other workflows). This can fail the job in repos/orgs with restricted default token permissions, and it will spam PR threads. Prefer using a create-or-update comment action (sticky comment) and add an explicit permissions block, or remove the commenting step entirely.
      - name: Comment PR with result
        if: github.event_name == 'pull_request' && always()
        uses: actions/github-script@v7
        with:
          script: |
            const status = '${{ job.status }}';
            const emoji = status === 'success' ? '✅' : '❌';
            const message = status === 'success' 
              ? `${emoji} Playwright tests passed on **${{ matrix.browser }}**!`
              : `${emoji} Playwright tests failed on **${{ matrix.browser }}**. Check the [workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details.`;
            
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: message
            });

package.json:56

  • @types/node was bumped from v18 to v25 while the repo’s GitHub Actions workflows run Node 18. This mismatch can introduce confusing/incorrect Node API typings (and may require newer TS features) compared to the actual runtime. Consider pinning @types/node to the major that matches the supported runtime (e.g., ^18.x) unless there’s a specific reason to target Node 25 types.
    "@playwright/test": "^1.58.2",
    "@types/node": "^25.3.0",
    "@types/prismjs": "^1.26.3",

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Signed-off-by: DSingh0304 <deepshekhar0306@gmail.com>
Signed-off-by: DSingh0304 <deepshekhar0306@gmail.com>
@DSingh0304 DSingh0304 force-pushed the main branch 4 times, most recently from d9ef83a to 0b72371 Compare February 24, 2026 12:52
Signed-off-by: DSingh0304 <deepshekhar0306@gmail.com>
Copy link
Contributor

@manasmanohar manasmanohar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DSingh0304, could you please update the PR description to include the TODOs, WIP items, the current status of the PR, and the Playwright test run video?

Signed-off-by: DSingh0304 <deepshekhar0306@gmail.com>
… for PR comments

Signed-off-by: DSingh0304 <deepshekhar0306@gmail.com>
@DSingh0304
Copy link
Author

@DSingh0304, could you please update the PR description to include the TODOs, WIP items, the current status of the PR, and the Playwright test run video?

Yes sir I have updated the PR description with the following requirements.

Signed-off-by: DSingh0304 <deepshekhar0306@gmail.com>
…s component.

Signed-off-by: DSingh0304 <deepshekhar0306@gmail.com>
Signed-off-by: DSingh0304 <deepshekhar0306@gmail.com>
Signed-off-by: DSingh0304 <deepshekhar0306@gmail.com>
Signed-off-by: DSingh0304 <deepshekhar0306@gmail.com>
Signed-off-by: DSingh0304 <deepshekhar0306@gmail.com>
Signed-off-by: DSingh0304 <deepshekhar0306@gmail.com>
Signed-off-by: DSingh0304 <deepshekhar0306@gmail.com>
Signed-off-by: DSingh0304 <deepshekhar0306@gmail.com>
Signed-off-by: DSingh0304 <deepshekhar0306@gmail.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 46 out of 48 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Deep and others added 2 commits March 18, 2026 17:25
…isibility checks for first post

Signed-off-by: Deep <deep@example.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Deep Shekhar Singh <deepshekhar0306@gmail.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 46 out of 48 changed files in this pull request and generated 8 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

DSingh0304 and others added 5 commits March 18, 2026 17:37
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Deep Shekhar Singh <deepshekhar0306@gmail.com>
…horizontal overflow checks

Signed-off-by: Deep <deep@example.com>
…ency in mobile layout tests

Signed-off-by: Deep <deep@example.com>
… clicks across multiple components

Signed-off-by: Deep <deep@example.com>
… MobileNavigation for improved visibility and reliability of elements before interactions

Signed-off-by: Deep <deep@example.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 46 out of 48 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

DSingh0304 and others added 3 commits March 18, 2026 18:05
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Deep Shekhar Singh <deepshekhar0306@gmail.com>
…locator strategies for better reliability

Signed-off-by: Deep <deep@example.com>
…rovide clearer warnings when .env.test is missing

Signed-off-by: Deep <deep@example.com>
@DSingh0304
Copy link
Author

@manasmanohar Sir I have addressed all the comments and ran copilot review and fixed required issues, I have added screenshot in the PR description for the test report, please allow the workflows now so that I can see if all the checks are passing.

@DSingh0304
Copy link
Author

@manasmanohar Hello Sir, I see all the checks are passing. Is there anything else I need to do to get this PR merged?

@DSingh0304
Copy link
Author

I see one test is failing I will go through it and fix it.

…checks and refining URL wait conditions in tests.

Signed-off-by: Deep <deep@example.com>
@manasmanohar
Copy link
Contributor

HI @DSingh0304, will review the pr today once again as discussed in the email thread.

Please check the failing tests once
https://github.com/keploy/blog-website/actions/runs/23297765581/job/67749857228?pr=328

Copy link
Contributor

@manasmanohar manasmanohar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please go through the tests file by file and make sure you fully understand what each test is actually validating.

A good way to verify this is to intentionally break the behavior the test is supposed to cover and confirm the test fails. If it still passes, the test likely isn’t asserting anything meaningful.

This helps catch silent passes caused by stale selectors, incorrect scoping, or guards like if (count > 0) that skip assertions.

A few such cases are already present in this PR (flagged inline). Running this check yourself will be much faster than going through multiple review iterations.

test('TOC should be sticky on desktop while scrolling', async ({ page }) => {
const tocContainer = page.locator('.hidden.lg\\:inline-block');
const count = await tocContainer.count();
if (count > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we using css class selector instead of data-testid?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have migrated all CSS/ID-based selectors to data-testid across the components and updated the tests. I also removed the conditional guards that were causing silent passes.

test('TOC should be sticky on desktop while scrolling', async ({ page }) => {
const tocContainer = page.locator('.hidden.lg\\:inline-block');
const count = await tocContainer.count();
if (count > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we had already discussed issues with such assertions and logic. please address all such instances without any fail before proceeding.

Using if (count > 0) makes the test pass even if the TOC is missing, which defeats the purpose of the test.

  • locator.count() + manual checks bypass Playwright’s built-in auto-waiting and assertions.
  • Reading class via getAttribute is brittle and unnecessary.
  • The Tailwind selector (.hidden.lg\:inline-block) is fragile and tightly coupled to styling.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have migrated all tests to removed all if (count > 0) guards, and replaced brittle .getAttribute('class') logic with Playwright's toHaveClass()

await expect(tocToggle.first()).toBeVisible();
});

test('desktop TOC sidebar should be hidden on mobile', async ({ page }) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similar issue here.

  • brittle selector '.hidden.lg\\:inline-block');
  • .not.toBeVisible() assertion passes even when no element is found.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replaced brittle .getAttribute('class') logic with Playwright's toHaveClass()

});

test.describe('API Mocking — Client-Side Search Resilience', () => {

Copy link
Contributor

@manasmanohar manasmanohar Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we testing using ssr mock data or client

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests use the mock data for both SSR and Client.

The configuration in

playwright.config.ts sets the GraphQL endpoint to our mock server localhost:4000 for both environments:

SSR: via the WORDPRESS_API_URL environment variable.

Client: via the NEXT_PUBLIC_WORDPRESS_API_URL environment variable.

This ensures consistency whether the content is rendered on the server or fetched dynamically in the browser.

test('each tag should have non-empty text', async ({ page }) => {
const tagLinks = page.locator('a[href*="/tag/"]');
const count = await tagLinks.count();
if (count > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is every test body is inside if (count > 0)?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed all if (count > 0) guards

});

test('each tag should have non-empty text', async ({ page }) => {
const tagLinks = page.locator('a[href*="/tag/"]');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please look into the playwright selector best practices, seeing multiple other files with css based selectors

The test should verify what the user sees, not how it's styled.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have replaced all brittle CSS and href selectors with data-testid="tag-link" in the Tag component and its spec, ensuring all 6 tests now strictly follow Playwright best practices and pass.

});

test('post cards should be single column on mobile', async ({ page }) => {
const postGrid = page.locator('.grid.grid-cols-1').first();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test should verify what the user sees, not how it's styled.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have replaced the .grid.grid-cols-1 selector in MobileLayout.spec.ts with data-testid="post-grid" and updated the assertion to verify the actual layout to ensure posts are stacked vertically, making the test fully agnostic of styling

Deep added 2 commits March 20, 2026 20:34
…o components and improving test selectors.

Signed-off-by: Deep <deep@example.com>
… for content and data-testid locators.

Signed-off-by: Deep <deep@example.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants