Skip to content
Merged
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
28 changes: 28 additions & 0 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Playwright Tests
on:
pull_request:
branches: [main]
jobs:
test:
timeout-minutes: 10
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: yarn
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium
- name: Run Playwright tests
run: yarn test:e2e
env:
BASE_URL: https://hrdevfest.org
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: playwright-report/
retention-days: 14
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@ pnpm-debug.log*

# macOS-specific files
.DS_Store

# Playwright
test-results/
playwright-report/
5 changes: 3 additions & 2 deletions astro.config.mjs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { defineConfig } from "astro/config";
import tailwind from "@astrojs/tailwind";
import sitemap from "@astrojs/sitemap";
import tailwindcss from "@tailwindcss/vite";

// https://astro.build/config
export default defineConfig({
site: "https://hrdevfest.org",
integrations: [tailwind(), sitemap()],
integrations: [sitemap()],
vite: {
plugins: [tailwindcss()],
server: {
allowedHosts: ['host.docker.internal'],
},
Expand Down
38 changes: 38 additions & 0 deletions e2e/homepage.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { test, expect } from "@playwright/test";

test.describe("Homepage", () => {
test.beforeEach(async ({ page }) => {
await page.goto("/");
});

test("has correct title", async ({ page }) => {
await expect(page).toHaveTitle(/Hampton Roads DevFest/);
});

test("hero section is visible with event details", async ({ page }) => {
const hero = page.locator(".hero-section");
await expect(hero).toBeVisible();
await expect(hero.getByText("Hampton Roads DevFest 2026")).toBeVisible();
await expect(hero.getByText(/Feb 27th, 2026/)).toBeVisible();
});

test("hero has Buy Tickets button", async ({ page }) => {
// Exclude mobile menu links which are hidden
await expect(
page.locator(".hero-section a.btn-primary:not(.mobile-menu-link)").first()
).toBeVisible();
});

test("sponsors section is visible", async ({ page }) => {
await expect(
page.getByRole("heading", { name: "Our Sponsors" })
).toBeVisible();
});

test("footer is visible with social links", async ({ page }) => {
const footer = page.locator("footer");
await expect(footer).toBeVisible();
await expect(footer.getByText(/RevolutionVA/)).toBeVisible();
await expect(footer.locator("a[href*='x.com/hrdevfest']")).toBeVisible();
});
});
38 changes: 38 additions & 0 deletions e2e/navigation.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { test, expect } from "@playwright/test";

test.describe("Site Navigation", () => {
test("speakers page loads with speaker cards", async ({ page }) => {
await page.goto("/speakers");
await expect(page).toHaveTitle(/Speakers.*Hampton Roads DevFest/);
await expect(
page.getByRole("heading", { name: "Featured Speakers" })
).toBeVisible();
const speakerCards = page.locator(".card-asymmetric");
expect(await speakerCards.count()).toBeGreaterThan(0);
});

test("schedule page loads with schedule items", async ({ page }) => {
await page.goto("/schedule");
await expect(page).toHaveTitle(/Schedule.*Hampton Roads DevFest/);
await expect(
page.getByRole("heading", { name: "Schedule" })
).toBeVisible();
await expect(page.getByText("8:00 AM")).toBeVisible();
});

test("FAQ page loads with FAQ categories", async ({ page }) => {
await page.goto("/faq");
await expect(page).toHaveTitle(/FAQ.*Hampton Roads DevFest/);
await expect(
page.getByRole("heading", { name: "General" })
).toBeVisible();
await expect(
page.getByRole("heading", { name: "Tickets" })
).toBeVisible();
});

test("2024 archive page loads", async ({ page }) => {
await page.goto("/years/2024");
await expect(page).toHaveTitle(/Hampton Roads DevFest.*2024/);
});
});
54 changes: 54 additions & 0 deletions e2e/responsive.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { test, expect } from "@playwright/test";

test.describe("Responsive Layout", () => {
test.describe("mobile viewport", () => {
test.use({ viewport: { width: 375, height: 667 } });

test("mobile menu button is visible", async ({ page }) => {
await page.goto("/");
const menuBtn = page.locator("#mobile-menu-btn");
await expect(menuBtn).toBeVisible();
});

test("desktop nav links are hidden on mobile", async ({ page }) => {
await page.goto("/");
// The desktop nav container should be hidden
const desktopNav = page.locator("nav .hidden.md\\:flex");
await expect(desktopNav).toBeHidden();
});

test("mobile menu opens and closes", async ({ page }) => {
await page.goto("/");
const menuBtn = page.locator("#mobile-menu-btn");
const mobileMenu = page.locator("#mobile-menu");

// Menu should start hidden
await expect(mobileMenu).toBeHidden();

// Open menu
await menuBtn.click();
await expect(mobileMenu).toBeVisible();

// Close menu
await menuBtn.click();
await expect(mobileMenu).toBeHidden();
});
});

test.describe("desktop viewport", () => {
test.use({ viewport: { width: 1280, height: 720 } });

test("desktop nav links are visible", async ({ page }) => {
await page.goto("/");
const nav = page.locator("nav");
await expect(nav.getByRole("link", { name: "Speakers" })).toBeVisible();
await expect(nav.getByRole("link", { name: "Schedule" })).toBeVisible();
});

test("mobile menu button is hidden on desktop", async ({ page }) => {
await page.goto("/");
const menuBtn = page.locator("#mobile-menu-btn");
await expect(menuBtn).toBeHidden();
});
});
});
11 changes: 8 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,20 @@
"start": "astro dev",
"build": "astro check && astro build",
"preview": "astro preview",
"astro": "astro"
"astro": "astro",
"test:e2e": "playwright test",
"test:e2e:headed": "playwright test --headed"
},
"dependencies": {
"@astrojs/check": "0.9.6",
"@astrojs/sitemap": "^3.6.0",
"@astrojs/tailwind": "6.0.2",
"@tailwindcss/vite": "^4.0.0",
"astro": "5.17.2",
"tailwindcss": "^3.4.1",
"tailwindcss": "^4.0.0",
"typescript": "^5.3.3"
},
"devDependencies": {
"@playwright/test": "^1.50.0"
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
24 changes: 24 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { defineConfig, devices } from "@playwright/test";

export default defineConfig({
testDir: "./e2e",
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: "html",
use: {
baseURL: process.env.BASE_URL || "https://hrdevfest.org",
trace: "on-first-retry",
},
projects: [
{
name: "desktop-chromium",
use: { ...devices["Desktop Chrome"] },
},
{
name: "mobile-chromium",
use: { ...devices["Pixel 5"] },
},
],
});
1 change: 1 addition & 0 deletions src/pages/faq.astro
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
import "../styles/global.css";
import headerDots from "../assets/dots/header_dots.svg";

interface FAQItem {
Expand Down
1 change: 1 addition & 0 deletions src/pages/index.astro
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
import "../styles/global.css";
import { Image } from "astro:assets";
import logo from "../assets/logo.png";
import logoWhite from "../assets/logo-white.png";
Expand Down
1 change: 1 addition & 0 deletions src/pages/schedule.astro
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
import "../styles/global.css";
import headerDots from "../assets/dots/header_dots.svg";

interface ScheduleItem {
Expand Down
1 change: 1 addition & 0 deletions src/pages/speakers.astro
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
import "../styles/global.css";
import { Image } from "astro:assets";
import logoWhite from "../assets/logo-white.png";
import headerDots from "../assets/dots/header_dots.svg";
Expand Down
1 change: 1 addition & 0 deletions src/pages/years/2024/index.astro
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
import "../../../styles/global.css";
import { Image } from "astro:assets";
import logoWhite from "../../../assets/logo-white.png";
import header2024 from "../../../assets/header_2024.png";
Expand Down
1 change: 1 addition & 0 deletions src/pages/years/2024/schedule.astro
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
import "../../../styles/global.css";
import { Image } from "astro:assets";
import logo from "../../../assets/logo.png";
import headerImage from "../../../assets/header-image.png";
Expand Down
1 change: 1 addition & 0 deletions src/styles/global.css
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import "tailwindcss";
8 changes: 0 additions & 8 deletions tailwind.config.mjs

This file was deleted.

Loading