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
31 changes: 31 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
## Link to ticket

This commit resolves {replace with ticket link placeholder}

## What was done?

- Explain the implementation goals being solved or the feature with the reviewer in mind
- Mention any relevant issues, insights, or alternatives considered to be shared with the reviewer.

## Accessibility

- [ ] I have made sure this works with a screenreader!
- [ ] I have checked this with the [WAVE extension](https://wave.webaim.org/extension/).

## Steps to test

- Describe how a reviewer should test the changes, including:
- Unit/integration/manual tests
- Test data used
- New migrations or libraries

## Screenshots (for visual changes)

- Before
- After

## Notes

Any additional information about changes to approach or new patterns? Any future development
considerations or refactorings?

18 changes: 18 additions & 0 deletions .github/workflows/npm-audit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: npm audit

on:
pull_request:
branches: ["main"]
push:
branches: ["main"]

permissions:
contents: read

jobs:
npm-audit:
uses: newjersey/innovation-shared-actions/.github/workflows/npm-audit.yml@main
with:
node-version: ".nvmrc"
audit-level: "critical"

27 changes: 0 additions & 27 deletions .github/workflows/playwright.yml

This file was deleted.

167 changes: 167 additions & 0 deletions .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
# Runs on every pull request:
# 1. biome – lint + format check (fails fast; annotates changed lines in the PR diff)
# 2. vitest – unit/integration tests with coverage (posts a summary comment on the PR)
# 3. playwright – e2e tests (uploads an HTML report as an artifact; posts a pass/fail comment)
#
# Required repository permissions (already granted to GITHUB_TOKEN by default for
# non-fork PRs; no extra secrets needed):
# • contents: read
# • pull-requests: write

name: PR Checks

on:
pull_request:
branches:
- main # adjust if your default branch is named differently
- master

# Cancel any in-progress run for the same PR branch so pushes don't queue up.
concurrency:
group: pr-checks-${{ github.head_ref }}
cancel-in-progress: true

jobs:
# ─────────────────────────────────────────────
# Job 1 · Biome – lint & format
# ─────────────────────────────────────────────
biome:
name: Biome (lint + format)
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v4

# biomejs/setup-biome installs the exact version declared in your
# package.json / biome.json. Pin to "latest" to always use the newest
# release, or pin to a semver string for reproducibility.
- name: Setup Biome
uses: biomejs/setup-biome@v2
with:
version: latest

# `biome ci` is the recommended command for CI:
# • exits non-zero on any lint/format error
# • emits GitHub annotations so errors appear inline in the PR diff
# • never auto-fixes (safe for CI)
- name: Run Biome CI
run: biome ci .

# ─────────────────────────────────────────────
# Job 2 · Vitest – unit & integration tests
# ─────────────────────────────────────────────
vitest:
name: Vitest (unit tests + coverage)
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write # needed to post the coverage comment
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: lts/*
cache: npm

- name: Install dependencies
run: npm ci

# Run Vitest with coverage enabled.
# Your vitest.config.ts should include at minimum:
#
# coverage: {
# provider: 'v8', // or 'istanbul'
# reporter: ['text', 'json-summary', 'json'],
# }
#
# The `json-summary` reporter is required by vitest-coverage-report-action.
# The `json` reporter enables per-file coverage detail in the PR comment.
- name: Run tests with coverage
run: npx vitest run --coverage

# Upload the coverage directory so the reporting step can consume it.
- name: Upload coverage artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: vitest-coverage
path: coverage/
retention-days: 7

# Post (or update) a coverage summary comment directly on the PR.
# Uses: https://github.com/davelosert/vitest-coverage-report-action
- name: Report coverage on PR
if: always()
uses: davelosert/vitest-coverage-report-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
json-summary-path: coverage/coverage-summary.json
json-final-path: coverage/coverage-final.json

# ─────────────────────────────────────────────
# Job 3 · Playwright – end-to-end tests
# ─────────────────────────────────────────────
playwright:
name: Playwright (e2e)
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write # needed to post the test-result comment
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: lts/*
cache: npm

- name: Install dependencies
run: npm ci

# Install Playwright's browser binaries + OS-level dependencies.
# Remove browsers you don't need to speed up the job.
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium firefox webkit

# Build the Next.js app before running e2e tests.
# Remove this step if your Playwright config handles the dev server itself
# via the `webServer` option (recommended for most setups).
- name: Build Next.js app
run: npm run build

# Run Playwright. The `json` reporter writes results.json which is
# consumed by the PR-comment action below.
# Your playwright.config.ts reporter array should include:
# reporter: [['html'], ['json', { outputFile: 'results.json' }]]
- name: Run Playwright tests
run: npx playwright test --reporter=html,json
env:
# Ensure Playwright writes the JSON report to the project root.
PLAYWRIGHT_JSON_OUTPUT_NAME: results.json

# Always upload the HTML report so you can inspect failures even when
# the job is marked red.
- name: Upload Playwright HTML report
if: always()
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: playwright-report/
retention-days: 14

# Post (or update) a pass/fail summary comment on the PR.
# Uses: https://github.com/daun/playwright-report-summary
- name: Post Playwright results to PR
if: always()
uses: daun/playwright-report-summary@v4
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
report-file: results.json

2 changes: 2 additions & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
24

11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,14 @@ Currently, we have issue templates for the following:

You can clone this repo to create your own `[project]-pm` repository, with these templates as a starting point. Feel free to modify for your project as needed.

If you are interested in adding an additional template for everyone's use, or have suggestions for improving the existing templates, reach out to Amani or feel free to submit a PR!
If you are interested in adding an additional template for everyone's use, or have suggestions for improving the existing templates, reach out to Amani or feel free to submit a PR!

## CI/CD

This project runs the following processes via Github Actions:

### Pull-Requests

- File formatting via [Biome](https://biomejs.dev/)
- Unit Tests via [Vitest](https://vitest.dev/)
- End-to-End Tests via [Playwright](https://playwright.dev/)
14 changes: 7 additions & 7 deletions __tests__/page.test.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { expect, test } from 'vitest'
import { render, screen } from '@testing-library/react'
import Page from '../app/page'
import { render, screen } from "@testing-library/react";
import { expect, test } from "vitest";
import Page from "../app/page";

test('Page', () => {
render(<Page />)
expect(screen.getByRole('heading', { level: 1, name: 'Home' })).toBeDefined()
})
test("Page", () => {
render(<Page />);
expect(screen.getByRole("heading", { level: 1, name: "Home" })).toBeDefined();
});
11 changes: 3 additions & 8 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import './globals.css';
import "./globals.css";

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
);
}

7 changes: 1 addition & 6 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
export default function Page() {
return (
<h1 className="text-3xl font-bold underline">
Home
</h1>
)
return <h1 className="text-3xl font-bold underline">Home</h1>;
}

80 changes: 80 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
{
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
"files": {
"includes": [
"app/**",
"e2e/**",
"__tests__/**",
"!**/.yarn/*",
"!package-lock.json",
"!pnpm-lock.yaml",
"!yarn.lock",
"!bun.lockb",
"!.claude"
]
},
"formatter": {
"enabled": true,
"lineWidth": 100,
"indentStyle": "space",
"indentWidth": 2,
"lineEnding": "lf"
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"complexity": {
"noForEach": "error",
"useArrowFunction": "error",
"useMaxParams": {
"level": "error",
"options": { "max": 4 }
}
},
"correctness": {
"noUnusedImports": "error",
"noUnusedVariables": "error"
},
"style": {
"noCommonJs": "error",
"noParameterAssign": "error",
"useConst": "error",
"useExportType": "error",
"useImportType": "error",
"useNodejsImportProtocol": "error",
"useTemplate": "error",
"useThrowOnlyError": "error"
},
"suspicious": {
"noConsole": "error",
"noExplicitAny": "error",
"noImportCycles": "error",
"noVar": "error"
},
"nursery": {
"noFloatingPromises": "error",
"noNestedPromises": "error",
"useErrorCause": "error"
}
}
},
"assist": {
"actions": {
"source": {
"organizeImports": "on"
}
}
},
"javascript": {
"formatter": {
"arrowParentheses": "always",
"bracketSameLine": false,
"bracketSpacing": true,
"jsxQuoteStyle": "double",
"quoteStyle": "double",
"semicolons": "always",
"trailingCommas": "all"
}
}
}
Loading
Loading