Testing adding Stripe credit card

- Added: iframeLoaded method for Cypress
- Fixed: saving payment method id for CreditCard.php
- Added: chromeWebSecurity: false flag for insecure iframe connections
- Formatted: payment_methods/index
- Formatted: payment-methods-table.blade.php
- Added: Test for adding credit card to Stripe
- Fixed: Removing client gateway tokens
This commit is contained in:
Benjamin Beganović 2020-07-01 18:28:57 +02:00
parent 107e3faa6e
commit 4918269bf2
7 changed files with 134 additions and 77 deletions

View File

@ -48,7 +48,7 @@ class PaymentMethodController extends Controller
return $gateway return $gateway
->driver(auth()->user()->client) ->driver(auth()->user()->client)
->setPaymentMethod(GatewayType::BANK_TRANSFER) ->setPaymentMethod(GatewayType::CREDIT_CARD)
->authorizeView($data); ->authorizeView($data);
} }
@ -64,7 +64,7 @@ class PaymentMethodController extends Controller
return $gateway return $gateway
->driver(auth()->user()->client) ->driver(auth()->user()->client)
->setPaymentMethod(GatewayType::BANK_TRANSFER) ->setPaymentMethod(GatewayType::CREDIT_CARD)
->authorizeResponse($request); ->authorizeResponse($request);
} }
@ -133,7 +133,7 @@ class PaymentMethodController extends Controller
public function destroy(ClientGatewayToken $payment_method) public function destroy(ClientGatewayToken $payment_method)
{ {
try { try {
event(new MethodDeleted($payment_method)); event(new MethodDeleted($payment_method, auth('contact')->user()->company));
$payment_method->delete(); $payment_method->delete();
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error(json_encode($e)); Log::error(json_encode($e));

View File

@ -45,7 +45,7 @@ class CreditCard
$server_response = json_decode($request->input('gateway_response')); $server_response = json_decode($request->input('gateway_response'));
$gateway_id = $request->input('gateway_id'); $gateway_id = $request->input('gateway_id');
$gateway_type_id = $request->input('gateway_type_id'); $gateway_type_id = $request->input('payment_method_id');
$is_default = $request->input('is_default'); $is_default = $request->input('is_default');
$payment_method = $server_response->payment_method; $payment_method = $server_response->payment_method;

View File

@ -1,4 +1,5 @@
{ {
"video": false, "video": false,
"baseUrl": "http://invoiceninja.wip/" "baseUrl": "http://invoiceninja.wip/",
"chromeWebSecurity": false
} }

View File

@ -19,6 +19,35 @@ context('Payment methods', () => {
.should('contain.text', 'Payment Method'); .should('contain.text', 'Payment Method');
}); });
it('should add stripe credit card', () => {
cy.visit('/client/payment_methods');
cy.get('body')
.find('#add-payment-method')
.first()
.should('contain.text', 'Add Payment Method')
.click()
cy.location().should(location => {
expect(location.pathname).to.eq('/client/payment_methods/create');
});
cy.wait(3000);
cy.get('#cardholder-name').type('Invoice Ninja');
cy.getWithinIframe('[name="cardnumber"]').type('4242424242424242');
cy.getWithinIframe('[name="exp-date"]').type('2442');
cy.getWithinIframe('[name="cvc"]').type('242');
cy.getWithinIframe('[name="postal"]').type('12345');
cy.get('#card-button').click();
cy.location().should(location => {
expect(location.pathname).to.eq('/client/payment_methods');
});
});
it('should have per page options dropdown', () => { it('should have per page options dropdown', () => {
cy.visit('/client/payment_methods'); cy.visit('/client/payment_methods');

View File

@ -44,3 +44,33 @@ Cypress.Commands.add('clientLogin', () => {
}); });
}); });
}); });
Cypress.Commands.add(
'iframeLoaded',
{prevSubject: 'element'},
($iframe) => {
const contentWindow = $iframe.prop('contentWindow');
return new Promise(resolve => {
if (
contentWindow
) {
resolve(contentWindow)
} else {
$iframe.on('load', () => {
resolve(contentWindow)
})
}
})
});
Cypress.Commands.add(
'getInDocument',
{prevSubject: 'Permission denied to access property "document" on cross-origin object'},
(document, selector) => Cypress.$(selector, document)
);
Cypress.Commands.add(
'getWithinIframe',
(targetElement) => cy.get('iframe').iframeLoaded().its('document').getInDocument(targetElement)
);

View File

