Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stripe.resources.Checkout.prototype seems to be broken? #2060

Open
jeffplays2005 opened this issue Apr 7, 2024 · 5 comments
Open

stripe.resources.Checkout.prototype seems to be broken? #2060

jeffplays2005 opened this issue Apr 7, 2024 · 5 comments
Assignees
Labels

Comments

@jeffplays2005
Copy link

Describe the bug

Seems to be empty compared to other prototypes.
Screenshot 2024-04-07 at 9 52 25 PM

Screenshot 2024-04-07 at 9 52 41 PM

To Reproduce

node
const stripe = require('stripe')
stripe.resources.Checkout.prototype

Expected behavior

{
create: [Function (anonymous)],
retrieve: [Function (anonymous)],
list: [Function (anonymous)],
expire: [Function (anonymous)],
listLineItems: [Function (anonymous)]
}

Code snippets

No response

OS

macOS

Node version

Node v20.0.0

Library version

14.23.0

API version

2022-08-01

Additional context

No response

@richardm-stripe
Copy link
Contributor

richardm-stripe commented Apr 7, 2024

@jeffplays2005 stripe.resources.Checkout isn't like stripe.resources.Product because checkout isn't a resource itself, it is a "namespace" that contains other resources like "checkout session".

Can you say a little bit about what you are hoping to accomplish? Using require('stripe') directly isn't really part of the public interface of the library -- we usually expect users to stripe = require('stripe')("<API_KEY>") and access things on the constructed stripe client, rather than interacting directly with the "building blocks" as you seem to be doing.

@jeffplays2005
Copy link
Author

jeffplays2005 commented Apr 10, 2024

I'm trying to use this in jest for route testing for a route that has the method, stripe.checkout.sessions.list.
I'm trying to change the function so that it can change the output of the data list.
E.g.

jest.mock("stripe", () => {
    const stripe = jest.requireActual("stripe")
  jest
    .spyOn(stripe.resources.Checkout.sessions, "list")
    .mockImplementation((props) => {
      const { limit = 10 } = props as {
        limit?: number
      }
      const items = Array(limit).fill(mock)
      return Promise.resolve({ data: items })
    })
})

@ramya-stripe
Copy link
Contributor

@jeffplays2005 That still does not tell us why you were looking for any of the create/list/del etc. methods on stripe.resources.Checkout...

@amuroBosetti
Copy link

What is the recommended way of mocking method calls? I'm trying to build a test in a similar fashion as @jeffplays2005, trying to spy on calls over checkout.sessions.create, but it isn't easy when importing Stripe using ES module.
I cannot access instance methods before Stripe instance creation, but I read a thread on StackOverflow pointing out that hte created instance references methods in the resources, meaning I could stub those, but to no success

@xavdid-stripe
Copy link
Member

@amuroBosetti @jeffplays2005 Rather than mocking the method calls directly (which is possible, see below), you might first consider mocking the HTTP calls themselves using a tool like https://github.com/nock/nock. The API endpoints are well-defined and you can use the CLI to make some test requests and record their responses. That will allow the most flexibility without diving into the internal structure of the Stripe package (which is subject to change).

That said, the following toy example worked for me using TS and an ES Module:

// index.ts
import Stripe from "stripe";
const stripe = new Stripe("sk_test_...");

export const loadSessions = async () => {
  const sessions = await stripe.checkout.sessions.create({
    success_url: "https://example.com/passed-in-value",
    mode: "setup",
    currency: "usd",
    payment_method_types: ["card"],
  });
  return sessions;
};

// index.test.ts
import { loadSessions } from ".";

jest.mock("stripe", () => {
  return jest.fn().mockImplementation(() => {
    return {
      checkout: {
        sessions: {
          create: jest.fn().mockResolvedValue({
            id: "cs_test_123",
            object: "checkout.session",
            billing_address_collection: "auto",
            cancel_url: "https://example.com/cancel",
            client_reference_id: null,
            customer: null,
            customer_email: null,
            display_items: [
              {
                amount: 1000,
                currency: "usd",
                custom: {
                  description: "Pasha's Subscription",
                  images: null,
                  name: "Pasha's Subscription",
                },
                quantity: 1,
                type: "custom",
              },
            ],
            livemode: false,
            locale: null,
            payment_intent: "pi_test_123",
            payment_method_types: ["card"],
            setup_intent: "seti_test_123",
            submit_type: null,
            subscription: null,
            success_url: "https://example.com/mocked-value",
          }),
        },
      },
    };
  });
});

it("should mock the whole stripe call", async () => {
  const sessions = await loadSessions();
  expect(sessions.success_url).toEqual("https://example.com/mocked-value");
});

Alternatively, you could wrap calls to stripe in helper methods and mock those directly:

// mock my loadSessions function:
jest.mock("./index", () => {
  return {
    loadSessions: jest.fn().mockResolvedValue({
      id: "cs_test_123",
      object: "checkout.session",
      billing_address_collection: "auto",
      success_url: "https://example.com/local-mock",
    }),
  };
});
it("should use a local mock", async () => {
  const sessions = await loadSessions();
  expect(sessions.success_url).toEqual("https://example.com/local-mock");
});

Though it's worth noting that you can't use those two approaches in the same file, since they'll conflict.

Will any of those 3 approaches work for you?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants