Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions css-isolation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ By default the Webpack style-loader will inject CSS in `<style>` tags into the `

**An additional wrapping `<body>` tag is always intentionally inserted into each Shadow DOM container. This makes it possible to use global reboot CSS rules inside the remote app which usually target the `<body>` tag and its contents. This should enable the user, for example, to have two different versions of Bootstrap one in the host and one in the remote.**

**Testing such a setup with tools like Cypress is possible with some additional settings and tweaks. Make sure to consult with the testing tool's documentation.**
**Testing such a setup with tools like Playwright is possible with some additional settings and tweaks. Make sure to consult with the testing tool's documentation for handling Shadow DOM interactions.**

# Running Demo

Expand All @@ -40,10 +40,13 @@ Run `pnpm run start`. This will build and serve both `app1` and `app2` on ports

<img src="https://ssl.google-analytics.com/collect?v=1&t=event&ec=email&ea=open&t=event&tid=UA-120967034-1&z=1589682154&cid=ae045149-9d17-0367-bbb0-11c41d92b411&dt=ModuleFederationExamples&dp=/email/BasicRemoteHost">

# Running Cypress E2E Tests
# Running Playwright E2E Tests

To run tests in interactive mode, run `npm run cypress:debug` from the root directory of the project. It will open Cypress Test Runner and allow to run tests in interactive mode. [More info about "How to run tests"](../../cypress-e2e/README.md#how-to-run-tests)
Run `pnpm test:e2e` from this workspace to execute the Playwright end-to-end suite against the development servers configured in [`playwright.config.ts`](./playwright.config.ts).

To build app and run test in headless mode, run `yarn e2e:ci`. It will build app and run tests for this workspace in headless mode. If tets failed cypress will create `cypress` directory in sample root folder with screenshots and videos.
For local debugging you can use the helper scripts:

["Best Practices, Rules amd more interesting information here](../../cypress-e2e/README.md)
- `pnpm test:e2e:ui` to explore the tests in Playwright UI mode.
- `pnpm test:e2e:debug` to launch the suite with Playwright's debug tools enabled.

In CI environments run `pnpm e2e:ci` to install the required browsers and execute the tests in headless mode. Use `pnpm legacy:e2e:ci` (or set `LEGACY_START=true`) to run the same checks against the legacy Webpack builds.
4 changes: 0 additions & 4 deletions css-isolation/cypress.env.json

This file was deleted.

128 changes: 0 additions & 128 deletions css-isolation/e2e/checkApplications.cy.ts

This file was deleted.

75 changes: 75 additions & 0 deletions css-isolation/e2e/checkApplications.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { test, expect } from '@playwright/test';

const hostUrl = 'http://localhost:3001';
const remoteUrl = 'http://localhost:3002';

test.describe('CSS isolation example', () => {
test.describe('host application', () => {
test.beforeEach(async ({ page }) => {
await page.goto(hostUrl);
});

test('renders host headings', async ({ page }) => {
await expect(
page.getByRole('heading', { level: 1, name: /Host Application - React Version/ }),
).toBeVisible();
await expect(page.getByRole('heading', { level: 2, name: 'App 1' })).toBeVisible();
});

test('mounts the remote inside a shadow DOM', async ({ page }) => {
const remoteMount = page.locator('#parent');
await expect(remoteMount).toBeVisible();

const hasShadowRoot = await remoteMount.evaluate(element => Boolean(element.shadowRoot));
expect(hasShadowRoot).toBe(true);

const remoteHeading = remoteMount.getByRole('heading', {
level: 1,
name: /Remote Application - React Version/,
});
const remoteButton = remoteMount.getByRole('button', { name: 'Make Everything Yellow' });

await expect(remoteHeading).toBeVisible();
await expect(remoteButton).toBeVisible();

await expect(
page.getByRole('heading', { level: 1, name: /Host Application - React Version/ }),
).toHaveCSS('font-style', 'italic');
});

test('retains host styles after interacting with the remote', async ({ page }) => {
const remoteMount = page.locator('#parent');
const remoteButton = remoteMount.getByRole('button', { name: 'Make Everything Yellow' });

await remoteButton.click();

await expect(remoteButton).toBeVisible();
await expect(remoteMount.getByRole('heading', { level: 2, name: 'App 2' })).toBeVisible();
await expect(
page.getByRole('heading', { level: 1, name: /Host Application - React Version/ }),
).toHaveCSS('font-style', 'italic');
});
});

test.describe('standalone remote application', () => {
test.beforeEach(async ({ page }) => {
await page.goto(remoteUrl);
});

test('renders remote headings and button', async ({ page }) => {
await expect(
page.getByRole('heading', { level: 1, name: /Remote Application - React Version/ }),
).toBeVisible();
await expect(page.getByRole('heading', { level: 2, name: 'App 2' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Make Everything Yellow' })).toBeVisible();
});

test('applies yellow styles after clicking the button', async ({ page }) => {
const button = page.getByRole('button', { name: 'Make Everything Yellow' });
await button.click();

await expect(page.locator('#root')).toHaveCSS('background-color', 'rgb(255, 255, 0)');
await expect(button).toHaveCSS('background-color', 'rgb(255, 255, 0)');
});
});
});
10 changes: 7 additions & 3 deletions css-isolation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@
"legacy:build": "pnpm --filter css-isolation_app* --parallel legacy:build",
"serve": "pnpm --filter css-isolation_app* --parallel serve",
"clean": "pnpm --filter css-isolation_app* --parallel clean",
"e2e:ci": "pnpm start & wait-on http-get://localhost:3001/ && npx cypress run --config-file ../cypress-e2e/config/cypress.config.ts --config '{\"supportFile\": \"../cypress-e2e/support/e2e.ts\"}' --spec \"./e2e/*.cy.ts\" --browser=chrome",
"legacy:e2e:ci": "pnpm legacy:start & wait-on http-get://localhost:3001/ && npx cypress run --config-file ../cypress-e2e/config/cypress.config.ts --config '{\"supportFile\": \"../cypress-e2e/support/e2e.ts\"}' --spec \"./e2e/*.cy.ts\" --browser=chrome"
"test:e2e": "pnpm exec playwright test",
"test:e2e:ui": "pnpm exec playwright test --ui",
"test:e2e:debug": "pnpm exec playwright test --debug",
"e2e:ci": "pnpm exec playwright install --with-deps && pnpm exec playwright test --reporter=list",
"legacy:e2e:ci": "LEGACY_START=true pnpm exec playwright install --with-deps && LEGACY_START=true pnpm exec playwright test --reporter=list"
},
"devDependencies": {
"wait-on": "7.2.0"
"@playwright/test": "^1.54.2",
"playwright": "^1.54.2"
}
}
51 changes: 51 additions & 0 deletions css-isolation/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { defineConfig, devices } from '@playwright/test';

const useLegacyStart = !!process.env.LEGACY_START;
const startCommand = useLegacyStart ? 'pnpm legacy:start' : 'pnpm start';

export default defineConfig({
testDir: './e2e',
timeout: 60_000,
expect: {
timeout: 15_000,
},
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 1 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: [
['html', { outputFolder: 'playwright-report', open: 'never' }],
['list'],
],
use: {
baseURL: 'http://localhost:3001',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
viewport: { width: 1920, height: 1080 },
},

projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],

webServer: [
{
command: startCommand,
cwd: 'app2',
port: 3002,
reuseExistingServer: !process.env.CI,
timeout: 120_000,
},
{
command: startCommand,
cwd: 'app1',
port: 3001,
reuseExistingServer: !process.env.CI,
timeout: 120_000,
},
],
});
Loading
Loading