# Testing Guide for MineSeeker

MineSeeker-specific testing setup and workflows. For general PHPUnit/Symfony testing, see [Symfony Testing Docs](https://symfony.com/doc/current/testing.html).

## Quick Start

```bash
# One-time setup
make test-db-setup

# Run tests
make test
```

---

## Test Database Configuration

MineSeeker uses a **separate test database** (`mineseeker_test`) with automatic transaction rollback for isolated tests.

### Stack

- **PHPUnit 13** - Testing framework
- **[Zenstruck Foundry](https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html)** - Factory library for test fixtures
- **[DAMA Doctrine Test Bundle](https://github.com/dmaicher/doctrine-test-bundle)** - Transaction isolation (rollback after each test)

### Configuration

**`phpunit.dist.xml`**:
```xml
<env name="DATABASE_URL" value="postgresql://...mineseeker_test..." />
<env name="DAMA_DISABLE_STATIC_CONNECTION" value="0" />
```

**`config/bundles.php`**:
```php
Zenstruck\Foundry\ZenstruckFoundryBundle::class => ['dev' => true, 'test' => true],
DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true],
```

---

## Setup

### One-time Setup

```bash
make test-db-setup
```

Creates `mineseeker_test` database and runs migrations.

### Reset Test Database

```bash
make test-db-reset
```

Drops and recreates test database (useful after schema changes).

---

## Running Tests

```bash
# All tests
make test

# Specific file
vendor/bin/phpunit tests/Controller/ProfileControllerTest.php

# Specific method
vendor/bin/phpunit --filter testCreateUser

# With test names
vendor/bin/phpunit --testdox
```

---

## MineSeeker Factories

See **[FACTORIES.md](./FACTORIES.md)** for complete factory API.

### Available Factories

| Factory | Entity | Location |
|---------|--------|----------|
| `UserFactory` | Registered users | `tests/Factory/UserFactory.php` |
| `GamerFactory` | Anonymous players | `tests/Factory/GamerFactory.php` |
| `PlayedGameFactory` | Game records | `tests/Factory/PlayedGameFactory.php` |
| `StepFactory` | Game moves | `tests/Factory/StepFactory.php` |
| `GridFactory` | 16×16 game grids | `tests/Factory/GridFactory.php` |
| `GridRowFactory` | Grid rows | `tests/Factory/GridRowFactory.php` |
| `WebAuthnCredentialFactory` | Passkey credentials | `tests/Factory/WebAuthnCredentialFactory.php` |
| `ContactMessageFactory` | Contact messages | `tests/Factory/ContactMessageFactory.php` |

### Example

```php
use App\Tests\Factory\PlayedGameFactory;
use App\Tests\WebTestCase;

class GameTest extends WebTestCase
{
    public function testGameCreation(): void
    {
        $game = PlayedGameFactory::new()
            ->withRegisteredPlayers()
            ->redWins()
            ->create();

        self::assertEquals(26, $game->redPoints);
    }
}
```

---

## Test Structure

All tests extend `App\Tests\WebTestCase`:

```php
<?php declare(strict_types=1);
/**
 * This file is part of the SplendidBear Websites' projects.
 *
 * Copyright (c) 2026 @ www.splendidbear.org
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace App\Tests\Controller;

use App\Tests\Factory\UserFactory;
use App\Tests\WebTestCase;

class MyControllerTest extends WebTestCase
{
    public function testExample(): void
    {
        $user = UserFactory::createOne();
        $client = static::createClient();
        
        $client->request('GET', '/profile');
        
        self::assertResponseRedirects('/login');
    }
}
```

**Important**: Always extend `App\Tests\WebTestCase`, not `Symfony\Bundle\FrameworkBundle\Test\WebTestCase`.

---

## Directory Structure

```
tests/
├── Controller/          # HTTP endpoint tests
├── Dto/                 # Data Transfer Object tests
├── Entity/              # Entity logic tests
├── Service/             # Service layer tests
├── Integration/         # Integration tests
├── Factory/             # Foundry factories
├── WebTestCase.php      # Base test class
└── bootstrap.php        # PHPUnit bootstrap
```

---

## MineSeeker-Specific Patterns

### Testing Game Flow

```php
public function testRedPlayerWinsGame(): void
{
    $game = PlayedGameFactory::new()
        ->withRegisteredPlayers()
        ->create();

    // Create steps to simulate gameplay
    for ($i = 0; $i < 26; $i++) {
        StepFactory::new()
            ->forPlayer('red')
            ->mine()
            ->create(['playedGame' => $game]);
    }

    self::assertEquals(26, $game->redPoints);
}
```

### Testing Battle Sharing

```php
public function testBattleSharePageReturnsValidGame(): void
{
    $game = PlayedGameFactory::new()
        ->withRegisteredPlayers()
        ->redWins()
        ->create();

    $client = static::createClient();
    $client->request('GET', '/battle/' . $game->uuid);

    self::assertResponseIsSuccessful();
    self::assertSelectorTextContains('h1', 'Battle Report');
}
```

### Testing Authentication

```php
public function testProfileRequiresAuthentication(): void
{
    $client = static::createClient();
    $client->request('GET', '/profile');

    self::assertResponseRedirects('/login');
}

public function testAuthenticatedUserCanAccessProfile(): void
{
    $user = UserFactory::createOne();
    $client = static::createClient();
    $client->loginUser($user->_real());

    $client->request('GET', '/profile');

    self::assertResponseIsSuccessful();
}
```

---

## Troubleshooting

### Tests interfering with each other?

Ensure you extend `App\Tests\WebTestCase`, not the base Symfony class.

### Schema out of sync?

```bash
make test-db-reset
```

### Memory limit errors?

```bash
php -d memory_limit=1024M vendor/bin/phpunit
```

Or increase in `phpunit.dist.xml`:
```xml
<ini name="memory_limit" value="1024M"/>
```

### Test database doesn't exist?

```bash
make test-db-setup
```

---

## External Resources

- **[Symfony Testing](https://symfony.com/doc/current/testing.html)** - Symfony testing guide
- **[Zenstruck Foundry](https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html)** - Factory documentation
- **[DAMA Doctrine Test Bundle](https://github.com/dmaicher/doctrine-test-bundle)** - Transaction isolation
- **[PHPUnit](https://docs.phpunit.de/)** - PHPUnit documentation

---

## Modern PHPUnit Attributes

MineSeeker tests use modern PHP 8 attributes instead of method name prefixes:

```php
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\TestDox;

#[TestDox('Security Controller')]
class SecurityControllerTest extends WebTestCase
{
    #[Test]
    #[TestDox('Login page loads successfully with form fields')]
    public function loginPageLoadsSuccessfully(): void
    {
        // Test implementation
    }
}
```

**Benefits:**
- ✅ More readable method names (no `test` prefix required)
- ✅ Self-documenting with `TestDox` descriptions
- ✅ Better IDE support and refactoring
- ✅ Cleaner `--testdox` output

**Run with documentation:**
```bash
vendor/bin/phpunit --testdox
```

Output:
```
Security Controller
 ✔ Login page loads successfully with form fields
 ✔ Login page has links to register and forgot password
 ✔ Register page loads successfully with form
```
