agentsclimarketplace

Webbyx laravel test

Skill Apikmmar/agent-laravel-skills/skills/webbyx-laravel-test

Use when generating PHPUnit tests for a Laravel GraphQL module. Triggers when user asks to write tests, generate test files, cover a module with tests, add test coverage, or create mutation/query tests.From its SKILL.md

Install
npx -y skills add Apikmmar/agent-laravel-skills --skill webbyx-laravel-test

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

5.8 KB, as published. Nobody here has run it

@agents/BRAINSTORM.md @agents/CONVENTION.md

Rule

Tests live in Modules/{ModuleName}/Tests/Feature/. One test class per operation group — mutations in {Model}MutationTest.php, queries in {Model}QueryTest.php. All tests use PHPUnit via Tests\TestCase, RefreshDatabase, and Lighthouse's MakesGraphQLRequests trait.

Tests must run against MySQL — never SQLite. Controllers use DB::beginTransaction() which conflicts with SQLite under RefreshDatabase (SQLite does not support nested transactions). Before generating any test, read phpunit.xml in the project root and confirm DB_CONNECTION is set to mysql. If it is set to sqlite, update it to mysql before proceeding.

File Creation

Run these commands from the project root first — AI edits the generated stubs, never creates from scratch:

php artisan module:make-test {ModelName}MutationTest {ModuleName}
php artisan module:make-test {ModelName}QueryTest {ModuleName}

Creates both {ModelName}MutationTest.php and {ModelName}QueryTest.php.

Why

Tests are scoped per module so they run independently and travel with the module. Separating mutation tests from query tests keeps each class focused and easy to scan. MySQL matches the production database — SQLite has subtle differences in type handling, JSON support, and transaction behaviour that can mask real bugs.

Conventions

File Location

Modules/{ModuleName}/Tests/Feature/{ModelName}MutationTest.php
Modules/{ModuleName}/Tests/Feature/{ModelName}QueryTest.php

Class Structure

namespace Modules\{Module}\Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Nuwave\Lighthouse\Testing\MakesGraphQLRequests;
use Tests\TestCase;

class {Model}MutationTest extends TestCase
{
    use RefreshDatabase, MakesGraphQLRequests;
}
  • Extends Tests\TestCase — the project base class
  • Always use RefreshDatabase — never share state between tests
  • Always use MakesGraphQLRequests — gives access to $this->graphQL()
  • Auth via $this->actingAs($user) before the request

Required Coverage — Mutations

For every mutation (create, update, delete, custom):

TestWhat to assert
Happy pathstatus: true, correct message, data fields present
Validation errorMissing or invalid input returns GraphQL validation error
UnauthorizedUnauthenticated request returns Unauthenticated. error
DB rollbackForced failure does NOT persist data — assert DB count unchanged

Required Coverage — Queries

TestWhat to assert
Paginated listingReturns data array and paginatorInfo fields
ListingReturns correct array of records
Detail — foundReturns correct model fields
Detail — not foundReturns a GraphQL error
UnauthorizedUnauthenticated request returns Unauthenticated. error

GraphQL Mutation Pattern

$user = User::factory()->create();
$this->actingAs($user);

$response = $this->graphQL('
    mutation {
        createPost(input: { title: "Test Title", body: "Body text", user_id: ' . $user->id . ' }) {
            status
            message
            data {
                id
                title
            }
        }
    }
');

$response->assertJson([
    'data' => [
        'createPost' => [
            'status'  => true,
            'message' => 'Successfully created a post.',
        ],
    ],
]);

GraphQL Query Pattern

$user = User::factory()->create();
$this->actingAs($user);

$response = $this->graphQL('
    {
        paginatedPosts(first: 10) {
            data { id title }
            paginatorInfo { total currentPage }
        }
    }
');

$response->assertJsonStructure([
    'data' => [
        'paginatedPosts' => [
            'data'          => [['id', 'title']],
            'paginatorInfo' => ['total', 'currentPage'],
        ],
    ],
]);

Unauthorized Pattern

// Do NOT call actingAs — send unauthenticated request
$response = $this->graphQL('mutation { createPost(input: { title: "x" }) { status } }');
$response->assertGraphQLErrorMessage('Unauthenticated.');

Validation Error Pattern

$this->actingAs(User::factory()->create());

$response = $this->graphQL('mutation { createPost(input: { title: "" }) { status } }');
$response->assertGraphQLValidationError('input.title', 'The title field is required.');

DB Rollback Pattern

// Assert record count is unchanged after a forced failure
$this->assertDatabaseCount('posts', 0);

setUp Pattern

Use setUp() to create shared fixtures across methods in the same class:

protected function setUp(): void
{
    parent::setUp();
    $this->user = User::factory()->create();
}

Non-Negotiables

  • Always RefreshDatabase — never let data bleed between tests
  • Always MySQL — never SQLite; verify phpunit.xml before writing tests and flag if DB_CONNECTION=sqlite is set
  • Always MakesGraphQLRequests — never use raw HTTP for GraphQL
  • Always test unauthorized access — never assume @guard works without a test
  • Always test validation — every required field must have a missing/invalid case
  • Never hardcode IDs — always use factory-created model IDs
  • paginatedListing tests must assert paginatorInfo
  • detail tests must cover both found and not-found cases

Clarifying Questions

  • What is the module and model name?
  • What mutations exist? (determines MutationTest methods)
  • What queries exist? (determines QueryTest methods)
  • What fields does each input require? (determines validation cases)
  • Is there a User factory already set up?

Reference

@references/TEST.md

Keep looking

Skills are one crate of 626,474. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.