Skip to content
Draft
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
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ DIRECT_URL="postgresql://postgres:password@localhost:5432/solar-car-website-next
FLAGS_SECRET=exampleFlagSecret
FLAGS=exampleFlag

# Playwright
E2E_ADMIN_EMAIL="admin@example.com"

# If you run Postgres locally via `docker-compose up -d`, the example DATABASE_URL
# and DIRECT_URL above will work as-is. To create a local runtime env file from
# this example run:
Expand Down
89 changes: 89 additions & 0 deletions .github/skills/playwright-ui-test/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
---
name: playwright-ui-test
description: 'Create Playwright UI tests for a page or feature on a page. Use when writing a new spec, choosing a test file name, structuring constants and fixtures, or standardizing test titles and descriptions for frontend coverage.'
user-invocable: true
---

# Playwright UI Test Skill

Use this skill when creating a Playwright UI test for a page or a feature on a page.

## What This Skill Produces
- A single Playwright spec file for one page or feature
- A clear, maintainable test name and file name
- Consistent setup with constants at the top of the file
- Shared fixtures or page objects when they improve reuse
- Clear `describe` and `test` titles

## Default Naming Rules
- Prefer a feature-based file name that is concise and descriptive.
- If the route is the clearest way to identify the UI surface, use a route-derived slug.
- Keep the spec name aligned with the behavior under test.
- Use the repository's existing `*.spec.ts` convention.

## Test Structure Rules
1. Start with the page or feature goal.
2. Identify the minimal path a user takes through the UI.
3. Define selectors, URLs, and test data as constants near the top of the file.
4. Keep assertions behavior-focused and visible to a reader.
5. Use `describe` blocks for the page or feature scope.
6. Use short, specific `test` titles that describe the outcome.
7. Prefer locators and expectations over hard-coded waits.
8. Use fixtures or page objects only when they reduce repetition or improve clarity.

## Authentication Rules for Protected Routes
1. Authentication must not be applied globally.
2. Public routes should run with the normal `page` fixture and no `storageState`.
3. Protected routes must explicitly import an authentication fixture such as `auth.fixture.ts`.
4. Authentication fixtures should load a pre-generated `storageState` file such as `admin.json` or `student.json`.
5. A one-time setup script such as `auth.setup.ts` should generate storage state files, but it should not run before every test.
6. Public and protected tests should be separated under `tests/e2e/specs/public/` and `tests/e2e/specs/protected/`.
7. Tests should make authentication requirements obvious by choosing the correct fixture import.
8. Authentication logic should live in fixtures and setup scripts, not inside spec files.

## Page Object Separation Rules
- Page Objects must live in `tests/e2e/pages/` and never inside application code such as `src/app/...`.
- Spec files must live in `tests/e2e/specs/` and should import Page Objects rather than embedding UI interaction logic directly.
- Page Objects should encapsulate navigation (`goto()`), UI interactions (`fillForm()`, `openCreateDialog()`), element lookups (`getRowByHeader()`), and reusable workflows (`save()`, `deleteRow()`).
- Spec files should contain test descriptions, assertions, and high-level flow using Page Object methods.
- Shared data builders, such as form data factories, must live in `tests/e2e/helpers/`.
- Tests should read like user stories; Page Objects should hide implementation details.

## Clarify Before Generating
Ask a follow-up question when any of these are unclear:
- Which page or feature should be covered
- Whether the file name should be feature-based or route-based for this case
- Which shared setup belongs in fixtures versus inline test code
- What the test should prove versus what should just be smoke coverage

## Recommended Workflow
1. Confirm the page, feature, or route under test.
2. Choose the spec file name.
3. Decide whether the test is a smoke check or a deeper flow.
4. Write constants, fixtures, and helpers before the test body.
5. Add a `describe` block with a clear page or feature label.
6. Add one or more focused `test` cases with explicit expectations.
7. Review the file for naming consistency, selector clarity, and unnecessary repetition.

## Quality Checklist
- The file name clearly matches the page or feature.
- The test title tells the reader what behavior is being verified.
- Constants are grouped at the top when they are reused.
- Fixtures or page objects are present only when they add value.
- Assertions describe visible outcomes, not implementation details.
- Page Objects live under `tests/e2e/pages/`, not in application code.
- Spec files live under `tests/e2e/specs/` and keep UI interaction details inside Page Objects.
- Shared data builders live under `tests/e2e/helpers/`.
- The spec reads like a user story and uses Page Object methods for the high-level flow.
- The spec follows the repo's Playwright conventions.
- Public tests do not import auth fixtures, while protected tests explicitly do.
- Protected tests load pre-generated storage state through imported fixtures only.
- One-time auth setup scripts create storage state files without being wired into every test run.

## Example Patterns
- `home-page.spec.ts` for a general page-level smoke test
- `portal-login.spec.ts` for a feature-specific flow
- `portal-admin.spec.ts` when the route and feature are tightly coupled

## If You Need More Detail
If the page structure, route naming, or fixture boundary is ambiguous, stop and ask before generating the spec.
85 changes: 85 additions & 0 deletions .github/workflows/portal-e2e-poc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: Portal E2E POC

on:
workflow_dispatch:

permissions:
contents: read

jobs:
portal-e2e-poc:
name: Portal E2E proof of concept
runs-on: ubuntu-latest
timeout-minutes: 15

services:
postgres:
image: postgres:15
env:
POSTGRES_DB: portal_e2e
POSTGRES_PASSWORD: password
POSTGRES_USER: postgres
options: >-
--health-cmd "pg_isready -U postgres -d portal_e2e"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432

