Loading...
Loading...
Guide for testing Shopify Apps, including Unit Testing with Remix, Mocking Shopify Context, and E2E Testing.
npx skill4agent add toilahuongg/google-antigravity-kit shopify-testingnpm install -D vitest @testing-library/react @testing-library/jest-dom jsdomshopify.server.tsauthenticate// test/mocks/shopify.ts
import { vi } from 'vitest';
export const mockShopify = {
authenticate: {
admin: vi.fn(),
public: vi.fn(),
webhook: vi.fn(),
},
};
// Usage in test file:
vi.mock('../app/shopify.server', () => mockShopify);
test('loader returns data for authenticated shop', async () => {
mockShopify.authenticate.admin.mockResolvedValue({
currentShop: 'test-shop.myshopify.com',
session: { shop: 'test-shop.myshopify.com', accessToken: 'fake_token' },
admin: {
graphql: vi.fn().mockResolvedValue({ /* mock response */ })
}
});
const response = await loader({ request: new Request('http://localhost/') });
// Assertions...
});createRemixStubloaderactionimport { loader } from '../app/routes/app.dashboard';
test('dashboard loader returns stats', async () => {
// Setup mocks...
const response = await loader({
request: new Request('http://localhost/app/dashboard'),
params: {}
});
const data = await response.json();
expect(data.stats).toBeDefined();
});import { test, expect } from '@playwright/test';
test('load dashboard', async ({ page }) => {
await page.goto('http://localhost:3000/app');
// Expect to see the Polaris Page title
await expect(page.locator('.Polaris-Page-Header__Title')).toHaveText('Dashboard');
});
shopify app webhook trigger --topic ORDERS_CREATEimport { action } from '../app/routes/webhooks';
import crypto from 'crypto';
test('webhook verifies hmac', async () => {
const payload = JSON.stringify({ id: 123 });
const hmac = crypto.createHmac('sha256', 'FULL_SECRET').update(payload).digest('base64');
const request = new Request('http://localhost/webhooks', {
method: 'POST',
body: payload,
headers: { 'X-Shopify-Hmac-Sha256': hmac }
});
// Mock authenticate.webhook to succeed
// ...
const response = await action({ request });
expect(response.status).toBe(200);
});