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
93 changes: 91 additions & 2 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ jobs:
contents: read
deployments: write
pull-requests: write
outputs:
deployment-url: ${{ steps.set-url.outputs.deployment-url }}
is-pr: ${{ github.event_name == 'pull_request' }}
steps:
- uses: actions/checkout@v4
- name: Setup yarn
Expand All @@ -38,11 +41,12 @@ jobs:

if [[ "$RAW_BRANCH" == "master" ]]; then
echo "VITE_DEPLOYMENT_URL=" >> "$GITHUB_ENV"
echo "SAFE_BRANCH=" >> "$GITHUB_ENV"
else
SAFE_BRANCH="${RAW_BRANCH//\//-}"

SAFE_BRANCH=$(echo "$SAFE_BRANCH" | tr '[:upper:]' '[:lower:]')

echo "SAFE_BRANCH=$SAFE_BRANCH" >> "$GITHUB_ENV"
echo "VITE_DEPLOYMENT_URL=https://${SAFE_BRANCH}.rescript-lang.pages.dev" >> "$GITHUB_ENV"
fi
Expand All @@ -61,6 +65,15 @@ jobs:
wranglerVersion: 4.63.0
env:
FORCE_COLOR: 0
- name: Set deployment URL output
id: set-url
shell: bash
run: |
if [[ "${{ github.ref_name }}" == "master" ]]; then
echo "deployment-url=https://rescript-lang.org" >> "$GITHUB_OUTPUT"
else
echo "deployment-url=${{ env.VITE_DEPLOYMENT_URL }}" >> "$GITHUB_OUTPUT"
fi
- name: Comment PR with deployment link
uses: marocchino/sticky-pull-request-comment@v2
with:
Expand All @@ -72,3 +85,79 @@ jobs:
Deployment Environment: ${{ steps.deploy.outputs.pages-environment }}

${{ steps.deploy.outputs.command-output }}

e2e:
name: E2E Tests
runs-on: ubuntu-latest
needs: [deploy]
# Only run E2E on pull requests from non-fork branches; push-to-master runs
# are excluded here since production smoke tests are a separate concern.
if: ${{ github.event_name == 'pull_request' && needs.deploy.outputs.deployment-url != '' }}
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4

- name: Setup node
uses: actions/setup-node@v4
with:
node-version-file: ".node-version"
cache: yarn

- name: Install dependencies
run: yarn install

# The e2e test files are written in ReScript and must be compiled to .jsx
# before Playwright can discover and run them.
- name: Build ReScript (includes e2e tests)
run: yarn build:res

- name: Install Playwright browsers (Chromium only)
run: yarn playwright install chromium --with-deps

- name: Run Playwright E2E tests
run: yarn e2e
env:
PLAYWRIGHT_BASE_URL: ${{ needs.deploy.outputs.deployment-url }}
CI: true

- name: Run Chromatic visual regression
# Always run Chromatic even when Playwright tests fail so that visual
# diffs are still captured and surfaced on the PR.
if: ${{ always() && needs.deploy.outputs.deployment-url != '' }}
run: yarn e2e:chromatic --exit-zero-on-changes
env:
CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
PLAYWRIGHT_BASE_URL: ${{ needs.deploy.outputs.deployment-url }}

- name: Upload Playwright report
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: playwright-report/
retention-days: 30

- name: Upload test results (traces / screenshots / videos)
if: ${{ failure() }}
uses: actions/upload-artifact@v4
with:
name: test-results
path: test-results/
retention-days: 7

- name: Comment PR with Playwright report link
if: ${{ failure() }}
uses: marocchino/sticky-pull-request-comment@v2
with:
recreate: true
header: e2e-report
message: |
## E2E Test Failures

One or more Playwright tests failed against the preview deployment.

**Preview URL:** ${{ needs.deploy.outputs.deployment-url }}

Download the full HTML report from the [workflow run artifacts](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}).
9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,11 @@ functions/**/*.mjs
functions/**/*.jsx
__tests__/**/*.mjs
__tests__/**/*.jsx
e2e/**/*.mjs
e2e/**/*.jsx
!_shims.mjs
!_shims.jsx
!src/bindings/playwright-shim.mjs

# Yarn
.yarn/*
Expand All @@ -72,4 +75,8 @@ _scripts

# Vitest screenshots
!__tests__/__screenshots__/**/*
.vitest-attachments
.vitest-attachments

# Playwright artifacts
playwright-report/
test-results/
4 changes: 4 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
e2e/**/*.mjs
e2e/**/*.jsx
playwright-report/
test-results/
!_shims.mjs
!public/_redirects
.DS_Store
Expand Down
69 changes: 69 additions & 0 deletions e2e/DocsPage.test.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
open Playwright