env:
CI: "true"
CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }}
DATABASE_URL: postgresql://postgres:password@127.0.0.1:5432/portal_e2e
DIRECT_URL: postgresql://postgres:password@127.0.0.1:5432/portal_e2e
E2E_ADMIN_EMAIL: ${{ secrets.E2E_ADMIN_EMAIL }}
FLAGS: e2e-flags
FLAGS_SECRET: e2e-flags-secret
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY }}
NEXT_PUBLIC_SUPABASE_ANON_KEY: e2e-supabase-anon-key
NEXT_PUBLIC_SUPABASE_URL: https://e2e.invalid
PROFILE_PICTURE_BUCKET: e2e-profile-pictures
SPONSORSHIP_PICTURE_BUCKET: e2e-sponsor-pictures
WEBHOOK_SECRET: e2e-webhook-secret

steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 20

- name: Enable Corepack
run: |
corepack enable
yarn --version

- name: Verify E2E secrets
run: |
test -n "$NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY"
test -n "$CLERK_SECRET_KEY"
test -n "$E2E_ADMIN_EMAIL"

- name: Install dependencies
run: yarn install --immutable

- name: Prepare database
run: |
yarn db:generate
yarn db:migrate:prod

- name: Install Playwright browser
run: yarn playwright install --with-deps chromium

- name: Run portal E2E POC
run: yarn test:e2e:ci

- name: Upload Playwright report
if: failure()
uses: actions/upload-artifact@v4
with:
name: portal-e2e-poc-report
path: |
playwright-report/
test-results/
retention-days: 7
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@

# testing
/coverage
/playwright-report/
/test-results/
/playwright/.auth/
.yarn/install-state.gz
tests/e2e/storage/*.json

# database
/prisma/db.sqlite
Expand Down
2 changes: 1 addition & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"recommendations": ["biomejs.biome"],
"recommendations": ["biomejs.biome", "ms-playwright.playwright"],
"unwantedRecommendations": [
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
Expand Down
2 changes: 2 additions & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
enableScripts: true
nodeLinker: node-modules
29 changes: 26 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Welcome to the public-facing website for [calgarysolarcar.ca](https://calgarysolarcar.ca)! This project is built on the **T3 Stack** and is designed to deliver a seamless web experience for our team members.

> **Note:** This project uses **Yarn v4**. To enable Yarn v4 with Corepack, simply run:
> **Note:** This project uses **Yarn 4.18.0**. Enable Corepack before installing dependencies.
>
> ```bash
> corepack enable yarn
Expand Down Expand Up @@ -52,7 +52,7 @@ Follow these steps to set up the app, database, and Clerk auth locally.
cd Solar-Car-Website-Next
```

2. **Enable Yarn v4:**
2. **Enable Yarn 4.18.0:**

```bash
corepack enable yarn
Expand Down Expand Up @@ -111,6 +111,26 @@ Follow these steps to set up the app, database, and Clerk auth locally.

If `yarn dev` fails with a Clerk middleware error, check the auth middleware entrypoint in `src/proxy.ts` and make sure you are using the current Clerk packages.

## Portal E2E POC

The Playwright proof of concept validates the authenticated Recruitment portal against a fresh PostgreSQL database. It is manual-only in GitHub Actions until the POC has passed its decision gate.

Configure these GitHub Actions secrets before dispatching the `Portal E2E POC` workflow:

- `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY`
- `CLERK_SECRET_KEY`
- `E2E_ADMIN_EMAIL`

The keys and account must belong to a dedicated Clerk development application. The account must have a portal administrator role in `publicMetadata.role`.

For a local run, start the local PostgreSQL container, provide the same Clerk and database variables in `.env`, then run the tests from the VS Code Testing panel.

1. Install the Microsoft Playwright Test extension in VS Code.
2. Open the Testing panel and discover the E2E suite.
3. Run the tests from there; the extension uses the same Playwright configuration as the project and will pick up your local `.env` values.

The test creates and deletes a Recruitment record. It must only be run against a disposable or dedicated test database.

## 🌐 Using Webhooks Locally

To ensure that Clerk syncs with our Supabase database, follow these steps for the first time while signing up on /portal locally.
Expand Down Expand Up @@ -145,6 +165,7 @@ To ensure that Clerk syncs with our Supabase database, follow these steps for th
- Navigate to: **Configure** > **Webhooks**.
- Edit the Webhook URL: Append `/api/webhooks` to your public URL.
**Example:**

```
https://rngwz-XXX-XXX-XXX-XXX.a.free.pinggy.link/api/webhooks
```
Expand All @@ -167,7 +188,7 @@ To ensure that Clerk syncs with our Supabase database, follow these steps for th
- **tRPC:** Provides end-to-end type safety between the client and the server.
- **ESLint & Prettier:** Ensures high-quality, consistent code throughout the project.

- **Framer Motion:** Used to animate images and carousels. Find the documentation here --> https://motion.dev/
- **Framer Motion:** Used to animate images and carousels. Find the documentation here --> <https://motion.dev/>

## 🛠️ Code Quality

Expand All @@ -188,11 +209,13 @@ docker-compose up -d
- Create a local `.env` from the example (then edit secrets if needed):

PowerShell:

```powershell
copy .env.example .env
```

bash / WSL / git-bash:

```bash
cp .env.example .env
```
Expand Down
Loading