Skip to content

Enable E2E Tests with Playwright in Remix Shopify App #890

Open
@Stepn0

Description

I want to integrate E2E tests using Playwright in my Remix Shopify app, which is currently set up with Vite and Vitest for component-level testing. I'm using jsdom with React Testing Library for testing frontend components, and Remix Stub for testing actions and loaders.

Here's the current setup:

Vite + Vitest for environment configuration and testing setup
jsdom + React Testing Library for frontend component testing
Remix Stub for testing Remix actions and loaders
Vite's setupFiles for mocking the Shopify app and Polaris provider
Shopify App setup using @shopify/shopify-app-remix for session storage and app configuration

I been getting a few errors such as:
Error: The shopify global is not defined. This likely means the App Bridge script tag was not added correctly to this page

TestingLibraryElementError: Unable to find an element with the text: 🤖 Dev & Testing. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

I based most of my setup on this pr:
https://github.com/Shopify/shopify-app-js/pull/1207/commits

Do you think it would be possible to create an official guide on setting up end-to-end (E2E) tests with this stack in the future? I understand that many people use different configurations based on their specific needs, but having an official reference configuration would be incredibly beneficial for the community. It could serve as a solid starting point for others looking to implement E2E tests with this setup.

Thanks!

export default mergeConfig(
  rootConfig,

  defineConfig({
    test: {
      environment: 'jsdom',
      include: ['*.test.?(c|m)[jt]s?(x)', '**/*.test.?(c|m)[jt]s?(x)'],
      setupFiles: ['../test-utilities/shopify.setup.js'],
    },
  })
);
import { shopifyApp } from '@shopify/shopify-app-remix/server';
import { testConfig } from '@shopify/shopify-app-remix/test-helpers';

import { MemorySessionStorage } from '@shopify/shopify-app-session-storage-memory';

const SHOPIFY_API_KEY = process.env.SHOPIFY_API_KEY || 'random';
const SHOPIFY_API_SECRET = process.env.SHOPIFY_API_SECRET || 'random';
const APPURL = process.env.SHOPIFY_APP_URL || 'https://www.random.com';

const SHOPIFY_TESTING = true;

export const config = {
  shopifyApiKey: SHOPIFY_API_KEY,
  apiKey: SHOPIFY_API_KEY,
  sessionStorage: new MemorySessionStorage(),
  appUrl: APPURL,
  apiSecretKey: SHOPIFY_API_SECRET,
};

if (SHOPIFY_TESTING) {
  Object.assign(config, testConfig());
}

export const shopifyAppTest = shopifyApp(config);
test('renders loader data', async () => {
  function MyComponent() {
    const data = useLoaderData() as { message: string };
    return <p>Message: {data.message}</p>;
  }

  const RemixStub = createRemixStub([
    {
      path: '/',
      Component: MyComponent,
      loader() {
        return json({ message: 'hello' });
      },
    },
  ]);

  render(<RemixStub />);

  await waitFor(() => screen.findByText('Message: hello'));
});
/** @param {{ children: import("react").ReactElement }} args */
function ShopifyAppProvider({ children }) {
  return <PolarisTestProvider i18n={translations}>{children}</PolarisTestProvider>;
}

/**
 *
 * @param {import("react").ReactElement} ui
 * @param {import("@testing-library/react").RenderOptions} [options]
 * @returns
 */
const shopifyRender = (ui, options) => render(ui, { wrapper: ShopifyAppProvider, ...options });

// re-export everything
export * from '@testing-library/react';

export { shopifyRender as render };

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions