Skip to content

End-to-End Testing

End-to-End Testing sits at the heart of testing in Module Federation. This guide walks through the concept step by step, with examples, a cheatsheet, and common mistakes to avoid.

End-to-End Testing Overview

End-to-End Testing is a building block you will reach for often in Module Federation. It keeps related logic together and makes your intent obvious to reviewers and future maintainers.

When you learn end-to-end testing properly, you avoid the guesswork that leads to bugs and rework. The example below shows the shape you will use in most real Module Federation projects.

import { render, screen } from '@testing-library/react';
import ProductList from './ProductList';

test('remote component renders products', () => {
  render(<ProductList products={[{ id: 1, name: 'Book' }]} />);
  expect(screen.getByText('Book')).toBeInTheDocument();
});

Test exposed components in isolation the same way you test any local component.

End-to-End Testing Example

new ModuleFederationPlugin({
  name: 'app',
  filename: 'remoteEntry.js',
  exposes: { './Widget': './src/Widget' },
  remotes: { other: 'other@http://host/remoteEntry.js' },
  shared: { react: { singleton: true } },
});
  • Start from a minimal End-to-End Testing example and grow it only as needed.
  • Keep configuration explicit so End-to-End Testing behaves the same in every environment.
  • Name things clearly so teammates understand your End-to-End Testing at a glance.
  • Add tests around End-to-End Testing early to lock in expected behaviour.

Module Federation Cheatsheet

Key Module Federation settings related to end-to-end testing.

Option Example Purpose
name name: 'shell' Unique container name
filename filename: 'remoteEntry.js' Remote entry manifest
exposes exposes: { './X': './src/X' } Modules a remote shares
remotes remotes: { app: 'app@url' } Remotes a host consumes
shared shared: { react: { singleton: true } } Deduplicate libraries
lazy load import('remote/Module') Load remotes on demand
Suspense <Suspense fallback={...}> Handle async loading

How End-to-End Testing Works in Module Federation

End-to-End Testing builds on Module Federation's ability to load code from another independently built and deployed application at runtime. Each app can be a host, a remote, or both.

Test exposed components in isolation the same way you test any local component.

  • Remotes expose modules through a remoteEntry.js manifest.
  • Hosts declare remotes and import exposed modules dynamically.
  • Shared dependencies are deduplicated, ideally as singletons.
  • Each micro frontend builds and deploys on its own schedule.

Practical Guidance for End-to-End Testing

In production, end-to-end testing needs careful version management and graceful failure handling. Align shared dependency versions and always render a fallback when a remote cannot load.

Concern Recommendation
Shared versions Use singletons with requiredVersion
Runtime errors Wrap remotes in error boundaries and fallbacks
Deployment Resolve remotes from a runtime manifest
Performance Lazy-load remotes and cache remoteEntry.js

Common Mistakes

  • Skipping error handling and edge cases when wiring up end-to-end testing.
  • Leaving end-to-end testing untested, so regressions slip into production.
  • Over-engineering end-to-end testing before you actually need the extra flexibility.
  • Ignoring documentation, which makes end-to-end testing hard for the next developer to change.

Key Takeaways

  • End-to-End Testing is a core part of working effectively with Module Federation.
  • Start small and keep end-to-end testing focused on a single responsibility.
  • Apply consistent patterns so end-to-end testing scales across your project.
  • Test and document end-to-end testing to keep it maintainable over time.

Pro Tip

Pair end-to-end testing with automated tests from day one. It is far cheaper to catch Module Federation regressions in CI than in production.