---
description: Laravel Back-end Tests
globs: api/tests/**/*.php
---

You are an expert in Laravel testing, particularly with Pest PHP for the Laravel back-end.

Key Principles
- Write concise, isolated tests that verify specific functionality.
- Follow the Arrange-Act-Assert pattern for test structure.
- Use descriptive test names that explain what is being tested.
- Prefer Pest PHP's expressive syntax over traditional PHPUnit syntax.
- Use mocking and test doubles appropriately to isolate components.
- Organize tests by the component they are testing.

Test Structure
- `tests/Feature/`: Contains feature tests that test the application as a whole.
- `tests/Unit/`: Contains unit tests that test individual components in isolation.
  - `Unit/Rules/`: Tests for validation rules.
  - `Unit/Service/`: Tests for service classes.
  - `Unit/Services/`: Tests for service classes (alternative structure).
- `tests/Helpers/`: Contains helper classes used across tests.
- `tests/Browser/`: Contains browser tests using Laravel Dusk.

Test Configuration
- Use `tests/Pest.php` for Pest PHP configuration.
- Use `tests/TestCase.php` as the base test case class.
- Use `tests/TestHelpers.php` for common helper methods.

Unit Testing Best Practices
1. **Test in Isolation**: Mock dependencies to ensure true unit testing.
2. **Single Responsibility**: Each test should verify one specific behavior.
3. **Descriptive Names**: Use descriptive test names that explain what is being tested.
4. **Arrange-Act-Assert**: Structure tests with clear arrangement, action, and assertion phases.
5. **Test Edge Cases**: Include tests for edge cases and error conditions.
6. **Use describe()**: Group related tests using describe() blocks.
7. **Use beforeEach()**: Set up common test state using beforeEach() hooks.
8. **Avoid Test Dependencies**: Tests should not depend on the state from other tests.
9. **Test Public API**: Focus on testing the public API of classes, not implementation details.
10. **Consistent Patterns**: Follow consistent patterns for similar types of tests.

Writing Unit Tests
- Use Pest PHP's expressive syntax:
  ```php
  it('can parse filenames', function () {
      $fileName = 'example_85e16d7b-58ed-43bc-8dce-7d3ff7d69f41.png';
      $parsedFilename = StorageFileNameParser::parse($fileName);
      expect($parsedFilename->fileName)->toBe('example');
  });
  ```

- Group related tests with describe():
  ```php
  describe('StorageFile validation', function () {
      it('accepts valid URLs without validation', function () {
          $validator = new StorageFile();
          expect($validator->passes('file', 'https://example.com/file.pdf'))->toBeTrue();
      });

      it('rejects files with invalid UUID format', function () {
          $validator = new StorageFile();
          expect($validator->passes('file', 'invalid-uuid.jpg'))->toBeFalse();
      });
  });
  ```

- Use beforeEach() for common setup:
  ```php
  beforeEach(function () {
      Storage::fake('local');
  });
  ```

- Mock dependencies:
  ```php
  it('rejects non-existent files', function () {
      $uuid = Str::uuid();
      $fileName = 'file-name_' . $uuid . '.jpg';

      Storage::shouldReceive('exists')
          ->with('tmp/' . $uuid)
          ->andReturn(false);

      $validator = new StorageFile();
      expect($validator->passes('file', $fileName))->toBeFalse();
  });
  ```

- Test edge cases:
  ```php
  it('can clean non-utf characters', function () {
      $fileName = 'Образец_для_заполнения_85e16d7b-58ed-43bc-8dce-7d3ff7d69f41.png';
      $parsedFilename = StorageFileNameParser::parse($fileName);
      expect($parsedFilename->getMovedFileName())->toBe('___85e16d7b-58ed-43bc-8dce-7d3ff7d69f41.png');
  });
  ```

Testing Validation Rules
- Create instances of the rule class.
- Test both valid and invalid inputs.
- Verify error messages for invalid inputs.
- Test edge cases and boundary conditions.

Testing Service Classes
- Mock dependencies using Mockery.
- Test each public method in isolation.
- Verify correct behavior for both success and failure cases.
- Test edge cases and error handling.

Running Tests
- Run all tests: `php artisan test`
- Run unit tests only: `php artisan test --testsuite=Unit`
- Run a specific test file: `php artisan test --filter=StorageFileTest`
- Run tests with coverage: `php artisan test --coverage`

Debugging Tests
- Use ray() for debugging test execution.
- Use dd() or dump() for quick inspection of variables.
- Check for race conditions in asynchronous tests.
- Verify that the database is being properly reset between tests.
- Ensure that tests are not dependent on each other. 