266 lines
5.6 KiB
Markdown
266 lines
5.6 KiB
Markdown
|
|
# Foundry Factories for MineSeeker
|
|||
|
|
|
|||
|
|
Factory classes for creating test data. For general Foundry usage, see [Zenstruck Foundry Docs](https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html).
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Available Factories
|
|||
|
|
|
|||
|
|
All factories are in `tests/Factory/`:
|
|||
|
|
|
|||
|
|
| Factory | Entity | Use For |
|
|||
|
|
|---------|--------|---------|
|
|||
|
|
| `UserFactory` | `User` | Registered users with auth |
|
|||
|
|
| `GamerFactory` | `Gamer` | Anonymous/guest players |
|
|||
|
|
| `PlayedGameFactory` | `PlayedGame` | Game records |
|
|||
|
|
| `StepFactory` | `Step` | Individual game moves |
|
|||
|
|
| `GridFactory` | `Grid` | 16×16 game grids |
|
|||
|
|
| `GridRowFactory` | `GridRow` | Grid row data |
|
|||
|
|
| `WebAuthnCredentialFactory` | `WebAuthnCredential` | Passkey credentials |
|
|||
|
|
| `ContactMessageFactory` | `ContactMessage` | Contact form messages |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Quick Examples
|
|||
|
|
|
|||
|
|
### UserFactory
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
// Basic user
|
|||
|
|
$user = UserFactory::createOne();
|
|||
|
|
|
|||
|
|
// Unverified user
|
|||
|
|
$user = UserFactory::createOne(['isVerified' => false]);
|
|||
|
|
|
|||
|
|
// Admin user
|
|||
|
|
$user = UserFactory::createOne(['roles' => ['ROLE_ADMIN']]);
|
|||
|
|
|
|||
|
|
// Multiple users
|
|||
|
|
UserFactory::createMany(5);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### GamerFactory
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
// Anonymous gamer
|
|||
|
|
$gamer = GamerFactory::new()->anonymous()->create();
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### PlayedGameFactory
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
// Game with registered players
|
|||
|
|
$game = PlayedGameFactory::new()
|
|||
|
|
->withRegisteredPlayers()
|
|||
|
|
->create();
|
|||
|
|
|
|||
|
|
// Game with anonymous players
|
|||
|
|
$game = PlayedGameFactory::new()
|
|||
|
|
->withAnonymousPlayers()
|
|||
|
|
->create();
|
|||
|
|
|
|||
|
|
// Red wins
|
|||
|
|
$game = PlayedGameFactory::new()
|
|||
|
|
->withRegisteredPlayers()
|
|||
|
|
->redWins()
|
|||
|
|
->create();
|
|||
|
|
|
|||
|
|
// Blue wins
|
|||
|
|
$game = PlayedGameFactory::new()
|
|||
|
|
->withRegisteredPlayers()
|
|||
|
|
->blueWins()
|
|||
|
|
->create();
|
|||
|
|
|
|||
|
|
// Resigned game
|
|||
|
|
$game = PlayedGameFactory::new()
|
|||
|
|
->resigned('red')
|
|||
|
|
->create();
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### StepFactory
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
// Mine hit
|
|||
|
|
$step = StepFactory::new()
|
|||
|
|
->forPlayer('red')
|
|||
|
|
->mine()
|
|||
|
|
->create(['playedGame' => $game]);
|
|||
|
|
|
|||
|
|
// Safe cell
|
|||
|
|
$step = StepFactory::new()
|
|||
|
|
->forPlayer('blue')
|
|||
|
|
->safe()
|
|||
|
|
->create(['playedGame' => $game]);
|
|||
|
|
|
|||
|
|
// With revealed cells
|
|||
|
|
$step = StepFactory::new()
|
|||
|
|
->withRevealedCells([
|
|||
|
|
['row' => 5, 'col' => 5],
|
|||
|
|
['row' => 5, 'col' => 6],
|
|||
|
|
])
|
|||
|
|
->create(['playedGame' => $game]);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### GridFactory
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
// Full 16×16 grid
|
|||
|
|
$grid = GridFactory::createOne(['playedGame' => $game]);
|
|||
|
|
|
|||
|
|
// Automatically creates 16 rows
|
|||
|
|
self::assertCount(16, $grid->gridRow);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### WebAuthnCredentialFactory
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
// Basic credential
|
|||
|
|
$credential = WebAuthnCredentialFactory::createOne(['user' => $user]);
|
|||
|
|
|
|||
|
|
// Named credential, recently used
|
|||
|
|
$credential = WebAuthnCredentialFactory::new()
|
|||
|
|
->withName('YubiKey 5C')
|
|||
|
|
->recentlyUsed()
|
|||
|
|
->create(['user' => $user]);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### ContactMessageFactory
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
// Basic message
|
|||
|
|
$message = ContactMessageFactory::createOne();
|
|||
|
|
|
|||
|
|
// Without consent
|
|||
|
|
$message = ContactMessageFactory::new()
|
|||
|
|
->withoutConsent()
|
|||
|
|
->create();
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Factory API Reference
|
|||
|
|
|
|||
|
|
### Common Methods (All Factories)
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
// Create single entity
|
|||
|
|
Factory::createOne([
|
|||
|
|
'property' => 'value',
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
// Create multiple
|
|||
|
|
Factory::createMany(5);
|
|||
|
|
|
|||
|
|
// Create with factory methods
|
|||
|
|
Factory::new()
|
|||
|
|
->customMethod()
|
|||
|
|
->create(['property' => 'value']);
|
|||
|
|
|
|||
|
|
// Access repository
|
|||
|
|
Factory::repository()->findAll();
|
|||
|
|
Factory::repository()->count([]);
|
|||
|
|
Factory::repository()->findBy(['field' => 'value']);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### PlayedGameFactory Methods
|
|||
|
|
|
|||
|
|
| Method | Description |
|
|||
|
|
|--------|-------------|
|
|||
|
|
| `withRegisteredPlayers()` | Creates game with 2 registered users |
|
|||
|
|
| `withAnonymousPlayers()` | Creates game with 2 anonymous gamers |
|
|||
|
|
| `withMixedPlayers()` | One registered, one anonymous |
|
|||
|
|
| `redWins()` | Red has 26 points |
|
|||
|
|
| `blueWins()` | Blue has 26 points |
|
|||
|
|
| `resigned(string $player)` | Set resignation ('red' or 'blue') |
|
|||
|
|
|
|||
|
|
### StepFactory Methods
|
|||
|
|
|
|||
|
|
| Method | Description |
|
|||
|
|
|--------|-------------|
|
|||
|
|
| `forPlayer(string $player)` | Set player ('red' or 'blue') |
|
|||
|
|
| `mine()` | Step hits a mine |
|
|||
|
|
| `safe()` | Step reveals safe cell |
|
|||
|
|
| `withRevealedCells(array $cells)` | Set revealed cells array |
|
|||
|
|
|
|||
|
|
### GamerFactory Methods
|
|||
|
|
|
|||
|
|
| Method | Description |
|
|||
|
|
|--------|-------------|
|
|||
|
|
| `anonymous()` | Set username as "Guest_12345" |
|
|||
|
|
|
|||
|
|
### WebAuthnCredentialFactory Methods
|
|||
|
|
|
|||
|
|
| Method | Description |
|
|||
|
|
|--------|-------------|
|
|||
|
|
| `withName(string $name)` | Set credential name |
|
|||
|
|
| `recentlyUsed()` | Set lastUsedAt to now |
|
|||
|
|
|
|||
|
|
### ContactMessageFactory Methods
|
|||
|
|
|
|||
|
|
| Method | Description |
|
|||
|
|
|--------|-------------|
|
|||
|
|
| `withoutConsent()` | Set consent to false |
|
|||
|
|
| `anonymous()` | Remove IP address |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## MineSeeker-Specific Patterns
|
|||
|
|
|
|||
|
|
### Complete Game Setup
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
// Create full game with steps and grid
|
|||
|
|
$game = PlayedGameFactory::new()
|
|||
|
|
->withRegisteredPlayers()
|
|||
|
|
->create();
|
|||
|
|
|
|||
|
|
// Add steps
|
|||
|
|
StepFactory::createMany(10, [
|
|||
|
|
'playedGame' => $game,
|
|||
|
|
'player' => 'red',
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
// Add grid
|
|||
|
|
$grid = GridFactory::createOne(['playedGame' => $game]);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Testing Battle History
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
// Create multiple finished games for a user
|
|||
|
|
$user = UserFactory::createOne();
|
|||
|
|
|
|||
|
|
PlayedGameFactory::new()
|
|||
|
|
->redWins()
|
|||
|
|
->create(['red' => $user]);
|
|||
|
|
|
|||
|
|
PlayedGameFactory::new()
|
|||
|
|
->blueWins()
|
|||
|
|
->create(['blue' => $user]);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Database Isolation
|
|||
|
|
|
|||
|
|
Tests automatically run in isolated transactions:
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
public function testDatabaseIsolation(): void
|
|||
|
|
{
|
|||
|
|
UserFactory::createMany(5);
|
|||
|
|
self::assertCount(5, UserFactory::repository()->findAll());
|
|||
|
|
|
|||
|
|
// Automatically rolled back after test
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
No manual cleanup needed. Each test starts with a clean database.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## External Resources
|
|||
|
|
|
|||
|
|
- **[Zenstruck Foundry Documentation](https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html)** - Complete Foundry guide
|
|||
|
|
- **[DAMA Doctrine Test Bundle](https://github.com/dmaicher/doctrine-test-bundle)** - Transaction isolation details
|