Skip to content

Setup GitHub Actions test suite with Docker, Busted, Playwright, and Luacheck#444

Open
cycomachead wants to merge 12 commits into
mainfrom
cycomachead/11-setup-github-actions-test-suite/1
Open

Setup GitHub Actions test suite with Docker, Busted, Playwright, and Luacheck#444
cycomachead wants to merge 12 commits into
mainfrom
cycomachead/11-setup-github-actions-test-suite/1

Conversation

@cycomachead
Copy link
Copy Markdown
Member

Add GitHub Actions CI suite with Luacheck, Busted, Playwright, and axe-core

Sets up a complete test infrastructure for Snap!Cloud with four independently-reported CI statuses, database safety guards, test factories, and scaffolding for future specs.

Changes

CI Workflow (.github/workflows/ci.yml)

  • Four separate jobs, each with its own CI status: Luacheck, Busted (Lua unit tests), Playwright (e2e), and Axe-core (a11y)
  • Each job spins up its own Postgres service container seeded from db/schema.sql + db/seeds.sql
  • Playwright and axe jobs are split so accessibility regressions are visible independently of e2e failures

Lua linting (luacheck)

  • .luacheckrc configured for Lua 5.1 + OpenResty (ngx) globals
  • Excludes third-party paths (node_modules/, lib/raven-lua/, etc.)
  • Baseline passes with 0 warnings/errors across 55 files; suppressed rules are documented with notes to tighten over time

Lua unit tests (busted)

  • .busted config pointing at spec/ with auto-discovery of *_spec.lua files
  • spec/spec_helper.lua hard-asserts LAPIS_ENVIRONMENT=test and DATABASE_NAME=snapcloud_test before any spec runs
  • spec/support/db_helper.lua re-checks the DB name on every query call (defense in depth) and provides truncate_all() and with_rollback() helpers
  • spec/support/factories.lua provides fixture-style factories.user/project/collection constructors (no raw SQL)
  • 13 passing specs in spec/unit/ (pure Lua, no DB); model spec in spec/models/ auto-pends if DB is unreachable

Browser tests (playwright + axe-core)

  • playwright.config.js with CI-aware webServer config (skips auto-boot in CI where the workflow manages the server)
  • spec/e2e/homepage.spec.js — smoke tests for page load, CTA visibility, and embed route
  • spec/e2e/accessibility.spec.js — WCAG 2.1 A/AA audits via @axe-core/playwright, tagged @axe for the dedicated job
  • Playwright HTML report uploaded as a CI artifact on every run

Test data scaffold

  • spec/data/projects/hello_world.xml — minimal Snap! project fixture
  • spec/data/users/seed_users.json — canonical user roles (admin, standard, student, banned)
  • spec/data/README.md — conventions for adding fixtures

Developer ergonomics

  • Makefile targets: make lint, make test-lua, make test-e2e, make test-a11y, make test
  • package.json scripts: test, test:e2e, test:a11y, test:ui
  • spec/README.md with setup instructions, directory layout, and guidance for writing new specs
  • .gitignore updated for Playwright report artifacts and luacov output

Superconductor Ticket Implementation | App Preview | Guided Review

cycomachead and others added 12 commits April 23, 2026 21:44
- Add GitHub Actions workflow with jobs for Luacheck, Busted, Playwright, and Axe-core.
- Configure Busted for Lua unit and model testing with a Postgres service container.
- Integrate Playwright for end-to-end and accessibility (axe-core) testing.
- Implement database safety guards to ensure tests only run against `snapcloud_test`.
- Scaffold test support including factories, DB helpers, and fixture data.
- Add Makefile targets and npm scripts for local test execution.

Co-authored-by: Claude Code <noreply@anthropic.com>
- Add e2e specs for project visibility, role-based access (admin/teacher), and auth flows.
- Implement unit tests for user permission predicates and visibility logic.
- Add axe-core accessibility audits for project pages with a `data-axe-excluded` convention.
- Fix GitHub Actions failures by installing global dev tools (luacheck/busted) outside of the project lockfile context to avoid C++17 compilation errors in legacy dependencies.
- Add `pg` to devDependencies for direct database seeding in tests.

