@graphcommerce/mollie-magento-payment 3.1.1 → 3.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,51 @@
1
1
  # Change Log
2
2
 
3
+ ## 3.2.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1399](https://github.com/graphcommerce-org/graphcommerce/pull/1399) [`fb277d8e1`](https://github.com/graphcommerce-org/graphcommerce/commit/fb277d8e1e3612c5e9cf890a30d19cfd1ff70542) Thanks [@paales](https://github.com/paales)! - Now using [@graphql-yoga](https://github.com/dotansimha/graphql-yoga) for GraphQL which has full support for [envelop](https://www.envelop.dev/) plugins.
8
+
9
+ * [#1399](https://github.com/graphcommerce-org/graphcommerce/pull/1399) [`fb277d8e1`](https://github.com/graphcommerce-org/graphcommerce/commit/fb277d8e1e3612c5e9cf890a30d19cfd1ff70542) Thanks [@paales](https://github.com/paales)! - Added a new @graphcommerce/cli package to generate the mesh so it can be generated _inside_ the @graphcommerce/graphql-mesh package to allow for better future extensibility.
10
+
11
+ - [#1399](https://github.com/graphcommerce-org/graphcommerce/pull/1399) [`da0ae7d02`](https://github.com/graphcommerce-org/graphcommerce/commit/da0ae7d0236e4908ba0bf0fa16656be516e841d4) Thanks [@paales](https://github.com/paales)! - Updated dependencies
12
+
13
+ - Updated dependencies [[`fb277d8e1`](https://github.com/graphcommerce-org/graphcommerce/commit/fb277d8e1e3612c5e9cf890a30d19cfd1ff70542), [`fb277d8e1`](https://github.com/graphcommerce-org/graphcommerce/commit/fb277d8e1e3612c5e9cf890a30d19cfd1ff70542), [`8652662cf`](https://github.com/graphcommerce-org/graphcommerce/commit/8652662cf9a8711d1c685d4f5cd788870a8242e2), [`da0ae7d02`](https://github.com/graphcommerce-org/graphcommerce/commit/da0ae7d0236e4908ba0bf0fa16656be516e841d4)]:
14
+ - @graphcommerce/graphql@3.1.0
15
+ - @graphcommerce/graphql-mesh@4.1.0
16
+ - @graphcommerce/magento-cart@4.2.6
17
+ - @graphcommerce/magento-cart-payment-method@3.1.2
18
+ - @graphcommerce/magento-store@4.1.7
19
+ - @graphcommerce/next-ui@4.6.1
20
+ - @graphcommerce/react-hook-form@3.1.1
21
+ - @graphcommerce/image@3.1.5
22
+
23
+ ## 3.2.1
24
+
25
+ ### Patch Changes
26
+
27
+ - Updated dependencies []:
28
+ - @graphcommerce/magento-cart@4.2.5
29
+ - @graphcommerce/magento-cart-payment-method@3.1.1
30
+
31
+ ## 3.2.0
32
+
33
+ ### Minor Changes
34
+
35
+ - [#1379](https://github.com/graphcommerce-org/graphcommerce/pull/1379) [`7c1b45348`](https://github.com/graphcommerce-org/graphcommerce/commit/7c1b45348bcf99a0dd16d2079893680c5cb6ffc9) Thanks [@paales](https://github.com/paales)! - Support for mollie credit cards and playwright tests
36
+
37
+ ### Patch Changes
38
+
39
+ - [#1379](https://github.com/graphcommerce-org/graphcommerce/pull/1379) [`b8d04130a`](https://github.com/graphcommerce-org/graphcommerce/commit/b8d04130a1b1cb8fc85308939235140288744465) Thanks [@paales](https://github.com/paales)! - Removed unused trigger: onChange for useForm handler
40
+
41
+ - Updated dependencies [[`3c801f45c`](https://github.com/graphcommerce-org/graphcommerce/commit/3c801f45c7df55131acf30ae2fe0d2344830d480), [`b8d04130a`](https://github.com/graphcommerce-org/graphcommerce/commit/b8d04130a1b1cb8fc85308939235140288744465), [`3192fab82`](https://github.com/graphcommerce-org/graphcommerce/commit/3192fab82560e2211dfcacadc3b0b305260527d8), [`104abd14e`](https://github.com/graphcommerce-org/graphcommerce/commit/104abd14e1585ef0d8de77937d25156b8fa1e201), [`0e425e85e`](https://github.com/graphcommerce-org/graphcommerce/commit/0e425e85ee8fed280349317ee0440c7bceea5823), [`2a125b1f9`](https://github.com/graphcommerce-org/graphcommerce/commit/2a125b1f98bb9272d96c3577f21d6c984caad892), [`8a354d1cd`](https://github.com/graphcommerce-org/graphcommerce/commit/8a354d1cd4757497ddfc9b1969a0addbc8ff616b), [`6ebe9d12d`](https://github.com/graphcommerce-org/graphcommerce/commit/6ebe9d12db9fcaa2af67a475e64a08d63e232b46)]:
42
+ - @graphcommerce/next-ui@4.6.0
43
+ - @graphcommerce/magento-cart@4.2.4
44
+ - @graphcommerce/magento-cart-payment-method@3.1.0
45
+ - @graphcommerce/react-hook-form@3.1.0
46
+ - @graphcommerce/image@3.1.4
47
+ - @graphcommerce/magento-store@4.1.6
48
+
3
49
  ## 3.1.1
4
50
 
5
51
  ### Patch Changes
@@ -1,6 +1,27 @@
1
1
  import { PaymentOptionsProps } from '@graphcommerce/magento-cart-payment-method'
2
+ import { Trans } from '@lingui/macro'
3
+ import { Box } from '@mui/material'
2
4
  import { MollieIssuerOptions } from './MollieIssuerOptions'
3
5
 
4
6
  export function MollieIdealOptions(props: PaymentOptionsProps) {
5
- return <MollieIssuerOptions label='Choose your bank' {...props} />
7
+ return (
8
+ <MollieIssuerOptions label='Choose your bank' {...props}>
9
+ <Box
10
+ component='ul'
11
+ sx={(theme) => ({ typography: 'body2', paddingLeft: theme.spacings.xs, margin: 0 })}
12
+ >
13
+ <li>
14
+ <Trans>Choose your bank, and place your order.</Trans>
15
+ </li>
16
+ <li>
17
+ <Trans>Complete the payment on your bank’s website.</Trans>
18
+ </li>
19
+ <li>
20
+ <Trans>
21
+ As soon as the payment is completed, you will automatically return to the webshop.
22
+ </Trans>
23
+ </li>
24
+ </Box>
25
+ </MollieIssuerOptions>
26
+ )
6
27
  }
@@ -1,23 +1,18 @@
1
1
  import { useFormGqlMutationCart } from '@graphcommerce/magento-cart'
2
2
  import { PaymentOptionsProps } from '@graphcommerce/magento-cart-payment-method'
3
- import { extendableComponent, FormRow, InputCheckmark } from '@graphcommerce/next-ui'
3
+ import { FormRow, InputCheckmark } from '@graphcommerce/next-ui'
4
4
  import { useFormCompose, useFormPersist, useFormValidFields } from '@graphcommerce/react-hook-form'
5
5
  import { Trans } from '@lingui/macro'
6
- import { Box, TextField, Typography } from '@mui/material'
6
+ import { TextField, Typography } from '@mui/material'
7
7
  import { SetMolliePaymentMethodIssuerOnCartDocument } from './SetMolliePaymentMethodIssuerOnCart.gql'
8
8
 
9
- type MollieIssuerOptionsProps = PaymentOptionsProps & { label: string }
10
-
11
- const compName = 'MollieIssuerOptions' as const
12
- const parts = ['root', 'list'] as const
13
- const { classes } = extendableComponent(compName, parts)
9
+ type MollieIssuerOptionsProps = PaymentOptionsProps & { label: string; children?: React.ReactNode }
14
10
 
15
11
  export function MollieIssuerOptions(props: MollieIssuerOptionsProps) {
16
- const { mollie_available_issuers = [], selected } = props
12
+ const { mollie_available_issuers = [], children } = props
17
13
  const { code, step, Container, label, title = '' } = props
18
14
 
19
15
  const form = useFormGqlMutationCart(SetMolliePaymentMethodIssuerOnCartDocument, {
20
- mode: 'onChange',
21
16
  defaultValues: { code },
22
17
  })
23
18
 
@@ -25,7 +20,13 @@ export function MollieIssuerOptions(props: MollieIssuerOptionsProps) {
25
20
  const submit = handleSubmit(() => {})
26
21
  const valid = useFormValidFields(form, required)
27
22
 
28
- useFormPersist({ form, name: `PaymentMethodOptions_${code}` })
23
+ // Since the issuer isn't retrievable from Magento we persist this value.
24
+ useFormPersist({
25
+ form,
26
+ name: `PaymentMethodOptions_${code}`,
27
+ persist: ['issuer'],
28
+ storage: 'localStorage',
29
+ })
29
30
  useFormCompose({ form, step, submit, key: `PaymentMethodOptions_${code}` })
30
31
 
31
32
  return (
@@ -44,7 +45,9 @@ export function MollieIssuerOptions(props: MollieIssuerOptionsProps) {
44
45
  helperText={formState.isSubmitted && formState.errors.issuer?.message}
45
46
  label={label}
46
47
  required={required.issuer}
47
- {...muiRegister('issuer', { required: required.issuer })}
48
+ {...muiRegister('issuer', {
49
+ required: { value: required.issuer, message: 'Please provide an issuer' },
50
+ })}
48
51
  InputProps={{
49
52
  endAdornment: <InputCheckmark show={valid.issuer} select />,
50
53
  }}
@@ -62,24 +65,8 @@ export function MollieIssuerOptions(props: MollieIssuerOptionsProps) {
62
65
  })}
63
66
  </TextField>
64
67
  </FormRow>
65
- <Box
66
- component='ul'
67
- className={classes.list}
68
- sx={(theme) => ({ typography: 'body2', paddingLeft: theme.spacings.xs, margin: 0 })}
69
- >
70
- <li>
71
- <Trans>Choose your bank, and place your order.</Trans>
72
- </li>
73
- <li>
74
- <Trans>Complete the payment on your bank’s website.</Trans>
75
- </li>
76
- <li>
77
- <Trans>
78
- As soon as the payment is completed, you will automatically return to the webshop.
79
- </Trans>
80
- </li>
81
- </Box>
82
68
  </form>
69
+ {children}
83
70
  </Container>
84
71
  )
85
72
  }
@@ -20,7 +20,6 @@ export function MollieCreditCardOptions(props: PaymentOptionsProps) {
20
20
  const conf = useQuery(StoreConfigDocument)
21
21
 
22
22
  const form = useFormGqlMutationCart(SetMolliePaymentMethodTokenOnCartDocument, {
23
- mode: 'onChange',
24
23
  defaultValues: { code },
25
24
  onBeforeSubmit: async (variables) => {
26
25
  const result = await mollie?.createToken()
@@ -1,10 +1,10 @@
1
- import { PaymentStatusEnum, useMutation } from '@graphcommerce/graphql'
1
+ import { useMutation } from '@graphcommerce/graphql'
2
+ import { PaymentStatusEnum } from '@graphcommerce/graphql-mesh'
3
+ import { ApolloCartErrorFullPage, useClearCurrentCartId } from '@graphcommerce/magento-cart'
2
4
  import {
3
- ApolloCartErrorFullPage,
4
- useClearCurrentCartId,
5
- useCurrentCartId,
6
- } from '@graphcommerce/magento-cart'
7
- import { usePaymentMethodContext } from '@graphcommerce/magento-cart-payment-method'
5
+ PaymentHandlerProps,
6
+ usePaymentMethodContext,
7
+ } from '@graphcommerce/magento-cart-payment-method'
8
8
  import { ErrorSnackbar } from '@graphcommerce/next-ui'
9
9
  import { Trans } from '@lingui/macro'
10
10
  import { Button, Dialog } from '@mui/material'
@@ -16,15 +16,15 @@ import { MollieRecoverCartDocument } from './MollieRecoverCart.gql'
16
16
 
17
17
  const successStatusses: PaymentStatusEnum[] = ['AUTHORIZED', 'COMPLETED', 'PAID', 'SHIPPING']
18
18
 
19
- export function MolliePaymentHandler() {
19
+ export function MolliePaymentHandler({ code }: PaymentHandlerProps) {
20
20
  const router = useRouter()
21
21
  const method = usePaymentMethodContext()
22
22
  const clear = useClearCurrentCartId()
23
23
 
24
- const isMollie = method.selectedMethod?.code.startsWith('mollie_methods')
25
-
26
24
  const [lockState] = useCartLockWithToken()
27
25
 
26
+ const isActive = method.selectedMethod?.code === code || lockState.method === code
27
+
28
28
  const [handle, handleResult] = useMutation(MolliePaymentHandlerDocument)
29
29
  const [recoverCart, recoverResult] = useMutation(MollieRecoverCartDocument)
30
30
 
@@ -33,7 +33,8 @@ export function MolliePaymentHandler() {
33
33
  useEffect(() => {
34
34
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
35
35
  ;(async () => {
36
- if (lockState.locked && lockState.redirecting) return
36
+ if (!isActive) return
37
+ if (lockState.locked && lockState.justLocked) return
37
38
 
38
39
  if (!lockState.mollie_payment_token) return
39
40
  if (called || error) return
@@ -61,7 +62,7 @@ export function MolliePaymentHandler() {
61
62
  router.replace('/checkout/payment')
62
63
  }
63
64
  })()
64
- }, [called, clear, error, handle, lockState, recoverCart, router])
65
+ }, [called, clear, error, handle, isActive, lockState, recoverCart, router])
65
66
 
66
67
  const paymentStatus = data?.mollieProcessTransaction?.paymentStatus
67
68
  if (paymentStatus)
@@ -1,9 +1,8 @@
1
+ import { useCurrentCartId, useFormGqlMutationCart } from '@graphcommerce/magento-cart'
1
2
  import {
2
- useClearCurrentCartId,
3
- useCurrentCartId,
4
- useFormGqlMutationCart,
5
- } from '@graphcommerce/magento-cart'
6
- import { PaymentPlaceOrderProps } from '@graphcommerce/magento-cart-payment-method'
3
+ PaymentPlaceOrderProps,
4
+ usePaymentMethodContext,
5
+ } from '@graphcommerce/magento-cart-payment-method'
7
6
  import { useFormCompose } from '@graphcommerce/react-hook-form'
8
7
  import { useRouter } from 'next/router'
9
8
  import { useEffect } from 'react'
@@ -15,8 +14,9 @@ export function MolliePlaceOrder(props: PaymentPlaceOrderProps) {
15
14
  const { push } = useRouter()
16
15
  const cartId = useCurrentCartId()
17
16
  const [, lock] = useCartLockWithToken()
17
+ const { selectedMethod } = usePaymentMethodContext()
18
18
 
19
- const form = useFormGqlMutationCart(MolliePlaceOrderDocument, { mode: 'onChange' })
19
+ const form = useFormGqlMutationCart(MolliePlaceOrderDocument)
20
20
 
21
21
  const { handleSubmit, data, error, register, setValue } = form
22
22
 
@@ -25,9 +25,11 @@ export function MolliePlaceOrder(props: PaymentPlaceOrderProps) {
25
25
  // current.searchParams.append('locked', '1')
26
26
  current.searchParams.set('cart_id', cartId ?? '')
27
27
  current.searchParams.set('mollie_payment_token', 'PAYMENT_TOKEN')
28
+ current.searchParams.set('method', selectedMethod?.code ?? '')
29
+ current.searchParams.set('locked', '1')
28
30
  const replaced = current.toString().replace('PAYMENT_TOKEN', '{{payment_token}}')
29
31
  setValue('returnUrl', replaced)
30
- }, [cartId, setValue])
32
+ }, [cartId, selectedMethod?.code, setValue])
31
33
 
32
34
  const submit = handleSubmit(() => {})
33
35
 
@@ -38,11 +40,15 @@ export function MolliePlaceOrder(props: PaymentPlaceOrderProps) {
38
40
 
39
41
  // When redirecting to the payment gateway
40
42
  if (redirectUrl && mollie_payment_token) {
41
- lock({ mollie_payment_token })
43
+ lock({
44
+ mollie_payment_token,
45
+ method: selectedMethod?.code ?? null,
46
+ })
47
+
42
48
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
43
49
  push(redirectUrl)
44
50
  }
45
- }, [cartId, data?.placeOrder?.order, error, lock, push])
51
+ }, [cartId, data?.placeOrder?.order, error, lock, push, selectedMethod?.code])
46
52
 
47
53
  useFormCompose({ form, step, submit, key: `PaymentMethodPlaceOrder_${code}` })
48
54
 
@@ -1,22 +1,5 @@
1
1
  import { CartLockState, useCartLock } from '@graphcommerce/magento-cart-payment-method'
2
- import { useState } from 'react'
3
2
 
4
- type MollieLockState = { mollie_payment_token?: string }
3
+ type MollieLockState = CartLockState & { mollie_payment_token: string | null }
5
4
 
6
- export const useCartLockWithToken = () => {
7
- const [queryState, setRouterQuery] = useCartLock<MollieLockState>()
8
- const [redirecting, setRedirecting] = useState(false)
9
-
10
- const lock = (params: MollieLockState & CartLockState) => {
11
- setRedirecting(true)
12
- setRouterQuery(params)
13
- }
14
-
15
- const state = {
16
- ...queryState,
17
- locked: queryState.locked === '1',
18
- redirecting,
19
- }
20
-
21
- return [state, lock] as const
22
- }
5
+ export const useCartLockWithToken = () => useCartLock<MollieLockState>()
@@ -1,5 +1,5 @@
1
1
  import { PaymentMethodOptionsNoop, PaymentModule } from '@graphcommerce/magento-cart-payment-method'
2
- import { MollieCreditCardOptions } from '../components/MollieOptionsToken/MollieCreditCardOptions'
2
+ import { MolliePaymentHandler } from '../components/MolliePaymentHandler/MolliePaymentHandler'
3
3
  import { PaymentToggle } from '../components/MolliePaymentToggle/MolliePaymentToggle'
4
4
  import { MolliePlaceOrder } from '../components/MolliePlaceOrder/MolliePlaceOrder'
5
5
 
@@ -7,4 +7,5 @@ export const mollie_methods_creditcard: PaymentModule = {
7
7
  PaymentToggle,
8
8
  PaymentOptions: PaymentMethodOptionsNoop,
9
9
  PaymentPlaceOrder: MolliePlaceOrder,
10
+ PaymentHandler: MolliePaymentHandler,
10
11
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@graphcommerce/mollie-magento-payment",
3
3
  "homepage": "https://www.graphcommerce.org/",
4
4
  "repository": "github:graphcommerce-org/graphcommerce",
5
- "version": "3.1.1",
5
+ "version": "3.2.2",
6
6
  "sideEffects": false,
7
7
  "engines": {
8
8
  "node": "14.x"
@@ -15,23 +15,24 @@
15
15
  }
16
16
  },
17
17
  "devDependencies": {
18
- "@graphcommerce/eslint-config-pwa": "^4.1.4",
19
- "@graphcommerce/magento-cart-shipping-address": "3.0.6",
20
- "@graphcommerce/magento-product": "4.1.4",
21
- "@graphcommerce/magento-product-configurable": "4.0.8",
22
- "@graphcommerce/prettier-config-pwa": "^4.0.5",
18
+ "@graphcommerce/eslint-config-pwa": "^4.1.5",
19
+ "@graphcommerce/magento-cart-shipping-address": "3.0.9",
20
+ "@graphcommerce/magento-product": "4.1.7",
21
+ "@graphcommerce/magento-product-configurable": "4.0.11",
22
+ "@graphcommerce/prettier-config-pwa": "^4.0.6",
23
23
  "@graphcommerce/typescript-config-pwa": "^4.0.2",
24
- "@playwright/test": "^1.20.1",
25
- "type-fest": "2.12.1"
24
+ "@playwright/test": "^1.21.1",
25
+ "type-fest": "^2.12.2"
26
26
  },
27
27
  "dependencies": {
28
- "@graphcommerce/graphql": "3.0.7",
29
- "@graphcommerce/image": "3.1.3",
30
- "@graphcommerce/magento-cart": "4.2.3",
31
- "@graphcommerce/magento-cart-payment-method": "3.0.7",
32
- "@graphcommerce/magento-store": "4.1.5",
33
- "@graphcommerce/next-ui": "4.5.1",
34
- "@graphcommerce/react-hook-form": "3.0.7"
28
+ "@graphcommerce/graphql": "3.1.0",
29
+ "@graphcommerce/graphql-mesh": "4.1.0",
30
+ "@graphcommerce/image": "3.1.5",
31
+ "@graphcommerce/magento-cart": "4.2.6",
32
+ "@graphcommerce/magento-cart-payment-method": "3.1.2",
33
+ "@graphcommerce/magento-store": "4.1.7",
34
+ "@graphcommerce/next-ui": "4.6.1",
35
+ "@graphcommerce/react-hook-form": "3.1.1"
35
36
  },
36
37
  "peerDependencies": {
37
38
  "@lingui/macro": "^3.13.2",
@@ -1,70 +1,55 @@
1
1
  /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
- import { waitForGraphQlResponse } from '@graphcommerce/graphql/test/apolloClient.fixture'
2
+ import { selectPaymentMethod } from '@graphcommerce/magento-cart-payment-method/test'
3
3
  import { goToPayment } from '@graphcommerce/magento-cart-payment-method/test/goToPayment'
4
4
  import { addConfigurableProductToCart } from '@graphcommerce/magento-product-configurable/test/addConfigurableProductToCart'
5
5
  import { test } from '@graphcommerce/magento-product/test/productURL.fixture'
6
- import { expect, Page } from '@playwright/test'
7
- import { MolliePaymentHandlerDocument } from '../components/MolliePaymentHandler/MolliePaymentHandler.gql'
6
+ import { expect } from '@playwright/test'
7
+ import { placeOrderOffsite } from './utils'
8
8
 
9
- const selectCreditCard = async (page: Page) => {
10
- await page.click('button[value=mollie_methods_creditcard]')
9
+ const method = 'mollie_methods_creditcard'
11
10
 
12
- // Select Rabobank
13
- }
14
-
15
- type Statuses = 'paid' | 'failed' | 'canceled' | 'open' | 'expired'
16
-
17
- const placeOrder = async (page: Page, status: Statuses) => {
18
- await Promise.all([page.waitForNavigation(), page.click('#place-order')])
19
-
20
- await page.pause()
21
- // await page.click(`input[name="final_state"][value=${status}]`)
22
- // await Promise.all([page.waitForNavigation(), page.click('.footer button')])
23
-
24
- const result = await waitForGraphQlResponse(page, MolliePaymentHandlerDocument)
25
- expect(result.errors).toBeUndefined()
26
- expect(result.data?.mollieProcessTransaction?.paymentStatus).toBe(status.toUpperCase())
27
- }
28
-
29
- test.describe('mollie creditcard place order', () => {
30
- // test('CANCELED', async ({ page, productURL, apolloClient }) => {
31
- // await addConfigurableProductToCart(page, productURL.ConfigurableProduct)
32
- // await goToPayment(page, apolloClient)
33
- // await selectCreditCard(page)
34
- // await placeOrder(page, 'canceled')
35
- // await placeOrder(page, 'paid')
36
- // expect(await page.locator('text=Back to home').innerText()).toBeDefined()
37
- // })
11
+ test.describe.only('mollie creditcard place order', () => {
12
+ test('Should be able to place an order and return on the success page', async ({
13
+ page,
14
+ productURL,
15
+ apolloClient,
16
+ }) => {
17
+ await addConfigurableProductToCart(page, productURL.ConfigurableProduct)
18
+ await goToPayment(page, apolloClient)
19
+ await selectPaymentMethod(page, method)
38
20
 
39
- // test('OPEN', async ({ page, productURL, apolloClient }) => {
40
- // await addConfigurableProductToCart(page, productURL.ConfigurableProduct)
41
- // await goToPayment(page, apolloClient)
42
- // await selectIdeal(page)
43
- // await placeOrder(page, 'open')
44
- // await placeOrder(page, 'paid')
45
- // expect(await page.locator('text=Back to home').innerText()).toBeDefined()
46
- // })
21
+ await placeOrderOffsite(page, 'paid')
22
+ expect(await page.locator('#back-to-home').innerText()).toBeDefined()
23
+ })
47
24
 
48
- test('PAID', async ({ page, productURL, apolloClient }) => {
25
+ test('Should be possible to cancel an order and then place the order', async ({
26
+ page,
27
+ productURL,
28
+ apolloClient,
29
+ }) => {
49
30
  await addConfigurableProductToCart(page, productURL.ConfigurableProduct)
50
31
  await goToPayment(page, apolloClient)
51
- await selectCreditCard(page)
52
- await placeOrder(page, 'paid')
53
- expect(await page.locator('text=Back to home').innerText()).toBeDefined()
32
+ await selectPaymentMethod(page, method)
33
+ await placeOrderOffsite(page, 'canceled')
34
+ await placeOrderOffsite(page, 'paid')
35
+ expect(await page.locator('#back-to-home').innerText()).toBeDefined()
54
36
  })
55
37
 
56
- // test('Pressed back', async ({ page, productURL, apolloClient }) => {
57
- // await addConfigurableProductToCart(page, productURL.ConfigurableProduct)
58
- // await goToPayment(page, apolloClient)
59
- // await selectIdeal(page)
60
- // await Promise.all([page.waitForNavigation(), page.click('#place-order')])
38
+ test.only('Should be possible to press back on the payment gateway and then place the order', async ({
39
+ page,
40
+ productURL,
41
+ apolloClient,
42
+ }) => {
43
+ await addConfigurableProductToCart(page, productURL.ConfigurableProduct)
44
+ await goToPayment(page, apolloClient)
45
+ await selectPaymentMethod(page, method)
46
+ await Promise.all([page.waitForNavigation(), page.click('#place-order')])
61
47
 
62
- // await page.pause()
63
- // await page.goBack()
48
+ await page.goBack()
64
49
 
65
- // expect(await page.locator('text=Payment failed with status: OPEN').innerText()).toBeDefined()
50
+ expect(await page.locator('text=Payment failed with status: OPEN').innerText()).toBeDefined()
66
51
 
67
- // await placeOrder(page, 'paid')
68
- // expect(await page.locator('text=Back to home').innerText()).toBeDefined()
69
- // })
52
+ await placeOrderOffsite(page, 'paid')
53
+ expect(await page.locator('#back-to-home').innerText()).toBeDefined()
54
+ })
70
55
  })
@@ -1,70 +1,91 @@
1
1
  /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
- import { waitForGraphQlResponse } from '@graphcommerce/graphql/test/apolloClient.fixture'
3
- import { goToPayment } from '@graphcommerce/magento-cart-payment-method/test/goToPayment'
2
+ import { goToPayment, selectPaymentMethod } from '@graphcommerce/magento-cart-payment-method/test'
4
3
  import { addConfigurableProductToCart } from '@graphcommerce/magento-product-configurable/test/addConfigurableProductToCart'
5
4
  import { test } from '@graphcommerce/magento-product/test/productURL.fixture'
6
- import { expect, Page } from '@playwright/test'
7
- import { MolliePaymentHandlerDocument } from '../components/MolliePaymentHandler/MolliePaymentHandler.gql'
5
+ import { expect } from '@playwright/test'
6
+ import { handleOffsitePayment, placeOrderOffsite, selectIssuer } from './utils'
8
7
 
9
- const selectIdeal = async (page: Page) => {
10
- await page.click('button[value=mollie_methods_ideal]')
8
+ const method = 'mollie_methods_ideal'
11
9
 
12
- // Select Rabobank
13
- await page.selectOption('select[name="issuer"]', 'ideal_RABONL2U')
14
- }
15
-
16
- type Statuses = 'paid' | 'failed' | 'canceled' | 'open' | 'expired'
17
-
18
- const placeOrder = async (page: Page, status: Statuses) => {
19
- await Promise.all([page.waitForNavigation(), page.click('#place-order')])
20
-
21
- await page.click(`input[name="final_state"][value=${status}]`)
22
- await Promise.all([page.waitForNavigation(), page.click('.footer button')])
23
-
24
- const result = await waitForGraphQlResponse(page, MolliePaymentHandlerDocument)
25
- expect(result.errors).toBeUndefined()
26
- expect(result.data?.mollieProcessTransaction?.paymentStatus).toBe(status.toUpperCase())
27
- }
28
-
29
- test.describe('mollie ideal place order', () => {
30
- test('CANCELED', async ({ page, productURL, apolloClient }) => {
10
+ test.describe(method, () => {
11
+ test('Should be able to place an order and return on the success page', async ({
12
+ page,
13
+ productURL,
14
+ apolloClient,
15
+ }) => {
31
16
  await addConfigurableProductToCart(page, productURL.ConfigurableProduct)
32
17
  await goToPayment(page, apolloClient)
33
- await selectIdeal(page)
34
- await placeOrder(page, 'canceled')
35
- await placeOrder(page, 'paid')
36
- expect(await page.locator('text=Back to home').innerText()).toBeDefined()
18
+ await selectPaymentMethod(page, method)
19
+
20
+ await selectIssuer(page, 'ideal_RABONL2U')
21
+ await placeOrderOffsite(page, 'paid')
22
+ expect(await page.locator('#back-to-home').innerText()).toBeDefined()
37
23
  })
38
24
 
39
- test('OPEN', async ({ page, productURL, apolloClient }) => {
25
+ test("Should not allow submission when all fields aren't filled yet", async ({
26
+ page,
27
+ productURL,
28
+ apolloClient,
29
+ }) => {
40
30
  await addConfigurableProductToCart(page, productURL.ConfigurableProduct)
41
31
  await goToPayment(page, apolloClient)
42
- await selectIdeal(page)
43
- await placeOrder(page, 'open')
44
- await placeOrder(page, 'paid')
45
- expect(await page.locator('text=Back to home').innerText()).toBeDefined()
32
+ await selectPaymentMethod(page, method)
33
+ await page.click('#place-order')
34
+
35
+ await expect(page.locator('select[name="issuer"]')).toHaveAttribute('aria-invalid', 'true')
46
36
  })
47
37
 
48
- test('PAID', async ({ page, productURL, apolloClient }) => {
38
+ test('Should be possible to cancel an order and then place the order', async ({
39
+ page,
40
+ productURL,
41
+ apolloClient,
42
+ }) => {
49
43
  await addConfigurableProductToCart(page, productURL.ConfigurableProduct)
50
44
  await goToPayment(page, apolloClient)
51
- await selectIdeal(page)
52
- await placeOrder(page, 'paid')
53
- expect(await page.locator('text=Back to home').innerText()).toBeDefined()
45
+ await selectPaymentMethod(page, method)
46
+ await selectIssuer(page, 'ideal_RABONL2U')
47
+ await placeOrderOffsite(page, 'canceled')
48
+ await placeOrderOffsite(page, 'paid')
49
+ expect(await page.locator('#back-to-home').innerText()).toBeDefined()
54
50
  })
55
51
 
56
- test('Pressed back', async ({ page, productURL, apolloClient }) => {
52
+ test('Should be possible to press back on the payment gateway and then place the order', async ({
53
+ page,
54
+ productURL,
55
+ apolloClient,
56
+ }) => {
57
57
  await addConfigurableProductToCart(page, productURL.ConfigurableProduct)
58
58
  await goToPayment(page, apolloClient)
59
- await selectIdeal(page)
59
+ await selectPaymentMethod(page, method)
60
+ await selectIssuer(page, 'ideal_RABONL2U')
60
61
  await Promise.all([page.waitForNavigation(), page.click('#place-order')])
61
62
 
62
- await page.pause()
63
63
  await page.goBack()
64
64
 
65
65
  expect(await page.locator('text=Payment failed with status: OPEN').innerText()).toBeDefined()
66
66
 
67
- await placeOrder(page, 'paid')
68
- expect(await page.locator('text=Back to home').innerText()).toBeDefined()
67
+ await placeOrderOffsite(page, 'paid')
68
+ expect(await page.locator('#back-to-home').innerText()).toBeDefined()
69
+ })
70
+
71
+ test('Should be possible to place the order even though there is a completely separate session', async ({
72
+ page,
73
+ productURL,
74
+ apolloClient,
75
+ context,
76
+ }) => {
77
+ await addConfigurableProductToCart(page, productURL.ConfigurableProduct)
78
+ await goToPayment(page, apolloClient)
79
+ await selectPaymentMethod(page, method)
80
+ await selectIssuer(page, 'ideal_RABONL2U')
81
+ await Promise.all([page.waitForNavigation(), page.click('#place-order')])
82
+
83
+ const page2 = await context.newPage()
84
+ await Promise.all([page2.waitForNavigation(), page2.goto(page.url())])
85
+ await page.close()
86
+
87
+ await handleOffsitePayment(page2, 'paid')
88
+
89
+ expect(await page.locator('#back-to-home').innerText()).toBeDefined()
69
90
  })
70
91
  })
package/test/utils.ts ADDED
@@ -0,0 +1,25 @@
1
+ import { waitForGraphQlResponse } from '@graphcommerce/graphql/test/apolloClient.fixture'
2
+ import { Page, expect } from '@playwright/test'
3
+ import { MolliePaymentHandlerDocument } from '../components/MolliePaymentHandler/MolliePaymentHandler.gql'
4
+
5
+ type Statuses = 'paid' | 'failed' | 'canceled' | 'open' | 'expired'
6
+
7
+ export const handleOffsitePayment = async (page: Page, status: Statuses) => {
8
+ await page.click(`input[name="final_state"][value=${status}]`)
9
+
10
+ await Promise.all([page.waitForNavigation(), page.click('.footer button')])
11
+
12
+ const result = await waitForGraphQlResponse(page, MolliePaymentHandlerDocument)
13
+ expect(result.errors).toBeUndefined()
14
+ expect(result.data?.mollieProcessTransaction?.paymentStatus).toBe(status.toUpperCase())
15
+ }
16
+
17
+ export const placeOrderOffsite = async (page: Page, status: Statuses) => {
18
+ await Promise.all([page.waitForNavigation(), page.click('#place-order')])
19
+
20
+ await handleOffsitePayment(page, status)
21
+ }
22
+
23
+ export const selectIssuer = async (page: Page, issuer: string) => {
24
+ await page.locator('select[name="issuer"]').selectOption(issuer)
25
+ }