[6.x] Pest - #15140
Draft
jasonvarga wants to merge 23 commits into
Draft
Conversation
The provider keyed data sets by URL, and an empty string is one of the internal URLs, producing an empty-string key. PHPUnit rejects this when listing tests, which broke any tooling relying on --list-tests. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
setThemeColors() writes resource_path('preferences.yaml'), and while
setUp() deleted it, nothing cleaned up after the last test. The final
test's colors survived into unrelated tests that assert on preferences,
making the suite order dependent. Delete the file in tearDown() too,
matching DefaultPreferencesTest and PrecedenceTest.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Pest runs the existing PHPUnit test suite as-is, with no conversion to Pest syntax. It's added for its sharding support, which PHPUnit has no equivalent for. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The test run is around 90% of each job's wall clock, so sharding is close to linear. Four shards takes the workflow from ~12.8 to ~4 minutes. Windows needs its own include entry per shard, since an include that overrides a matrix key creates a standalone combination rather than merging, and so wouldn't inherit the shard dimension. shards.json holds recorded timings so shards are balanced by duration rather than test count. Regenerate it with --update-shards. Adds a php-tests-result job that aggregates every shard, so branch protection can require one check instead of one per matrix cell. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jasonvarga
marked this pull request as draft
August 8, 2026 05:10
NavItem::display() is a fluent get-or-set, so passing null meant "get". Chaining create() off it returned the current display (null) instead of the item, and pushed that null into the registered items. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Matches collections, taxonomies, asset containers, globals, roles, and user groups, which all humanize the handle when no title is set. Without it, a title-less form gave a null nav item display and broke the CP nav. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The skeleton at vendor/orchestra/testbench-core/laravel persists for the life of a
process, so anything a test writes there is visible to every test that follows it.
198 of our test files leave files behind, which is how a form file containing only
{} ends up crashing CoreNavTest - it only passes today because of lucky ordering,
and that luck runs out as soon as the suite is split across processes.
Snapshot the skeleton once per process and delete anything new after each test.
Directories the framework owns (bootstrap/cache, storage/framework/views and
friends) are left alone, both because deleting them breaks the app and because
walking them gets expensive. A process that starts against an already dirty
skeleton would bake that dirt into its snapshot, so testbench.yaml declares the
paths our tests are known to write and those get cleared before the first boot -
which also means vendor/bin/testbench package:purge-skeleton cleans up after us.
Making an addon with a fieldtype runs 'npm install' from the testbench app's base path. That app has no package.json, so npm walks up and installs against ours, rewriting package-lock.json in the working tree. The other commands that trigger this already fake the process.
The users it makes have no id, so saving them writes tests/__fixtures__/users/.yaml into the repo. Point the stache stores at the throwaway directory like the other tests that save users do.
It was asserting a custom namespace blueprint could be edited without ever creating one, and only passed because StoreCustomBlueprintTest had left one behind in the testbench skeleton.
Glide only makes the directory when it actually processes an image, which by definition never happens here. The test was relying on an earlier one in the file having made it, so make it up front and keep the assertion that nothing lands in it.
Temporary. So one shard failing doesn't cancel the rest of the matrix and we see every remaining failure in a single run. Revert before merge.
Not for merging. Confirms two things on Windows CI: 1. PHP does not recurse into mklink /J junctions via RecursiveDirectoryIterator with FOLLOW_SYMLINKS, but does recurse into real symlinks. 2. deleteDirectory() cannot remove directory symlinks, so TemplateFolderTest leaks them into the directory TemplatesTest reuses. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Overrides hasChildren() to fall back to is_dir(), which is true for junctions. Checks that recursion continues from the unresolved pathname so template names keep their virtual prefix. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The override had no effect, so log whether it is invoked at all, and try a plain recursive scan that leans on is_dir() instead of SPL recursion. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
parent::hasChildren() lstat()s the path first, and is_dir() appears to reuse that cached result. Compare is_dir() before and after clearing the cache. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Its findings are applied in the commits that follow. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both classes shared tests/Fieldtypes/templates-test-tmp, and their teardown used deleteDirectory(), which cannot remove a symlinked or junctioned directory on Windows. TemplateFolderTest's symlinks therefore survived into TemplatesTest, which reused them instead of the links it thought it had created. Give each class its own directory and a teardown that can remove reparse points. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
RecursiveDirectoryIterator treats a junction as a leaf, so a junctioned folder under a view path was offered as a bogus template and the templates inside it were invisible. Both the Templates and Template Folder fieldtypes were affected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
is_link() lstat's the path, and PHP caches an lstat result as the stat result when it decides the path isn't a link. A junction isn't reported as a link, so the following is_dir() was served that bogus mode and answered false, sending junctions to unlink(), which cannot remove them on Windows. Try unlink() then rmdir() and recurse into whatever survives both, so no stat is involved. Cover it with a test, since a teardown leak is otherwise silent. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds Pest as the test runner for CI. This allows us to use time-based sharding.