Skip to content

Commit b049705

Browse files
feat: Add tests and optimisation (#384)
1 parent 4c8433c commit b049705

87 files changed

Lines changed: 5443 additions & 432 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.dev.docker

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# Keycloak
44
AUTH_KEYCLOAK_ID=website
55
NEXT_PUBLIC_AUTH_REALM=cs-club
6-
AUTH_KEYCLOAK_SECRET=**********
6+
AUTH_KEYCLOAK_SECRET=secret
77
NEXT_PUBLIC_KEYCLOAK_REDIRECT_URI=http://localhost:3000/join
88
NEXT_PUBLIC_CONTAINER_KEYCLOAK_ENDPOINT=http://keycloak:8080
99
NEXT_PUBLIC_LOCAL_KEYCLOAK_URL=http://localhost:8080
@@ -35,4 +35,4 @@ SMTP_PASS=yourpassword
3535
SMTP_EMAIL_ADDRESS=from@example.com
3636

3737
# Payload CMS
38-
NEXT_PUBLIC_PAYLOAD_URI=https://cms.csclub.org.au
38+
NEXT_PUBLIC_PAYLOAD_URI=http://localhost:4000

.github/workflows/ci-dev-pr.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,23 @@ jobs:
1111
lint-format:
1212
name: Linting and Formatting Checks
1313
uses: ./.github/workflows/lint-and-format.yml
14+
unit-test:
15+
name: Unit Tests
16+
uses: ./.github/workflows/unit-tests.yml
17+
e2e-tests:
18+
name: E2E Tests
19+
uses: ./.github/workflows/e2e-tests.yml
1420

1521
build:
16-
needs: lint-format
22+
needs: [lint-format, unit-test, e2e-tests]
1723
name: Build
1824
runs-on: ubuntu-latest
1925
environment: Development
2026
steps:
2127
- name: Checkout repository
2228
uses: actions/checkout@900f2210b1d28bbbd0bd22d17926b9e224e8f231
2329
with:
24-
ref: ${{ github.event.pull_request.head.sha }}
30+
ref: ${{ github.event.pull_request.head.sha || github.sha }}
2531

2632
- name: Build Docker container
2733
env:
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: Daily Regression Tests
2+
on:
3+
schedule:
4+
- cron: '0 2 * * *'
5+
workflow_dispatch:
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
regression:
12+
name: Run Production Regression Tests
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
16+
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
17+
with:
18+
node-version: lts/*
19+
- name: Install dependencies
20+
run: npm install -g pnpm@11 && pnpm install
21+
22+
- name: Install Playwright Browsers
23+
run: pnpm exec playwright install --with-deps chromium
24+
25+
- name: Find working proxies
26+
run: node scripts/find-proxies.js
27+
28+
- name: Run Production Regression Tests
29+
run: |
30+
if [ -f working-proxies.txt ]; then
31+
success=false
32+
while read -r proxy; do
33+
if [ -z "$proxy" ]; then continue; fi
34+
echo "Attempting to run regression tests using proxy: $proxy"
35+
if PLAYWRIGHT_PROXY="http://$proxy" pnpm exec playwright test tests/e2e/production.spec.ts; then
36+
success=true
37+
break
38+
else
39+
echo "Tests failed using proxy $proxy. Retrying with next proxy..."
40+
fi
41+
done < working-proxies.txt
42+
if [ "$success" = false ]; then
43+
echo "All proxies failed."
44+
exit 1
45+
fi
46+
else
47+
echo "working-proxies.txt not found. Running without proxy..."
48+
pnpm exec playwright test tests/e2e/production.spec.ts
49+
fi
50+
51+
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
52+
if: ${{ !cancelled() }}
53+
with:
54+
name: playwright-report
55+
path: playwright-report/
56+
retention-days: 7

.github/workflows/e2e-tests.yml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: E2E Tests
2+
on:
3+
workflow_call:
4+
5+
permissions:
6+
contents: read
7+
8+
jobs:
9+
e2e-tests:
10+
timeout-minutes: 15
11+
runs-on: ubuntu-latest
12+
env:
13+
DATABASE_URL: "file:dev.sqlite"
14+
KEYCLOAK_ISSUER: "http://localhost:8080/realms/cs-club"
15+
KEYCLOAK_CLIENT_ID: "website"
16+
KEYCLOAK_CLIENT_SECRET: "secret"
17+
AUTH_SECRET: "secret"
18+
steps:
19+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
20+
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
21+
with:
22+
node-version: lts/*
23+
- name: Install dependencies
24+
run: npm install -g pnpm@11 && pnpm install
25+
26+
- name: Start Docker E2E Integration Services
27+
run: |
28+
docker compose -f docker-compose-dev.yml up -d keycloak redis
29+
30+
- name: Wait for Keycloak Service Health
31+
run: |
32+
echo "Waiting for Keycloak to boot and import realm..."
33+
for i in {1..30}; do
34+
if curl --fail -s http://localhost:8080/realms/cs-club >/dev/null; then
35+
echo "Keycloak is ready!"
36+
exit 0
37+
fi
38+
echo "Keycloak not ready yet, sleeping 5s..."
39+
sleep 5
40+
done
41+
echo "Keycloak failed to boot in time"
42+
docker compose -f docker-compose-dev.yml logs keycloak
43+
exit 1
44+
45+
- name: Push Database Schema
46+
run: pnpm run db:push
47+
48+
- name: Install Playwright Browsers
49+
run: pnpm exec playwright install --with-deps chromium
50+
51+
- name: Run Playwright tests
52+
env:
53+
REDIS_URI: redis://localhost:6379
54+
SKIP_ENV_VALIDATION: 'true'
55+
MOCK_SQUARE: 'true'
56+
NEXT_PUBLIC_PAYLOAD_URI: 'https://cms.csclub.org.au'
57+
run: pnpm test:e2e
58+
59+
- name: Stop Docker Services
60+
if: always()
61+
run: |
62+
docker compose -f docker-compose-dev.yml down
63+
64+
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
65+
if: ${{ !cancelled() }}
66+
with:
67+
name: playwright-report
68+
path: playwright-report/
69+
retention-days: 30

.github/workflows/unit-tests.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Unit Tests
2+
on:
3+
workflow_call:
4+
5+
permissions:
6+
contents: read
7+
8+
jobs:
9+
unit-tests:
10+
name: Unit Tests
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
15+
16+
- name: Set up Node.js
17+
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
18+
with:
19+
node-version: 26
20+
21+
- name: Install pnpm
22+
run: npm install -g pnpm@11
23+
24+
- name: Install dependencies
25+
run: pnpm install
26+
27+
- name: Run unit tests and verify high coverage
28+
run: pnpm run test:coverage:check

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,12 @@ next-env.d.ts
4444
# Keycloak
4545
/keycloak/*
4646
!/keycloak/docker-compose.yml
47+
48+
# Playwright
49+
node_modules/
50+
/test-results/
51+
/playwright-report/
52+
/blob-report/
53+
/playwright/.cache/
54+
/playwright/.auth/
55+
/working-proxies.txt

Dockerfile

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ FROM node:25-trixie-slim@sha256:aabbe39553d15ede8a97cc60c9e1a97034ff772afcf696ea
1010

1111
ENV PNPM_HOME="/root/.local/share/pnpm"
1212
ENV PATH="${PATH}:${PNPM_HOME}"
13+
ENV CI=true
1314
ENV SKIP_ENV_VALIDATION=true
1415
ENV SKIP_INSTALL_SIMPLE_GIT_HOOKS=1
1516

@@ -20,7 +21,7 @@ COPY pnpm-lock.yaml ./
2021
COPY pnpm-workspace.yaml ./
2122

2223
RUN npm install -g pnpm@11 \
23-
&& pnpm install --frozen-lockfile
24+
&& pnpm install --frozen-lockfile --config.confirmModulesPurge=false
2425

2526
COPY . .
2627

@@ -29,16 +30,16 @@ RUN pnpm run build
2930
# Final deployment image
3031
FROM node:25-trixie-slim@sha256:aabbe39553d15ede8a97cc60c9e1a97034ff772afcf696ea42b94e7f5f2ec71b AS runner
3132

32-
ENV PNPM_HOME="/root/.local/share/pnpm"
33-
ENV PATH="${PATH}:${PNPM_HOME}"
3433
ENV NODE_ENV=production
35-
36-
RUN npm install -g pnpm@11
34+
ENV HOSTNAME="0.0.0.0"
3735

3836
WORKDIR /app
3937

40-
COPY --from=builder /app /app
38+
# Copy standalone output and static assets
39+
COPY --from=builder /app/.next/standalone ./
40+
COPY --from=builder /app/.next/static ./.next/static
41+
COPY --from=builder /app/public ./public
4142

4243
EXPOSE $PORT
4344

44-
CMD [ "pnpm", "run", "start" ]
45+
CMD [ "node", "server.js" ]

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,32 @@ pnpm run dev
3434

3535
5. Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
3636

37+
## Development and Testing
38+
39+
### Seeding the CMS
40+
To seed the Payload CMS database with mock data for local development, run:
41+
```bash
42+
pnpm run db:seed-cms
43+
```
44+
45+
### Running Tests
46+
To run the full suite of unit tests and compute coverage:
47+
```bash
48+
pnpm test:coverage
49+
```
50+
51+
To run unit tests and verify required code coverage (as enforced in CI/CD checks):
52+
```bash
53+
pnpm test:coverage:check
54+
```
55+
56+
To run the Playwright end-to-end integration tests:
57+
```bash
58+
pnpm test:playwright
59+
```
60+
> [!NOTE]
61+
> Make sure no dev server is already running on port `3000` before starting Playwright tests, as the E2E test runner automatically provisions and controls its own Next.js instance.
62+
3763
## Contributing
3864

3965
We welcome contributions to enhance the CS Club Website! If you find any issues, have suggestions, or want to request a feature, please follow our [Contributing Guidelines](CONTRIBUTING.md).

dev.Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ FROM node:25-trixie-slim@sha256:aabbe39553d15ede8a97cc60c9e1a97034ff772afcf696ea
33
ENV PNPM_HOME="/root/.local/share/pnpm"
44
ENV PATH="${PNPM_HOME}:${PATH}"
55
ENV NODE_ENV=development
6+
ENV CI=true
67
ENV PORT=3000
78

89
WORKDIR /app
@@ -12,7 +13,7 @@ RUN apt-get update && apt-get install -y sqlite3
1213
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml drizzle.config.ts ./
1314
COPY src/db/schema.ts src/db/schema.ts
1415

15-
RUN npm install -g pnpm@11 && pnpm install --frozen-lockfile
16+
RUN npm install -g pnpm@11 && pnpm install --frozen-lockfile --config.confirmModulesPurge=false
1617

1718
EXPOSE $PORT
1819

next.config.mjs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ import './src/env.mjs';
22

33
/** @type {import('next').NextConfig} */
44
const nextConfig = {
5+
output: 'standalone',
6+
allowedDevOrigins: ['127.0.0.1', 'localhost', '127.0.0.1:3000', 'localhost:3000'],
57
images: {
8+
minimumCacheTTL: 86400,
69
remotePatterns: [
710
{
811
protocol: 'https',
@@ -27,6 +30,19 @@ const nextConfig = {
2730
// Ignore TypeScript errors during production build
2831
ignoreBuildErrors: process.env.PRODUCTION_BUILD === 'true',
2932
},
33+
async headers() {
34+
return [
35+
{
36+
source: '/:path*\\.(png|jpg|jpeg|gif|webp|svg|ico|mp4|webm|pdf|woff2|woff)',
37+
headers: [
38+
{
39+
key: 'Cache-Control',
40+
value: 'public, max-age=86400, immutable',
41+
},
42+
],
43+
},
44+
];
45+
},
3046
};
3147

3248
export default nextConfig;

0 commit comments

Comments
 (0)