From 3da2ba8dafbd7d0325e60a13570d3027c10dcb10 Mon Sep 17 00:00:00 2001 From: Christopher Gammie Date: Sat, 10 Aug 2019 11:29:37 +0100 Subject: [PATCH 1/3] Add {{stripe-elements}} contextual component --- README.md | 57 ++++++++++++++++--- addon/components/stripe-element.js | 11 +++- addon/components/stripe-elements.js | 17 ++++++ .../templates/components/stripe-elements.hbs | 17 ++++++ app/components/stripe-elements.js | 1 + .../components/stripe-elements-test.js | 48 ++++++++++++++++ 6 files changed, 141 insertions(+), 10 deletions(-) create mode 100644 addon/components/stripe-elements.js create mode 100644 addon/templates/components/stripe-elements.hbs create mode 100644 app/components/stripe-elements.js create mode 100644 tests/integration/components/stripe-elements-test.js diff --git a/README.md b/README.md index bdf9903..131f60f 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ ENV.stripe = { ### Mocking the Stripe API -You can configure the Stripe API to be mocked instead of loaded from `https://js.stripe.com/v3/`. This is useful for testing. +You can configure the Stripe API to be mocked instead of loaded from `https://js.stripe.com/v3/`. This is useful for testing. ```js ENV.stripe = { @@ -73,7 +73,7 @@ ENV.stripe = { }; ``` -When enabled, a [mock Stripe object](https://github.com/code-corps/ember-stripe-elements/blob/develop/addon/utils/stripe-mock.js) will be assigned to `window.Stripe` when your app is initialized. +When enabled, a [mock Stripe object](https://github.com/code-corps/ember-stripe-elements/blob/develop/addon/utils/stripe-mock.js) will be assigned to `window.Stripe` when your app is initialized. When using the Stripe mock in tests you will likely need to override the mock's methods according to the needs of your test like so: @@ -154,13 +154,54 @@ You could handle these actions yourself, for example: This addon gives you components that match the different [Element types](https://stripe.com/docs/elements/reference#element-types): -- `{{stripe-card}}` - `card` (recommended) A flexible single-line input that collects all necessary card details. -- `{{stripe-card-number}}` - `cardNumber` The card number. -- `{{stripe-card-expiry}}` - `cardExpiry` The card's expiration date. -- `{{stripe-card-cvc}}` - `cardCvc` The card's CVC number. -- `{{stripe-postal-code}}` - `postalCode` the ZIP/postal code. +Stripe recommend using the their `card` element - a flexible single-line input that collects all necessary card details. +The `{{stripe-card}}` component provides this input. -### Block usage with `options` +Additionally Stripe provide the following elements, which you can use to build your own form to collect card details: + +- `cardNumber`: the card number. +- `cardExpiry`: the card's expiration date. +- `cardCvc`: the card's CVC number. +- `postalCode`: the ZIP/postal code. + +These are provided via our `{{stripe-elements}}` contextual component, which yields sub-components for each element type: + +```hbs +{{#stripe-elements as |elements|}} + {{elements.cardNumber}} + {{elements.cardExpiry}} + {{elements.cardCvc}} + {{elements.postalCode}} +{{/stripe-elements}} +``` + +> The `{{stripe-elements}}` component is a tagless component, so does not have any classes etc on it. + +### Elements Options + +The `{{stripe-elements}}` contextual component ensures all the individual elements are created from +the same [Stripe Elements object](https://stripe.com/docs/stripe-js/reference#the-elements-object). + +If you want to pass options to the Stripe Elements object, pass them to the `{{stripe-elements}}` +contextual component. For example, when using the single-line `card` element: + +```hbs +{{#stripe-elements options=elementOptions as |elements|}} + {{elements.card options=cardOptions}} +{{/stripe-elements}} +``` + +Or when creating your own form: + +```hbs +{{#stripe-elements options=elementsOptions as |elements|}} + {{elements.cardNumber options=cardNumberOptions}} + {{elements.cardExpiry}} + {{elements.cardCvc}} +{{/stripe-elements}} +``` + +### Block usage with element `options` In addition to the simple usage above, like `{{stripe-card}}`, you can also yield to a block, which will yield both an `stripeError` object and [the `stripeElement` itself](https://stripe.com/docs/elements/reference#the-element). diff --git a/addon/components/stripe-element.js b/addon/components/stripe-element.js index df5f4bb..c78c260 100644 --- a/addon/components/stripe-element.js +++ b/addon/components/stripe-element.js @@ -17,8 +17,15 @@ export default Component.extend({ }, stripev3: service(), - elements: computed(function() { - return get(this, 'stripev3.elements')(); + + elements: computed({ + get() { + return get(this, 'stripev3.elements')(); + }, + + set(key, value) { + return value; + } }), didInsertElement() { diff --git a/addon/components/stripe-elements.js b/addon/components/stripe-elements.js new file mode 100644 index 0000000..ed00373 --- /dev/null +++ b/addon/components/stripe-elements.js @@ -0,0 +1,17 @@ +import Component from '@ember/component'; +import layout from '../templates/components/stripe-elements'; +import { inject as service } from '@ember/service'; +import { get, set } from '@ember/object'; + +export default Component.extend({ + stripe: service('stripev3'), + tagName: '', + layout, + + init() { + this._super(...arguments); + let options = get(this, 'options') || {}; + let elements = get(this, 'stripe').elements(options); + set(this, 'elements', elements); + } +}); diff --git a/addon/templates/components/stripe-elements.hbs b/addon/templates/components/stripe-elements.hbs new file mode 100644 index 0000000..2399548 --- /dev/null +++ b/addon/templates/components/stripe-elements.hbs @@ -0,0 +1,17 @@ +{{yield (hash + card=(component "stripe-card" + elements=elements + ) + cardNumber=(component "stripe-card-number" + elements=elements + ) + cardExpiry=(component "stripe-card-expiry" + elements=elements + ) + cardCvc=(component "stripe-card-cvc" + elements=elements + ) + postalCode=(component "stripe-postal-code" + elements=elements + ) +)}} diff --git a/app/components/stripe-elements.js b/app/components/stripe-elements.js new file mode 100644 index 0000000..ec46562 --- /dev/null +++ b/app/components/stripe-elements.js @@ -0,0 +1 @@ +export { default } from 'ember-stripe-elements/components/stripe-elements'; \ No newline at end of file diff --git a/tests/integration/components/stripe-elements-test.js b/tests/integration/components/stripe-elements-test.js new file mode 100644 index 0000000..c6a0f64 --- /dev/null +++ b/tests/integration/components/stripe-elements-test.js @@ -0,0 +1,48 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; +import StripeMock from 'ember-stripe-elements/utils/stripe-mock'; +import StripeService from 'dummy/services/stripev3'; +import env from 'dummy/config/environment'; + +module('Integration | Component | stripe-elements', function(hooks) { + setupRenderingTest(hooks); + + hooks.beforeEach(function() { + window.Stripe = StripeMock; + const config = { + mock: true, + publishableKey: env.stripe.publishableKey, + }; + + this.owner.register( + 'service:stripev3', + StripeService.create({ config }), + { instantiate: false } + ); + }); + + test('it renders single-line element', async function (assert) { + assert.expect(0); + + await render(hbs` + {{#stripe-elements as |elements|}} + {{elements.card}} + {{/stripe-elements}} + `); + }); + + test('it renders individual elements', async function (assert) { + assert.expect(0); + + await render(hbs` + {{#stripe-elements as |elements|}} + {{elements.cardNumber}} + {{elements.cardExpiry}} + {{elements.cardCvc}} + {{elements.postalCode}} + {{/stripe-elements}} + `); + }); +}); From 7c0220f95d4ee5b30d41c0b5c0c285e116fb46a9 Mon Sep 17 00:00:00 2001 From: Christopher Gammie Date: Sat, 10 Aug 2019 12:29:15 +0100 Subject: [PATCH 2/3] Update Stripe elements component test --- .../components/stripe-elements-test.js | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/tests/integration/components/stripe-elements-test.js b/tests/integration/components/stripe-elements-test.js index c6a0f64..bb0c4d6 100644 --- a/tests/integration/components/stripe-elements-test.js +++ b/tests/integration/components/stripe-elements-test.js @@ -1,6 +1,6 @@ import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; -import { render } from '@ember/test-helpers'; +import { render, find } from '@ember/test-helpers'; import hbs from 'htmlbars-inline-precompile'; import StripeMock from 'ember-stripe-elements/utils/stripe-mock'; import StripeService from 'dummy/services/stripev3'; @@ -24,18 +24,16 @@ module('Integration | Component | stripe-elements', function(hooks) { }); test('it renders single-line element', async function (assert) { - assert.expect(0); - await render(hbs` {{#stripe-elements as |elements|}} {{elements.card}} {{/stripe-elements}} `); + + assert.ok(find('.ember-stripe-card > [role="mount-point"]')); }); test('it renders individual elements', async function (assert) { - assert.expect(0); - await render(hbs` {{#stripe-elements as |elements|}} {{elements.cardNumber}} @@ -44,5 +42,17 @@ module('Integration | Component | stripe-elements', function(hooks) { {{elements.postalCode}} {{/stripe-elements}} `); + + let tests = [ + 'card-number', + 'card-expiry', + 'card-cvc', + 'postal-code' + ]; + + do { + let el = tests.shift(); + assert.ok(find(`.ember-stripe-${el} > [role="mount-point"]`), el); + } while(tests.length); }); }); From ecda8b603b713134189f7d0b93376e8fdd798316 Mon Sep 17 00:00:00 2001 From: Steve Date: Tue, 3 Sep 2019 13:37:54 +0200 Subject: [PATCH 3/3] fix typos --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 131f60f..fbe0667 100644 --- a/README.md +++ b/README.md @@ -154,10 +154,10 @@ You could handle these actions yourself, for example: This addon gives you components that match the different [Element types](https://stripe.com/docs/elements/reference#element-types): -Stripe recommend using the their `card` element - a flexible single-line input that collects all necessary card details. +Stripe recommends using the their `card` element - a flexible single-line input that collects all necessary card details. The `{{stripe-card}}` component provides this input. -Additionally Stripe provide the following elements, which you can use to build your own form to collect card details: +Additionally Stripe provides the following elements, which you can use to build your own form to collect card details: - `cardNumber`: the card number. - `cardExpiry`: the card's expiration date.