Skip to content

Getting Started

Arttu Jantunen edited this page Nov 2, 2026 · 1 revision

In your app's folder:

parityrun             # all of the below that isn't done yet, then where you are and the command to run next
parityrun init        # finds how to start the app and every route in its code, writes parityrun/
parityrun capture     # opens the app in your browser: use it, every route you visit is ticked off
parityrun record      # records what the app does now into parityrun/golden/
parityrun coverage    # the routes and (PHP) the lines of code no scenario ran yet

Your app's own files are never changed: every run uses a fresh copy of its folder.

parityrun

With no command, parityrun sets itself up (init) when the app's folder has no parityrun/ yet, records every scenario that has no recording, and then shows where the project stands:

  • the scenarios recorded,
  • the routes visited (for a library: the functions, methods and classes called),
  • the share of the PHP code run,
  • each port's parity at its last check.

It ends with the one command to run next: capture while routes are unvisited, port when there is no port yet, port again or check for a port that is behind, and, once every port is at 100 %, what they are proven on.

init

init tells the stack (PHP, Laravel, Symfony, WordPress, Node.js, Django, Flask, FastAPI, Rust, or a PHP library), starts the app once in a throwaway copy, reads its home page and its code, and writes parityrun/:

File What it is
impls.json how to start the app
parityrun_project.py the settings, with notes on anything init couldn't decide (such as a MySQL database)
golden/endpoints.json the routes found in the code
scenarios/smoke.yaml a first scenario: the home page and the pages it links to, hidden form tokens captured, nothing that signs out or deletes

Every run uses a fresh copy of the app's folder (isolate), so the app's own files are never changed and whatever it writes there is recorded. From the app's folder, the other commands find parityrun/ by themselves. Keep it with the code: git add parityrun.

capture

capture starts the app behind a proxy at http://127.0.0.1:8000. Use the site as people do: open the pages, send the forms. Each page shows how many of the app's routes have been visited, and http://127.0.0.1:8000/__parityrun lists them all with the ones still to go.

Press Finish there (or Ctrl+C in the terminal): what you did becomes scenarios/visit.yaml, one step per page or form.

  • Form tokens and new ids are captured from the answer that gave them (by the form field, attribute, JSON key or text around them), so the scenario replays on a fresh app.
  • Uploaded files are saved under fixtures/captured/.
  • Stylesheets, scripts and pictures the browser fetched are left out.

The scenario is then recorded twice to prove it replays. Run capture again until every route is visited.

routes

routes reads the routes from the code into golden/endpoints.json and shows which ones the scenarios visit. Laravel and Symfony are asked for their own list (artisan route:list, debug:router, in a throwaway copy); else the code is read: Laravel route files (prefix groups, resources), Symfony attributes, Slim, plain PHP pages, hand-made PHP, JavaScript, TypeScript and Rust routers ($path === '/x', preg_match('#^/x/(\d+)$#', ...)), Express-style routers, Flask, FastAPI, Django, axum and actix. Every route is written METHOD /path/{param}.

Code coverage

For PHP (coverage=True, which init sets), record measures which lines of the app's code each scenario ran, with the PCOV extension (or Xdebug), keeps it as golden/<name>/coverage.json and prints the total. parityrun coverage lists every file with the lines no scenario ran. Files no request loaded count too, with an estimate of their lines.

PCOV is found in PHP's ext/ folder even when php.ini doesn't load it. On Windows, copy php_pcov.dll from the PECL builds there. Without it, recording works as before and says so once.

What parity means

Identical on the recorded scenarios, which visit that many routes and run that share of the code. A path no scenario takes is not proven.

Next: check a new version against the recordings (parityrun check --impl NAME, see Project Settings for adding it to impls.json), or let your AI tool make one: Porting with an AI Tool.

Clone this wiki locally