Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message
Agents
nette/tester
claude-code
cursor
testing
phpunit
Xdebug
nette
unit
code coverage
assertions
clover
phpdbg
pcov

It is my fervent wish that this file guide every AI coding agent working with code in this repository.

Install
php artisan boost:add-skill nette/tester

Save this content to: AGENTS.md

# To My Agents!

It is my fervent wish that this file guide every AI coding agent working with code in this repository.

## Documentation

Any distilled, agent-facing documentation for this package - how it works
internally and the rationale behind key design decisions - lives in `docs/`.
Consult it before non-trivial changes; it is the source of truth from which the
public manual is distilled.

This repo is the *implementation* of Tester (not a guide to using it). It has two
seams - the in-process framework (assertions, `TestCase`, `Environment`) and the
out-of-process runner (orchestration, isolation, annotation dispatch) - bridged by
process exit codes and env vars. Read `docs/internals.md` before editing either.

`docs/upgrading.md` records, per released version, every change visible to
users of the package (renames, removals, deprecations, signatures, behavior,
configuration), each with its commit hash; internal changes are not in it. It
is the place to look up the history of a public symbol. Do not write to it; it
is extended at release time from the git history.

## Project Overview

Nette Tester is a lightweight, zero-dependency PHP testing framework. Each test
runs in a **fully isolated PHP process**; tests run in parallel by default (8
threads), are annotation-driven, and the framework is **self-hosting** (it tests
itself).

- **PHP Version**: 8.1–8.6 (composer upper bound)
- **Package**: `nette/tester`

## Essential Commands

```bash
# Run the suite with the in-repo runner (not vendor/bin)
src/tester tests -s
src/tester tests/Framework/Assert.same.phpt -s

# A single test is a plain runnable script
php tests/Framework/Assert.same.phpt

# Static analysis
composer phpstan
```

Useful runner flags: `-j <n>` (parallel jobs; `-j 1` = serial for debugging),
`-o <format>` (console/console-lines/github/tap/junit/log/none), `-C`/`-c`/`-d` (php.ini),
`--watch`, `--stop-on-fail`, `--timeout <s>`, `--slowest`, `--cider` (hidden, not in `--help`: live per-thread
panel; needs `-j` >= 2, otherwise falls back to console-lines).

## Conventions

