Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
51dc3f8
refactor: refactoring navbars
jderochervlk Feb 8, 2026
be70e99
making progress on the nav
jderochervlk Feb 8, 2026
0808cbc
scrolling works again
jderochervlk Feb 10, 2026
949389f
refactoring
jderochervlk Feb 10, 2026
bd7b348
mobile overlay works
jderochervlk Feb 15, 2026
482b405
tests are passing
jderochervlk Feb 15, 2026
80b836d
done with mobile overlay
jderochervlk Feb 16, 2026
3eb6f20
screenshots
jderochervlk Feb 16, 2026
53682b0
removing top padding
jderochervlk Feb 16, 2026
876486a
fix playground
jderochervlk Feb 16, 2026
57dae95
remove unused open
jderochervlk Feb 16, 2026
b7de7a6
fix issue with homepage reloading nonstop
jderochervlk Feb 16, 2026
86f806b
restor mdx route
jderochervlk Feb 16, 2026
09e42d4
remove dummy page
jderochervlk Feb 16, 2026
f642c1c
fixing docs
jderochervlk Feb 16, 2026
6e0bc9d
fix syntax lookup
jderochervlk Feb 16, 2026
c671d16
remove build errors and warnings
jderochervlk Feb 16, 2026
e0bf40d
commit screenshot changes
jderochervlk Feb 16, 2026
21a333c
chore: update vitest screenshots [skip ci]
jderochervlk Feb 16, 2026
f4ec369
remove unused values
jderochervlk Feb 16, 2026
f66a9f1
remove unused file
jderochervlk Feb 16, 2026
5e5c0e1
tidying up
jderochervlk Feb 16, 2026
76414e8
fix version dropdown
jderochervlk Feb 17, 2026
95b07eb
Update src/components/Search.res
jderochervlk Feb 18, 2026
a15986e
Update src/components/BreadCrumbs.res
jderochervlk Feb 18, 2026
588fc92
Fix mobile overlay not closing on navigation link clicks (#1198)
Copilot Feb 21, 2026
0f26f30
PR feedback.
jderochervlk Feb 21, 2026
17f7d42
PR feedback
jderochervlk Feb 21, 2026
2605d2a
cleanup
jderochervlk Feb 21, 2026
04ba370
Fix sidebar scrolling when it shouldn't
jderochervlk Feb 23, 2026
e578f9c
ci: add Playwright and run tests during CI
jderochervlk Feb 23, 2026
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 }}).
5 changes: 5 additions & 0 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,8 @@ jobs:
run: yarn playwright install --with-deps
- name: Vitest
run: yarn ci:test
- name: Commit and Push changes
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "chore: update vitest screenshots [skip ci]"
file_pattern: "**/__screenshots__/**/*.png"
13 changes: 12 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 @@ -68,4 +71,12 @@ __tests__/**/*.jsx
_scripts

# Local env files
.env.local
.env.local

# Vitest screenshots
!__tests__/__screenshots__/**/*
.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
28 changes: 0 additions & 28 deletions __tests__/Example.test.res

This file was deleted.

101 changes: 101 additions & 0 deletions __tests__/NavbarPrimary_.test.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
open ReactRouter
open Vitest

test("desktop has everything visible", async () => {
await viewport(1440, 500)

let screen = await render(
<BrowserRouter>
<NavbarPrimary />
</BrowserRouter>,
)

let leftContent = await screen->getByTestId("navbar-primary-left-content")

await element(await leftContent->getByText("Docs"))->toBeVisible
await element(await leftContent->getByText("Playground"))->toBeVisible
await element(await leftContent->getByText("Blog"))->toBeVisible
await element(await leftContent->getByText("Community"))->toBeVisible

let rightContent = await screen->getByTestId("navbar-primary-right-content")

await element(await rightContent->getByLabelText("GitHub"))->toBeVisible
await element(await rightContent->getByLabelText("X (formerly Twitter)"))->toBeVisible
await element(await rightContent->getByLabelText("Bluesky"))->toBeVisible
await element(await rightContent->getByLabelText("Forum"))->toBeVisible

let navbar = await screen->getByTestId("navbar-primary")

await element(navbar)->toMatchScreenshot("desktop-navbar-primary")
})

test("tablet has everything visible", async () => {
await viewport(900, 500)

let screen = await render(
<BrowserRouter>
<NavbarPrimary />
</BrowserRouter>,
)

let leftContent = await screen->getByTestId("navbar-primary-left-content")

await element(await leftContent->getByText("Docs"))->toBeVisible
await element(await leftContent->getByText("Playground"))->toBeVisible
await element(await leftContent->getByText("Blog"))->toBeVisible
await element(await leftContent->getByText("Community"))->toBeVisible

let rightContent = await screen->getByTestId("navbar-primary-right-content")

await element(await rightContent->getByLabelText("GitHub"))->toBeVisible
await element(await rightContent->getByLabelText("X (formerly Twitter)"))->toBeVisible
await element(await rightContent->getByLabelText("Bluesky"))->toBeVisible
await element(await rightContent->getByLabelText("Forum"))->toBeVisible

let navbar = await screen->getByTestId("navbar-primary")

await element(navbar)->toMatchScreenshot("tablet-navbar-primary")
})

