@graphcommerce/mollie-magento-payment 3.1.0 → 3.2.1

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,46 @@
1
1
  # Change Log
2
2
 
3
+ ## 3.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies []:
8
+ - @graphcommerce/magento-cart@4.2.5
9
+ - @graphcommerce/magento-cart-payment-method@3.1.1
10
+
11
+ ## 3.2.0
12
+
13
+ ### Minor Changes
14
+
15
+ - [#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
16
+
17
+ ### Patch Changes
18
+
19
+ - [#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
20
+
21
+ - 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)]:
22
+ - @graphcommerce/next-ui@4.6.0
23
+ - @graphcommerce/magento-cart@4.2.4
24
+ - @graphcommerce/magento-cart-payment-method@3.1.0
25
+ - @graphcommerce/react-hook-form@3.1.0
26
+ - @graphcommerce/image@3.1.4
27
+ - @graphcommerce/magento-store@4.1.6
28
+
29
+ ## 3.1.1
30
+
31
+ ### Patch Changes
32
+
33
+ - [#1378](https://github.com/graphcommerce-org/graphcommerce/pull/1378) [`b610a6e40`](https://github.com/graphcommerce-org/graphcommerce/commit/b610a6e4049e8c9e8b5d2aeff31b8e1bfc24abe5) Thanks [@paales](https://github.com/paales)! - Pin all versions internally so we can’t end up in an unfixable state for the user
34
+
35
+ - Updated dependencies [[`b610a6e40`](https://github.com/graphcommerce-org/graphcommerce/commit/b610a6e4049e8c9e8b5d2aeff31b8e1bfc24abe5), [`22ff9df16`](https://github.com/graphcommerce-org/graphcommerce/commit/22ff9df1677742ae8e07d9b7e5b12fbb487580dc)]:
36
+ - @graphcommerce/graphql@3.0.7
37
+ - @graphcommerce/image@3.1.3
38
+ - @graphcommerce/magento-cart@4.2.3
39
+ - @graphcommerce/magento-cart-payment-method@3.0.7
40
+ - @graphcommerce/magento-store@4.1.5
41
+ - @graphcommerce/next-ui@4.5.1
42
+ - @graphcommerce/react-hook-form@3.0.7
43
+
3
44
  ## 3.1.0
4
45
 
5
46
  ### Minor 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
  }
@@ -6,18 +6,15 @@ import { Trans } from '@lingui/macro'
6
6
  import { Box, TextField, Typography } from '@mui/material'
7
7
  import { SetMolliePaymentMethodIssuerOnCartDocument } from './SetMolliePaymentMethodIssuerOnCart.gql'
8
8
 
9
- type MollieIssuerOptionsProps = PaymentOptionsProps & { label: string }
9
+ type MollieIssuerOptionsProps = PaymentOptionsProps & { label: string; children?: React.ReactNode }
10
10
 
11
11
  const compName = 'MollieIssuerOptions' as const
12
- const parts = ['root', 'list'] as const
13
- const { classes } = extendableComponent(compName, parts)
14
12
 
15
13
  export function MollieIssuerOptions(props: MollieIssuerOptionsProps) {
16
- const { mollie_available_issuers = [], selected } = props
14
+ const { mollie_available_issuers = [], children } = props
17
15
  const { code, step, Container, label, title = '' } = props
18
16
 
19
17
  const form = useFormGqlMutationCart(SetMolliePaymentMethodIssuerOnCartDocument, {
20
- mode: 'onChange',
21
18
  defaultValues: { code },
22
19
  })
23
20
 
@@ -25,7 +22,13 @@ export function MollieIssuerOptions(props: MollieIssuerOptionsProps) {
25
22
  const submit = handleSubmit(() => {})
26
23
  const valid = useFormValidFields(form, required)
27
24
 
28
- useFormPersist({ form, name: `PaymentMethodOptions_${code}` })
25
+ // Since the issuer isn't retrievable from Magento we persist this value.
26
+ useFormPersist({
27
+ form,
28
+ name: `PaymentMethodOptions_${code}`,
29
+ persist: ['issuer'],
30
+ storage: 'localStorage',
31
+ })
29
32
  useFormCompose({ form, step, submit, key: `PaymentMethodOptions_${code}` })
30
33
 
31
34
  return (
@@ -44,7 +47,9 @@ export function MollieIssuerOptions(props: MollieIssuerOptionsProps) {
44
47
  helperText={formState.isSubmitted && formState.errors.issuer?.message}
45
48
  label={label}
46
49
  required={required.issuer}
47
- {...muiRegister('issuer', { required: required.issuer })}
50
+ {...muiRegister('issuer', {
51
+ required: { value: required.issuer, message: 'Please provide an issuer' },
52
+ })}
48
53
  InputProps={{
49
54
  endAdornment: <InputCheckmark show={valid.issuer} select />,
50
55
  }}
@@ -62,24 +67,8 @@ export function MollieIssuerOptions(props: MollieIssuerOptionsProps) {
62
67
  })}
63
68
  </TextField>
64
69
  </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
70
  </form>
71
+ {children}
83
72
  </Container>
84
73
  )
85
74
  }
@@ -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,9 @@
1
1
  import { PaymentStatusEnum, useMutation } from '@graphcommerce/graphql'
2
+ import { ApolloCartErrorFullPage, useClearCurrentCartId } from '@graphcommerce/magento-cart'
2
3
  import {
3
- ApolloCartErrorFullPage,
4
- useClearCurrentCartId,
5
- useCurrentCartId,
6
- } from '@graphcommerce/magento-cart'
7
- import { usePaymentMethodContext } from '@graphcommerce/magento-cart-payment-method'
4
+ PaymentHandlerProps,
5
+ usePaymentMethodContext,
6
+ } from '@graphcommerce/magento-cart-payment-method'
8
7
  import { ErrorSnackbar } from '@graphcommerce/next-ui'
9
8
  import { Trans } from '@lingui/macro'
10
9
  import { Button, Dialog } from '@mui/material'
@@ -16,15 +15,15 @@ import { MollieRecoverCartDocument } from './MollieRecoverCart.gql'
16
15
 
17
16
  const successStatusses: PaymentStatusEnum[] = ['AUTHORIZED', 'COMPLETED', 'PAID', 'SHIPPING']
18
17
 
19
- export function MolliePaymentHandler() {
18
+ export function MolliePaymentHandler({ code }: PaymentHandlerProps) {
20
19
  const router = useRouter()
21
20
  const method = usePaymentMethodContext()
22
21
  const clear = useClearCurrentCartId()
23
22
 
24
- const isMollie = method.selectedMethod?.code.startsWith('mollie_methods')
25
-
26
23
  const [lockState] = useCartLockWithToken()
27
24
 
25
+ const isActive = method.selectedMethod?.code === code || lockState.method === code
26
+
28
27
  const [handle, handleResult] = useMutation(MolliePaymentHandlerDocument)
29
28
  const [recoverCart, recoverResult] = useMutation(MollieRecoverCartDocument)
30
29
 
@@ -33,7 +32,8 @@ export function MolliePaymentHandler() {
33
32
  useEffect(() => {
34
33
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
35
34
  ;(async () => {
36
- if (lockState.locked && lockState.redirecting) return
35
+ if (!isActive) return
36
+ if (lockState.locked && lockState.justLocked) return
37
37
 
38
38
  if (!lockState.mollie_payment_token) return
39
39
  if (called || error) return
@@ -61,7 +61,7 @@ export function MolliePaymentHandler() {
61
61
  router.replace('/checkout/payment')
62
62
  }
63
63
  })()
64
- }, [called, clear, error, handle, lockState, recoverCart, router])
64
+ }, [called, clear, error, handle, isActive, lockState, recoverCart, router])
65
65
 
66
66
  const paymentStatus = data?.mollieProcessTransaction?.paymentStatus
67
67
  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.0",
5
+ "version": "3.2.1",
6
6
  "sideEffects": false,
7
7
  "engines": {
8
8
  "node": "14.x"
@@ -15,29 +15,29 @@
15
15
  }
16
16
  },
17
17
  "devDependencies": {
18
- "@graphcommerce/eslint-config-pwa": "^4.1.3",
19
- "@graphcommerce/magento-cart-shipping-address": "^3.0.5",
20
- "@graphcommerce/magento-product": "^4.1.3",
21
- "@graphcommerce/magento-product-configurable": "^4.0.7",
18
+ "@graphcommerce/eslint-config-pwa": "^4.1.4",
19
+ "@graphcommerce/magento-cart-shipping-address": "3.0.8",
20
+ "@graphcommerce/magento-product": "4.1.6",
21
+ "@graphcommerce/magento-product-configurable": "4.0.10",
22
22
  "@graphcommerce/prettier-config-pwa": "^4.0.5",
23
23
  "@graphcommerce/typescript-config-pwa": "^4.0.2",
24
24
  "@playwright/test": "^1.20.1",
25
25
  "type-fest": "2.12.1"
26
26
  },
27
27
  "dependencies": {
28
- "@graphcommerce/graphql": "^3.0.6",
29
- "@graphcommerce/image": "^3.1.2",
30
- "@graphcommerce/magento-cart": "^4.2.2",
31
- "@graphcommerce/magento-cart-payment-method": "^3.0.6",
32
- "@graphcommerce/magento-store": "^4.1.4",
33
- "@graphcommerce/next-ui": "^4.5.0",
34
- "@graphcommerce/react-hook-form": "^3.0.6"
28
+ "@graphcommerce/graphql": "3.0.7",
29
+ "@graphcommerce/image": "3.1.4",
30
+ "@graphcommerce/magento-cart": "4.2.5",
31
+ "@graphcommerce/magento-cart-payment-method": "3.1.1",
32
+ "@graphcommerce/magento-store": "4.1.6",
33
+ "@graphcommerce/next-ui": "4.6.0",
34
+ "@graphcommerce/react-hook-form": "3.1.0"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "@lingui/macro": "^3.13.2",
38
- "@mui/material": "^5.4.1",
38
+ "@mui/material": "5.5.3",
39
39
  "framer-motion": "^6.2.4",
40
- "next": "^12.0.10",
40
+ "next": "12.1.2",
41
41
  "react": "^17.0.1",
42
42
  "react-dom": "^17.0.1"
43
43
  }
@@ -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
+ }