paymentGateway = new FakePaymentGateway; $this->app->instance(PaymentGateway::class, $this->paymentGateway); } private function orderTickets($concert, $params) { $savedRequest = $this->app['request']; $this->json('POST', "/concerts/{$concert->id}/orders", $params); $this->app['request'] = $savedRequest; } private function assertValidationError($field) { $this->assertResponseStatus(422); $this->assertArrayHasKey($field, $this->decodeResponseJson()); } /** @test */ function customer_can_purchase_tickets_to_a_published_concert() { $this->disableExceptionHandling(); $concert = factory(Concert::class)->states('published')->create(['ticket_price' => 3250])->addTickets(3); $this->orderTickets($concert, [ 'email' => 'john@example.com', 'ticket_quantity' => 3, 'payment_token' => $this->paymentGateway->getValidTestToken(), ]); $this->assertResponseStatus(201); $this->seeJsonSubset([ 'email' => 'john@example.com', 'ticket_quantity' => 3, 'amount' => 9750, ]); $this->assertEquals(9750, $this->paymentGateway->totalCharges()); $this->assertTrue($concert->hasOrderFor('john@example.com')); $this->assertEquals(3, $concert->ordersFor('john@example.com')->first()->ticketQuantity()); } /** @test */ function cannot_purchase_tickets_to_an_unpublished_concert() { $concert = factory(Concert::class)->states('unpublished')->create()->addTickets(3); $this->orderTickets($concert, [ 'email' => 'john@example.com', 'ticket_quantity' => 3, 'payment_token' => $this->paymentGateway->getValidTestToken(), ]); $this->assertResponseStatus(404); $this->assertFalse($concert->hasOrderFor('john@example.com')); $this->assertEquals(0, $this->paymentGateway->totalCharges()); } /** @test */ function an_order_is_not_created_if_payment_fails() { $concert = factory(Concert::class)->states('published')->create(['ticket_price' => 3250])->addTickets(3); $this->orderTickets($concert, [ 'email' => 'john@example.com', 'ticket_quantity' => 3, 'payment_token' => 'invalid-payment-token', ]); $this->assertResponseStatus(422); $this->assertFalse($concert->hasOrderFor('john@example.com')); $this->assertEquals(3, $concert->ticketsRemaining()); } /** @test */ function cannot_purchase_more_tickets_than_remain() { $concert = factory(Concert::class)->states('published')->create()->addTickets(50); $this->orderTickets($concert, [ 'email' => 'john@example.com', 'ticket_quantity' => 51, 'payment_token' => $this->paymentGateway->getValidTestToken(), ]); $this->assertResponseStatus(422); $this->assertFalse($concert->hasOrderFor('john@example.com')); $this->assertEquals(0, $this->paymentGateway->totalCharges()); $this->assertEquals(50, $concert->ticketsRemaining()); } /** @test */ function cannot_purchase_tickets_another_customer_is_already_trying_to_purchase() { $this->disableExceptionHandling(); $concert = factory(Concert::class)->states('published')->create([ 'ticket_price' => 1200 ])->addTickets(3); $this->paymentGateway->beforeFirstCharge(function ($paymentGateway) use ($concert) { $this->orderTickets($concert, [ 'email' => 'personB@example.com', 'ticket_quantity' => 1, 'payment_token' => $this->paymentGateway->getValidTestToken(), ]); $this->assertResponseStatus(422); $this->assertFalse($concert->hasOrderFor('personB@example.com')); $this->assertEquals(0, $this->paymentGateway->totalCharges()); }); $this->orderTickets($concert, [ 'email' => 'personA@example.com', 'ticket_quantity' => 3, 'payment_token' => $this->paymentGateway->getValidTestToken(), ]); $this->assertEquals(3600, $this->paymentGateway->totalCharges()); $this->assertTrue($concert->hasOrderFor('personA@example.com')); $this->assertEquals(3, $concert->ordersFor('personA@example.com')->first()->ticketQuantity()); } /** @test */ function email_is_required_to_purchase_tickets() { $concert = factory(Concert::class)->states('published')->create(); $this->orderTickets($concert, [ 'ticket_quantity' => 3, 'payment_token' => $this->paymentGateway->getValidTestToken(), ]); $this->assertValidationError('email'); } /** @test */ function email_must_be_valid_to_purchase_tickets() { $concert = factory(Concert::class)->states('published')->create(); $this->orderTickets($concert, [ 'email' => 'not-an-email-address', 'ticket_quantity' => 3, 'payment_token' => $this->paymentGateway->getValidTestToken(), ]); $this->assertValidationError('email'); } /** @test */ function ticket_quantity_is_required_to_purchase_tickets() { $concert = factory(Concert::class)->states('published')->create(); $this->orderTickets($concert, [ 'email' => 'john@example.com', 'payment_token' => $this->paymentGateway->getValidTestToken(), ]); $this->assertValidationError('ticket_quantity'); } /** @test */ function ticket_quantity_must_be_at_least_1_to_purchase_tickets() { $concert = factory(Concert::class)->states('published')->create(); $this->orderTickets($concert, [ 'email' => 'john@example.com', 'ticket_quantity' => 0, 'payment_token' => $this->paymentGateway->getValidTestToken(), ]); $this->assertValidationError('ticket_quantity'); } /** @test */ function payment_token_is_required() { $concert = factory(Concert::class)->states('published')->create(); $this->orderTickets($concert, [ 'email' => 'john@example.com', 'ticket_quantity' => 3, ]); $this->assertValidationError('payment_token'); } }