- Every file starts with `declare(strict_types=1);`; **tabs**; Nette Coding Standard.
- Tests are `.phpt` (auto-discovered) or `*Test.php`; **`.phptx` is deliberately
  NOT auto-discovered** (used in Tester's own suite for fixtures). There is **no
  autoloading** - `tester.php` loads classes manually to avoid autoloader conflicts.
- Code must run on all supported PHP versions; run changed tests on the lowest one
  too, as the platform branches (Windows < PHP 8.5, DOM < PHP 8.4) behave differently;
  on Windows < PHP 8.5 the test time limit (`--timeout`, `@timeout`) is not enforced.

## Working in this repo

- **`AssertException` is deliberately catchable, and this is the single most
  important invariant.** `Assert::notEqual` catches it to invert an `Expect`
  comparison, `TestCase::runTest` catches it to decorate the failure message,
  `TestCase::run` and the `test()` helper catch (and rethrow) so a `TestCase`
  continues after one method fails and `test()` can print its × marker. **Never
  turn `Assert::fail()` into a hard `exit`.**
- **`Assert::$counter` increments at the top of every assertion, before the check**
  (it counts attempts). It backs the "No assertions were executed in this test"
  guard, which `setup()` disables for `@outputMatch`/`@outputMatchFile` tests.
  `fail()` throws during the test body but delegates to `$onFailure` once
  `Environment` installs it in a shutdown handler.
- **`match()` uses PCRE only when the pattern is delimited with `~` or `#`**
  (`isPcre`); otherwise it's a wildcard mask (`%a%`, `%A%`, `%d%`, `%h%`, ...). Keep
  the two branches distinct - the delimiter is the only signal.
- **The runner reads annotations statically (regex over the source) before spawning
  the process,** then dispatches by reflection to `initiate*`/`assess*` methods.
  Consequences: file-level annotations **cannot** be replaced by PHP attributes, and
  adding a new annotation usually means adding a method (`@timeout` is the exception,
  read by `resolveTimeout`). Method-level `@dataProvider`/`@throws` are resolved in the
  child by `TestCase`, which is why `#[DataProvider]`/`#[Throws]` attributes work there.
  `@testCase` fans out in two phases: a listing job runs in parallel with other
  tests and its completion callback adds one job per method; the method list is
  cached in temp and invalidated by mtime of the class + parents + traits files, so
  it must not depend on the environment. The test count thus grows during the run.
- **No test process outlives `Runner::run()`**: after `--stop-on-fail` running jobs
  are finished, on an exception they are terminated; a job over its time limit is
  terminated and reported as failed.
- **`FileMutator` (`bypassFinals`) registers itself as the `file://` stream
  wrapper;** its `native()` must restore the original wrapper and re-register itself
  in a `finally`, or every internal fs call recurses. Preserve that dance.
- **`Environment::print()` bypasses the ANSI-stripping `ob_start` buffer** (writes
  straight to STDOUT), which is why status/fatal lines always appear.
- **The CLI help text IS the option grammar.** `CommandLine` parses option names,
  arguments, enums and defaults out of the usage string (`(default: 8)` is where
  `-j`'s default lives), so rewording `--help` can change parsing; hidden options
  (`--debug`, `--cider`, ...) exist only in the `$defaults` array.
- Jobs are ordered by the previous run's result (cache in temp): new tests first,
  then failed, passed, and skipped last. Jobs discovered during the run are appended
  unsorted.
- User-facing how-to (writing tests, the assertion/annotation catalog, HttpAssert,
  DomQuery, FileMock, coverage usage) is manual material and lives in the web docs.

To My Agents!

It is my fervent wish that this file guide every AI coding agent working with code in this repository.

Documentation

Any distilled, agent-facing documentation for this package - how it works internally and the rationale behind key design decisions - lives in docs/. Consult it before non-trivial changes; it is the source of truth from which the public manual is distilled.

This repo is the implementation of Tester (not a guide to using it). It has two seams - the in-process framework (assertions, TestCase, Environment) and the out-of-process runner (orchestration, isolation, annotation dispatch) - bridged by process exit codes and env vars. Read docs/internals.md before editing either.

docs/upgrading.md records, per released version, every change visible to users of the package (renames, removals, deprecations, signatures, behavior, configuration), each with its commit hash; internal changes are not in it. It is the place to look up the history of a public symbol. Do not write to it; it is extended at release time from the git history.

Project Overview

Nette Tester is a lightweight, zero-dependency PHP testing framework. Each test runs in a fully isolated PHP process; tests run in parallel by default (8 threads), are annotation-driven, and the framework is self-hosting (it tests itself).

  • PHP Version: 8.1–8.6 (composer upper bound)
  • Package: nette/tester

Essential Commands

# Run the suite with the in-repo runner (not vendor/bin)
src/tester tests -s
src/tester tests/Framework/Assert.same.phpt -s

# A single test is a plain runnable script
php tests/Framework/Assert.same.phpt

# Static analysis
composer phpstan

Useful runner flags: -j <n> (parallel jobs; -j 1 = serial for debugging), -o <format> (console/console-lines/github/tap/junit/log/none), -C/-c/-d (php.ini), --watch, --stop-on-fail, --timeout <s>, --slowest, --cider (hidden, not in --help: live per-thread panel; needs -j >= 2, otherwise falls back to console-lines).

Conventions

  • Every file starts with declare(strict_types=1);; tabs; Nette Coding Standard.
  • Tests are .phpt (auto-discovered) or *Test.php; .phptx is deliberately NOT auto-discovered (used in Tester's own suite for fixtures). There is no autoloading - tester.php loads classes manually to avoid autoloader conflicts.
  • Code must run on all supported PHP versions; run changed tests on the lowest one too, as the platform branches (Windows < PHP 8.5, DOM < PHP 8.4) behave differently; on Windows < PHP 8.5 the test time limit (--timeout, @timeout) is not enforced.

Working in this repo

  • AssertException is deliberately catchable, and this is the single most important invariant. Assert::notEqual catches it to invert an Expect comparison, TestCase::runTest catches it to decorate the failure message, TestCase::run and the test() helper catch (and rethrow) so a TestCase continues after one method fails and test() can print its × marker. Never turn Assert::fail() into a hard exit.
  • Assert::$counter increments at the top of every assertion, before the check (it counts attempts). It backs the "No assertions were executed in this test" guard, which setup() disables for @outputMatch/@outputMatchFile tests. fail() throws during the test body but delegates to $onFailure once Environment installs it in a shutdown handler.
  • match() uses PCRE only when the pattern is delimited with ~ or # (isPcre); otherwise it's a wildcard mask (%a%, %A%, %d%, %h%, ...). Keep the two branches distinct - the delimiter is the only signal.
  • The runner reads annotations statically (regex over the source) before spawning the process, then dispatches by reflection to initiate*/assess* methods. Consequences: file-level annotations cannot be replaced by PHP attributes, and adding a new annotation usually means adding a method (@timeout is the exception, read by resolveTimeout). Method-level @dataProvider/@throws are resolved in the child by TestCase, which is why #[DataProvider]/#[Throws] attributes work there. @testCase fans out in two phases: a listing job runs in parallel with other tests and its completion callback adds one job per method; the method list is cached in temp and invalidated by mtime of the class + parents + traits files, so it must not depend on the environment. The test count thus grows during the run.
  • No test process outlives Runner::run(): after --stop-on-fail running jobs are finished, on an exception they are terminated; a job over its time limit is terminated and reported as failed.
  • FileMutator (bypassFinals) registers itself as the file:// stream wrapper; its native() must restore the original wrapper and re-register itself in a finally, or every internal fs call recurses. Preserve that dance.
  • Environment::print() bypasses the ANSI-stripping ob_start buffer (writes straight to STDOUT), which is why status/fatal lines always appear.
  • The CLI help text IS the option grammar. CommandLine parses option names, arguments, enums and defaults out of the usage string ((default: 8) is where -j's default lives), so rewording --help can change parsing; hidden options (--debug, --cider, ...) exist only in the $defaults array.
  • Jobs are ordered by the previous run's result (cache in temp): new tests first, then failed, passed, and skipped last. Jobs discovered during the run are appended unsorted.
  • User-facing how-to (writing tests, the assertion/annotation catalog, HttpAssert, DomQuery, FileMock, coverage usage) is manual material and lives in the web docs.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin