skip to Main Content

Evening,

When a user signs up for a subscription the checkout.session.completed event is fired and I can test that everything is working correctly via the CLI command: stripe trigger checkout.session.completed --add checkout_session:customer="REPLACE WITH CUSTOMER ID".

I want to be able to do the same to test when a SPECIFIC customer has failed to make a payment and the invoice.payment_failed event is triggered.

I need the email value from event.data.object to match an email address on my database so I can check that the status value is correctly changing from ‘member’ to ‘pastMember’.

My intuition is the command I want is something like stripe trigger invoice.payment_failed --add invoice:customer="REPLACE WITH CUSTOMER ID" but unfortunately this doesn’t work.

Editing the fixture for invoice doesn’t work either. Changing the customer id has no effect and I cannot add a customer_email parameter to the params object despite the fact the field exists as part of the invoice schema defined here

I have tried everything I can think of but I can’t make sense of stripe. I find the documentation regarding testing absolutely appalling.

export async function postWebhook(req: Request, res: Response) {
    const event = req.body
    const type = event.type
    switch (type) {
// -- Working
        case 'checkout.session.completed': {
            const {customer_details, customer: customerId} = event.data.object
            const {email} = customer_details
            const user = await User.findOneAndUpdate({email}, {status: 'member', stripeId: customerId})
            await instance.customers.update(customerId, {
                metadata: {
                    mongoId: user?.id,
                },
            })
            break
        }
// -- Not working
        case 'invoice.payment_failed': {
            const email = event.data.object[???]
            await User.findOneAndUpdate({email}, {status: 'pastMember'})
            break
        }
        default:
            break
    }
    res.sendStatus(200)
}

2

Answers


  1. Chosen as BEST ANSWER

    karllekko provided 95% of the answer I needed. I have provided the complete json fixture below to help the next poor sod trying to achieve this. The params off_session and confirm passed to payment intent were the missing magic for me:

    {
        "_meta": {
            "template_version": 0
        },
        "fixtures": [
            {
                "name": "customer",
                "path": "/v1/customers/REPLACE_WITH_CUSTOMER_ID",
                "method": "post"
            },
            {
                "name": "payment_method",
                "path": "/v1/payment_methods/REPLACE_WITH_PAYMENT_ID/attach",
                "method": "post",
                "params": {
                    "customer": "${customer:id}"
                }
            },
            {
                "name": "invoiceitem",
                "path": "/v1/invoiceitems",
                "method": "post",
                "params": {
                    "amount": 2000,
                    "currency": "usd",
                    "customer": "${customer:id}"
                }
            },
            {
                "name": "invoice",
                "path": "/v1/invoices",
                "method": "post",
                "params": {
                    "customer": "${customer:id}",
                    "pending_invoice_items_behavior": "include"
                }
            },
            {
                "name": "payment_intent",
                "path": "/v1/payment_intents",
                "method": "post",
                "params": {
                    "amount": "${invoiceitem:amount}",
                    "currency": "${invoiceitem:currency}",
                    "customer": "${customer:id}",
                    "payment_method": "${payment_method:id}",
                    "off_session": true,
                    "confirm": true
                }
            }
        ]
    }
    
    

  2. The complication here is that you have to use --override here to set the Customer ID(--add only works to add a parameter there was not already present in the fixture, you need to override when the fixture already sets that parameter to something, as the invoice trigger fixtures do).

    However that in itself won’t work out of the box, because the fixture will try to attach and use a certain PaymentMethod, so you’d end up having to try and override many things. So really I would just write my own fixture for this, instead.

    Editing the fixture for invoice doesn’t work either

    That would work, but hard to say without seeing what exact edits you made. Here’s how I would do it. Basically edit the existing fixture so it loads an existing Customer, and then uses that for all the subsequent steps.

    {
          "name": "customer",
          "path": "/v1/customers/${.env:CUSTOMER_ID|REMEMBER_TO_SET_CUSTOMER_ID}",
          "method": "get"
        },
    
    • the rest can remain the same.
    • now you can do ENV CUSTOMER_ID="cus_QX87JKPRilxAOU" stripe fixtures ./custom_invoice_payment_failed.json and it should just work.

    https://docs.stripe.com/cli/fixtures

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search