Skip to content

Commit d19b24f

Browse files
committed
improve coverage
1 parent 7f9a3f4 commit d19b24f

File tree

2 files changed

+387
-23
lines changed

2 files changed

+387
-23
lines changed
Lines changed: 387 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,387 @@
1+
<?php
2+
3+
/**
4+
* SPDX-License-Identifier: MIT
5+
* Copyright (c) 2017-2018 Tobias Reich
6+
* Copyright (c) 2018-2025 LycheeOrg.
7+
*/
8+
9+
/**
10+
* We don't care for unhandled exceptions in tests.
11+
* It is the nature of a test to throw an exception.
12+
* Without this suppression we had 100+ Linter warning in this file which
13+
* don't help anything.
14+
*
15+
* @noinspection PhpDocMissingThrowsInspection
16+
* @noinspection PhpUnhandledExceptionInspection
17+
*/
18+
19+
namespace Tests\Webshop;
20+
21+
use App\Enum\PaymentStatusType;
22+
use App\Models\Order;
23+
use App\Models\OrderItem;
24+
use Illuminate\Support\Str;
25+
26+
/**
27+
* Test class for OrderController markAsDelivered functionality.
28+
*
29+
* This class tests the order mark as delivered (closed) functionality:
30+
* - Marking completed orders as delivered with proper authorization
31+
* - Handling different order statuses
32+
* - Authentication and authorization checks
33+
* - Invalid order handling
34+
*/
35+
class OrderControllerMarkAsDeliveredTest extends BaseCheckoutControllerTest
36+
{
37+
/**
38+
* Test marking a completed order as delivered from completed status.
39+
*
40+
* @return void
41+
*/
42+
public function testMarkCompletedOrderAsDelivered(): void
43+
{
44+
$this->test_order->status = PaymentStatusType::COMPLETED;
45+
$this->test_order->save();
46+
47+
$response = $this->actingAs($this->admin)
48+
->putJson('Shop/Order/' . $this->test_order->id);
49+
50+
$this->assertNoContent($response);
51+
52+
$this->assertDatabaseHas('orders', [
53+
'id' => $this->test_order->id,
54+
'status' => PaymentStatusType::CLOSED->value,
55+
]);
56+
}
57+
58+
/**
59+
* Test marking order as delivered without authentication.
60+
*
61+
* @return void
62+
*/
63+
public function testMarkOrderAsDeliveredWithoutAuth(): void
64+
{
65+
$this->test_order->status = PaymentStatusType::COMPLETED;
66+
$this->test_order->save();
67+
68+
$response = $this->putJson('Shop/Order/' . $this->test_order->id);
69+
70+
$this->assertUnauthorized($response);
71+
72+
// Verify status wasn't changed
73+
$this->assertDatabaseHas('orders', [
74+
'id' => $this->test_order->id,
75+
'status' => PaymentStatusType::COMPLETED->value,
76+
]);
77+
}
78+
79+
/**
80+
* Test marking order as delivered as non-admin user.
81+
*
82+
* @return void
83+
*/
84+
public function testMarkOrderAsDeliveredAsNonAdmin(): void
85+
{
86+
$this->test_order->status = PaymentStatusType::COMPLETED;
87+
$this->test_order->save();
88+
89+
$response = $this->actingAs($this->userMayUpload1)
90+
->putJson('Shop/Order/' . $this->test_order->id);
91+
92+
$this->assertForbidden($response);
93+
94+
// Verify status wasn't changed
95+
$this->assertDatabaseHas('orders', [
96+
'id' => $this->test_order->id,
97+
'status' => PaymentStatusType::COMPLETED->value,
98+
]);
99+
}
100+
101+
/**
102+
* Test marking order as delivered with non-existent order ID.
103+
*
104+
* @return void
105+
*/
106+
public function testMarkNonExistentOrderAsDelivered(): void
107+
{
108+
$non_existent_id = 99999;
109+
110+
$response = $this->actingAs($this->admin)
111+
->putJson('Shop/Order/' . $non_existent_id);
112+
113+
$this->assertNotFound($response);
114+
}
115+
116+
/**
117+
* Test marking order as delivered with invalid order ID format.
118+
*
119+
* @return void
120+
*/
121+
public function testMarkOrderAsDeliveredWithInvalidId(): void
122+
{
123+
$response = $this->actingAs($this->admin)
124+
->putJson('Shop/Order/invalid-id');
125+
126+
$this->assertUnprocessable($response);
127+
$response->assertJsonValidationErrors(['order_id']);
128+
}
129+
130+
/**
131+
* Test marking a pending order as delivered (should fail).
132+
*
133+
* @return void
134+
*/
135+
public function testMarkPendingOrderAsDelivered(): void
136+
{
137+
$this->test_order->status = PaymentStatusType::PENDING;
138+
$this->test_order->save();
139+
140+
$response = $this->actingAs($this->admin)
141+
->putJson('Shop/Order/' . $this->test_order->id);
142+
143+
$this->assertNotFound($response);
144+
145+
// Verify status wasn't changed
146+
$this->assertDatabaseHas('orders', [
147+
'id' => $this->test_order->id,
148+
'status' => PaymentStatusType::PENDING->value,
149+
]);
150+
}
151+
152+
/**
153+
* Test marking an offline order as delivered (should fail).
154+
*
155+
* @return void
156+
*/
157+
public function testMarkOfflineOrderAsDelivered(): void
158+
{
159+
$this->test_order->status = PaymentStatusType::OFFLINE;
160+
$this->test_order->save();
161+
162+
$response = $this->actingAs($this->admin)
163+
->putJson('Shop/Order/' . $this->test_order->id);
164+
165+
$this->assertNotFound($response);
166+
167+
// Verify status wasn't changed
168+
$this->assertDatabaseHas('orders', [
169+
'id' => $this->test_order->id,
170+
'status' => PaymentStatusType::OFFLINE->value,
171+
]);
172+
}
173+
174+
/**
175+
* Test marking a cancelled order as delivered (should fail).
176+
*
177+
* @return void
178+
*/
179+
public function testMarkCancelledOrderAsDelivered(): void
180+
{
181+
$this->test_order->status = PaymentStatusType::CANCELLED;
182+
$this->test_order->save();
183+
184+
$response = $this->actingAs($this->admin)
185+
->putJson('Shop/Order/' . $this->test_order->id);
186+
187+
$this->assertNotFound($response);
188+
189+
// Verify status wasn't changed
190+
$this->assertDatabaseHas('orders', [
191+
'id' => $this->test_order->id,
192+
'status' => PaymentStatusType::CANCELLED->value,
193+
]);
194+
}
195+
196+
/**
197+
* Test marking a processing order as delivered (should fail).
198+
*
199+
* @return void
200+
*/
201+
public function testMarkProcessingOrderAsDelivered(): void
202+
{
203+
$this->test_order->status = PaymentStatusType::PROCESSING;
204+
$this->test_order->save();
205+
206+
$response = $this->actingAs($this->admin)
207+
->putJson('Shop/Order/' . $this->test_order->id);
208+
209+
$this->assertNotFound($response);
210+
211+
// Verify status wasn't changed
212+
$this->assertDatabaseHas('orders', [
213+
'id' => $this->test_order->id,
214+
'status' => PaymentStatusType::PROCESSING->value,
215+
]);
216+
}
217+
218+
/**
219+
* Test marking an already closed order as delivered (should fail).
220+
*
221+
* @return void
222+
*/
223+
public function testMarkClosedOrderAsDelivered(): void
224+
{
225+
$this->test_order->status = PaymentStatusType::CLOSED;
226+
$this->test_order->save();
227+
228+
$response = $this->actingAs($this->admin)
229+
->putJson('Shop/Order/' . $this->test_order->id);
230+
231+
$this->assertNotFound($response);
232+
233+
// Verify status wasn't changed
234+
$this->assertDatabaseHas('orders', [
235+
'id' => $this->test_order->id,
236+
'status' => PaymentStatusType::CLOSED->value,
237+
]);
238+
}
239+
240+
/**
241+
* Test that marking order as delivered preserves other order data.
242+
*
243+
* @return void
244+
*/
245+
public function testMarkOrderAsDeliveredPreservesOrderData(): void
246+
{
247+
// Set some existing data on the order
248+
$this->test_order->status = PaymentStatusType::COMPLETED;
249+
$this->test_order->comment = 'Test comment';
250+
$this->test_order->email = 'customer@example.com';
251+
$this->test_order->save();
252+
253+
$response = $this->actingAs($this->admin)
254+
->putJson('Shop/Order/' . $this->test_order->id);
255+
256+
$this->assertNoContent($response);
257+
258+
// Verify other data is preserved
259+
$this->assertDatabaseHas('orders', [
260+
'id' => $this->test_order->id,
261+
'status' => PaymentStatusType::CLOSED->value,
262+
'comment' => 'Test comment',
263+
'email' => 'customer@example.com',
264+
]);
265+
}
266+
267+
/**
268+
* Test marking order as delivered updates only the status field.
269+
*
270+
* @return void
271+
*/
272+
public function testMarkOrderAsDeliveredUpdatesOnlyStatus(): void
273+
{
274+
// Set order to completed status
275+
$this->test_order->status = PaymentStatusType::COMPLETED;
276+
$this->test_order->save();
277+
278+
$original_transaction_id = $this->test_order->transaction_id;
279+
$original_email = $this->test_order->email;
280+
$original_amount = $this->test_order->amount_cents;
281+
282+
$response = $this->actingAs($this->admin)
283+
->putJson('Shop/Order/' . $this->test_order->id);
284+
285+
$this->assertNoContent($response);
286+
287+
// Refresh order from database
288+
$this->test_order->refresh();
289+
290+
// Verify only status changed
291+
$this->assertEquals(PaymentStatusType::CLOSED, $this->test_order->status);
292+
$this->assertEquals($original_transaction_id, $this->test_order->transaction_id);
293+
$this->assertEquals($original_email, $this->test_order->email);
294+
$this->assertEquals($original_amount, $this->test_order->amount_cents);
295+
}
296+
297+
/**
298+
* Test marking multiple completed orders as delivered sequentially.
299+
*
300+
* @return void
301+
*/
302+
public function testMarkMultipleCompletedOrdersAsDelivered(): void
303+
{
304+
// Create additional completed orders
305+
$order2 = Order::factory()
306+
->withTransactionId(Str::uuid()->toString())
307+
->withEmail('test@example.com')
308+
->completed()
309+
->withAmountCents(1999)
310+
->create();
311+
OrderItem::factory()->forOrder($order2)->forPurchasable($this->purchasable1)->forPhoto($this->photo1)->fullSize()->create();
312+
313+
$order3 = Order::factory()
314+
->withTransactionId(Str::uuid()->toString())
315+
->withEmail('test@example.com')
316+
->completed()
317+
->withAmountCents(1999)
318+
->create();
319+
OrderItem::factory()->forOrder($order3)->forPurchasable($this->purchasable1)->forPhoto($this->photo1)->fullSize()->create();
320+
321+
// Set original test order to completed
322+
$this->test_order->status = PaymentStatusType::COMPLETED;
323+
$this->test_order->save();
324+
325+
// Mark all orders as delivered
326+
$response1 = $this->actingAs($this->admin)
327+
->putJson('Shop/Order/' . $this->test_order->id);
328+
329+
$response2 = $this->actingAs($this->admin)
330+
->putJson('Shop/Order/' . $order2->id);
331+
332+
$response3 = $this->actingAs($this->admin)
333+
->putJson('Shop/Order/' . $order3->id);
334+
335+
$this->assertNoContent($response1);
336+
$this->assertNoContent($response2);
337+
$this->assertNoContent($response3);
338+
339+
// Verify all orders were updated
340+
$this->assertDatabaseHas('orders', [
341+
'id' => $this->test_order->id,
342+
'status' => PaymentStatusType::CLOSED->value,
343+
]);
344+
345+
$this->assertDatabaseHas('orders', [
346+
'id' => $order2->id,
347+
'status' => PaymentStatusType::CLOSED->value,
348+
]);
349+
350+
$this->assertDatabaseHas('orders', [
351+
'id' => $order3->id,
352+
'status' => PaymentStatusType::CLOSED->value,
353+
]);
354+
}
355+
356+
/**
357+
* Test the complete order lifecycle: offline -> paid -> delivered.
358+
*
359+
* @return void
360+
*/
361+
public function testCompleteOrderLifecycle(): void
362+
{
363+
// Start with offline order
364+
$this->test_order->status = PaymentStatusType::OFFLINE;
365+
$this->test_order->save();
366+
367+
// Step 1: Mark as paid
368+
$response = $this->actingAs($this->admin)
369+
->postJson('Shop/Order/' . $this->test_order->id);
370+
371+
$this->assertNoContent($response);
372+
$this->assertDatabaseHas('orders', [
373+
'id' => $this->test_order->id,
374+
'status' => PaymentStatusType::COMPLETED->value,
375+
]);
376+
377+
// Step 2: Mark as delivered
378+
$response = $this->actingAs($this->admin)
379+
->putJson('Shop/Order/' . $this->test_order->id);
380+
381+
$this->assertNoContent($response);
382+
$this->assertDatabaseHas('orders', [
383+
'id' => $this->test_order->id,
384+
'status' => PaymentStatusType::CLOSED->value,
385+
]);
386+
}
387+
}

0 commit comments

Comments
 (0)