Files
n8n-enterprise-unlocked/packages/testing/playwright/tests/ui/14-mapping.spec.ts

372 lines
14 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { test, expect } from '../../fixtures/base';
test.describe('Data Mapping', () => {
test.describe
.serial('Expression Preview', () => {
test('maps expressions from table json, and resolves value based on hover', async ({
n8n,
}) => {
// This test is marked as serial because hover/tooltips are unreliable when running in parallel against a single server due to resource contention.
await n8n.start.fromImportedWorkflow('Test_workflow_3.json');
await n8n.canvas.openNode('Set');
await n8n.ndv.inputPanel.switchDisplayMode('table');
await expect(n8n.ndv.inputPanel.getTable()).toBeVisible();
await expect(n8n.ndv.getParameterInputField('name')).toHaveValue('other');
await expect(n8n.ndv.getParameterInputField('value')).toHaveValue('');
const countCell = n8n.ndv.inputPanel.getTableCellSpan(0, 0, 'count');
await expect(countCell).toBeVisible();
const valueParameter = n8n.ndv.getParameterInput('value');
await n8n.interactions.precisionDragToTarget(countCell, valueParameter, 'bottom');
await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText(
'{{ $json.input[0].count }}',
);
await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('0');
await n8n.ndv.inputPanel.getTbodyCell(0, 0).hover();
await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('0');
await n8n.ndv.inputPanel.getTbodyCell(1, 0).hover();
await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('1');
await n8n.ndv.execute();
await expect(n8n.ndv.outputPanel.getTable()).toBeVisible();
await n8n.ndv.outputPanel.getTbodyCell(0, 0).hover();
await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('0');
await n8n.ndv.outputPanel.getTbodyCell(1, 0).hover();
await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('1');
});
});
test('maps expressions from json view', async ({ n8n }) => {
await n8n.start.fromImportedWorkflow('Test_workflow_3.json');
await n8n.canvas.openNode('Set');
await n8n.ndv.inputPanel.switchDisplayMode('json');
const expectedJsonText =
'[{"input": [{"count": 0,"with space": "!!","with.dot": "!!","with"quotes": "!!"}]},{"input": [{"count": 1}]}]';
await expect(n8n.ndv.inputPanel.get().getByText(expectedJsonText)).toBeVisible();
await expect(n8n.ndv.inputPanel.getJsonDataContainer()).toBeVisible();
const inputSpan = n8n.ndv.inputPanel.getJsonProperty('input');
await expect(inputSpan).toBeVisible();
const valueParameterInput = n8n.ndv.getParameterInput('value');
await expect(valueParameterInput).toBeVisible();
await inputSpan.dragTo(valueParameterInput);
const expressionEditor = n8n.ndv.getInlineExpressionEditorInput();
await expect(expressionEditor).toBeVisible();
await expect(expressionEditor).toHaveText('{{ $json.input }}');
await n8n.page.keyboard.press('Escape');
await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('Array:');
await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('"count": 0');
const countSpan = n8n.ndv.inputPanel.getJsonPropertyContaining('count');
await expect(countSpan).toBeVisible();
await n8n.interactions.precisionDragToTarget(
countSpan,
n8n.ndv.getInlineExpressionEditorInput(),
'bottom',
);
await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText(
'{{ $json.input }}{{ $json.input[0].count }}',
);
await n8n.page.keyboard.press('Escape');
const previewElement = n8n.ndv.getParameterExpressionPreviewValue();
await expect(previewElement).toBeVisible();
});
test('maps expressions from previous nodes', async ({ n8n }) => {
await n8n.start.fromImportedWorkflow('Test_workflow_3.json');
await n8n.canvas.openNode('Set1');
await n8n.ndv.executePrevious();
const scheduleNode = n8n.ndv.inputPanel.get().getByText('Schedule Trigger');
await expect(scheduleNode).toBeVisible();
await scheduleNode.click();
const schemaItem = n8n.ndv.inputPanel.getSchemaItemText('count');
await expect(schemaItem).toBeVisible();
const valueParameterInput = n8n.ndv.getParameterInput('value');
await expect(valueParameterInput).toBeVisible();
await n8n.interactions.precisionDragToTarget(
schemaItem.locator('span'),
valueParameterInput,
'top',
);
await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText(
"{{ $('Schedule Trigger').item.json.input[0].count }}",
);
await n8n.page.keyboard.press('Escape');
await n8n.ndv.inputPanel.switchDisplayMode('table');
await n8n.ndv.selectInputNode('Schedule Trigger');
const headerElement = n8n.ndv.inputPanel.getTableHeader(0);
await expect(headerElement).toBeVisible();
await n8n.interactions.precisionDragToTarget(
headerElement,
n8n.ndv.getInlineExpressionEditorInput(),
'top',
);
await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText(
"{{ $('Schedule Trigger').item.json.input }}{{ $('Schedule Trigger').item.json.input[0].count }}",
);
await n8n.ndv.selectInputNode('Set');
});
test('maps expressions from table header', async ({ n8n }) => {
await n8n.start.fromImportedWorkflow('Test_workflow-actions_paste-data.json');
await n8n.canvas.openNode('Set');
await n8n.ndv.executePrevious();
await n8n.ndv.inputPanel.switchDisplayMode('table');
await expect(n8n.ndv.inputPanel.getTable()).toBeVisible();
const addValueButton = n8n.ndv.getAddValueButton();
await expect(addValueButton).toBeVisible();
await addValueButton.click();
await n8n.page.getByRole('option', { name: 'String' }).click();
await expect(n8n.ndv.getParameterInputField('name')).toHaveValue('propertyName');
await expect(n8n.ndv.getParameterInputField('value')).toHaveValue('');
const firstHeader = n8n.ndv.inputPanel.getTableHeader(0);
await expect(firstHeader).toBeVisible();
const valueParameter = n8n.ndv.getParameterInput('value');
await n8n.interactions.precisionDragToTarget(firstHeader, valueParameter, 'bottom');
await expect(n8n.ndv.getInlineExpressionEditorInput()).toBeVisible();
await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText('{{ $json.timestamp }}');
await n8n.page.keyboard.press('Escape');
const currentYear = new Date().getFullYear().toString();
await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText(currentYear);
const secondHeader = n8n.ndv.inputPanel.getTableHeader(1);
await expect(secondHeader).toBeVisible();
await n8n.interactions.precisionDragToTarget(
secondHeader,
n8n.ndv.getInlineExpressionEditorInput(),
'top',
);
await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText(
"{{ $json['Readable date'] }}{{ $json.timestamp }}",
);
});
test('maps expressions from schema view', async ({ n8n }) => {
await n8n.start.fromImportedWorkflow('Test_workflow_3.json');
await n8n.canvas.openNode('Set');
await n8n.ndv.getParameterInputField('value').clear();
await n8n.page.keyboard.press('Escape');
const countSchemaItem = n8n.ndv.inputPanel.getSchemaItemText('count');
await expect(countSchemaItem).toBeVisible();
const valueParameter = n8n.ndv.getParameterInput('value');
await n8n.interactions.precisionDragToTarget(countSchemaItem, valueParameter, 'bottom');
await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText('{{ $json.input[0].count }}');
await n8n.page.keyboard.press('Escape');
await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('0');
const inputSchemaItem = n8n.ndv.inputPanel.getSchemaItemText('input');
await expect(inputSchemaItem).toBeVisible();
await n8n.interactions.precisionDragToTarget(inputSchemaItem, valueParameter, 'top');
await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText(
'{{ $json.input }}{{ $json.input[0].count }}',
);
await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('[object Object]0');
});
test('maps keys to path', async ({ n8n }) => {
await n8n.start.fromBlankCanvas();
await n8n.canvas.addNode('Manual Trigger');
await n8n.canvas.openNode('When clicking Execute workflow');
await n8n.ndv.setPinnedData([
{
input: [
{
'hello.world': {
'my count': 0,
},
},
],
},
{
input: [
{
'hello.world': {
'my count': 1,
},
},
],
},
]);
await n8n.ndv.close();
await n8n.canvas.addNode('Sort');
const addFieldButton = n8n.ndv.getAddFieldToSortByButton();
await addFieldButton.click();
const myCountSpan = n8n.ndv.inputPanel.getSchemaItemText('my count');
await expect(myCountSpan).toBeVisible();
const fieldNameParameter = n8n.ndv.getParameterInput('fieldName');
await n8n.interactions.precisionDragToTarget(myCountSpan, fieldNameParameter, 'bottom');
await expect(n8n.ndv.getInlineExpressionEditorInput()).toBeHidden();
await expect(n8n.ndv.getParameterInputField('fieldName')).toHaveValue(
"input[0]['hello.world']['my count']",
);
});
test('maps expressions to updated fields correctly', async ({ n8n }) => {
await n8n.start.fromImportedWorkflow('Test_workflow_3.json');
await n8n.canvas.openNode('Set');
await n8n.ndv.fillParameterInputByName('value', 'delete me');
await n8n.ndv.fillParameterInputByName('name', 'test');
await n8n.ndv.getParameterInputField('name').blur();
await n8n.ndv.fillParameterInputByName('value', 'fun');
await n8n.ndv.getParameterInputField('value').clear();
const countSchemaItem = n8n.ndv.inputPanel.getSchemaItemText('count');
await expect(countSchemaItem).toBeVisible();
const valueParameter = n8n.ndv.getParameterInput('value');
await n8n.interactions.precisionDragToTarget(countSchemaItem, valueParameter, 'bottom');
await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText('{{ $json.input[0].count }}');
await n8n.page.keyboard.press('Escape');
await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('0');
const inputSchemaItem = n8n.ndv.inputPanel.getSchemaItemText('input');
await expect(inputSchemaItem).toBeVisible();
await n8n.interactions.precisionDragToTarget(inputSchemaItem, valueParameter, 'top');
await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText(
'{{ $json.input }}{{ $json.input[0].count }}',
);
await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('[object Object]0');
});
test('renders expression preview when a previous node is selected', async ({ n8n }) => {
await n8n.start.fromImportedWorkflow('Test_workflow_3.json');
await n8n.canvas.openNode('Set');
await n8n.ndv.fillParameterInputByName('value', 'test_value');
await n8n.ndv.fillParameterInputByName('name', 'test_name');
await n8n.ndv.close();
await n8n.canvas.openNode('Set1');
await n8n.ndv.executePrevious();
await n8n.ndv.inputPanel.switchDisplayMode('table');
const firstHeader = n8n.ndv.inputPanel.getTableHeader(0);
await expect(firstHeader).toBeVisible();
const valueParameter = n8n.ndv.getParameterInput('value');
await n8n.interactions.precisionDragToTarget(firstHeader, valueParameter, 'bottom');
await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('test_value');
await n8n.ndv.selectInputNode('Schedule Trigger');
await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText('test_value');
});
test('shows you can drop to inputs, including booleans', async ({ n8n }) => {
await n8n.start.fromImportedWorkflow('Test_workflow_3.json');
await n8n.canvas.openNode('Set');
await expect(n8n.ndv.getParameterSwitch('includeOtherFields')).toBeVisible();
await expect(n8n.ndv.getParameterTextInput('includeOtherFields')).toBeHidden();
const countSpan = n8n.ndv.inputPanel.getSchemaItemText('count');
await expect(countSpan).toBeVisible();
await countSpan.hover();
await n8n.page.mouse.down();
await n8n.page.mouse.move(100, 100);
await expect(n8n.ndv.getParameterSwitch('includeOtherFields')).toBeHidden();
await expect(n8n.ndv.getParameterTextInput('includeOtherFields')).toBeVisible();
const includeOtherFieldsInput = n8n.ndv.getParameterTextInput('includeOtherFields');
await expect(includeOtherFieldsInput).toHaveCSS('border', /dashed.*rgb\(90, 76, 194\)/);
const valueInput = n8n.ndv.getParameterTextInput('value');
await expect(valueInput).toHaveCSS('border', /dashed.*rgb\(90, 76, 194\)/);
await n8n.page.mouse.up();
});
test('maps expressions to a specific location in the editor', async ({ n8n }) => {
await n8n.start.fromImportedWorkflow('Test_workflow_3.json');
await n8n.canvas.openNode('Set');
await n8n.ndv.fillParameterInputByName('value', '=');
await n8n.ndv.getInlineExpressionEditorContent().fill('hello world\n\nnewline');
await n8n.page.keyboard.press('Escape');
const countSchemaItem = n8n.ndv.inputPanel.getSchemaItemText('count');
await expect(countSchemaItem).toBeVisible();
const valueParameter = n8n.ndv.getParameterInput('value');
await n8n.interactions.precisionDragToTarget(countSchemaItem, valueParameter, 'top');
await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText(
'{{ $json.input[0].count }}hello worldnewline',
);
await n8n.page.keyboard.press('Escape');
await expect(n8n.ndv.getParameterExpressionPreviewValue()).toContainText(
'0hello world\n\nnewline',
);
const inputSchemaItem = n8n.ndv.inputPanel.getSchemaItemText('input');
await expect(inputSchemaItem).toBeVisible();
await n8n.interactions.precisionDragToTarget(inputSchemaItem, valueParameter, 'center');
await expect(n8n.ndv.getInlineExpressionEditorInput()).toHaveText(
'{{ $json.input[0].count }}hello world{{ $json.input }}newline',
);
});
});