Shopify / ui-extensions

MIT License
267 stars 35 forks source link

Checkout Extensions Unit Tests #712

Open adityaagashe1 opened 1 year ago

adityaagashe1 commented 1 year ago

Please list the package(s) involved in the issue, and include the version you are using

"@shopify/checkout-ui-extensions-react": "^0.23.0", "@shopify/cli": "3.23.0", "@shopify/react-testing": "^5.0.1",

Describe the bug

I have implemented checkout extensions using React components. I am using react-testing library provided by Shopify to write unit tests for my react component. To mount component I've created a customMount. Unit tests which I've are working with package version 0.20.0 but unit tests fails on latest @shopify/checkout-ui-extensions-react package. I get the following error.

Attempted to operate on a mounted tree, but the component is no longer mounted

  66 |       })
  67 |       wrapper.act(() => {
> 68 |         console.log(wrapper.debug())
     |                             ^
  69 |       })
  70 |       expect(wrapper).toContainReactComponent(SpOfferCheckbox)
  71 |       expect(wrapper).toContainReactComponent(Text, { id: 'sp-offer-header' })

Custom mount code that I have is as follows:


interface Options {
  asyncCall: typeof jest.fn
}

const mountWithAsync = createMount<Options, Record<string, unknown>, true>({
  render(element) {
    return element
  },
  async afterMount(root, { asyncCall }) {
    await root.act(() => {
      if (asyncCall) {
        asyncCall()
      }
    })
  },
})

export default mountWithAsync

My unit tests is very simple

it('renders correct elements when quote is available and premium > 0', async () => {
      const wrapper = await mountWithAsync(<SPOffer />, {
        asyncCall: testHarness.mockFetchSpDetails.mockResolvedValue(generateSpDetailsResponse()),
      })

      expect(wrapper).toContainReactComponent(SpOfferCheckbox)
      expect(wrapper).toContainReactComponent(Text, { id: 'sp-offer-header' })
      expect(wrapper).toContainReactComponent(Text, { id: 'sp-quote-price' })
    })

React component will load data from async api in the useEffect.

Can someone help me resolve the issue? I need new version new components.

Steps to reproduce the behavior:

1. 1. 1.

Expected behavior

Screenshots

Additional context

kumar303 commented 1 year ago

I am using react-testing library provided by Shopify to write unit tests for my react component.

Hi. Are you using the remote-ui/testing library specifically?

You might want to double check your react version and use something like yarn-deduplicate to make sure you're only loading one version of react.

adityaagashe1 commented 1 year ago

I am using react-testing library provided by Shopify to write unit tests for my react component.

Hi. Are you using the remote-ui/testing library specifically?

You might want to double check your react version and use something like yarn-deduplicate to make sure you're only loading one version of react.

I tried this but no success. Unit tests work fine on 0.20.0. They're broken in 0.23.0 and 0.24.0

andrewpye commented 1 year ago

Piggybacking on this issue, I'd like to add here that documentation around testing components is too sparse and/or undiscoverable for developers to be able to easily test their extensions.

I reached out on the Shopify Partners Slack Community here to try and get some assistance with this and received some input from someone which was enough to get some tests that at least run and pass – albeit with what seems like a pretty clunky way of getting them to render in tests, including having to use mock timers to ensure effects etc. are completed before making assertions.

After raising the issue in a checkout extensibility AMA/office hours session, I was pointed to this document, which in turn seems to be recommending using @quilted/react-testing for this purpose. I've just tried converting the existing tests I'd written to follow the examples in @quilted/react-testing's documentation, but when I run the tests I get the error

No remote-ui Render instance found in context

So far, I haven't been able to find anything about this issue or how we're expected to provide a "remote-ui Render instance" so that we can test in the way we seem to be being pointed towards 😕

Since Shopify presumably wants app developers to be able to provide robust and reliable customer experiences, it seems like the lack of clear examples as to how checkout UI components can be tested is a bit of an oversight and leaving engineers to figure it out for themselves is counterproductive.

P.S. @adityaagashe1 or whoever else is involved here: if you'd prefer me to open a separate issue relating to what I've described, please let me know and I'll gladly do so.

noelia-lencina commented 1 year ago

Any updates on this? Looks like the documentation is also now behind with the current way of rendering the extension. Is there any other place with guidelines about testing the extensions?

jomarsantos commented 9 months ago

I also ran into the No remote-ui Render instance found in context error when trying to test an AdminAction component:

import { mount } from '@shopify/react-testing'

describe('Header', () => {
  it('renders the header', () => {
    const wrapper = mount(<AdminAction />)
    ...
  })
})

The workaround I ended up using which uses @remote-ui directly looks like this:

import { mount } from '@remote-ui/testing'
import { createRoot } from '@remote-ui/react'

describe('Header', () => {
  it('renders the header', () => {
    const app = mount((root) => {
      createRoot(root).render(<AdminAction />)
    })
    ...
  })
})

From my investigation this might be the reason but I'm not 100% sure it is / why this is the case:

andrewpye commented 6 months ago

@kumar303 (or maybe @lemonmade): apologies for tagging directly but we've been finding it impossible to get any assistance from Shopify on this topic via any channels (Slack, office hours, GitHub...). The No remote-ui Render instance found in context message as reported above has just become fairly critical for us: we're currently in the process of updating from @shopify/checkout-ui-extensions-react to @shopify/ui-extensions-react and have found that the tests we'd cobbled together based on community suggestions suddenly started breaking with the same message. The context is that we're attempting to test a simple component of our own that wraps Shopify's Link component and just manipulates a couple of the props. I've spent 2-3 days trying to work this out with no success so far, meaning that we're either stuck on deprecated packages, or have to disable all of our component tests in order to proceed with the update to ui-extensions-react – neither of which are ideal 😅 So, any help or hints that can be offered here would be much appreciated. Thanks! 🙇

shawngrona commented 6 months ago

same, please update

michellecolin commented 6 months ago

Same here, it would be great if you could prioritize looking into this issue. Being able to test the extensions properly is really important

kumar303 commented 6 months ago

@andrewpye did you try this workaround? I'll try to see what changed here.

The workaround is to call render() directly

createRoot(root).render(<AdminAction />)

kumar303 commented 6 months ago

Upon closer investigation, calling .render() is what you need. It probably became necessary when we added the context for fragment support.

andrewpye commented 6 months ago

@kumar303 thanks for the replies 🙇 We tried that workaround and many other things that we could think to try – none of them worked.

In the last day or two, our failing tests randomly started passing again as they were in their original form – probably as a result of updating our Shopify dependencies, but we're not sure exactly what caused it or when because we'd marked those failing tests as skipped as a last-ditch measure to be able to proceed with our work, and just thought to try them again and found they passed once more 🤷

Is there any up-to-date documentation on how developers can/should be testing their UI extension components? Having tests is vital to providing reliable, robust merchant and customer experiences, which is obviously critical to both app developers and Shopify themselves. Hoping to hear some good news here soon! Thanks 😁

kumar303 commented 4 months ago

I'm glad it's working after upgrading your dependencies ✨

The docs for @remote-ui/testing moved over here: https://github.com/Shopify/remote-dom/tree/remote-ui/packages/testing

suryarajendhran commented 3 months ago

For anyone encountering this issue in the future, I’ve put together a more comprehensive example of a Shopify app with a checkout UI extension written in React, including a simple unit test for reference.

You can find it here: https://github.com/suryarajendhran/testing-checkout-ui-extensions