Co-authored-by: Claude Code <noreply@anthropic.com>
- Extract shared CI logic into local composite actions for Lua setup, DB loading, and browser testing.
- Add `bin/install-lua-deps.sh` to fix `xml` rock compilation by forcing the C++14 standard.
- Separate E2E and Axe-core accessibility tests into independent CI jobs.
- Update `Makefile` and documentation to use the new dependency installation script.

Co-authored-by: Claude Code <noreply@anthropic.com>
The xml rock fails to build on modern toolchains because it uses dynamic
exception specifications disallowed in C++17. Standard environment
variables like CXX and CXXFLAGS are often ignored by luarocks or
stripped by sudo.

This change introduces a temporary g++ shim in the installation script
that forces the -std=gnu++14 flag. By prepending this shim to PATH and
invoking luarocks via `sudo env PATH=...`, we ensure all C++
compilations (builtin, make, or cmake) use the compatible language
standard.

Co-authored-by: Claude Code <noreply@anthropic.com>
luarocks's builtin build invokes `gcc` (not g++) to compile .cpp files,
relying on gcc's extension-based language detection. The previous shim
only intercepted g++, so xml's Parser.cpp still compiled under the
default C++17 dialect and hit the "ISO C++17 does not allow dynamic
exception specifications" error from dub.h.

The new shim wraps gcc/cc/g++/c++ via a single script that scans argv
for C++ source extensions or `-x c++` and only injects -std=gnu++14
when one is present. Pure C compiles pass through unchanged.

Also adds a self-test that compiles a real .cpp through the shim before
running luarocks, so a broken shim fails loudly instead of silently
letting the original error reproduce.
…github-actions-test-suite/1

# Conflicts:
#	.gitignore
Adding @axe-core/playwright, @playwright/test, and pg to package.json
in earlier commits never updated package-lock.json, so `npm ci` (which
is strict by design) fails the playwright + axe CI jobs with EUSAGE
"Missing: <pkg> from lock file" once it gets past the install step.

Run `npm install --package-lock-only --ignore-scripts` to refresh the
lockfile without touching node_modules. `npm ci --dry-run` now
completes cleanly.
The Lapis app's lib/exceptions.lua requires('raven') unconditionally,
and raven-lua is a git submodule at lib/raven-lua. actions/checkout@v4
doesn't pull submodules by default, so every request to the test server
returned HTTP 500:

  module 'raven' not found:
        no file './lib/raven-lua/raven.lua'
        ...

That cascaded into 30+ Playwright failures (homepage 500, sign-up form
not rendering, login 500) and 57 axe violations on what was effectively
the default error page rather than the real homepage.

snap-cloud/raven-lua is public, so submodules: recursive over HTTPS
with the default GITHUB_TOKEN works without further config. Apply to
all four checkouts so the pattern stays consistent and busted specs
that touch lib/exceptions.lua won't regress later.
- Skip rate_limit in the test environment. The "session_reused" guard
  rejects the very first request from a fresh session, so any e2e
  signup POST gets a 409 "Please use the Snap! site, not scripts."
  The skip list already covered development and staging.
- Pin the sign-up form spec to #js-signup; the page also includes a
  site-wide search form, so locator('form') hit a strict-mode error.
- Special-case /learners in teacher-access: site.lua:515-519 renders
  only for is_teacher and redirects non-teacher admins to /, so the
  generic admin-fallback assertion can't apply to that route.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
start.sh fetches the Tor exit list at boot and cron refreshes it, but
fresh clones and CI environments have nothing on disk. Without the file,
io.open returned nil and prevent_tor_access crashed with "attempt to
index local [string] (a nil value)" on every gated endpoint (signup,
password reset, etc).

Fail open when the list is absent rather than blocking all guarded
requests. Also close the file handle on the happy path.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
- deleteUser now clears tokens before users; signup writes a verify_user
  row to public.tokens with an FK on users.username (no ON DELETE), so
  afterAll cleanup blew up with users_fkey violations.
- 'rejects duplicate usernames' seeds and tears down its own collision
  target. The previous version relied on the prior test having created
  newUsername, which broke under Playwright retry: retries spin up a
  fresh worker, re-import the spec, and re-randomize newUsername, so
  the duplicate signup actually succeeded.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant