n8n/packages/testing/playwright/tests/e2e/workflows/demo-diff.spec.ts
Declan Carroll 66087e2dd5
chore: Apply biome formatting to playwright package (no-changelog) (#26586)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 10:47:20 +00:00

292 lines
7.3 KiB
TypeScript

import { test, expect } from '../../../fixtures/base';
import type { TestRequirements } from '../../../Types';
const requirements: TestRequirements = {
config: {
settings: {
previewMode: true,
},
},
};
// Simple workflow structures for testing
const oldWorkflow = {
id: 'old-workflow-id',
name: 'Test Workflow - Before',
nodes: [
{
parameters: {},
id: '1',
name: 'Manual Trigger',
type: 'n8n-nodes-base.manualTrigger',
typeVersion: 1,
position: [250, 300],
},
{
parameters: {},
id: '2',
name: 'Set',
type: 'n8n-nodes-base.set',
typeVersion: 1,
position: [450, 300],
},
],
connections: {
'Manual Trigger': {
main: [
[
{
node: 'Set',
type: 'main',
index: 0,
},
],
],
},
},
};
const newWorkflow = {
id: 'new-workflow-id',
name: 'Test Workflow - After',
nodes: [
{
parameters: {},
id: '1',
name: 'Manual Trigger',
type: 'n8n-nodes-base.manualTrigger',
typeVersion: 1,
position: [250, 300],
},
{
parameters: {
options: {
keepOnlySet: true,
},
},
id: '2',
name: 'Set',
type: 'n8n-nodes-base.set',
typeVersion: 1,
position: [450, 300],
},
{
parameters: {},
id: '3',
name: 'Code',
type: 'n8n-nodes-base.code',
typeVersion: 1,
position: [650, 300],
},
],
connections: {
'Manual Trigger': {
main: [
[
{
node: 'Set',
type: 'main',
index: 0,
},
],
],
},
Set: {
main: [
[
{
node: 'Code',
type: 'main',
index: 0,
},
],
],
},
},
};
test.describe(
'Workflow Diff Demo',
{
annotation: [{ type: 'owner', description: 'Adore' }],
},
() => {
test.beforeEach(async ({ setupRequirements }) => {
await setupRequirements(requirements);
});
test('shows waiting state initially', async ({ n8n }) => {
await n8n.page.goto('/workflows/demo/diff');
// Verify the waiting state message is shown
await expect(n8n.page.getByText('Waiting for workflow data...')).toBeVisible();
});
test('renders diff view when receiving workflow data via postMessage', async ({ n8n }) => {
await n8n.page.goto('/workflows/demo/diff');
// Verify the waiting state is initially shown
await expect(n8n.page.getByText('Waiting for workflow data...')).toBeVisible();
// Send postMessage with workflow data
await n8n.page.evaluate(
({ oldWf, newWf }) => {
window.postMessage(
JSON.stringify({
command: 'openDiff',
oldWorkflow: oldWf,
newWorkflow: newWf,
}),
'*',
);
},
{ oldWf: oldWorkflow, newWf: newWorkflow },
);
// Wait for the diff view to appear - the waiting message should disappear
await expect(n8n.page.getByText('Waiting for workflow data...')).toBeHidden();
// The workflow name should appear in the header
await expect(
n8n.page.getByRole('heading', { name: /Test Workflow/, exact: false }),
).toBeVisible();
// The Changes button should be visible (part of the diff view header)
await expect(n8n.page.getByRole('button', { name: /Changes/ })).toBeVisible();
});
test('renders diff view with only new workflow (creation scenario)', async ({ n8n }) => {
await n8n.page.goto('/workflows/demo/diff');
// Wait for the page to be ready (component mounted with event listener active)
await expect(n8n.page.getByText('Waiting for workflow data...')).toBeVisible();
// Send postMessage with only newWorkflow (simulating workflow creation)
await n8n.page.evaluate(
({ newWf }) => {
window.postMessage(
JSON.stringify({
command: 'openDiff',
newWorkflow: newWf,
}),
'*',
);
},
{ newWf: newWorkflow },
);
// Wait for the diff view to appear
await expect(n8n.page.getByText('Waiting for workflow data...')).toBeHidden();
// The workflow name from newWorkflow should appear
await expect(n8n.page.getByRole('heading', { name: 'Test Workflow - After' })).toBeVisible();
});
test('renders diff view with only old workflow (deletion scenario)', async ({ n8n }) => {
await n8n.page.goto('/workflows/demo/diff');
// Wait for the page to be ready (component mounted with event listener active)
await expect(n8n.page.getByText('Waiting for workflow data...')).toBeVisible();
// Send postMessage with only oldWorkflow (simulating workflow deletion)
await n8n.page.evaluate(
({ oldWf }) => {
window.postMessage(
JSON.stringify({
command: 'openDiff',
oldWorkflow: oldWf,
}),
'*',
);
},
{ oldWf: oldWorkflow },
);
// Wait for the diff view to appear
await expect(n8n.page.getByText('Waiting for workflow data...')).toBeHidden();
// The workflow name from oldWorkflow should appear
await expect(n8n.page.getByRole('heading', { name: 'Test Workflow - Before' })).toBeVisible();
});
test('applies tidy up when tidyUp option is true', async ({ n8n }) => {
await n8n.page.goto('/workflows/demo/diff');
// Wait for the page to be ready (component mounted with event listener active)
await expect(n8n.page.getByText('Waiting for workflow data...')).toBeVisible();
// Send postMessage with tidyUp: true
await n8n.page.evaluate(
({ oldWf, newWf }) => {
window.postMessage(
JSON.stringify({
command: 'openDiff',
oldWorkflow: oldWf,
newWorkflow: newWf,
tidyUp: true,
}),
'*',
);
},
{ oldWf: oldWorkflow, newWf: newWorkflow },
);
// Wait for the diff view to appear
await expect(n8n.page.getByText('Waiting for workflow data...')).toBeHidden();
// The diff view should render (tidyUp affects node positioning but view should still render)
await expect(
n8n.page.getByRole('heading', { name: /Test Workflow/, exact: false }),
).toBeVisible();
// The Changes button should be visible (part of the diff view header)
await expect(n8n.page.getByRole('button', { name: /Changes/ })).toBeVisible();
});
test('ignores malformed postMessage data', async ({ n8n }) => {
await n8n.page.goto('/workflows/demo/diff');
// Verify initial waiting state
await expect(n8n.page.getByText('Waiting for workflow data...')).toBeVisible();
// Send malformed message
await n8n.page.evaluate(() => {
window.postMessage('not valid json {{{', '*');
});
// Waiting state should still be shown
await expect(n8n.page.getByText('Waiting for workflow data...')).toBeVisible();
});
test('ignores non-openDiff commands', async ({ n8n }) => {
await n8n.page.goto('/workflows/demo/diff');
// Verify initial waiting state
await expect(n8n.page.getByText('Waiting for workflow data...')).toBeVisible();
// Send a different command
await n8n.page.evaluate(() => {
window.postMessage(
JSON.stringify({
command: 'someOtherCommand',
data: {},
}),
'*',
);
});
// Waiting state should still be shown
await expect(n8n.page.getByText('Waiting for workflow data...')).toBeVisible();
});
test('can override theme to dark', async ({ n8n }) => {
await n8n.page.goto('/workflows/demo/diff?theme=dark');
await expect(n8n.page.locator('body')).toHaveAttribute('data-theme', 'dark');
});
test('can override theme to light', async ({ n8n }) => {
await n8n.page.goto('/workflows/demo/diff?theme=light');
await expect(n8n.page.locator('body')).toHaveAttribute('data-theme', 'light');
});
},
);