|
| 1 | +import stripe from 'stripe'; |
| 2 | +import { test, expect } from '@playwright/test'; |
| 3 | +import config from 'config'; |
| 4 | +import { payments } from '../../utils'; |
| 5 | + |
| 6 | +const { |
| 7 | + emptyCart, |
| 8 | + setupProductCheckout, |
| 9 | + setupCheckout, |
| 10 | + fillCardDetails, |
| 11 | +} = payments; |
| 12 | + |
| 13 | +test( 'merchant can issue a full refund @smoke', async ( { browser } ) => { |
| 14 | + let orderId, stripeChargeId, stripeRefundId; |
| 15 | + |
| 16 | + const adminContext = await browser.newContext( { |
| 17 | + storageState: process.env.ADMINSTATE, |
| 18 | + } ); |
| 19 | + const adminPage = await adminContext.newPage(); |
| 20 | + |
| 21 | + const userContext = await browser.newContext(); |
| 22 | + const userPage = await userContext.newPage(); |
| 23 | + |
| 24 | + await test.step( 'customer checkout with Stripe', async () => { |
| 25 | + await emptyCart( userPage ); |
| 26 | + |
| 27 | + await setupProductCheckout( userPage ); |
| 28 | + await setupCheckout( |
| 29 | + userPage, |
| 30 | + config.get( 'addresses.customer.billing' ) |
| 31 | + ); |
| 32 | + |
| 33 | + await fillCardDetails( userPage, config.get( 'cards.basic' ) ); |
| 34 | + await userPage.locator( 'text=Place order' ).click(); |
| 35 | + await userPage.waitForNavigation(); |
| 36 | + |
| 37 | + await expect( userPage.locator( 'h1.entry-title' ) ).toHaveText( |
| 38 | + 'Order received' |
| 39 | + ); |
| 40 | + |
| 41 | + const orderUrl = await userPage.url(); |
| 42 | + orderId = orderUrl.split( 'order-received/' )[ 1 ].split( '/?' )[ 0 ]; |
| 43 | + } ); |
| 44 | + |
| 45 | + await test.step( |
| 46 | + 'merchant issue a full refund in the dashboard', |
| 47 | + async () => { |
| 48 | + await adminPage.goto( |
| 49 | + `/wp-admin/post.php?post=${ orderId }&action=edit` |
| 50 | + ); |
| 51 | + |
| 52 | + // Ensure this isn't already refunded. |
| 53 | + await expect( adminPage.locator( '.order_notes' ) ).not.toHaveText( |
| 54 | + /Refunded .* – Refund ID: .* – Reason:.*/ |
| 55 | + ); |
| 56 | + |
| 57 | + stripeChargeId = await adminPage |
| 58 | + .locator( '.woocommerce-order-data__meta a' ) |
| 59 | + .innerText(); |
| 60 | + |
| 61 | + await adminPage |
| 62 | + .locator( '#woocommerce-order-items button.refund-items' ) |
| 63 | + .click(); |
| 64 | + await adminPage.locator( '.refund_order_item_qty' ).fill( '1' ); |
| 65 | + |
| 66 | + adminPage.on( 'dialog', ( dialog ) => dialog.accept() ); |
| 67 | + await adminPage |
| 68 | + .locator( '.refund-actions .button.do-api-refund' ) |
| 69 | + .filter( { hasText: /Refund.*via Stripe/ } ) |
| 70 | + .click(); |
| 71 | + |
| 72 | + await adminPage.waitForNavigation(); |
| 73 | + |
| 74 | + // Ensure the order status is updated. |
| 75 | + await expect( adminPage.locator( '#order_status' ) ).toHaveValue( |
| 76 | + 'wc-refunded' |
| 77 | + ); |
| 78 | + |
| 79 | + // Ensure the refund note is present. |
| 80 | + await expect( adminPage.locator( '.order_notes' ) ).toHaveText( |
| 81 | + /Refunded .* – Refund ID: .* – Reason:.*/ |
| 82 | + ); |
| 83 | + |
| 84 | + stripeRefundId = await adminPage |
| 85 | + .locator( '.order_notes' ) |
| 86 | + .filter( { |
| 87 | + hasText: /Refunded .* – Refund ID: .* – Reason:.*/, |
| 88 | + } ) |
| 89 | + .innerText() |
| 90 | + .then( |
| 91 | + ( text ) => |
| 92 | + text.match( /(?<=Refund ID: ).*?(?= – Reason)/ )[ 0 ] |
| 93 | + ); |
| 94 | + } |
| 95 | + ); |
| 96 | + |
| 97 | + await test.step( 'check Stripe payment status ', async () => { |
| 98 | + const stripeClient = stripe( process.env.STRIPE_SECRET_KEY ); |
| 99 | + |
| 100 | + const charge = await stripeClient.charges.retrieve( stripeChargeId ); |
| 101 | + |
| 102 | + expect( charge.refunded ).toBeTruthy(); |
| 103 | + expect( charge.refunds.data[ 0 ].id ).toBe( stripeRefundId ); |
| 104 | + } ); |
| 105 | +} ); |
0 commit comments