Claude-skill-registry feature-test
Create a PHPUnit feature test for API endpoints following this project's patterns. Use when testing controllers, API responses, and database interactions.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/feature-test" ~/.claude/skills/majiayu000-claude-skill-registry-feature-test && rm -rf "$T"
manifest:
skills/data/feature-test/SKILL.mdsource content
Create Feature Test
Create a PHPUnit feature test for
$ARGUMENTS following Laravel testing conventions.
Test Location
tests/Feature/
Current Test Setup
- PHPUnit 9.5.10
- Uses
trait for clean DB stateRefreshDatabase - Environment: testing (defined in phpunit.xml)
- Factories available:
(others need to be created)UserFactory
Standard API Test Structure
<?php namespace Tests\Feature; use App\Models\User; use App\Models\{ModelName}; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\TestCase; class {ModelName}ControllerTest extends TestCase { use RefreshDatabase; protected User $user; protected function setUp(): void { parent::setUp(); $this->user = User::factory()->create(); } /** @test */ public function it_can_list_all_resources() { // Arrange {ModelName}::factory()->count(3)->create(); // Act $response = $this->actingAs($this->user) ->getJson('/api/{resources}'); // Assert $response->assertStatus(200) ->assertJsonCount(3, 'data'); } /** @test */ public function it_can_show_a_single_resource() { $resource = {ModelName}::factory()->create(); $response = $this->actingAs($this->user) ->getJson("/api/{resource}/{$resource->id}"); $response->assertStatus(200) ->assertJsonPath('data.id', $resource->id); } /** @test */ public function it_can_create_a_resource() { $data = [ 'name' => 'Test Resource', 'category_id' => 1, // ... other required fields ]; $response = $this->actingAs($this->user) ->postJson('/api/{resources}', $data); $response->assertStatus(201); $this->assertDatabaseHas('{table_name}', ['name' => 'Test Resource']); } /** @test */ public function it_validates_required_fields_on_create() { $response = $this->actingAs($this->user) ->postJson('/api/{resources}', []); $response->assertStatus(422) ->assertJsonValidationErrors(['name', 'category_id']); } /** @test */ public function it_can_update_a_resource() { $resource = {ModelName}::factory()->create(); $response = $this->actingAs($this->user) ->putJson("/api/backoffice/{resources}/{$resource->id}", [ 'name' => 'Updated Name' ]); $response->assertStatus(200); $this->assertDatabaseHas('{table_name}', ['name' => 'Updated Name']); } /** @test */ public function it_can_delete_a_resource() { $resource = {ModelName}::factory()->create(); $response = $this->actingAs($this->user) ->deleteJson("/api/backoffice/{resources}/{$resource->id}"); $response->assertStatus(200); $this->assertDatabaseMissing('{table_name}', ['id' => $resource->id]); } }
Testing POS-Specific Flows
Order Creation Test
/** @test */ public function it_can_create_an_order_for_table() { $table = Table::factory()->create(); $inventory = Inventory::factory()->create(['price' => 100]); $orderData = [ 'table_id' => $table->id, 'order' => [ [ 'id' => $inventory->id, 'name' => $inventory->name, 'price' => $inventory->price, 'qty' => 2, ] ] ]; $response = $this->actingAs($this->user) ->postJson('/api/orders', $orderData); $response->assertStatus(201); $this->assertDatabaseHas('orders', ['table_id' => $table->id]); }
Invoice Creation Test
/** @test */ public function it_can_create_invoice_from_order() { $table = Table::factory()->create(); $order = Order::factory()->create(['table_id' => $table->id]); $invoiceData = [ 'user_id' => $this->user->id, 'table_id' => $table->id, 'order' => $order->order, 'total' => 500, ]; $response = $this->actingAs($this->user) ->postJson('/api/invoices', $invoiceData); $response->assertStatus(201); // Order should be deleted after invoice creation $this->assertDatabaseMissing('orders', ['id' => $order->id]); }
Refund Test
/** @test */ public function it_can_refund_an_invoice() { $invoice = Invoice::factory()->create([ 'status' => Invoice::STATUS_PAYED ]); $refundReason = RefundReason::factory()->create(); $response = $this->actingAs($this->user) ->postJson("/api/invoices/{$invoice->id}/refund", [ 'refund_reason_id' => $refundReason->id ]); $response->assertStatus(200); $this->assertDatabaseHas('invoices', [ 'id' => $invoice->id, 'status' => Invoice::STATUS_REFUNDED ]); }
Factory Creation Pattern
Create factories in
database/factories/:
<?php namespace Database\Factories; use App\Models\{ModelName}; use Illuminate\Database\Eloquent\Factories\Factory; class {ModelName}Factory extends Factory { protected $model = {ModelName}::class; public function definition() { return [ 'name' => $this->faker->word(), 'description' => $this->faker->sentence(), 'price' => $this->faker->numberBetween(100, 10000), 'status' => 1, 'category_id' => Category::factory(), ]; } // State methods public function inactive() { return $this->state(['status' => 0]); } }
Running Tests
# Run all tests ./vendor/bin/phpunit # Run specific test file ./vendor/bin/phpunit tests/Feature/InvoiceControllerTest.php # Run specific test method ./vendor/bin/phpunit --filter=it_can_create_an_order # Run with coverage ./vendor/bin/phpunit --coverage-html coverage/
Steps
- Create test file in
tests/Feature/ - Create necessary factories in
database/factories/ - Use
traitRefreshDatabase - Test all CRUD operations
- Test validation rules
- Test business logic (refunds, status changes, etc.)
- Run tests to verify