Improve tests coverage#2
Conversation
…ethod for settings
…improve translation pattern generation
…cluding service providers, middleware, models, and rules
…es actions, and filters
…te, and completed tests for the `redot/core` Laravel package
There was a problem hiding this comment.
Pull request overview
This PR expands automated coverage for the redot/core Laravel package by adding a substantial Pest/Orchestra Testbench suite across core domains and bundled subpackages, plus a few small production-code adjustments and CI wiring to support reliable, hermetic test execution.
Changes:
- Added broad Unit/Feature Pest coverage for core helpers/rules/models and several subpackages (auth, datatables, lang-extractor, sidebar, toastify).
- Improved runtime behavior discovered via tests (nested Setting cache invalidation,
parse_csv()reindexing, LangExtractor extension handling/regex robustness). - Added CI workflow for running tests and updated contributor/testing documentation and planning docs.
Reviewed changes
Copilot reviewed 32 out of 32 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
tests/Unit/Packages/Toastify/ToastifyTest.php |
Adds unit coverage for session storage and view rendering helpers. |
tests/Unit/Packages/Sidebar/ItemTest.php |
Adds unit coverage for fluent item building, parent/child behavior, and hidden filtering. |
tests/Unit/Packages/LangExtractor/LangExtractorTest.php |
Adds unit coverage for extraction and merge behaviors. |
tests/Unit/Packages/Datatables/FilterTest.php |
Adds database-backed unit coverage for filter query application. |
tests/Unit/Packages/Datatables/ColumnTest.php |
Adds unit coverage for column configuration and escaping vs HTML behavior. |
tests/Unit/Packages/Datatables/ActionTest.php |
Adds unit coverage for action attributes, validation, grouping, and visibility. |
tests/Unit/Packages/Auth/RedotAuthManagerTest.php |
Adds unit coverage for context resolution and guard config validation. |
tests/Unit/Packages/Auth/AuthContextTest.php |
Adds unit coverage for route naming, middleware composition, feature disabling, and URLs. |
tests/Unit/Core/Rules/PhoneTest.php |
Adds unit coverage for phone rule pass/fail behavior. |
tests/Unit/Core/Rules/CaptchaTest.php |
Adds unit coverage for captcha behavior including production HTTP verification. |
tests/Unit/Core/Models/SettingTest.php |
Adds unit coverage for schema/defaults/rules, persistence, and cache invalidation. |
tests/Unit/Core/Models/LanguageTokenTest.php |
Adds unit coverage for casts, relationships, change side effects, and scopes. |
tests/Unit/Core/Models/LanguageTest.php |
Adds unit coverage for route key, direction, and current language resolution. |
tests/Unit/Core/HelpersTest.php |
Adds unit coverage for helper behaviors including API exception formatting and parse_csv(). |
tests/Unit/Core/Casts/UnionTest.php |
Adds unit coverage for Union cast get/set behavior across types. |
tests/TestCase.php |
Makes test view compilation hermetic by compiling to a temp directory. |
tests/Fixtures/Datatables/DatatableFilterFixture.php |
Adds Eloquent fixture model for filter tests. |
tests/Fixtures/Datatables/DatatableColumnRow.php |
Adds fixture model for column value rendering tests. |
tests/Fixtures/Datatables/DatatableActionRow.php |
Adds fixture model for action attribute/visibility tests. |
tests/Fixtures/Core/EmptyModel.php |
Adds minimal model fixture for casting/action tests. |
tests/Fixtures/Auth/VerifiableAuthContextUser.php |
Adds fixture model implementing MustVerifyEmail for auth context tests. |
tests/Fixtures/Auth/CapturingLoginRoutes.php |
Adds registrar fixture to capture AuthContext passed into route registration. |
tests/Feature/Core/StaticIntegrityTest.php |
Adds feature-level integrity checks for autoloading, commands, and view existence. |
tests/Feature/Core/ServiceProviderTest.php |
Adds feature smoke tests for boot/config/migrations/commands. |
tests/Feature/Core/Middleware/LocalizationTest.php |
Adds feature coverage for locale middleware behavior and redirects. |
tests/Feature/Core/Middleware/EnsureDependenciesBuiltTest.php |
Adds feature coverage for “no rebuild needed” middleware path. |
src/packages/lang-extractor/src/LangExtractor.php |
Fixes constructor extension handling; makes ignore-regex safe when ignore list is empty. |
src/helpers.php |
Reindexes filtered CSV parsing results. |
src/Models/Setting.php |
Expands cache invalidation to clear nested cached keys. |
PLAN.md |
Adds/updates a comprehensive testing coverage plan. |
AGENTS.md |
Updates contributor guidance to reflect the committed Pest/Testbench suite. |
.github/workflows/tests.yml |
Adds CI workflow for running the test suite on PRs and master. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| $directory = sys_get_temp_dir() . '/redot-lang-extractor'; | ||
|
|
||
| File::deleteDirectory($directory); | ||
| File::ensureDirectoryExists($directory); | ||
| File::put($directory . '/view.blade.php', "{{ __('Hello world') }} @lang('Dashboard') {{ __('Hello world') }}"); | ||
| File::put($directory . '/component.php', "<?php echo trans('Saved successfully');"); | ||
|
|
||
| $translations = (new LangExtractor([$directory], ['php', 'blade.php'])) | ||
| ->withExtensions('php', 'blade.php') | ||
| ->extract() | ||
| ->all(); | ||
|
|
||
| expect($translations)->toHaveCount(3) | ||
| ->and($translations)->toMatchArray([ | ||
| 'Hello world' => 'Hello world', | ||
| 'Dashboard' => 'Dashboard', | ||
| 'Saved successfully' => 'Saved successfully', | ||
| ]); | ||
| }); | ||
|
|
||
| it('merges extracted translations with arrays and existing json files', function () { | ||
| $directory = sys_get_temp_dir() . '/redot-lang-extractor-merge'; | ||
| $path = sys_get_temp_dir() . '/redot-translations.json'; | ||
|
|
||
| File::deleteDirectory($directory); | ||
| File::ensureDirectoryExists($directory); | ||
| File::put($directory . '/view.php', "<?php __('New key');"); | ||
| File::put($path, json_encode(['Existing key' => 'Existing value'])); | ||
|
|
||
| $translations = (new LangExtractor([$directory], ['php'])) | ||
| ->extract() | ||
| ->mergeWithArray(['Array key' => 'Array value']) | ||
| ->mergeWithFile($path) | ||
| ->all(); | ||
|
|
||
| expect($translations)->toBe([ | ||
| 'Array key' => 'Array value', | ||
| 'Existing key' => 'Existing value', | ||
| 'New key' => 'New key', | ||
| ]); |
There was a problem hiding this comment.
This test writes to a fixed path in the system temp dir (/tmp/redot-translations.json) and never deletes it. That can make runs non-hermetic and can cause cross-test / cross-run interference (especially in parallel CI). Prefer a unique temp file (e.g., include a random suffix) and ensure it’s removed at the end of the test (or in an afterEach).
| $directory = sys_get_temp_dir() . '/redot-lang-extractor'; | |
| File::deleteDirectory($directory); | |
| File::ensureDirectoryExists($directory); | |
| File::put($directory . '/view.blade.php', "{{ __('Hello world') }} @lang('Dashboard') {{ __('Hello world') }}"); | |
| File::put($directory . '/component.php', "<?php echo trans('Saved successfully');"); | |
| $translations = (new LangExtractor([$directory], ['php', 'blade.php'])) | |
| ->withExtensions('php', 'blade.php') | |
| ->extract() | |
| ->all(); | |
| expect($translations)->toHaveCount(3) | |
| ->and($translations)->toMatchArray([ | |
| 'Hello world' => 'Hello world', | |
| 'Dashboard' => 'Dashboard', | |
| 'Saved successfully' => 'Saved successfully', | |
| ]); | |
| }); | |
| it('merges extracted translations with arrays and existing json files', function () { | |
| $directory = sys_get_temp_dir() . '/redot-lang-extractor-merge'; | |
| $path = sys_get_temp_dir() . '/redot-translations.json'; | |
| File::deleteDirectory($directory); | |
| File::ensureDirectoryExists($directory); | |
| File::put($directory . '/view.php', "<?php __('New key');"); | |
| File::put($path, json_encode(['Existing key' => 'Existing value'])); | |
| $translations = (new LangExtractor([$directory], ['php'])) | |
| ->extract() | |
| ->mergeWithArray(['Array key' => 'Array value']) | |
| ->mergeWithFile($path) | |
| ->all(); | |
| expect($translations)->toBe([ | |
| 'Array key' => 'Array value', | |
| 'Existing key' => 'Existing value', | |
| 'New key' => 'New key', | |
| ]); | |
| $directory = sys_get_temp_dir() . '/redot-lang-extractor-' . uniqid('', true); | |
| try { | |
| File::deleteDirectory($directory); | |
| File::ensureDirectoryExists($directory); | |
| File::put($directory . '/view.blade.php', "{{ __('Hello world') }} @lang('Dashboard') {{ __('Hello world') }}"); | |
| File::put($directory . '/component.php', "<?php echo trans('Saved successfully');"); | |
| $translations = (new LangExtractor([$directory], ['php', 'blade.php'])) | |
| ->withExtensions('php', 'blade.php') | |
| ->extract() | |
| ->all(); | |
| expect($translations)->toHaveCount(3) | |
| ->and($translations)->toMatchArray([ | |
| 'Hello world' => 'Hello world', | |
| 'Dashboard' => 'Dashboard', | |
| 'Saved successfully' => 'Saved successfully', | |
| ]); | |
| } finally { | |
| File::deleteDirectory($directory); | |
| } | |
| }); | |
| it('merges extracted translations with arrays and existing json files', function () { | |
| $directory = sys_get_temp_dir() . '/redot-lang-extractor-merge-' . uniqid('', true); | |
| $path = sys_get_temp_dir() . '/redot-translations-' . uniqid('', true) . '.json'; | |
| try { | |
| File::deleteDirectory($directory); | |
| File::ensureDirectoryExists($directory); | |
| File::put($directory . '/view.php', "<?php __('New key');"); | |
| File::put($path, json_encode(['Existing key' => 'Existing value'])); | |
| $translations = (new LangExtractor([$directory], ['php'])) | |
| ->extract() | |
| ->mergeWithArray(['Array key' => 'Array value']) | |
| ->mergeWithFile($path) | |
| ->all(); | |
| expect($translations)->toBe([ | |
| 'Array key' => 'Array value', | |
| 'Existing key' => 'Existing value', | |
| 'New key' => 'New key', | |
| ]); | |
| } finally { | |
| File::deleteDirectory($directory); | |
| File::delete($path); | |
| } |
| $packagePaths = collect($prefixes) | ||
| ->reject(fn (string $path, string $namespace): bool => $namespace === 'Redot\\') | ||
| ->map(fn (string $path): string => realpath($root . '/' . $path)) | ||
| ->filter() | ||
| ->all(); |
There was a problem hiding this comment.
$packagePaths is computed but never used. Dropping it (or using it to constrain which paths are scanned) would reduce noise and keep the test intent clearer.
| $packagePaths = collect($prefixes) | |
| ->reject(fn (string $path, string $namespace): bool => $namespace === 'Redot\\') | |
| ->map(fn (string $path): string => realpath($root . '/' . $path)) | |
| ->filter() | |
| ->all(); |
No description provided.