Skip to content

Latest commit

 

History

History
277 lines (212 loc) · 9.83 KB

File metadata and controls

277 lines (212 loc) · 9.83 KB
title layout
Writing an integration tests with Playwright
default

Development - Writing an integration tests with Playwright

This guide explains how to create and run integration tests using Playwright in your Alokai multistore project. Integration tests verify that different parts of your store work together correctly by:

  • Running against composed stores (respecting inheritance)
  • Using mocked API responses to test user flows without external services
  • Verifying UI components and page behavior
  • Running in the Playwright test runner

What You'll Learn

::list{type="success"}

  • Understanding integration tests in multistore setup
  • Creating and configuring test mocks
  • Writing your first Playwright test
  • Running tests locally ::

Prerequisites

Before writing integration tests, make sure you understand:

Adding Integration Tests - Real-World Example

Let's walk through adding integration tests to a fashion-brand store that uses an LLM-based recommendations system to suggest products based on user behavior and preferences.

Here's our project structure:

apps/
├── storefront-unified-nextjs/          # Base shared code
└── stores/
    ├── fashion-brand/
    │   ├── playwright/
    │   ├── storefront-middleware/      # Middleware customizations
    │   │   └── integrations/
    │   │       └── <ecommerce>/
    │   │           └── extensions/
    │   │               └── recommendations.ts  # LLM recommendations logic
    │   └── storefront-unified-nextjs/  # Frontend customizations
    │       └── app/
    │           └── [locale]/
    │               └── (default)/
    │                   └── recommendations/
    │                       └── page.tsx # Recommendations page
    └── sports-brand/                    # Another store

In this example:

  1. The fashion-brand store has a custom recommendations extension in the middleware
  2. The extension adds a new getRecommendations method to the eCommerce API
  3. A new /recommendations page displays personalized product recommendations
  4. We would like to test that the recommendations are displayed correctly

::tip Adding features for all stores If you want to add a new feature for all stores, you can add them to the base apps within the apps/storefront-unified-nextjs, apps/storefront-unified-nuxt and apps/storefront-middleware folders. Similarly, tests that should run for all stores can be added to the apps/playwright folder. ::

::steps

#step-1

Creating Test Mocks

Mocks simulate API responses during testing, making tests reliable and fast. Let's create the necessary mocks for our recommendations feature.

::info Mocks are set up with the h3 package. This is a lightweight HTTP server library that is used to create mock APIs for your tests. ::

1. Create Mock Endpoint

First, create a mock handler for your API endpoint:

// apps/stores/fashion-brand/playwright/mocks/recommendations/endpoints/getRecommendations.ts
import type { MockFactoryContext } from '@core';
import { defineEventHandler } from 'h3';

export default function ({ router }: MockFactoryContext) {
  return router.post(
    `/getRecommendations`,
    defineEventHandler(async (event) => {
      return Promise.resolve([
        // Mock data for recommendations
      ])
    }),
  );
}

2. Create Mock Server Factory

Next, create a server factory to organize your mock endpoints:

// apps/stores/fashion-brand/playwright/mocks/recommendations/server.ts
import type { MockFactoryContext } from '@core';
import { getRecommendations } from './endpoints';

export const serverFactory = [(ctx: MockFactoryContext) => getRecommendations(ctx)];

3. Register Mock Server

Finally, register your mock server by overriding the mainRouterFactory:

  1. Copy the apps/playwright/mocks/init.ts file to your store
  2. Then, add your new mock server to the mainRouterFactory
// apps/stores/fashion-brand/playwright/mocks/init.ts
import { pipe } from '@core';
import { createRouter, defineEventHandler, sendNoContent, useBase } from 'h3';

import { serverFactory as cmsEndpoints } from './cms/server';
import { serverFactory as unifiedEndpoints } from './unified/server';
import { serverFactory as recommendationsEndpoints } from './recommendations/server';

export const mainRouterFactory = () => {
  const mainRouter = createRouter();

  // ... existing router setup ...

  // Add your new mock router
  const recommendationsRouter = pipe(recommendationsEndpoints, createRouter());
  mainRouter.use(
    '/commerce/recommendations/**',
    useBase('/commerce/recommendations', recommendationsRouter.handler)
  );

  return mainRouter;
};

