简体   繁体   English

Cypress stub out loadStripe

[英]Cypress stub out loadStripe

I'm having some trouble stub'ing out Stripe from my tests我在从测试中剔除 Stripe 时遇到了一些麻烦

CartCheckoutButton.ts CartCheckoutButton.ts

import React from 'react'
import { loadStripe } from '@stripe/stripe-js'

import useCart from '~/state/CartContext'
import styles from './CartCheckoutButton.module.scss'

const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY)

const CartCheckoutButton = ({}: TCartCheckoutButtonProps) => {
  const { cartItems } = useCart()

  const handleCheckOutOnClick = async (event) => {
    const { sessionId } = await fetch('/api/checkout/session', {
      method: 'POST',
      headers: {
        'content-type': 'application/json',
      },
      body: JSON.stringify({ cartItems }),
    }).then((res) => res.json())

    const stripe = await stripePromise
    const { error } = await stripe.redirectToCheckout({
      sessionId,
    })

    if (error) {
      // TODO: Show some error message
      console.log(error)
    }
  }

  return (
    <div className={styles.container}>
      <button onClick={handleCheckOutOnClick} disabled={cartItems.length == 0}>
        CHECKOUT
      </button>
    </div>
  )
}

export default CartCheckoutButton

EndUserExperience.spec.js EndUserExperience.spec.js

import * as stripeJS from '@stripe/stripe-js'

describe('End user experience', () => {
  beforeEach(() => {
    cy.visit('http://localhost:3000/')

    cy.stub(stripeJS, 'loadStripe').resolves(
      new Promise(function (resolve, reject) {
        resolve({
          redirectToCheckout({ sessionId }) {
            console.log(`redirectToCheckout called with sessionId: ${sessionId}`)
            return new Promise(function (resolve, reject) {
              resolve({ error: true })
            })
          },
        })
      })
    )
  })

  it('Orders some dishes and makes a checkout', () => {
    console.log('working on it')
  })
})

When I click around it still redirects me.当我点击它时,它仍然会重定向我。 So the stub did not seem to kick in..所以存根似乎没有启动..

Update II更新二

Trying out the following solution suggested by @RichardMatsen尝试@RichardMatsen 建议的以下解决方案

import React from 'react'
import * as stripeModule from '@stripe/stripe-js'

import useCart from '~/state/CartContext'
import styles from './CartCheckoutButton.module.scss'

const stripePublishableKey = process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY

const CartCheckoutButton = ({}: TCartCheckoutButtonProps) => {
  const { cartItems } = useCart()

  // https://stackoverflow.com/questions/67565714/cypress-stub-out-loadstripe
  const stripePromise = React.useCallback(() => {
    window['stripeModule'] = stripeModule
    return stripeModule.loadStripe(stripePublishableKey)
  }, [stripeModule, stripePublishableKey])

  const handleCheckOutOnClick = async (event) => {
    const { sessionId } = await fetch('/api/checkout/session', {
      method: 'POST',
      headers: {
        'content-type': 'application/json',
      },
      body: JSON.stringify({ cartItems }),
    }).then((res) => res.json())

    const stripe = await stripePromise()
    const { error } = await stripe.redirectToCheckout({
      sessionId,
    })

    if (error) {
      // TODO: Show some error message
      console.log(error)
      throw error
    }
  }

  return (
    <div className={styles.container}>
      <button onClick={handleCheckOutOnClick} disabled={cartItems.length == 0}>
        TILL KASSAN
      </button>
    </div>
  )
}

export default CartCheckoutButton

test.spec.js test.spec.js

describe('End user experience', async () => {
  beforeEach(() => {
    cy.visit('http://localhost:3000/')

    cy.window().then((win) => {
      console.log(win)
      cy.stub(win.stripeModule, 'loadStripe').resolves(
        new Promise(function (resolve, reject) {
          resolve({
            redirectToCheckout({ sessionId }) {
              console.log(`redirectToCheckout called with sessionId: ${sessionId}`)
              return new Promise(function (resolve, reject) {
                resolve({ error: true })
              })
            },
          })
        })
      )
    })

    cy.intercept('GET', /.*stripe.*/, (req) => {
      req.redirect('http://localhost:3000/checkout/success')
    })
  })

  it('Orders some dishes and makes a checkout', () => {
    console.log('working on it')
  })
})

But it still redirect me and display an error但它仍然重定向我并显示错误

Trying to stub property 'loadStripe' of undefined

As far as I can tell, you can't stub a method in the app by importing it's module in the test, it looks like you get a different "instance".据我所知,你不能通过在测试中导入它的模块来存根应用程序中的方法,看起来你得到了一个不同的“实例”。

Please see this recent question How to Stub a module in Cypress , an approach that works is to pass the instance to be stubbed via window .请参阅这个最近的问题How to Stub a module in Cypress ,一种有效的方法是通过window传递要存根的实例。

CartCheckoutButton.ts CartCheckoutButton.ts

import React, { useCallback } from 'react'
import * as stripeModule from '@stripe/stripe-js';

if (process.browser) {                  // this check needed for NextJS SSR
  if (window.Cypress) {
    window.stripeModule = stripeModule;
  }
}

// const stripePromise = loadStripe(...)  // need to defer this call
                                          // from load time to runtime
                                          // see useCallback below

// Maybe put this outside the React function, 
// since dependencies shouldn't have property references
const stripeKey = process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY;



const CartCheckoutButton = ({}: TCartCheckoutButtonProps) => {

   const stripePromise = useCallback(() => {
     return stripeModule.loadStripe(stripeKey);
   }, [stripeModule, stripeKey]);

EndUserExperience.spec.js EndUserExperience.spec.js

beforeEach(() => {

  cy.visit('http://localhost:3000/')
    .then(win => {                      // wait for app to initialize

      const stripeModule = win.stripeModule;
      cy.stub(stripeModule, 'loadStripe').resolves(...

    })

Reproducable example可重现的例子

Build the default Next app构建默认的 Next 应用

npx create-next-app nextjs-blog --use-npm --example "https://github.com/vercel/next-learn-starter/tree/master/learn-starter"

Add stripeModule reference and useCallback() to /pages/index.js将 stripeModule 引用和 useCallback() 添加到 /pages/index.js

import React, { useCallback } from 'react'
import * as stripeModule from '@stripe/stripe-js';

import Head from 'next/head'

if (process.browser) {
  if (window.Cypress) {
    window.stripeModule = stripeModule; 
  }
}

const stripeKey = process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY;

export default function Home() {

  const stripePromise = useCallback(() => {
    return stripeModule.loadStripe(stripeKey);
  }, [stripeModule, stripeKey]);

  return (
    <div className="container">
    ...

Add a basic test添加基本测试

it('stubs loadStripe', () => {

  cy.visit('http://localhost:3000/').then(win => {
    const stripeModule = win.stripeModule;
    cy.stub(stripeModule, 'loadStripe').resolves(
      console.log('Hello from stubbed loadStripe')
    )
  })
})

Build, start, test构建、启动、测试

yarn build
yarn start
yarn cypress open

The message from cy.stub() is printed to the console.来自cy.stub()的消息被打印到控制台。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM