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

View File

@ -45,7 +45,7 @@ class CreditCard
$server_response = json_decode($request->input('gateway_response'));
$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');
$payment_method = $server_response->payment_method;
@ -192,7 +192,7 @@ class CreditCard
];
SystemLogger::dispatch($logger_message, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::TYPE_STRIPE, $this->stripe->client);
return redirect()->route('client.payments.show', ['payment' => $this->stripe->encodePrimaryKey($payment->id)]);
}

View File

@ -1,4 +1,5 @@
{
"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');
});
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', () => {
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>
</div>
@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
</div>
<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">
<table class="min-w-full shadow rounded border border-gray-200 mt-4 payment-methods-table">
<thead>
<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">
<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">
<span role="button" wire:click="sortBy('created_at')" class="cursor-pointer">
{{ ctrans('texts.created_at') }}
</span>
</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>
<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">
{{ ctrans('texts.payment_type_id') }}
</span>
</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">
{{ ctrans('texts.type') }}
</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">
{{ ctrans('texts.expires') }}
</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">
{{ ctrans('texts.card_number') }}
</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">
{{ ctrans('texts.default') }}
</th>
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50"></th>
</tr>
</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">
{{ ctrans('texts.type') }}
</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">
{{ ctrans('texts.expires') }}
</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">
{{ ctrans('texts.card_number') }}
</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">
{{ ctrans('texts.default') }}
</th>
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50"></th>
</tr>
</thead>
<tbody>
@forelse($payment_methods as $payment_method)
<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">
{{ $payment_method->formatDateTimestamp($payment_method->created_at, $client->date_format()) }}
</td>
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500">
{{ ctrans("texts.{$payment_method->gateway_type->alias}") }}
</td>
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500">
{{ ucfirst(optional($payment_method->meta)->brand) }}
</td>
<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))
{{ $payment_method->meta->exp_month}} / {{ $payment_method->meta->exp_year }}
@endif
</td>
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500">
@isset($payment_method->meta->last4)
**** {{ $payment_method->meta->last4 }}
@endisset
</td>
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500">
@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">
<path d="M20 6L9 17l-5-5" />
</svg>
@endif
</td>
<td class="px-6 py-4 whitespace-no-wrap flex items-center justify-end text-sm leading-5 font-medium">
<a href="{{ route('client.payment_methods.show', $payment_method->hashed_id) }}" class="text-blue-600 hover:text-indigo-900 focus:outline-none focus:underline">
@lang('texts.view')
</a>
</td>
</tr>
@empty
<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" colspan="100%">
{{ ctrans('texts.no_results') }}
</td>
</tr>
@endforelse
@forelse($payment_methods as $payment_method)
<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">
{{ $payment_method->formatDateTimestamp($payment_method->created_at, $client->date_format()) }}
</td>
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500">
{{ ctrans("texts.{$payment_method->gateway_type->alias}") }}
</td>
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500">
{{ ucfirst(optional($payment_method->meta)->brand) }}
</td>
<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))
{{ $payment_method->meta->exp_month}} / {{ $payment_method->meta->exp_year }}
@endif
</td>
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500">
@isset($payment_method->meta->last4)
**** {{ $payment_method->meta->last4 }}
@endisset
</td>
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500">
@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">
<path d="M20 6L9 17l-5-5"/>
</svg>
@endif
</td>
<td class="px-6 py-4 whitespace-no-wrap flex items-center justify-end text-sm leading-5 font-medium">
<a href="{{ route('client.payment_methods.show', $payment_method->hashed_id) }}"
class="text-blue-600 hover:text-indigo-900 focus:outline-none focus:underline">
@lang('texts.view')
</a>
</td>
</tr>
@empty
<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" colspan="100%">
{{ ctrans('texts.no_results') }}
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@ -95,6 +99,7 @@
{{ ctrans('texts.showing_x_of', ['first' => $payment_methods->firstItem(), 'last' => $payment_methods->lastItem(), 'total' => $payment_methods->total()]) }}
</span>
@endif
{{ $payment_methods->links() }}
</div>
</div>
</div>

View File

@ -1,16 +1,8 @@
@extends('portal.ninja2020.layout.app')
@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')
<div class="flex flex-col">
@livewire('payment-methods-table', ['client' => $client])
</div>
@endsection
@endsection