diff --git a/src/tests/Browser/Pages/PaymentMollie.php b/src/tests/Browser/Pages/PaymentMollie.php --- a/src/tests/Browser/Pages/PaymentMollie.php +++ b/src/tests/Browser/Pages/PaymentMollie.php @@ -25,7 +25,7 @@ */ public function assert($browser) { - $browser->waitFor('form#body table, form#body iframe', 10); + $browser->waitFor('form'); } /** @@ -53,23 +53,28 @@ { // https://docs.mollie.com/overview/testing // https://docs.mollie.com/components/testing - if ($browser->element('form#body iframe')) { - $browser->withinFrame('#card-number iframe', function ($browser) { - $browser->type('#cardNumber', '2223 0000 1047 9399'); // Mastercard + $browser + ->withinFrame('#card-number iframe', function ($browser) { + $browser->waitFor('#cardNumber') + ->type('#cardNumber', '2223 0000 1047 9399'); // Mastercard }) ->withinFrame('#card-holder-name iframe', function ($browser) { - $browser->type('#cardHolder', 'Test'); + $browser->waitFor('#cardHolder') + ->type('#cardHolder', 'Test'); }) + ->click('#expiry-date iframe') ->withinFrame('#expiry-date iframe', function ($browser) { - $browser->type('#expiryDate', '12/' . (date('y') + 1)); + $browser->waitFor('#expiryDate') + ->type('#expiryDate', '12/' . (date('y') + 1)); }) + ->click('#cvv iframe') ->withinFrame('#cvv iframe', function ($browser) { - $browser->click('#verificationCode')->type('#verificationCode', '123'); + $browser->waitFor('#verificationCode') + ->click('#verificationCode') + ->type('#verificationCode', '123'); }) - ->click('#submit-button'); - } - - $browser->waitFor('input[value="' . $status . '"]') + ->click('#submit-button') + ->waitFor('input[value="' . $status . '"]') ->click('input[value="' . $status . '"]') ->click('button.form__button'); } diff --git a/src/tests/BrowserAddonTrait.php b/src/tests/BrowserAddonTrait.php --- a/src/tests/BrowserAddonTrait.php +++ b/src/tests/BrowserAddonTrait.php @@ -82,4 +82,44 @@ { // This method is required by SupportsChrome trait } + + /** + * Create Mollie's auto-payment mandate using our API and Chrome browser + */ + public function createMollieMandate(\App\Wallet $wallet, array $params) + { + $wallet->setSetting('mollie_mandate_id', null); + + // Use the API to create a first payment with a mandate + $response = $this->actingAs($wallet->owner)->post("api/v4/payments/mandate", $params); + $response->assertStatus(200); + $json = $response->json(); + + $this->assertSame('success', $json['status']); + $this->assertMatchesRegularExpression('|^https://www.mollie.com|', $json['redirectUrl']); + + // There's no easy way to confirm a created mandate. + // The only way seems to be to fire up Chrome on checkout page + // and do actions with use of Dusk browser. + $this->startBrowser()->visit($json['redirectUrl']); + + $molliePage = new \Tests\Browser\Pages\PaymentMollie(); + $molliePage->assert($this->browser); + $molliePage->submitPayment($this->browser, 'paid'); + + // Because of https://github.com/mollie/mollie-api-php/issues/649 mandate does not + // exist until payment is paid. As we do not expect a webhook to be handled, we + // manually get the mandate ID from Mollie. + if (!$wallet->getSetting('mollie_mandate_id')) { + $mollie_payment = \mollie()->payments()->get($json['id']); + + $this->assertTrue(!empty($mollie_payment->mandateId)); + $wallet->setSetting('mollie_mandate_id', $mollie_payment->mandateId); + $json['mandateId'] = $mollie_payment->mandateId; + } + + $this->stopBrowser(); + + return $json; + } } diff --git a/src/tests/Feature/Controller/PaymentsCoinbaseTest.php b/src/tests/Feature/Controller/PaymentsCoinbaseTest.php --- a/src/tests/Feature/Controller/PaymentsCoinbaseTest.php +++ b/src/tests/Feature/Controller/PaymentsCoinbaseTest.php @@ -11,13 +11,11 @@ use GuzzleHttp\Psr7\Response; use Illuminate\Support\Facades\Bus; use Tests\TestCase; -use Tests\BrowserAddonTrait; use Tests\CoinbaseMocksTrait; class PaymentsCoinbaseTest extends TestCase { use CoinbaseMocksTrait; - use BrowserAddonTrait; /** * {@inheritDoc} diff --git a/src/tests/Feature/Controller/PaymentsMollieEuroTest.php b/src/tests/Feature/Controller/PaymentsMollieEuroTest.php --- a/src/tests/Feature/Controller/PaymentsMollieEuroTest.php +++ b/src/tests/Feature/Controller/PaymentsMollieEuroTest.php @@ -50,6 +50,7 @@ * Test creating/updating/deleting an outo-payment mandate * * @group mollie + * @group slow */ public function testMandates(): void { @@ -117,14 +118,12 @@ $this->assertSame("The specified amount does not cover the balance on the account.", $json['errors']['amount']); // Test creating a mandate (valid input) - $post = ['amount' => 20.10, 'balance' => 0, 'methodId' => PaymentProvider::METHOD_CREDITCARD]; - $response = $this->actingAs($user)->post("api/v4/payments/mandate", $post); - $response->assertStatus(200); + $json = $this->createMollieMandate( + $wallet->fresh(), + ['amount' => 20.10, 'balance' => 0, 'methodId' => PaymentProvider::METHOD_CREDITCARD] + ); - $json = $response->json(); - - $this->assertSame('success', $json['status']); - $this->assertMatchesRegularExpression('|^https://www.mollie.com|', $json['redirectUrl']); + $mandate_id = $json['mandateId']; // Assert the proper payment amount has been used $payment = Payment::where('id', $json['id'])->first(); @@ -141,31 +140,11 @@ $this->assertEquals(20.10, $json['amount']); $this->assertEquals(0, $json['balance']); - $this->assertEquals('Credit Card', $json['method']); - $this->assertSame(true, $json['isPending']); - $this->assertSame(false, $json['isValid']); + $this->assertTrue(in_array($json['method'], ['Mastercard (**** **** **** 9399)', 'Credit Card'])); + $this->assertSame(false, $json['isPending']); + $this->assertSame(true, $json['isValid']); $this->assertSame(false, $json['isDisabled']); - $mandate_id = $json['id']; - - // We would have to invoke a browser to accept the "first payment" to make - // the mandate validated/completed. Instead, we'll mock the mandate object. - $mollie_response = [ - 'resource' => 'mandate', - 'id' => $mandate_id, - 'status' => 'valid', - 'method' => 'creditcard', - 'details' => [ - 'cardNumber' => '4242', - 'cardLabel' => 'Visa', - ], - 'customerId' => 'cst_GMfxGPt7Gj', - 'createdAt' => '2020-04-28T11:09:47+00:00', - ]; - - $responseStack = $this->mockMollie(); - $responseStack->append(new Response(200, [], json_encode($mollie_response))); - $wallet = $user->wallets()->first(); $wallet->setSetting('mandate_disabled', 1); @@ -176,7 +155,7 @@ $this->assertEquals(20.10, $json['amount']); $this->assertEquals(0, $json['balance']); - $this->assertEquals('Visa (**** **** **** 4242)', $json['method']); + $this->assertTrue(in_array($json['method'], ['Mastercard (**** **** **** 9399)', 'Credit Card'])); $this->assertSame(false, $json['isPending']); $this->assertSame(true, $json['isValid']); $this->assertSame(true, $json['isDisabled']); @@ -210,8 +189,6 @@ $this->assertMatchesRegularExpression("/[0-9.,]+ €\.$/", $json['errors']['amount']); // Test updating a mandate (valid input) - $responseStack->append(new Response(200, [], json_encode($mollie_response))); - $post = ['amount' => 30.10, 'balance' => 10]; $response = $this->actingAs($user)->put("api/v4/payments/mandate", $post); $response->assertStatus(200); @@ -247,8 +224,6 @@ $this->assertSame('The specified amount does not cover the balance on the account.', $json['errors']['amount']); // Test updating a disabled mandate (valid input) - $responseStack->append(new Response(200, [], json_encode($mollie_response))); - $post = ['amount' => 30, 'balance' => 1]; $response = $this->actingAs($user)->put("api/v4/payments/mandate", $post); $response->assertStatus(200); @@ -266,8 +241,6 @@ return $job_wallet_id === $wallet->id; }); - $this->unmockMollie(); - // Delete mandate $response = $this->actingAs($user)->delete("api/v4/payments/mandate"); $response->assertStatus(200); @@ -277,12 +250,13 @@ $this->assertSame('success', $json['status']); $this->assertSame('The auto-payment has been removed.', $json['message']); - // Confirm with Mollie the mandate does not exist - $customer_id = $wallet->getSetting('mollie_id'); - $this->expectException(\Mollie\Api\Exceptions\ApiException::class); - $this->expectExceptionMessageMatches('/410: Gone/'); - $mandate = mollie()->mandates()->getForId($customer_id, $mandate_id); + // Confirm the mandate does not exist (is not valid) anymore + $response = $this->actingAs($user)->get("api/v4/payments/mandate"); + $response->assertStatus(200); + + $json = $response->json(); + $this->assertFalse($json['isValid']); $this->assertNull($wallet->fresh()->getSetting('mollie_mandate_id')); // Test Mollie's "410 Gone" response handling when fetching the mandate info @@ -465,6 +439,7 @@ * Test automatic payment charges * * @group mollie + * @group slow */ public function testTopUp(): void { @@ -476,7 +451,7 @@ $wallet->save(); // Create a valid mandate first (balance=0, so there's no extra payment yet) - $this->createMandate($wallet, ['amount' => 20.10, 'balance' => 0, 'methodId' => 'creditcard']); + $this->createMollieMandate($wallet, ['amount' => 20.10, 'balance' => 0, 'methodId' => 'creditcard']); $wallet->setSetting('mandate_balance', 10); @@ -802,28 +777,6 @@ $this->unmockMollie(); } - /** - * Create Mollie's auto-payment mandate using our API and Chrome browser - */ - protected function createMandate(Wallet $wallet, array $params) - { - // Use the API to create a first payment with a mandate - $response = $this->actingAs($wallet->owner)->post("api/v4/payments/mandate", $params); - $response->assertStatus(200); - $json = $response->json(); - - // There's no easy way to confirm a created mandate. - // The only way seems to be to fire up Chrome on checkout page - // and do actions with use of Dusk browser. - $this->startBrowser()->visit($json['redirectUrl']); - - $molliePage = new \Tests\Browser\Pages\PaymentMollie(); - $molliePage->assert($this->browser); - $molliePage->submitPayment($this->browser, 'paid'); - - $this->stopBrowser(); - } - /** * Test listing a pending payment * diff --git a/src/tests/Feature/Controller/PaymentsMollieTest.php b/src/tests/Feature/Controller/PaymentsMollieTest.php --- a/src/tests/Feature/Controller/PaymentsMollieTest.php +++ b/src/tests/Feature/Controller/PaymentsMollieTest.php @@ -86,6 +86,7 @@ * Test creating/updating/deleting an outo-payment mandate * * @group mollie + * @group slow */ public function testMandates(): void { @@ -152,14 +153,12 @@ $this->assertSame("The specified amount does not cover the balance on the account.", $json['errors']['amount']); // Test creating a mandate (valid input) - $post = ['amount' => 20.10, 'balance' => 0, 'methodId' => PaymentProvider::METHOD_CREDITCARD]; - $response = $this->actingAs($user)->post("api/v4/payments/mandate", $post); - $response->assertStatus(200); - - $json = $response->json(); + $json = $this->createMollieMandate( + $wallet->fresh(), + ['amount' => 20.10, 'balance' => 0, 'methodId' => PaymentProvider::METHOD_CREDITCARD] + ); - $this->assertSame('success', $json['status']); - $this->assertMatchesRegularExpression('|^https://www.mollie.com|', $json['redirectUrl']); + $mandate_id = $json['mandateId']; // Assert the proper payment amount has been used $payment = Payment::where('id', $json['id'])->first(); @@ -176,31 +175,11 @@ $this->assertEquals(20.10, $json['amount']); $this->assertEquals(0, $json['balance']); - $this->assertEquals('Credit Card', $json['method']); - $this->assertSame(true, $json['isPending']); - $this->assertSame(false, $json['isValid']); + $this->assertTrue(in_array($json['method'], ['Mastercard (**** **** **** 9399)', 'Credit Card'])); + $this->assertSame(false, $json['isPending']); + $this->assertSame(true, $json['isValid']); $this->assertSame(false, $json['isDisabled']); - $mandate_id = $json['id']; - - // We would have to invoke a browser to accept the "first payment" to make - // the mandate validated/completed. Instead, we'll mock the mandate object. - $mollie_response = [ - 'resource' => 'mandate', - 'id' => $mandate_id, - 'status' => 'valid', - 'method' => 'creditcard', - 'details' => [ - 'cardNumber' => '4242', - 'cardLabel' => 'Visa', - ], - 'customerId' => 'cst_GMfxGPt7Gj', - 'createdAt' => '2020-04-28T11:09:47+00:00', - ]; - - $responseStack = $this->mockMollie(); - $responseStack->append(new Response(200, [], json_encode($mollie_response))); - $wallet = $user->wallets()->first(); $wallet->setSetting('mandate_disabled', 1); @@ -211,7 +190,7 @@ $this->assertEquals(20.10, $json['amount']); $this->assertEquals(0, $json['balance']); - $this->assertEquals('Visa (**** **** **** 4242)', $json['method']); + $this->assertTrue(in_array($json['method'], ['Mastercard (**** **** **** 9399)', 'Credit Card'])); $this->assertSame(false, $json['isPending']); $this->assertSame(true, $json['isValid']); $this->assertSame(true, $json['isDisabled']); @@ -244,8 +223,6 @@ $this->assertSame("Minimum amount for a single payment is {$min}.", $json['errors']['amount']); // Test updating a mandate (valid input) - $responseStack->append(new Response(200, [], json_encode($mollie_response))); - $post = ['amount' => 30.10, 'balance' => 10]; $response = $this->actingAs($user)->put("api/v4/payments/mandate", $post); $response->assertStatus(200); @@ -281,8 +258,6 @@ $this->assertSame('The specified amount does not cover the balance on the account.', $json['errors']['amount']); // Test updating a disabled mandate (valid input) - $responseStack->append(new Response(200, [], json_encode($mollie_response))); - $post = ['amount' => 30, 'balance' => 1]; $response = $this->actingAs($user)->put("api/v4/payments/mandate", $post); $response->assertStatus(200); @@ -300,8 +275,6 @@ return $job_wallet_id === $wallet->id; }); - $this->unmockMollie(); - // Test mandate reset $wallet->payments()->delete(); $response = $this->actingAs($user)->post("api/v4/payments/mandate/reset", []); @@ -321,12 +294,13 @@ $this->assertSame('success', $json['status']); $this->assertSame('The auto-payment has been removed.', $json['message']); - // Confirm with Mollie the mandate does not exist - $customer_id = $wallet->getSetting('mollie_id'); - $this->expectException(\Mollie\Api\Exceptions\ApiException::class); - $this->expectExceptionMessageMatches('/410: Gone/'); - $mandate = mollie()->mandates()->getForId($customer_id, $mandate_id); + // Confirm the mandate does not exist (is not valid) anymore + $response = $this->actingAs($user)->get("api/v4/payments/mandate"); + $response->assertStatus(200); + $json = $response->json(); + + $this->assertFalse($json['isValid']); $this->assertNull($wallet->fresh()->getSetting('mollie_mandate_id')); // Test Mollie's "410 Gone" response handling when fetching the mandate info @@ -589,6 +563,7 @@ * Test automatic payment charges * * @group mollie + * @group slow */ public function testTopUp(): void { @@ -598,7 +573,7 @@ $wallet = $user->wallets()->first(); // Create a valid mandate first (balance=0, so there's no extra payment yet) - $this->createMandate($wallet, ['amount' => 20.10, 'balance' => 0]); + $this->createMollieMandate($wallet, ['amount' => 20.10, 'balance' => 0]); $wallet->setSetting('mandate_balance', 10); @@ -766,6 +741,7 @@ * Test payment/top-up with VAT_MODE=1 * * @group mollie + * @group slow */ public function testPaymentsWithVatModeOne(): void { @@ -800,7 +776,7 @@ // Top-up (mandate creation) // Create a valid mandate first (expect an extra payment) - $this->createMandate($wallet, ['amount' => 20.10, 'balance' => 0]); + $this->createMollieMandate($wallet, ['amount' => 20.10, 'balance' => 0]); // Check that the payments table contains a new record with proper amount(s) $payment = $wallet->payments()->first(); @@ -1077,28 +1053,6 @@ $this->unmockMollie(); } - /** - * Create Mollie's auto-payment mandate using our API and Chrome browser - */ - protected function createMandate(Wallet $wallet, array $params) - { - // Use the API to create a first payment with a mandate - $response = $this->actingAs($wallet->owner)->post("api/v4/payments/mandate", $params); - $response->assertStatus(200); - $json = $response->json(); - - // There's no easy way to confirm a created mandate. - // The only way seems to be to fire up Chrome on checkout page - // and do actions with use of Dusk browser. - $this->startBrowser()->visit($json['redirectUrl']); - - $molliePage = new \Tests\Browser\Pages\PaymentMollie(); - $molliePage->assert($this->browser); - $molliePage->submitPayment($this->browser, 'paid'); - - $this->stopBrowser(); - } - /** * Test listing a pending payment * diff --git a/src/tests/Feature/Controller/Reseller/PaymentsMollieTest.php b/src/tests/Feature/Controller/Reseller/PaymentsMollieTest.php --- a/src/tests/Feature/Controller/Reseller/PaymentsMollieTest.php +++ b/src/tests/Feature/Controller/Reseller/PaymentsMollieTest.php @@ -61,6 +61,7 @@ * Test creating/updating/deleting an outo-payment mandate * * @group mollie + * @group slow */ public function testMandates(): void { @@ -80,14 +81,9 @@ $wallet->save(); // Test creating a mandate (valid input) - $post = ['amount' => 20.10, 'balance' => 0]; - $response = $this->actingAs($reseller)->post("api/v4/payments/mandate", $post); - $response->assertStatus(200); - - $json = $response->json(); + $json = $this->createMollieMandate($wallet, ['amount' => 20.10, 'balance' => 0]); - $this->assertSame('success', $json['status']); - $this->assertMatchesRegularExpression('|^https://www.mollie.com|', $json['redirectUrl']); + $mandate_id = $json['mandateId']; // Assert the proper payment amount has been used $payment = Payment::where('id', $json['id'])->first(); @@ -105,31 +101,11 @@ $this->assertEquals(20.10, $json['amount']); $this->assertEquals(0, $json['balance']); - $this->assertEquals('Credit Card', $json['method']); - $this->assertSame(true, $json['isPending']); - $this->assertSame(false, $json['isValid']); + $this->assertTrue(in_array($json['method'], ['Mastercard (**** **** **** 9399)', 'Credit Card'])); + $this->assertSame(false, $json['isPending']); + $this->assertSame(true, $json['isValid']); $this->assertSame(false, $json['isDisabled']); - $mandate_id = $json['id']; - - // We would have to invoke a browser to accept the "first payment" to make - // the mandate validated/completed. Instead, we'll mock the mandate object. - $mollie_response = [ - 'resource' => 'mandate', - 'id' => $mandate_id, - 'status' => 'valid', - 'method' => 'creditcard', - 'details' => [ - 'cardNumber' => '4242', - 'cardLabel' => 'Visa', - ], - 'customerId' => 'cst_GMfxGPt7Gj', - 'createdAt' => '2020-04-28T11:09:47+00:00', - ]; - - $responseStack = $this->mockMollie(); - $responseStack->append(new Response(200, [], json_encode($mollie_response))); - $wallet = $reseller->wallets()->first(); $wallet->setSetting('mandate_disabled', 1); @@ -140,7 +116,7 @@ $this->assertEquals(20.10, $json['amount']); $this->assertEquals(0, $json['balance']); - $this->assertEquals('Visa (**** **** **** 4242)', $json['method']); + $this->assertTrue(in_array($json['method'], ['Mastercard (**** **** **** 9399)', 'Credit Card'])); $this->assertSame(false, $json['isPending']); $this->assertSame(true, $json['isValid']); $this->assertSame(true, $json['isDisabled']); @@ -151,8 +127,6 @@ $wallet->save(); // Test updating a mandate (valid input) - $responseStack->append(new Response(200, [], json_encode($mollie_response))); - $post = ['amount' => 30.10, 'balance' => 10]; $response = $this->actingAs($reseller)->put("api/v4/payments/mandate", $post); $response->assertStatus(200);