mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
Merge pull request #8503 from jibees/split-checkout-payment-forms
Split checkout payment forms
This commit is contained in:
@@ -97,6 +97,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
.stripe-card {
|
||||
background: white;
|
||||
box-sizing: border-box;
|
||||
font-weight: 400;
|
||||
padding: 0.6rem 0.5rem;
|
||||
border: 1px solid #cccccc;
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 0;
|
||||
height: 42px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
label {
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
@@ -106,23 +118,6 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
span.formError {
|
||||
background-color: rgba(193, 18, 43, 0.1);
|
||||
color: $red-700;
|
||||
font-style: normal;
|
||||
margin: 0;
|
||||
font-size: 0.8rem;
|
||||
display: block;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
|
||||
&.standalone {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
#distributor_address.panel {
|
||||
font-size: 0.875rem;
|
||||
padding: 1rem;
|
||||
@@ -138,6 +133,29 @@
|
||||
}
|
||||
}
|
||||
|
||||
.checkout-input span.formError, div.error.card-errors {
|
||||
background-color: rgba(193, 18, 43, 0.1);
|
||||
color: $red-700;
|
||||
font-style: normal;
|
||||
margin: 0;
|
||||
font-size: 0.8rem;
|
||||
display: block;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
|
||||
&.standalone {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
div.error.card-errors {
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.checkout-submit {
|
||||
margin-top: 5rem;
|
||||
margin-bottom: 5rem;
|
||||
|
||||
@@ -13,7 +13,7 @@ module CheckoutCallbacks
|
||||
prepend_before_action :require_order_cycle
|
||||
prepend_before_action :require_distributor_chosen
|
||||
|
||||
before_action :load_order, :associate_user, :load_saved_addresses
|
||||
before_action :load_order, :associate_user, :load_saved_addresses, :load_saved_credit_cards
|
||||
before_action :load_shipping_methods, :load_countries, if: -> { params[:step] == "details" }
|
||||
|
||||
before_action :ensure_order_not_completed
|
||||
@@ -41,6 +41,11 @@ module CheckoutCallbacks
|
||||
@order.ship_address ||= finder.ship_address
|
||||
end
|
||||
|
||||
def load_saved_credit_cards
|
||||
@saved_credit_cards = spree_current_user&.credit_cards&.with_payment_profile.to_a
|
||||
@selected_card = nil
|
||||
end
|
||||
|
||||
def load_shipping_methods
|
||||
@shipping_methods = Spree::ShippingMethod.for_distributor(@order.distributor).order(:name)
|
||||
end
|
||||
|
||||
@@ -143,4 +143,13 @@ module CheckoutHelper
|
||||
def checkout_step?(step)
|
||||
checkout_step == step.to_s
|
||||
end
|
||||
|
||||
def stripe_card_options(cards)
|
||||
cards.map do |cc|
|
||||
[
|
||||
"#{cc.brand} #{cc.last_digits} #{I18n.t(:card_expiry_abbreviation)}:#{cc.month.to_s.rjust(2, '0')}/#{cc.year}",
|
||||
cc.id
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -23,10 +23,13 @@ module Checkout
|
||||
|
||||
def apply_strong_parameters
|
||||
@order_params = params.require(:order).permit(
|
||||
:email, :shipping_method_id, :special_instructions,
|
||||
:email, :shipping_method_id, :special_instructions, :existing_card_id,
|
||||
bill_address_attributes: ::PermittedAttributes::Address.attributes,
|
||||
ship_address_attributes: ::PermittedAttributes::Address.attributes,
|
||||
payments_attributes: [:payment_method_id]
|
||||
payments_attributes: [
|
||||
:payment_method_id,
|
||||
{ source_attributes: PermittedAttributes::PaymentSource.attributes }
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@@ -11,14 +11,20 @@
|
||||
name: "order[payments_attributes][][payment_method_id]",
|
||||
checked: (payment_method.id == selected_payment_method),
|
||||
"data-action": "paymentmethod#selectPaymentMethod",
|
||||
"data-paymentmethod-description": "#{payment_method.description}"
|
||||
"data-paymentmethod-id": "paymentmethod#{payment_method.id}"
|
||||
= f.label :payment_method_id, "#{payment_method.name} (#{payment_or_shipping_price(payment_method, @order)})", for: "payment_method_#{payment_method.id}"
|
||||
|
||||
= f.error_message_on :payment_method, standalone: true
|
||||
|
||||
%div
|
||||
.panel{"data-paymentmethod-target": "panel", style: "display: none"}
|
||||
- available_payment_methods.each do |payment_method|
|
||||
.paymentmethod-container{id: "paymentmethod#{payment_method.id}", style: "display: #{payment_method.id == selected_payment_method ? "block" : "none"}"}
|
||||
- if payment_method.description && !payment_method.description.empty?
|
||||
.paymentmethod-description.panel
|
||||
#{payment_method.description}
|
||||
|
||||
.paymentmethod-form
|
||||
= render partial: "split_checkout/payment/#{payment_method.method_type}", locals: { payment_method: payment_method, f: f }
|
||||
|
||||
%div.checkout-substep
|
||||
= t("split_checkout.step2.explaination")
|
||||
|
||||
|
||||
0
app/views/split_checkout/payment/_check.html.erb
Normal file
0
app/views/split_checkout/payment/_check.html.erb
Normal file
27
app/views/split_checkout/payment/_gateway.html.haml
Normal file
27
app/views/split_checkout/payment/_gateway.html.haml
Normal file
@@ -0,0 +1,27 @@
|
||||
= f.fields :bill_address, model: @order.bill_address do |bill_address|
|
||||
%div.checkout-input
|
||||
= bill_address.label :firstname, t("split_checkout.step1.your_details.first_name.label")
|
||||
= bill_address.text_field :firstname, { placeholder: t("split_checkout.step1.your_details.first_name.placeholder") }
|
||||
= f.error_message_on "bill_address.firstname"
|
||||
|
||||
%div.checkout-input
|
||||
= bill_address.label :lastname, t("split_checkout.step1.your_details.last_name.label")
|
||||
= bill_address.text_field :lastname, { placeholder: t("split_checkout.step1.your_details.last_name.placeholder") }
|
||||
= f.error_message_on "bill_address.lastname"
|
||||
|
||||
.flex{style: "justify-content: space-between; gap: 10px;" }
|
||||
%div.checkout-input{style: "flex-grow: 2;" }
|
||||
= f.label :card_number, t("split_checkout.step2.form.card_number.label")
|
||||
= f.text_field :card_number, { placeholder: t("split_checkout.step2.form.card_number.placeholder") }
|
||||
|
||||
%div.checkout-input{style: "flex: 0 1 100px;"}
|
||||
= f.label :card_verification_value, t("split_checkout.step2.form.card_verification_value.label")
|
||||
= f.number_field :card_verification_value, { placeholder: t("split_checkout.step2.form.card_verification_value.placeholder") }
|
||||
|
||||
%div.checkout-input{style: "flex: 0 1 70px;"}
|
||||
= f.label :card_month, t("split_checkout.step2.form.card_month.label")
|
||||
= f.number_field :card_month, { placeholder: t("split_checkout.step2.form.card_month.placeholder"), max: 12 }
|
||||
|
||||
%div.checkout-input{style: "flex: 0 1 70px;"}
|
||||
= f.label :card_year, t("split_checkout.step2.form.card_year.label")
|
||||
= f.number_field :card_year, { placeholder: t("split_checkout.step2.form.card_year.placeholder"), min: Time.now.year, max: Time.now.year + 10 }
|
||||
1
app/views/split_checkout/payment/_paypal.html.haml
Normal file
1
app/views/split_checkout/payment/_paypal.html.haml
Normal file
@@ -0,0 +1 @@
|
||||
-# This file intentionally overrides the view in the spree_paypal_express gem
|
||||
31
app/views/split_checkout/payment/_stripe_sca.html.haml
Normal file
31
app/views/split_checkout/payment/_stripe_sca.html.haml
Normal file
@@ -0,0 +1,31 @@
|
||||
%div{"data-controller": "stripe-cards"}
|
||||
- if @saved_credit_cards.any?
|
||||
.checkout-input
|
||||
%label
|
||||
= t('split_checkout.step2.form.stripe.use_saved_card')
|
||||
= select_tag :existing_card,
|
||||
options_for_select(stripe_card_options(@saved_credit_cards) + [[t('split_checkout.step2.form.stripe.create_new_card'), ""]], @selected_card),
|
||||
{ "data-action": "change->stripe-cards#onSelectCard", "data-stripe-cards-target": "select" }
|
||||
|
||||
.checkout-input{"data-stripe-cards-target": "stripeelements"}
|
||||
- if @saved_credit_cards.none?
|
||||
%label
|
||||
= t('split_checkout.step2.form.stripe.use_new_card')
|
||||
|
||||
%div.stripe-card{ "data-controller": "stripe", "data-stripe-key": "#{Stripe.publishable_key}" }
|
||||
= hidden_field_tag "order[payments_attributes][][source_attributes][first_name]", @order.bill_address.first_name
|
||||
= hidden_field_tag "order[payments_attributes][][source_attributes][last_name]", @order.bill_address.last_name
|
||||
= hidden_field_tag "order[payments_attributes][][source_attributes][month]", nil, { "data-stripe-target": "expMonth" }
|
||||
= hidden_field_tag "order[payments_attributes][][source_attributes][year]", nil, { "data-stripe-target": "expYear" }
|
||||
= hidden_field_tag "order[payments_attributes][][source_attributes][cc_type]", nil, { "data-stripe-target": "brand" }
|
||||
= hidden_field_tag "order[payments_attributes][][source_attributes][last_digits]", nil, { "data-stripe-target": "last4" }
|
||||
= hidden_field_tag "order[payments_attributes][][source_attributes][gateway_payment_profile_id]", nil, { "data-stripe-target": "pmId" }
|
||||
|
||||
%div.card-element{ "data-stripe-target": "cardElement" }
|
||||
%div.card-errors{ "data-stripe-target": "cardErrors" }
|
||||
|
||||
- if spree_current_user
|
||||
.checkout-input
|
||||
= check_box_tag "order[payments_attributes][][source_attributes][save_requested_by_customer]", 1, false
|
||||
= label :save_requested_by_customer, t('split_checkout.step2.form.stripe.save_card'), { for: "save_requested_by_customer" }
|
||||
|
||||
@@ -1,9 +1,54 @@
|
||||
import { Controller } from "stimulus";
|
||||
export default class extends Controller {
|
||||
static targets = ["panel"];
|
||||
static targets = ["paymentMethod"];
|
||||
|
||||
selectPaymentMethod(event) {
|
||||
this.panelTarget.innerHTML = `<span>${event.target.dataset.paymentmethodDescription}</span>`;
|
||||
this.panelTarget.style.display = "block";
|
||||
const paymentMethodContainerId = event.target.dataset.paymentmethodId;
|
||||
Array.from(
|
||||
document.getElementsByClassName("paymentmethod-container")
|
||||
).forEach((e) => {
|
||||
if (e.id === paymentMethodContainerId) {
|
||||
e.style.display = "block";
|
||||
this.addRequiredAttributeOnInputIfNeeded(e);
|
||||
this.removeDisabledAttributeOnInput(e);
|
||||
} else {
|
||||
e.style.display = "none";
|
||||
this.removeRequiredAttributeOnInput(e);
|
||||
this.addDisabledAttributeOnInput(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getFormElementsArray(container) {
|
||||
return Array.from(container.querySelectorAll("input, select, textarea"));
|
||||
}
|
||||
|
||||
addDisabledAttributeOnInput(container) {
|
||||
this.getFormElementsArray(container).forEach((i) => {
|
||||
i.disabled = true;
|
||||
});
|
||||
}
|
||||
|
||||
removeDisabledAttributeOnInput(container) {
|
||||
this.getFormElementsArray(container).forEach((i) => {
|
||||
i.disabled = false;
|
||||
});
|
||||
}
|
||||
|
||||
removeRequiredAttributeOnInput(container) {
|
||||
this.getFormElementsArray(container).forEach((i) => {
|
||||
if (i.required) {
|
||||
i.dataset.required = i.required;
|
||||
i.required = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
addRequiredAttributeOnInputIfNeeded(container) {
|
||||
this.getFormElementsArray(container).forEach((i) => {
|
||||
if (i.dataset.required === "true") {
|
||||
i.required = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
23
app/webpacker/controllers/stripe_cards_controller.js
Normal file
23
app/webpacker/controllers/stripe_cards_controller.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Controller } from "stimulus";
|
||||
|
||||
// Handles form elements for selecting previously saved Stripe cards from a list of cards
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = ["stripeelements", "select"];
|
||||
|
||||
connect() {
|
||||
this.selectCard(this.selectTarget.value);
|
||||
}
|
||||
|
||||
onSelectCard(event) {
|
||||
this.selectCard(event.target.value);
|
||||
}
|
||||
|
||||
selectCard(cardValue) {
|
||||
if (cardValue == "") {
|
||||
this.stripeelementsTarget.style.display = "block";
|
||||
} else {
|
||||
this.stripeelementsTarget.style.display = "none";
|
||||
}
|
||||
}
|
||||
}
|
||||
63
app/webpacker/controllers/stripe_controller.js
Normal file
63
app/webpacker/controllers/stripe_controller.js
Normal file
@@ -0,0 +1,63 @@
|
||||
import { Controller } from "stimulus"
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = [ "cardElement", "cardErrors", "expMonth", "expYear", "brand", "last4", "pmId" ];
|
||||
static styles = {
|
||||
base: {
|
||||
fontFamily: "Roboto, Arial, sans-serif",
|
||||
fontSize: "16px",
|
||||
color: "#5c5c5c",
|
||||
"::placeholder": {
|
||||
color: "#6c6c6c"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
connect() {
|
||||
const stripe = Stripe(this.data.get("key"));
|
||||
const elements = stripe.elements();
|
||||
const form = this.pmIdTarget.form;
|
||||
const error_container = this.cardErrorsTarget;
|
||||
const exp_month_field = this.expMonthTarget;
|
||||
const exp_year_field = this.expYearTarget;
|
||||
const brand_field = this.brandTarget;
|
||||
const last4_field = this.last4Target;
|
||||
const pm_id_field = this.pmIdTarget;
|
||||
|
||||
const stripe_element = elements.create("card", {
|
||||
style: this.constructor.styles,
|
||||
hidePostalCode: true
|
||||
});
|
||||
|
||||
// Mount Stripe Elements JS to the field and add form validations
|
||||
stripe_element.mount(this.cardElementTarget);
|
||||
stripe_element.addEventListener("change", event => {
|
||||
if (event.error) {
|
||||
error_container.textContent = event.error.message;
|
||||
} else {
|
||||
error_container.textContent = "";
|
||||
}
|
||||
});
|
||||
|
||||
// Before the form is submitted we send the card details directly to Stripe (via StripeJS),
|
||||
// and receive a token which represents the card object, and add that token into the form.
|
||||
form.addEventListener("submit", event => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
stripe.createPaymentMethod({type: "card", card: stripe_element}).then(response => {
|
||||
if (response.error) {
|
||||
error_container.textContent = response.error.message;
|
||||
} else {
|
||||
pm_id_field.setAttribute("value", response.paymentMethod.id);
|
||||
exp_month_field.setAttribute("value", response.paymentMethod.card.exp_month);
|
||||
exp_year_field.setAttribute("value", response.paymentMethod.card.exp_year);
|
||||
brand_field.setAttribute("value", response.paymentMethod.card.brand);
|
||||
last4_field.setAttribute("value", response.paymentMethod.card.last4);
|
||||
|
||||
form.submit();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1724,6 +1724,24 @@ en:
|
||||
step2:
|
||||
payment_method:
|
||||
title: Payment method
|
||||
form:
|
||||
card_number:
|
||||
label: Card number
|
||||
placeholder: e.g. 4242 4242 4242 4242
|
||||
card_verification_value:
|
||||
label: CVC
|
||||
placeholder: 123
|
||||
card_month:
|
||||
label: Month
|
||||
placeholder: 01
|
||||
card_year:
|
||||
label: Year
|
||||
placeholder: 2020
|
||||
stripe:
|
||||
use_saved_card: Use saved card
|
||||
use_new_card: Enter your card identifiers
|
||||
save_card: Save card for future use
|
||||
create_new_card: or enter new card details below
|
||||
explaination: You can review and confirm your order in the next step which includes the final costs.
|
||||
submit: Next - Order summary
|
||||
cancel: Back to Your details
|
||||
|
||||
137
spec/javascripts/stimulus/paymentmethod_controller_test.js
Normal file
137
spec/javascripts/stimulus/paymentmethod_controller_test.js
Normal file
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import { Application } from "stimulus";
|
||||
import paymentmethod_controller from "../../../app/webpacker/controllers/paymentmethod_controller";
|
||||
|
||||
describe("PaymentmethodController", () => {
|
||||
describe("#selectPaymentMethod", () => {
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = `<div data-controller="paymentmethod">
|
||||
<span id="paymentmethod_1" data-action="click->paymentmethod#selectPaymentMethod" data-paymentmethod-id="paymentmethod1" />
|
||||
<span id="paymentmethod_2" data-action="click->paymentmethod#selectPaymentMethod" data-paymentmethod-id="paymentmethod2" />
|
||||
<span id="paymentmethod_3" data-action="click->paymentmethod#selectPaymentMethod" data-paymentmethod-id="paymentmethod3" />
|
||||
|
||||
<div class="paymentmethod-container" style="display: none;" id="paymentmethod1">
|
||||
<input type="number" required id="input1" />
|
||||
<select id="select1" >
|
||||
<option value="1">1</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="paymentmethod-container" style="display: block;" id="paymentmethod2">
|
||||
<input type="number" required="true" id="input2" />
|
||||
<select id="select2" >
|
||||
<option value="1">1</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="paymentmethod-container" style="display: none;" id="paymentmethod3">
|
||||
<input type="number" id="input3" />
|
||||
<select id="select3" >
|
||||
<option value="1">1</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
const application = Application.start();
|
||||
application.register("paymentmethod", paymentmethod_controller);
|
||||
});
|
||||
|
||||
it("fill the right payment container", () => {
|
||||
const paymentMethod1 = document.getElementById("paymentmethod_1");
|
||||
const paymentMethod2 = document.getElementById("paymentmethod_2");
|
||||
const paymentMethod3 = document.getElementById("paymentmethod_3");
|
||||
|
||||
const paymentMethod1Container = document.getElementById("paymentmethod1");
|
||||
const paymentMethod2Container = document.getElementById("paymentmethod2");
|
||||
const paymentMethod3Container = document.getElementById("paymentmethod3");
|
||||
|
||||
expect(paymentMethod1Container.style.display).toBe("none");
|
||||
expect(paymentMethod2Container.style.display).toBe("block");
|
||||
expect(paymentMethod3Container.style.display).toBe("none");
|
||||
|
||||
paymentMethod1.click();
|
||||
expect(paymentMethod1Container.style.display).toBe("block");
|
||||
expect(paymentMethod2Container.style.display).toBe("none");
|
||||
expect(paymentMethod3Container.style.display).toBe("none");
|
||||
|
||||
paymentMethod3.click();
|
||||
expect(paymentMethod1Container.style.display).toBe("none");
|
||||
expect(paymentMethod2Container.style.display).toBe("none");
|
||||
expect(paymentMethod3Container.style.display).toBe("block");
|
||||
});
|
||||
|
||||
it("handle well the add/remove on 'required' attribute on each input", () => {
|
||||
const paymentMethod1 = document.getElementById("paymentmethod_1");
|
||||
const paymentMethod2 = document.getElementById("paymentmethod_2");
|
||||
const paymentMethod3 = document.getElementById("paymentmethod_3");
|
||||
|
||||
const input1 = document.getElementById("input1");
|
||||
const input2 = document.getElementById("input2");
|
||||
const input3 = document.getElementById("input3");
|
||||
|
||||
paymentMethod1.click();
|
||||
expect(input1.required).toBe(true);
|
||||
expect(input2.dataset.required).toBe("true");
|
||||
expect(input2.required).toBe(false);
|
||||
expect(input3.required).toBe(false);
|
||||
|
||||
paymentMethod2.click();
|
||||
expect(input2.required).toBe(true);
|
||||
expect(input1.dataset.required).toBe("true");
|
||||
expect(input1.required).toBe(false);
|
||||
expect(input3.required).toBe(false);
|
||||
|
||||
paymentMethod3.click();
|
||||
expect(input1.required).toBe(false);
|
||||
expect(input2.required).toBe(false);
|
||||
expect(input3.required).toBe(false);
|
||||
|
||||
paymentMethod1.click();
|
||||
expect(input1.required).toBe(true);
|
||||
expect(input2.dataset.required).toBe("true");
|
||||
expect(input2.required).toBe(false);
|
||||
expect(input3.required).toBe(false);
|
||||
});
|
||||
|
||||
it("handle well the add/remove 'disabled='disabled'' attribute on each input/select", () => {
|
||||
const paymentMethod1 = document.getElementById("paymentmethod_1");
|
||||
const paymentMethod2 = document.getElementById("paymentmethod_2");
|
||||
const paymentMethod3 = document.getElementById("paymentmethod_3");
|
||||
|
||||
const input1 = document.getElementById("input1");
|
||||
const input2 = document.getElementById("input2");
|
||||
const input3 = document.getElementById("input3");
|
||||
const select1 = document.getElementById("select1");
|
||||
const select2 = document.getElementById("select2");
|
||||
const select3 = document.getElementById("select3");
|
||||
|
||||
paymentMethod1.click();
|
||||
expect(input1.disabled).toBe(false);
|
||||
expect(select1.disabled).toBe(false);
|
||||
|
||||
expect(input2.disabled).toBe(true);
|
||||
expect(select2.disabled).toBe(true);
|
||||
expect(input3.disabled).toBe(true);
|
||||
expect(select3.disabled).toBe(true);
|
||||
|
||||
paymentMethod2.click();
|
||||
expect(input2.disabled).toBe(false);
|
||||
expect(select2.disabled).toBe(false);
|
||||
|
||||
expect(input1.disabled).toBe(true);
|
||||
expect(select1.disabled).toBe(true);
|
||||
expect(input3.disabled).toBe(true);
|
||||
expect(select3.disabled).toBe(true);
|
||||
|
||||
paymentMethod3.click();
|
||||
expect(input3.disabled).toBe(false);
|
||||
expect(select3.disabled).toBe(false);
|
||||
|
||||
expect(input1.disabled).toBe(true);
|
||||
expect(select1.disabled).toBe(true);
|
||||
expect(input2.disabled).toBe(true);
|
||||
expect(select2.disabled).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
55
spec/javascripts/stimulus/stripe_cards_controller_test.js
Normal file
55
spec/javascripts/stimulus/stripe_cards_controller_test.js
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import { Application } from "stimulus";
|
||||
import stripe_cards_controller from "../../../app/webpacker/controllers/stripe_cards_controller";
|
||||
|
||||
describe("StripeCardsController", () => {
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = `<div data-controller="stripe-cards">
|
||||
<select data-action="change->stripe-cards#onSelectCard" id="select">
|
||||
<option value="">Blank</option>
|
||||
<option value="1">Card #1</option>
|
||||
<option value="2">Card #2</option>
|
||||
</select>
|
||||
<div data-stripe-cards-target="stripeelements" id="stripeelements" />
|
||||
</div>`;
|
||||
|
||||
const application = Application.start();
|
||||
application.register("stripe-cards", stripe_cards_controller);
|
||||
});
|
||||
describe("#connect", () => {
|
||||
it("initialize with the right display state", () => {
|
||||
const select = document.getElementById("select");
|
||||
select.value = "";
|
||||
select.dispatchEvent(new Event("change"));
|
||||
expect(document.getElementById("stripeelements").style.display).toBe(
|
||||
"block"
|
||||
);
|
||||
});
|
||||
});
|
||||
describe("#selectCard", () => {
|
||||
it("fill the right payment container", () => {
|
||||
const select = document.getElementById("select");
|
||||
select.value = "1";
|
||||
select.dispatchEvent(new Event("change"));
|
||||
|
||||
expect(document.getElementById("stripeelements").style.display).toBe(
|
||||
"none"
|
||||
);
|
||||
|
||||
select.value = "2";
|
||||
select.dispatchEvent(new Event("change"));
|
||||
expect(document.getElementById("stripeelements").style.display).toBe(
|
||||
"none"
|
||||
);
|
||||
|
||||
select.value = "";
|
||||
select.dispatchEvent(new Event("change"));
|
||||
expect(document.getElementById("stripeelements").style.display).toBe(
|
||||
"block"
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user