Automated Testing
Available from v11.1
Automated testing helps us verify that the application behaves as expected and gives us confidence when making changes.
We use PestPHP as our testing framework. Tests should be considered part of the development process, not an afterthought: new features, bug fixes and changes to existing behaviour should be covered by appropriate automated tests where practical.
This guide explains how we approach automated testing in ResourceSpace, including how tests are structured, how to run them and the conventions or patterns we expect developers to follow.
Environment setup
Your development/test run environment will require PHP 8.4+ for all dependency criteria to be met. Composer might complain about additional requirements (e.g. sockets, pcntl).
Ensure your development dependencies are installed:
composer install
pnpm install --frozen-lockfile
pnpm exec playwright install --with-deps chromium
Then you can run all tests (unit, integration and E2E; in that order) with:
composer test:full
Integration and Browser (E2E) tests share a database, filestore and configuration. Parallel browser execution is rejected by its runner. Avoid overlapping browser and integration runs against the same test environment.
Writing tests
to be confirmed...
Browser (E2E) testing
Browser (E2E) tests use Pest’s browser plugin and Playwright to exercise ResourceSpace in a real browser. Tests live in tests/Browser/ and you can run only the browser tests from the repository root with:
composer test:browser
Server logs and troubleshooting
The temporary PHP server’s output is written to tests/.runtime/php-server.log.
This includes request logs and PHP errors reported by the server. The file remains available after the run, including after successful cleanup, but is overwritten when the next temporary server starts.
Pest also saves screenshots for browser assertion failures in tests/Browser/Screenshots/, where applicable.
Browser test runner flags
The browser test runner supports two optional command line flags for skipping the normal test environment setup and teardown steps. The flags are passed to the browser test runner after Composer's argument separator (--).
- Use --nosetup to skip `composer test:env:provision` - useful when the test environment has already been provisioned and you want to rerun browser tests without recreating it;
composer test:browser -- --nosetup
- Use --noteardown to skip `composer test:env:cleanup` - leaves the test environment in place after the test run. Default behaviour for failed tests, however can be useful during development when combined with --nosetup for a fast write code-test loop. For obvious reasons, when combining these two flags, always run the test with --noteardown first then with both of them.
composer test:browser -- --noteardown
You can pass Pest specific options after Composer’s argument separator as needed (e.g. to select/filter tests):
composer test:browser -- --filter "SimpleSearchTest"
composer test:browser -- --filter "SimpleSearchTest" --headed
composer test:browser -- --filter "SimpleSearchTest" --debug
Pest options can be combined with the runner’s environment options too:
composer test:browser -- --noteardown --nosetup --filter "SimpleSearchTest"
composer test:browser -- --noteardown --nosetup --filter "search filter panel can be opened"
Hooks
PestPHP provides hooks that allow setup and clean-up code to run automatically at different points during a test run. Hooks are useful for preparing test data, configuring the test environment and resetting any state changed by tests.
The main hooks are:
- beforeEach() and afterEach() which run before or after every test in the current test file, and;
- beforeAll() and afterAll() which run once before or after all tests in the file;
- after() which runs after a specific test.
Hooks can also be scoped to a group of tests by defining them inside a describe() block.
Example - configure environment for all browser (e2e) tests in a file:
beforeAll(fn() => setTestConfiguration(<<<'PHP'
$upload_then_edit = false;
$example = 'value';
PHP));
afterAll(fn() => setTestConfiguration(''));
Example - configure environment only for one browser (e2e) test:
afterAll(fn() => setTestConfiguration(''));
test('example description', function (): void {
setTestConfiguration('$show_resource_type = true;');
...
});
Example - tear down a specific test:
test('example description', function (): void {
$this->rtf = create_resource_type_field("Example field");
expect($this->rtf)->toBeInt();
...
})->after(fn () => delete_resource_type_field($this->rtf));