diff --git a/Modules/Exercise01/Tests/Feature/Http/Controllers/OrderControllerTest.php b/Modules/Exercise01/Tests/Feature/Http/Controllers/OrderControllerTest.php new file mode 100644 index 0000000..35bd519 --- /dev/null +++ b/Modules/Exercise01/Tests/Feature/Http/Controllers/OrderControllerTest.php @@ -0,0 +1,144 @@ +priceServiceMock = $this->mock(PriceService::class); + } + + function test_it_show_form_order() + { + $url = action([OrderController::class, 'showForm']); + + $response = $this->get($url); + + $response->assertViewIs('exercise01::order'); + $response->assertViewHasAll([ + 'unitPrice', + 'voucherUnitPrice', + 'specialTimeUnitPrice', + 'specialTimePeriod', + ]); + $response->assertSessionMissing('order'); + } + + private function inValidInputs($inputs) + { + $validInputs = [ + 'quantity' => 1, + 'voucher' => null, + ]; + + return array_filter(array_merge($validInputs, $inputs), function ($value) { + return $value !== null; + }); + } + + /** + * @dataProvider provideWrongQuantity + * @dataProvider provideWrongVoucher + */ + function test_it_show_error_when_input_invalid($inputKey, $inputValue) + { + $url = action([OrderController::class, 'create']); + $inputs = $this->inValidInputs([ + $inputKey => is_callable($inputValue) ? $inputValue() : $inputValue, + ]); + + $response = $this->post($url, $inputs); + + $response->assertSessionHasErrors([$inputKey]); + } + + function provideWrongQuantity() + { + return [ + 'Quantity is required' => ['quantity', null], + 'Quantity should be integer' => ['quantity', 1.1], + 'Quantity should be greater than 1' => ['quantity', 0], + ]; + } + + function provideWrongVoucher() + { + return [ + 'Voucher must exist' => ['voucher', 'this-voucher-not-exist'], + 'Voucher must be active' => [ + 'voucher', + function () { + Voucher::factory()->inactive()->create(['code' => 'existed-voucher-but-inactive']); + + return 'existed-voucher-but-inactive'; + }, + ], + ]; + } + + /** + * @dataProvider provideEmptyVoucher + */ + function test_it_should_not_error_when_input_empty_voucher($voucher) + { + $url = action([OrderController::class, 'create']); + $dummyPrice = new Price(100, 0, 0); + $this->priceServiceMock + ->shouldReceive('calculate') + ->andReturn($dummyPrice); + + $response = $this->post($url, [ + 'quantity' => 1, + 'voucher' => $voucher, + ]); + + $response->assertSessionDoesntHaveErrors(['voucher']); + } + + function provideEmptyVoucher() + { + return [ + 'Voucher can be null' => [null], + 'Voucher can be empty string' => [''], + 'Voucher can be string with spaces only' => [' '], + ]; + } + + function test_it_create_order_when_input_valid_quantity_and_voucher_code() + { + Voucher::factory()->active()->create(['code' => 'existed-voucher']); + $dummyPrice = new Price(100, 0, 0); + $this->priceServiceMock + ->shouldReceive('calculate') + ->andReturn($dummyPrice); + + $url = action([OrderController::class, 'create']); + + $response = $this->post($url, [ + 'quantity' => 1, + 'voucher' => 'existed-voucher', + ]); + + $response->assertSessionDoesntHaveErrors(['quantity']); + $response->assertSessionDoesntHaveErrors(['voucher']); + $response->assertSessionHasInput(['quantity', 'voucher']); + $response->assertSessionHas('order', function ($order) { + return $order['quantity'] == 1 && $order['price'] instanceof Price; + }); + } +} diff --git a/infection.json b/infection.json index e93241b..8d8b3de 100644 --- a/infection.json +++ b/infection.json @@ -1,7 +1,11 @@ { "source": { "directories": [ - "Modules/" + "Modules/Exercise01/", + "Modules/Exercise03/", + "Modules/Exercise04/", + "Modules/Exercise05/", + "Modules/Exercise07/" ], "excludes": [ "Config", diff --git a/phpunit.xml b/phpunit.xml index 77442f0..6be7968 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -6,9 +6,11 @@ > - ./tests/Unit - ./tests/Feature - ./Modules/**/Tests + ./Modules/Exercise01/Tests + ./Modules/Exercise03/Tests + ./Modules/Exercise04/Tests + ./Modules/Exercise05/Tests + ./Modules/Exercise07/Tests ./Modules/Exercise01/Tests @@ -43,8 +45,11 @@ - ./app - ./Modules + ./Modules/Exercise01 + ./Modules/Exercise03 + ./Modules/Exercise04 + ./Modules/Exercise05 + ./Modules/Exercise07 ./Modules/**/Config