describe("Docs Page", () => {
test("has the correct page title", async ({page}) => {
let _ = await page->goto("/docs")
await page->expect->toHaveTitle("ReScript Documentation")
})

test("renders the docs overview heading", async ({page}) => {
let _ = await page->goto("/docs")
let heading = page->getByRole("heading", ~options={name: "Documentation"})
await heading->expect->toBeVisible
})

test("docs navigation sidebar is present on the introduction page", async ({page}) => {
let _ = await page->goto("/docs/manual/latest/introduction")
let sidebar = page->getByRole("navigation")
await sidebar->expect->toBeVisible
})

test("can navigate from the overview to the introduction", async ({page}) => {
let _ = await page->goto("/docs")
let introLink = page->getByRole("link", ~options={name: "Introduction"})
await introLink->first->click
await page->expect->toHaveURL("/docs/manual/latest/introduction")
})

test("introduction page renders main content with h1", async ({page}) => {
let _ = await page->goto("/docs/manual/latest/introduction")
let mainContent = page->locator("main")
await mainContent->expect->toBeVisible
let heading = page->getByRole("heading", ~options={name: "Introduction", level: 1})
await heading->expect->toBeVisible
})

test("syntax lookup page loads with heading", async ({page}) => {
let _ = await page->goto("/syntax-lookup")
let heading = page->getByRole("heading", ~options={name: "Syntax Lookup"})
await heading->expect->toBeVisible
})

test("packages page loads", async ({page}) => {
let _ = await page->goto("/packages")
let heading = page->getByRole("heading", ~options={name: "Packages"})
await heading->expect->toBeVisible
})

test("has no accessibility violations on the docs overview", async ({page}) => {
let _ = await page->goto("/docs")
await page->assertNoA11yViolations
})

test("has no accessibility violations on the introduction page", async ({page}) => {
let _ = await page->goto("/docs/manual/latest/introduction")
await page->assertNoA11yViolations
})

test("visual snapshot — docs overview", async ({page}) => {
let _ = await page->goto("/docs")
await page->waitForLoadState("networkidle")
await takeSnapshot(page, "Docs Overview")
})

test("visual snapshot — introduction page", async ({page}) => {
let _ = await page->goto("/docs/manual/latest/introduction")
await page->waitForLoadState("networkidle")
await takeSnapshot(page, "Docs Introduction")
})
})
63 changes: 63 additions & 0 deletions e2e/LandingPage.test.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
open Playwright

describe("Landing Page", () => {
test("has the correct page title", async ({page}) => {
let _ = await page->goto("/")
await page
->expect
->toHaveTitle(
"ReScript - A robustly typed language that compiles to efficient and human-readable JavaScript.",
)
})

test("renders the hero section heading", async ({page}) => {
let _ = await page->goto("/")
let hero =
page->getByRole(
"heading",
~options={name: "Fast, Simple, Fully Typed JavaScript from the Future"},
)
await hero->expect->toBeVisible
})

test("primary navigation links are present and visible", async ({page}) => {
let _ = await page->goto("/")

await page->getByRole("link", ~options={name: "Docs"})->expect->toBeVisible
await page->getByRole("link", ~options={name: "Playground"})->expect->toBeVisible
await page->getByRole("link", ~options={name: "Blog"})->expect->toBeVisible
await page->getByRole("link", ~options={name: "Community"})->expect->toBeVisible
})

test("Get Started link navigates to the introduction", async ({page}) => {
let _ = await page->goto("/")

let getStarted = page->getByRole("link", ~options={name: "Get Started"})
await getStarted->first->click

await page->expect->toHaveURL("/docs/manual/latest/introduction")
})

test("GitHub social link is present", async ({page}) => {
let _ = await page->goto("/")
let githubLink = page->getByRole("link", ~options={name: "GitHub"})
await githubLink->expect->toBeVisible
})

test("has no accessibility violations", async ({page}) => {
let _ = await page->goto("/")
await page->assertNoA11yViolations
})

test("visual snapshot — desktop", async ({page}) => {
let _ = await page->goto("/")
await page->waitForLoadState("networkidle")
await takeSnapshot(page, "Landing Page — Desktop")
})

test("visual snapshot — mobile", async ({page}) => {
let _ = await page->goto("/")
await page->waitForLoadState("networkidle")
await takeSnapshot(page, "Landing Page — Mobile")
})
})
Binary file added functions/yoga.wasm
Binary file not shown.
8 changes: 8 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
"build": "yarn build:res && yarn build:scripts && yarn build:update-index && yarn build:vite",
"ci:format": "prettier . --check --experimental-cli",
"ci:test": "yarn vitest --run --browser.headless --update",
"e2e": "playwright test",
"e2e:chromatic": "chromatic --playwright",
"e2e:report": "playwright show-report",
"clean:res": "rescript clean",
"convert-images": "auto-convert-images",
"dev:res": "rescript watch",
Expand Down Expand Up @@ -77,10 +80,15 @@
"remark-gfm": "^4.0.1",
"remark-validate-links": "^13.1.0",
"rescript": "^12.0.0",
"satori": "^0.19.2",
"shiki": "^3.22.0",
"unified": "^11.0.5",
"vfile-matter": "^5.0.0"
},
"devDependencies": {
"@axe-core/playwright": "^4.11.1",
"@chromatic-com/playwright": "^0.12.8",
"@playwright/test": "^1.58.2",
"@prettier/plugin-oxc": "^0.0.4",
"@react-router/dev": "^7.8.1",
"@tailwindcss/vite": "^4.1.13",
Expand Down
Loading
Loading