base-api-scramble-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,355 @@
1
+ # KONTEKS & TUJUAN
2
+ Anda adalah Laravel Testing Expert. Tugas Anda: membuat automated feature tests untuk semua module/endpoint API di aplikasi Laravel, dengan pendekatan sistematis dan problem-solving otomatis.
3
+
4
+ # AUTHENTICATION & AUTHORIZATION
5
+
6
+ ## Default Test Account
7
+ Aplikasi ini memiliki akun default dari seeder untuk testing:
8
+ - **Email:** admin@gmail.com
9
+ - **Password:** password
10
+
11
+ ## Cara Mendapatkan Token untuk Authenticated Requests
12
+ ```php
13
+ // Di dalam test method atau setUp()
14
+ $response = $this->postJson('/api/v1/login', [
15
+ 'email' => 'admin@gmail.com',
16
+ 'password' => 'password',
17
+ ]);
18
+
19
+ $this->token = $response->json('token');
20
+ ```
21
+
22
+ ## Penggunaan Token dalam Request
23
+ ```php
24
+ // Untuk endpoint yang memerlukan authentication
25
+ $response = $this->withHeaders([
26
+ 'Authorization' => 'Bearer ' . $this->token,
27
+ ])->getJson('/api/v1/endpoint');
28
+
29
+ // ATAU menggunakan method helper (jika tersedia)
30
+ $response = $this->withToken($this->token)
31
+ ->getJson('/api/v1/endpoint');
32
+ ```
33
+
34
+ ## Template Test Class dengan Authentication
35
+ ```php
36
+ <?php
37
+
38
+ namespace Tests\Feature;
39
+
40
+ use Tests\TestCase;
41
+ use Illuminate\Foundation\Testing\RefreshDatabase;
42
+ use App\Models\{ModelName};
43
+
44
+ class {ModuleName}Test extends TestCase
45
+ {
46
+ use RefreshDatabase;
47
+
48
+ protected string $token;
49
+
50
+ protected function setUp(): void
51
+ {
52
+ parent::setUp();
53
+
54
+ // Seed database (jika diperlukan)
55
+ $this->seed();
56
+
57
+ // Get authentication token
58
+ $response = $this->postJson('/api/v1/login', [
59
+ 'email' => 'admin@gmail.com',
60
+ 'password' => 'password',
61
+ ]);
62
+
63
+ $this->token = $response->json('token');
64
+ }
65
+
66
+ /** @test */
67
+ public function it_can_list_{module}_with_pagination()
68
+ {
69
+ $response = $this->withHeaders([
70
+ 'Authorization' => 'Bearer ' . $this->token,
71
+ ])->getJson('/api/v1/{endpoint}');
72
+
73
+ $response->assertStatus(200);
74
+ // ... assertions lainnya
75
+ }
76
+
77
+ // ... test methods lainnya
78
+ }
79
+ ```
80
+
81
+ ## Strategi Authentication dalam Test
82
+
83
+ 1. **Setup Method (Recommended):**
84
+ - Login sekali di `setUp()` untuk semua test dalam class
85
+ - Efisien untuk multiple test methods
86
+ - Token tersedia di semua test methods via `$this->token`
87
+
88
+ 2. **Per Test Method:**
89
+ - Login di setiap test method jika butuh kondisi berbeda
90
+ - Gunakan jika test memerlukan user dengan role/permission berbeda
91
+
92
+ 3. **Helper Method (Optional):**
93
+ ```php
94
+ protected function authenticatedRequest(string $method, string $uri, array $data = [])
95
+ {
96
+ return $this->withHeaders([
97
+ 'Authorization' => 'Bearer ' . $this->token,
98
+ ])->json($method, $uri, $data);
99
+ }
100
+
101
+ // Penggunaan:
102
+ $response = $this->authenticatedRequest('GET', '/api/v1/endpoint');
103
+ ```
104
+
105
+ # LANGKAH KERJA SISTEMATIS
106
+
107
+ ## FASE 1: DISCOVERY & MAPPING
108
+ 1. Jalankan `php artisan route:list --json` untuk mendapatkan daftar lengkap routes
109
+ 2. Identifikasi routes yang memerlukan authentication (middleware: auth, auth:sanctum, dll)
110
+ 3. Kelompokkan routes berdasarkan module/resource (prefix atau controller)
111
+ 4. Identifikasi struktur CRUD untuk setiap module:
112
+ - Index/List (GET)
113
+ - Show/Detail (GET)
114
+ - Store/Create (POST)
115
+ - Update (PUT/PATCH)
116
+ - Delete (DELETE)
117
+ - Custom endpoints lainnya
118
+
119
+ ## FASE 2: ANALISIS PER MODULE
120
+ Sebelum membuat test untuk setiap module, lakukan analisis:
121
+
122
+ 1. **Authentication Requirements:**
123
+ - Cek apakah endpoint memerlukan authentication
124
+ - Identifikasi middleware yang digunakan (auth:sanctum, auth:api, dll)
125
+ - Catat jika ada role/permission tertentu yang diperlukan
126
+
127
+ 2. **Request Requirements:**
128
+ - Buka file FormRequest atau validasi di Controller
129
+ - Catat semua field yang required, optional, dan rule validasinya
130
+ - Identifikasi field relationship (belongsTo, hasMany, dll)
131
+
132
+ 3. **Response Structure:**
133
+ - Periksa struktur response dari Controller/Resource
134
+ - Identifikasi field yang di-return di response JSON
135
+ - Catat struktur nested data (relationships yang di-load)
136
+
137
+ 4. **Dependencies:**
138
+ - Identifikasi model dependencies (foreign keys)
139
+ - Tentukan urutan factory/seeding yang diperlukan
140
+ - Catat middleware atau authorization yang digunakan
141
+
142
+ ## FASE 3: IMPLEMENTASI TEST PER MODULE
143
+
144
+ Untuk setiap module, buat test file dengan struktur lengkap:
145
+
146
+ ### Template Test Structure:
147
+ ```php
148
+ <?php
149
+
150
+ namespace Tests\Feature;
151
+
152
+ use Tests\TestCase;
153
+ use Illuminate\Foundation\Testing\RefreshDatabase;
154
+ use App\Models\{ModelName};
155
+ // Import models lain yang dibutuhkan
156
+
157
+ class {ModuleName}Test extends TestCase
158
+ {
159
+ use RefreshDatabase;
160
+
161
+ protected string $token;
162
+
163
+ protected function setUp(): void
164
+ {
165
+ parent::setUp();
166
+
167
+ // Seed database (pastikan UserSeeder dijalankan)
168
+ $this->seed();
169
+
170
+ // Login to get authentication token
171
+ $response = $this->postJson('/api/v1/login', [
172
+ 'email' => 'admin@gmail.com',
173
+ 'password' => 'password',
174
+ ]);
175
+
176
+ $this->token = $response->json('token');
177
+ }
178
+
179
+ /** @test */
180
+ public function it_requires_authentication()
181
+ {
182
+ // Test tanpa token harus return 401
183
+ $response = $this->getJson('/api/v1/{endpoint}');
184
+ $response->assertStatus(401);
185
+ }
186
+
187
+ /** @test */
188
+ public function it_can_list_{module}_with_pagination()
189
+ {
190
+ // Setup: Create sample data
191
+ // Act: Hit endpoint with token
192
+ $response = $this->withHeaders([
193
+ 'Authorization' => 'Bearer ' . $this->token,
194
+ ])->getJson('/api/v1/{endpoint}');
195
+
196
+ // Assert: Check response structure, pagination, data
197
+ $response->assertStatus(200);
198
+ }
199
+
200
+ /** @test */
201
+ public function it_can_show_{module}_detail()
202
+ {
203
+ // Test dengan data valid dan token
204
+ }
205
+
206
+ /** @test */
207
+ public function it_returns_404_when_{module}_not_found()
208
+ {
209
+ // Test edge case dengan authentication
210
+ }
211
+
212
+ /** @test */
213
+ public function it_can_create_{module}_with_valid_data()
214
+ {
215
+ // Setup: Prepare valid payload sesuai FormRequest
216
+ $payload = [
217
+ // ... data sesuai validation rules
218
+ ];
219
+
220
+ // Act: POST request with authentication
221
+ $response = $this->withHeaders([
222
+ 'Authorization' => 'Bearer ' . $this->token,
223
+ ])->postJson('/api/v1/{endpoint}', $payload);
224
+
225
+ // Assert: Check 201, response structure, database
226
+ $response->assertStatus(201);
227
+ }
228
+
229
+ /** @test */
230
+ public function it_validates_required_fields_when_creating_{module}()
231
+ {
232
+ // Test validation untuk setiap required field dengan auth
233
+ $response = $this->withHeaders([
234
+ 'Authorization' => 'Bearer ' . $this->token,
235
+ ])->postJson('/api/v1/{endpoint}', []);
236
+
237
+ $response->assertStatus(422);
238
+ }
239
+
240
+ /** @test */
241
+ public function it_can_update_{module}_with_valid_data()
242
+ {
243
+ // Test update dengan partial/full data dan authentication
244
+ }
245
+
246
+ /** @test */
247
+ public function it_can_delete_{module}()
248
+ {
249
+ // Test soft delete atau hard delete dengan authentication
250
+ }
251
+
252
+ // Tambahkan test untuk custom endpoints jika ada
253
+ }
254
+ ```
255
+
256
+ ### Assertion Checklist untuk Setiap Test:
257
+ - ✅ Authentication check (401 without token)
258
+ - ✅ HTTP Status Code (200, 201, 204, 404, 422, dll)
259
+ - ✅ Response JSON structure (`assertJsonStructure`)
260
+ - ✅ Response data accuracy (`assertJsonFragment`, `assertJson`)
261
+ - ✅ Database changes (`assertDatabaseHas`, `assertDatabaseMissing`)
262
+ - ✅ Database count (`assertDatabaseCount`)
263
+ - ✅ Validation error messages (untuk negative tests)
264
+
265
+ ## FASE 4: PROBLEM SOLVING OTOMATIS
266
+
267
+ Jika test GAGAL, lakukan troubleshooting sistematis:
268
+
269
+ 1. **Analisis Error Message:**
270
+ - Baca error stack trace dengan teliti
271
+ - Identifikasi root cause (validation, missing data, logic error, auth issue)
272
+
273
+ 2. **Authentication Issues:**
274
+ - Jika error 401: Pastikan token sudah diset dengan benar
275
+ - Jika error 403: Check role/permission requirements
276
+ - Jika token null: Pastikan seeder sudah dijalankan dan login berhasil
277
+ - Verify endpoint login (`/api/v1/login`) dan token location di response
278
+
279
+ 3. **Perbaikan Bertahap:**
280
+ - Jika authentication error: Periksa token dan header Authorization
281
+ - Jika validation error: Sesuaikan payload dengan FormRequest rules
282
+ - Jika database error: Periksa foreign key constraints dan dependencies
283
+ - Jika response mismatch: Update assertion atau perbaiki Controller
284
+
285
+ 4. **Iterasi & Verifikasi:**
286
+ - Perbaiki satu issue pada satu waktu
287
+ - Re-run test setelah setiap perbaikan
288
+ - Jika masih gagal, cek file Controller dan Model terkait
289
+ - Dokumentasikan perubahan yang dilakukan
290
+
291
+ 5. **Edge Cases:**
292
+ - Test tanpa authentication (should return 401)
293
+ - Test dengan invalid/expired token
294
+ - Test dengan data kosong
295
+ - Test dengan data invalid (wrong type, format)
296
+ - Test dengan foreign key yang tidak exist
297
+ - Test authorization (jika ada role/permission)
298
+
299
+ ## FASE 5: EKSEKUSI BERTAHAP
300
+
301
+ **PENTING - RULES EKSEKUSI:**
302
+ 1. ⚠️ Pastikan seeder sudah dijalankan (`$this->seed()` atau `php artisan db:seed`)
303
+ 2. ⚠️ Verify akun admin@gmail.com tersedia dan bisa login
304
+ 3. ⚠️ Kerjakan SATU module FULL hingga SEMUA test PASS
305
+ 4. ⚠️ Jangan lanjut ke module berikutnya jika masih ada test yang FAILED
306
+ 5. ⚠️ Jalankan `php artisan test --filter={ModuleName}Test` untuk verifikasi
307
+ 6. ⚠️ Setelah ALL PASS, commit perubahan sebelum lanjut module berikutnya
308
+ 7. ⚠️ Ulangi proses untuk module berikutnya
309
+
310
+ ## FASE 6: REPORTING
311
+
312
+ Setelah menyelesaikan setiap module, buat summary:
313
+ ```
314
+ ✅ Module: {Nama Module}
315
+ - Total Endpoints: X
316
+ - Total Tests: X (including authentication tests)
317
+ - Status: ALL PASSED
318
+ - Coverage: Authentication + List/Show/Create/Update/Delete + custom endpoints
319
+ - Waktu Eksekusi: X seconds
320
+ - Authentication: ✅ Token-based (Sanctum/Passport)
321
+ ```
322
+
323
+ # MODULE YANG DIABAIKAN (SKIP)
324
+ - User
325
+ - Permissions
326
+ - Roles
327
+ - Telescope
328
+ - Activity Log
329
+ - Post
330
+ - Label
331
+
332
+ Jika menemukan routes dari module ini, SKIP dan lanjut ke module berikutnya.
333
+
334
+ # OUTPUT YANG DIHARAPKAN
335
+ 1. Test file PHP yang executable dan comprehensive
336
+ 2. Semua test PASS tanpa error
337
+ 3. Authentication handling yang proper di setiap test
338
+ 4. Coverage minimal: Authentication check + CRUD lengkap per module
339
+ 5. Code yang clean, readable, dan well-documented
340
+ 6. Problem solving dilakukan secara otomatis hingga test berhasil
341
+
342
+ # VALIDASI AKHIR
343
+ Sebelum declare selesai:
344
+ - [ ] Seeder berhasil dijalankan dan akun admin tersedia
345
+ - [ ] Login endpoint working dan return token dengan benar
346
+ - [ ] Token digunakan di semua authenticated requests
347
+ - [ ] Semua module (kecuali yang di-skip) sudah memiliki test
348
+ - [ ] Semua test berstatus PASSED
349
+ - [ ] Authentication tests included (401 without token)
350
+ - [ ] Response structure sesuai dengan actual API
351
+ - [ ] Request payload sesuai dengan validation rules
352
+ - [ ] Database assertions akurat
353
+ - [ ] Jalankan `php artisan test` untuk final check
354
+
355
+ Mulai dengan menjalankan `php artisan route:list --json` dan laporkan hasilnya.
@@ -0,0 +1,215 @@
1
+ # Make Export Excel Command
2
+
3
+ Command untuk generate controller dan DataProvider export Excel secara otomatis.
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ php artisan make:export-excel {namaExport}
9
+ ```
10
+
11
+ ### Contoh
12
+
13
+ ```bash
14
+ php artisan make:export-excel Category
15
+ ```
16
+
17
+ Akan menghasilkan:
18
+ - **DataProvider**: `app/Exports/DataProviders/CategoryExportDataProvider.php`
19
+ - **Controller**: `app/Http/Controllers/Api/V1/CategoryExportController.php`
20
+
21
+ ## File yang di-generate
22
+
23
+ ### 1. DataProvider (`CategoryExportDataProvider.php`)
24
+
25
+ DataProvider akan otomatis:
26
+ - Membaca data dari model yang sesuai (misal: `Category` model)
27
+ - Menyediakan method `getRawData()` untuk query data
28
+ - Menyediakan method `getHeaders()` untuk header kolom
29
+ - Menyediakan method `getDataMapper()` untuk mapping data
30
+ - Support filtering via Request (search, status, dll)
31
+
32
+ **Contoh struktur:**
33
+ ```php
34
+ namespace App\Exports\DataProviders;
35
+
36
+ use App\Models\Category;
37
+ use Illuminate\Http\Request;
38
+
39
+ class CategoryExportDataProvider implements ExportDataProviderInterface
40
+ {
41
+ private Request $request;
42
+
43
+ public function __construct(Request $request)
44
+ {
45
+ $this->request = $request;
46
+ }
47
+
48
+ public function getRawData($filters = null): array
49
+ {
50
+ $query = Category::query();
51
+
52
+ // Apply filters dari request
53
+ if ($this->request->filled('search')) {
54
+ $query->where('name', 'like', '%' . $this->request->search . '%');
55
+ }
56
+
57
+ return $query->get()->toArray();
58
+ }
59
+
60
+ public function getHeaders(): array
61
+ {
62
+ return ['ID', 'Name', 'Created At', 'Updated At'];
63
+ }
64
+
65
+ public function getDataMapper(): array
66
+ {
67
+ return [
68
+ 'id',
69
+ 'name',
70
+ 'created_at' => function($item) {
71
+ return date('Y-m-d H:i:s', strtotime($item['created_at']));
72
+ },
73
+ 'updated_at' => function($item) {
74
+ return date('Y-m-d H:i:s', strtotime($item['updated_at']));
75
+ },
76
+ ];
77
+ }
78
+
79
+ public function getOptions(): array
80
+ {
81
+ return [
82
+ 'report_title' => 'Category Export Report',
83
+ 'include_summary' => true,
84
+ 'auto_size' => true,
85
+ 'bold_header' => true,
86
+ 'freeze_header' => true,
87
+ ];
88
+ }
89
+ }
90
+ ```
91
+
92
+ ### 2. Controller (`CategoryExportController.php`)
93
+
94
+ Controller akan otomatis:
95
+ - Berada di namespace `App\Http\Controllers\Api\V1`
96
+ - Memiliki method `export(Request $request)`
97
+ - Menggunakan DataProvider untuk get data
98
+ - Menggunakan `FlexibleExport` template
99
+ - Support download langsung atau save to file
100
+
101
+ **Contoh struktur:**
102
+ ```php
103
+ namespace App\Http\Controllers\Api\V1;
104
+
105
+ use App\Http\Controllers\Controller;
106
+ use App\Exports\Templates\FlexibleExport;
107
+ use App\Exports\DataProviders\CategoryExportDataProvider;
108
+ use Illuminate\Http\Request;
109
+
110
+ class CategoryExportController extends Controller
111
+ {
112
+ public function export(Request $request)
113
+ {
114
+ try {
115
+ $provider = new CategoryExportDataProvider($request);
116
+
117
+ $rawData = $provider->getRawData();
118
+ $headers = $provider->getHeaders();
119
+ $dataMapper = $provider->getDataMapper();
120
+ $options = $provider->getOptions();
121
+
122
+ $export = FlexibleExport::create($rawData, $headers, array_merge($options, [
123
+ 'data_mapper' => $dataMapper
124
+ ]));
125
+
126
+ if ($request->boolean('download', true)) {
127
+ return $export->download();
128
+ } else {
129
+ $filePath = $export->toFile();
130
+ return response()->json([
131
+ 'success' => true,
132
+ 'message' => 'Category export created successfully',
133
+ 'file_path' => $filePath,
134
+ 'filename' => $export->getFilename()
135
+ ]);
136
+ }
137
+ } catch (\Exception $e) {
138
+ return response()->json([
139
+ 'success' => false,
140
+ 'message' => 'Export failed: ' . $e->getMessage()
141
+ ], 500);
142
+ }
143
+ }
144
+ }
145
+ ```
146
+
147
+ ## Langkah Setelah Generate
148
+
149
+ 1. **Pastikan Model Ada**
150
+ - Command akan menggunakan nama yang sama untuk model
151
+ - Contoh: `make:export-excel Category` akan menggunakan model `App\Models\Category`
152
+
153
+ 2. **Tambahkan Route**
154
+
155
+ Edit file `routes/api_v1.php`:
156
+ ```php
157
+ use App\Http\Controllers\Api\V1\CategoryExportController;
158
+
159
+ Route::get('categories/export', [CategoryExportController::class, 'export']);
160
+ ```
161
+
162
+ 3. **Customize DataProvider** (Optional)
163
+
164
+ Sesuaikan logic di DataProvider:
165
+ - Tambah filter custom
166
+ - Ubah field yang di-export
167
+ - Sesuaikan header
168
+ - Tambah relationship jika perlu
169
+
170
+ ## Contoh Penggunaan API
171
+
172
+ ### Export dengan download langsung
173
+ ```bash
174
+ GET /api/v1/categories/export
175
+ ```
176
+
177
+ ### Export save to file
178
+ ```bash
179
+ GET /api/v1/categories/export?download=false
180
+ ```
181
+
182
+ ### Export dengan filter
183
+ ```bash
184
+ GET /api/v1/categories/export?search=electronics
185
+ ```
186
+
187
+ ## Fitur
188
+
189
+ ✅ Auto-generate DataProvider dengan model binding
190
+ ✅ Auto-generate Controller di folder `api/v1`
191
+ ✅ Support filtering via Request
192
+ ✅ Support download atau save to file
193
+ ✅ Menggunakan FlexibleExport template
194
+ ✅ Include header styling (bold, freeze)
195
+ ✅ Auto-size columns
196
+ ✅ Customizable data mapping
197
+
198
+ ## Tips
199
+
200
+ 1. **Naming Convention**:
201
+ - Command akan menghapus suffix "Export" jika ada
202
+ - `make:export-excel CategoryExport` = `make:export-excel Category`
203
+
204
+ 2. **Model Detection**:
205
+ - Model harus ada di `App\Models\{Name}`
206
+ - Pastikan model sudah dibuat sebelumnya
207
+
208
+ 3. **Customization**:
209
+ - Edit DataProvider untuk logic export yang lebih complex
210
+ - Tambah relationship dengan eager loading
211
+ - Tambah filter custom sesuai kebutuhan
212
+
213
+ 4. **Route Naming**:
214
+ - Recommended format: `{plural-resource}/export`
215
+ - Example: `products/export`, `users/export`, `categories/export`