@ -10,81 +10,85 @@
</select> </select>
</div> </div>
@if($client->getCreditCardGateway()) @if($client->getCreditCardGateway())
<a href="{{ route('client.payment_methods.create') }}" class="button button-primary">{{ ctrans('texts.add_payment_method') }}</a> <a href="{{ route('client.payment_methods.create') }}" id="add-payment-method"
class="button button-primary">{{ ctrans('texts.add_payment_method') }}</a>
@endif @endif
</div> </div>
<div class="-my-2 py-2 overflow-x-auto sm:-mx-6 sm:px-6 lg:-mx-8 lg:px-8"> <div class="-my-2 py-2 overflow-x-auto sm:-mx-6 sm:px-6 lg:-mx-8 lg:px-8">
<div class="align-middle inline-block min-w-full overflow-hidden rounded"> <div class="align-middle inline-block min-w-full overflow-hidden rounded">
<table class="min-w-full shadow rounded border border-gray-200 mt-4 payment-methods-table"> <table class="min-w-full shadow rounded border border-gray-200 mt-4 payment-methods-table">
<thead> <thead>
<tr> <tr>
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider"> <th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">
<span role="button" wire:click="sortBy('created_at')" class="cursor-pointer"> <span role="button" wire:click="sortBy('created_at')" class="cursor-pointer">
{{ ctrans('texts.created_at') }} {{ ctrans('texts.created_at') }}
</span> </span>
</th> </th>
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider"> <th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">
<span role="button" wire:click="sortBy('type_id')" class="cursor-pointer"> <span role="button" wire:click="sortBy('type_id')" class="cursor-pointer">
{{ ctrans('texts.payment_type_id') }} {{ ctrans('texts.payment_type_id') }}
</span> </span>
</th> </th>
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider"> <th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">
{{ ctrans('texts.type') }} {{ ctrans('texts.type') }}
</th> </th>
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider"> <th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">
{{ ctrans('texts.expires') }} {{ ctrans('texts.expires') }}
</th> </th>
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider"> <th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">
{{ ctrans('texts.card_number') }} {{ ctrans('texts.card_number') }}
</th> </th>
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider"> <th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">
{{ ctrans('texts.default') }} {{ ctrans('texts.default') }}
</th> </th>
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50"></th> <th class="px-6 py-3 border-b border-gray-200 bg-gray-50"></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@forelse($payment_methods as $payment_method) @forelse($payment_methods as $payment_method)
<tr class="bg-white group hover:bg-gray-100"> <tr class="bg-white group hover:bg-gray-100">
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500"> <td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500">
{{ $payment_method->formatDateTimestamp($payment_method->created_at, $client->date_format()) }} {{ $payment_method->formatDateTimestamp($payment_method->created_at, $client->date_format()) }}
</td> </td>
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500"> <td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500">
{{ ctrans("texts.{$payment_method->gateway_type->alias}") }} {{ ctrans("texts.{$payment_method->gateway_type->alias}") }}
</td> </td>
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500"> <td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500">
{{ ucfirst(optional($payment_method->meta)->brand) }} {{ ucfirst(optional($payment_method->meta)->brand) }}
</td> </td>
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500"> <td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500">
@if(isset($payment_method->meta->exp_month) && isset($payment_method->meta->exp_year)) @if(isset($payment_method->meta->exp_month) && isset($payment_method->meta->exp_year))
{{ $payment_method->meta->exp_month}} / {{ $payment_method->meta->exp_year }} {{ $payment_method->meta->exp_month}} / {{ $payment_method->meta->exp_year }}
@endif @endif
</td> </td>
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500"> <td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500">
@isset($payment_method->meta->last4) @isset($payment_method->meta->last4)
**** {{ $payment_method->meta->last4 }} **** {{ $payment_method->meta->last4 }}
@endisset @endisset
</td> </td>
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500"> <td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500">
@if($payment_method->is_default) @if($payment_method->is_default)
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none"
<path d="M20 6L9 17l-5-5" /> stroke="currentColor" stroke-width="2" stroke-linecap="round"
</svg> stroke-linejoin="round" class="feather feather-check">
@endif <path d="M20 6L9 17l-5-5"/>
</td> </svg>
<td class="px-6 py-4 whitespace-no-wrap flex items-center justify-end text-sm leading-5 font-medium"> @endif
<a href="{{ route('client.payment_methods.show', $payment_method->hashed_id) }}" class="text-blue-600 hover:text-indigo-900 focus:outline-none focus:underline"> </td>
@lang('texts.view') <td class="px-6 py-4 whitespace-no-wrap flex items-center justify-end text-sm leading-5 font-medium">
</a> <a href="{{ route('client.payment_methods.show', $payment_method->hashed_id) }}"
</td> class="text-blue-600 hover:text-indigo-900 focus:outline-none focus:underline">
</tr> @lang('texts.view')
@empty </a>
<tr class="bg-white group hover:bg-gray-100"> </td>
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500" colspan="100%"> </tr>
{{ ctrans('texts.no_results') }} @empty
</td> <tr class="bg-white group hover:bg-gray-100">
</tr> <td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500" colspan="100%">
@endforelse {{ ctrans('texts.no_results') }}
</td>
</tr>
@endforelse
</tbody> </tbody>
</table> </table>
</div> </div>
@ -95,6 +99,7 @@
{{ ctrans('texts.showing_x_of', ['first' => $payment_methods->firstItem(), 'last' => $payment_methods->lastItem(), 'total' => $payment_methods->total()]) }} {{ ctrans('texts.showing_x_of', ['first' => $payment_methods->firstItem(), 'last' => $payment_methods->lastItem(), 'total' => $payment_methods->total()]) }}
</span> </span>
@endif @endif
{{ $payment_methods->links() }} {{ $payment_methods->links() }}
</div> </div>
</div> </div>

View File

@ -1,14 +1,6 @@
@extends('portal.ninja2020.layout.app') @extends('portal.ninja2020.layout.app')
@section('meta_title', ctrans('texts.payment_methods')) @section('meta_title', ctrans('texts.payment_methods'))
@section('header')
<div class="mt-5 sm:mt-0 sm:ml-6 sm:flex-shrink-0 sm:flex sm:items-center">
<div class="inline-flex rounded-md shadow-sm">
</div>
</div>
@endsection
@section('body') @section('body')
<div class="flex flex-col"> <div class="flex flex-col">
@livewire('payment-methods-table', ['client' => $client]) @livewire('payment-methods-table', ['client' => $client])