#step-2

Creating Page Objects

1. Create Page Object Class

// apps/stores/fashion-brand/playwright/setup/pageObjects/recommendations.page.ts
import { BasePage } from '@core';

export class RecommendationsPage extends BasePage {
  // Define page elements
  public readonly recommendationsGrid = this.page.getByTestId('recommendations-grid');

  override async prepare() {
    // Add custom preparation logic if needed. For example, you
    // can set up the mock database here.
    return this;
  }
}

::tip Learn more about Page Objects Models Page Object Models are a common pattern in test automation that can significantly improve test maintenance and readability. To learn more about implementing effective Page Objects, check out the Playwright Page Object Models documentation. ::

2. Register Page Object

Playwright Test uses fixtures to establish isolated test environments. Fixtures provide tests with all necessary dependencies and are automatically cleaned up between test runs. Let's register our page object as a fixture. For this, we need to create a new test setup file that will extend the base test setup and add our page object as a fixture.

// apps/stores/fashion-brand/playwright/setup/fashion-brand-test.ts
import { RecommendationsPage } from '@setup/pageObjects/recommendations.page';
import { test as baseTest } from '@setup/test';

// Define the types for our fixtures
interface FashionBrandTestFixtures {
  recommendationsPage: RecommendationsPage;
}

// Extend the base test with our fixtures
export const test = baseTest.extend<FashionBrandTestFixtures>({
  // Each fixture is defined as an async function
  recommendationsPage: async ({ dataFactory, db, framework, frontendUrl, page, utils }, use) => {
    // Setup: Create and prepare the page object
    const recommendationsPage = new RecommendationsPage({ dataFactory, db, framework, frontendUrl, page, utils });
    await use(await recommendationsPage.prepare());
  },
});

This setup:

  1. Defines TypeScript types for all our fixtures
  2. Creates page objects that are isolated between tests
  3. Handles automatic setup and cleanup
  4. Makes page objects available in test functions

::info Test Setup Inheritance fashion-brand-test.ts extends the base test setup with store-specific fixtures. This allows you to reuse base fixtures while adding store-specific test configurations. Instead of overriding apps/playwright/setup/test.ts, you should extend it with your store-specific test setup. ::

You can now use the recommendationsPage fixture in your tests:

import { test } from '@setup/fashion-brand-test';

test('should show recommendations', async ({ recommendationsPage }) => {
  await recommendationsPage.navigate();
  // ... rest of the test
});

::tip Learn more about Fixtures Fixtures are a powerful concept in Playwright Test that enable isolated test environments, shared setup code, automatic cleanup, and composition of complex test dependencies. To learn more about how fixtures can improve your testing workflow, check out the Playwright Test Fixtures documentation. ::

#step-3

Writing Tests

Now you can write your test using the page object and mocks you've created:

// apps/stores/fashion-brand/playwright/tests/recommendations.test.ts
import { expect } from '@playwright/test';
import { test } from '@setup/fashion-brand-test';

test.describe('Recommendations page', () => {
  test('should show recommendations', async ({ recommendationsPage }) => {
    // Navigate to the page
    await recommendationsPage.navigate();

    // Verify recommendations are visible
    await expect(recommendationsPage.recommendationsGrid).toBeVisible();

    // Add more assertions as needed
  });
});

#step-4

Running Tests

You can run tests in two modes:

Standard Mode

# Run all tests for a specific store
yarn alokai store test --store-id=fashion-brand

UI Mode (for debugging)

# Open Playwright UI for interactive debugging
yarn alokai store test --store-id=fashion-brand --ui

::tip UI mode is great for debugging as it shows test execution step by step and lets you inspect the page state. ::

Playwright UI

::

Advanced Topics

This guide covered the basics of writing integration tests. For more advanced topics, see:

::card{title="Next: Deployment - How it works?" icon="tabler:number-3-small" }

#description Learn how Alokai handles store deployment and what happens behind the scenes.

#cta :::docs-arrow-link{to="/guides/multistore/tooling-and-concepts/deployment"} Next ::: ::