一键导入
goravel-crud-test
Generate and fix comprehensive CRUD tests for a Goravel entity. Covers all CRUD operations, sorting, pagination, search, and permissions.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Generate and fix comprehensive CRUD tests for a Goravel entity. Covers all CRUD operations, sorting, pagination, search, and permissions.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Create a broadcast notification system that sends notifications and messages to eligible users based on entity-specific criteria. Use when adding a new entity type that needs to notify users when records are created, updated, or published.
Guide for building non-CRUD pages with consistent design. Use when creating portal pages, custom views, detail modals, sidebar widgets, notification drawers, or any page that is not a standard CRUD table. Covers fullscreen modals, minimal text patterns, calendar widgets, doorbell notifications, optimistic updates, and CrudPage read-only integration.
Guide for building dashboards, charts, KPI cards, and data visualizations. Use when creating dashboard pages, adding charts to features, building stat displays, aggregating data for visual presentation, or implementing export (CSV/PNG/fullscreen) for charts. Based on the Books dashboard implementation using Recharts and shadcn/ui chart components.
Deploy the application to staging or production. Validates, builds, pushes Docker image, deploys via Helm, and runs smoke tests.
Run a comprehensive E2E browser test suite for a newly scaffolded Goravel entity. Tests navigation, CRUD operations, search, filters, row actions, form validation, FK dropdowns, and cross-entity integration using Playwright MCP.
Create a Go database seeder for a Goravel entity with 25+ realistic records. Covers all status/enum values, diverse data for sorting/pagination testing, and proper nullable field handling.
| name | goravel-crud-test |
| description | Generate and fix comprehensive CRUD tests for a Goravel entity. Covers all CRUD operations, sorting, pagination, search, and permissions. |
| argument-hint | [EntityName] |
| allowed-tools | Bash, Read, Write, Edit, Grep, Glob |
Generate tests for $ARGUMENTS.
go run . artisan make:crud-test --controller=$ARGUMENTS
This creates tests/feature/crud/<entity>_crud_test.go.
The generator produces a template with known issues. Fix in this order:
// WRONG (generator creates):
Slug: fmt.Sprintf("entitycontrollers_%s", perm)
// CORRECT (use service name from permission_constants.go):
Slug: fmt.Sprintf("entity_%s", perm)
Check app/auth/permission_constants.go for the exact ServiceRegistry value.
// WRONG (generator creates):
s.makeRequest("POST", "/api/entitycontrollers", data)
// CORRECT (use hyphenated plural from routes/api.go):
s.makeRequest("POST", "/api/entity-names", data)
// WRONG:
orm.Query().Exec("DELETE FROM entitycontrollers")
// CORRECT:
orm.Query().Exec("DELETE FROM entity_names")
API request payloads MUST use snake_case keys (matching request struct form/json tags):
func (s *TestSuite) TestCreateEntity() {
data := map[string]interface{}{
"first_name": "Test", // snake_case — NOT "firstName"
"last_name": "Entity", // snake_case — NOT "lastName"
"description": "A test",
"status": "ACTIVE",
"birth_date": "1990-01-15", // snake_case — NOT "birthDate"
"tags": []string{"tag1"}, // Include arrays
}
resp, result := s.makeRequest("POST", "/api/entities", data)
s.Equal(http.StatusCreated, resp.StatusCode)
}
API responses return camelCase (from model json tags), so assertions use camelCase:
data := result["data"].(map[string]interface{})
s.Equal("Test", data["firstName"]) // camelCase in response
entity := &models.Entity{
Title: "Test",
Description: "Test",
Tags: []string{}, // MUST initialize arrays - NOT NULL constraint
CreatedBy: &createdByInt,
}
Common error: NOT NULL constraint failed: table.array_field
Fix: Always initialize JSON array fields to []string{} or []int{}.
// Create date for test data:
date := *carbon.NewDateTime(carbon.Parse("2025-12-01"))
entity := &models.Entity{
Date: date, // Non-pointer carbon.DateTime
}
If entity has foreign keys, create parents in setup:
func (s *TestSuite) SetupTest() {
s.RefreshDatabase()
s.setupTestUser()
// Create parent entity
parent := &models.Parent{Name: "Test Parent"}
s.Nil(facades.Orm().Query().Create(parent))
s.testParent = parent
}
The test suite's s.client has a cookie jar that holds the auth token from SetupTest() login. For unauthenticated tests, you MUST use a separate client without the cookie jar:
func (s *TestSuite) makeUnauthenticatedRequest(method, path string, body interface{}) (*http.Response, map[string]interface{}) {
// ... build request ...
// MUST use fresh client — s.client's cookie jar auto-sends auth token
unauthClient := &http.Client{
Timeout: 10 * time.Second,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
resp, err := unauthClient.Do(req)
// ...
}
The JWT middleware returns 302 redirect (not 401/403) for unauthenticated non-Inertia API requests. Test assertions should use NotEqual against success codes:
resp, _ := s.makeUnauthenticatedRequest("POST", "/api/entities", data)
s.NotEqual(http.StatusCreated, resp.StatusCode,
"Unauthenticated request should not create an entity")
TimestampsTz() creates timestamp(0) columns — second precision only. Records created within the same second have identical timestamps, making sort order indeterminate. Don't rely on millisecond sleeps for ordering:
// WRONG — 10ms sleep doesn't help with timestamp(0) precision
s.createTestEntity("First")
time.Sleep(10 * time.Millisecond)
s.createTestEntity("Second")
// CORRECT — use deterministic fields (name, ID) for sort order tests
// or accept any valid result for timestamp sorts
func (s *TestSuite) TestReadOnlyFieldCannotBeSet() {
data := s.getValidData()
data["score"] = 99 // Try to set read-only field
resp, result := s.makeRequest("POST", "/api/entities", data)
s.Equal(http.StatusCreated, resp.StatusCode)
var entity models.Entity
facades.Orm().Query().Find(&entity, result["data"].(map[string]interface{})["id"])
s.Equal(0, entity.Score, "read-only field should NOT be settable")
}
Before running tests, ensure the test file compiles:
go vet ./tests/feature/crud/...
APP_ENV=testing go test -v ./tests/feature/crud -run Test<Entity>CRUDTestSuite
Fix each failure, re-run, iterate until all pass.
After ALL tests pass, proceed to frontend work:
/inertia-types to create TypeScript types and i18n translations/inertia-scaffold to generate all frontend components at onceDo NOT start UI work until all CRUD tests pass. Backend bugs (Bind issues, validation key mismatches, GORM mapping errors) are much easier to catch and fix via API tests than through the UI.