test("phone has some things hidden and a mobile nav that can be toggled", async () => {
await viewport(600, 1200)

let screen = await render(
<BrowserRouter>
<NavbarPrimary />
</BrowserRouter>,
)

let leftContent = await screen->getByTestId("navbar-primary-left-content")

await element(await leftContent->getByText("Docs"))->toBeVisible
await element(await leftContent->getByText("Playground"))->notToBeVisible
await element(await leftContent->getByText("Blog"))->notToBeVisible
await element(await leftContent->getByText("Community"))->notToBeVisible

let rightContent = await screen->getByTestId("navbar-primary-right-content")

await element(await rightContent->getByLabelText("GitHub"))->notToBeVisible
await element(await rightContent->getByLabelText("X (formerly Twitter)"))->notToBeVisible
await element(await rightContent->getByLabelText("Bluesky"))->notToBeVisible
await element(await rightContent->getByLabelText("Forum"))->notToBeVisible

let mobileNav = await screen->getByTestId("mobile-nav")
await element(mobileNav)->notToBeVisible

let button = await screen->getByTestId("toggle-mobile-overlay")

await element(button)->toBeVisible

await button->click

let mobileNavAfterOpen = await screen->getByTestId("mobile-nav")

await element(mobileNavAfterOpen)->toBeVisible

let navbar = await screen->getByTestId("navbar-primary")

await element(navbar)->toMatchScreenshot("mobile-navbar-primary")

await element(mobileNavAfterOpen)->toMatchScreenshot("mobile-overlay-navbar-primary")
})
93 changes: 93 additions & 0 deletions __tests__/NavbarTertiary_.test.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
open ReactRouter
open Vitest

let sidebarContent =
<aside>
<div dataTestId="sidebar-version-select"> {React.string("v12 (latest)")} </div>
<div dataTestId="sidebar-categories">
<div> {React.string("OVERVIEW")} </div>
<div> {React.string("Introduction")} </div>
</div>
</aside>

let breadcrumbs =
<span dataTestId="breadcrumbs"> {React.string("Docs / Language Manual / Installation")} </span>

let editLink = <a dataTestId="edit-link" href="#"> {React.string("Edit")} </a>

test("desktop shows breadcrumbs and edit link", async () => {
await viewport(1440, 500)

let screen = await render(
<BrowserRouter>
<NavbarTertiary sidebar=sidebarContent>
breadcrumbs
editLink
</NavbarTertiary>
</BrowserRouter>,
)

let navbar = await screen->getByTestId("navbar-tertiary")

await element(navbar)->toBeVisible

let crumbs = await screen->getByTestId("breadcrumbs")
await element(crumbs)->toBeVisible

let edit = await screen->getByTestId("edit-link")
await element(edit)->toBeVisible

await element(navbar)->toMatchScreenshot("desktop-navbar-tertiary")
})

test("mobile shows breadcrumbs and drawer button", async () => {
await viewport(600, 1200)

let screen = await render(
<BrowserRouter>
<NavbarTertiary sidebar=sidebarContent>
breadcrumbs
editLink
</NavbarTertiary>
</BrowserRouter>,
)

let navbar = await screen->getByTestId("navbar-tertiary")
await element(navbar)->toBeVisible

let crumbs = await screen->getByTestId("breadcrumbs")
await element(crumbs)->toBeVisible

let edit = await screen->getByTestId("edit-link")
await element(edit)->toBeVisible

await element(navbar)->toMatchScreenshot("mobile-navbar-tertiary")
})

test("mobile drawer can be toggled open", async () => {
await viewport(600, 1200)

let screen = await render(
<BrowserRouter>
<NavbarTertiary sidebar=sidebarContent>
breadcrumbs
editLink
</NavbarTertiary>
</BrowserRouter>,
)

// Sidebar dialog should not be visible initially
let sidebar = await screen->getByTestId("sidebar-categories")
await element(sidebar)->notToBeVisible

// Click the drawer toggle button
let drawerButton = await screen->getByRole(#button)
await drawerButton->click

// Sidebar content should now be visible
let sidebarAfter = await screen->getByTestId("sidebar-categories")
await element(sidebarAfter)->toBeVisible

let versionSelect = await screen->getByTestId("sidebar-version-select")
await element(versionSelect)->toBeVisible
})
Loading
Loading