Skip to content

Commit

Permalink
fix(editor): Testing flaky resource mapper feature in e2e tests (#7165)
Browse files Browse the repository at this point in the history
  • Loading branch information
MiloradFilipovic authored Sep 14, 2023
1 parent 0c6169e commit aaf87c3
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 58 deletions.
53 changes: 50 additions & 3 deletions cypress/e2e/28-resource-mapper.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe('Resource Mapper', () => {
.resourceMapperFieldsContainer()
.should('be.visible')
.findChildByTestId('parameter-input')
.should('have.length', 2);
.should('have.length', 3);

ndv.actions.setInvalidExpression('fieldId');

Expand All @@ -34,7 +34,7 @@ describe('Resource Mapper', () => {
.resourceMapperFieldsContainer()
.should('be.visible')
.findChildByTestId('parameter-input')
.should('have.length', 2);
.should('have.length', 3);

ndv.actions.setInvalidExpression('otherField');

Expand All @@ -43,6 +43,53 @@ describe('Resource Mapper', () => {
.resourceMapperFieldsContainer()
.should('be.visible')
.findChildByTestId('parameter-input')
.should('have.length', 2);
.should('have.length', 3);
});

it('should correctly delete single field', () => {
workflowPage.actions.addInitialNodeToCanvas('E2e Test', {
action: 'Resource Mapping Component',
});
ndv.getters.parameterInput('id').type('001');
ndv.getters.parameterInput('name').type('John');
ndv.getters.parameterInput('age').type('30');
ndv.getters.nodeExecuteButton().click();
ndv.getters.outputTableHeaderByText('id').should('exist');
ndv.getters.outputTableHeaderByText('name').should('exist');
ndv.getters.outputTableHeaderByText('age').should('exist');
// Remove the 'name' field
ndv.getters.resourceMapperRemoveFieldButton('name').should('exist').click({ force: true });
ndv.getters.nodeExecuteButton().click();
ndv.getters.parameterInput('id').should('exist');
ndv.getters.outputTableHeaderByText('id').should('exist');
// After removing the field, text field and the output table column for the 'name' should not be there anymore
ndv.getters.parameterInput('age').should('exist');
ndv.getters.outputTableHeaderByText('age').should('exist');
ndv.getters.parameterInput('name').should('not.exist');
ndv.getters.outputTableHeaderByText('name').should('not.exist');
});

it('should correctly delete all fields', () => {
workflowPage.actions.addInitialNodeToCanvas('E2e Test', {
action: 'Resource Mapping Component',
});
ndv.getters.parameterInput('id').type('001');
ndv.getters.parameterInput('name').type('John');
ndv.getters.parameterInput('age').type('30');
ndv.getters.nodeExecuteButton().click();
ndv.getters.outputTableHeaderByText('id').should('exist');
ndv.getters.outputTableHeaderByText('name').should('exist');
ndv.getters.outputTableHeaderByText('age').should('exist');
ndv.getters.resourceMapperColumnsOptionsButton().click();
// Click on the 'Remove All Fields' option
ndv.getters.resourceMapperRemoveAllFieldsOption().should('be.visible').click();
ndv.getters.nodeExecuteButton().click();
ndv.getters.parameterInput('id').should('exist');
ndv.getters.outputTableHeaderByText('id').should('exist');
// After removing the all fields, only required one should be in UI and output table
ndv.getters.parameterInput('name').should('not.exist');
ndv.getters.outputTableHeaderByText('name').should('not.exist');
ndv.getters.parameterInput('age').should('not.exist');
ndv.getters.outputTableHeaderByText('age').should('not.exist');
});
});
4 changes: 4 additions & 0 deletions cypress/pages/ndv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export class NDV extends BasePage {
this.getters.runDataPaneHeader().find('button').filter(':visible').contains('Save'),
outputTableRows: () => this.getters.outputDataContainer().find('table tr'),
outputTableHeaders: () => this.getters.outputDataContainer().find('table thead th'),
outputTableHeaderByText: (text: string) => this.getters.outputTableHeaders().contains(text),
outputTableRow: (row: number) => this.getters.outputTableRows().eq(row),
outputTbodyCell: (row: number, col: number) =>
this.getters.outputTableRow(row).find('td').eq(col),
Expand Down Expand Up @@ -71,6 +72,9 @@ export class NDV extends BasePage {
this.getters.resourceLocator(paramName).find('[data-test-id="rlc-mode-selector"]'),
resourceMapperFieldsContainer: () => cy.getByTestId('mapping-fields-container'),
resourceMapperSelectColumn: () => cy.getByTestId('matching-column-select'),
resourceMapperRemoveFieldButton: (fieldName: string) => cy.getByTestId(`remove-field-button-${fieldName}`),
resourceMapperColumnsOptionsButton: () => cy.getByTestId('columns-parameter-input-options-container'),
resourceMapperRemoveAllFieldsOption: () => cy.getByTestId('action-removeAllFields'),
};

actions = {
Expand Down
7 changes: 5 additions & 2 deletions packages/editor-ui/src/components/ParameterInputWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
:expressionEvaluated="expressionValueComputed"
:additionalExpressionData="resolvedAdditionalExpressionData"
:label="label"
:data-test-id="`parameter-input-${parameter.name}`"
:data-test-id="`parameter-input-${parsedParameterName}`"
:event-bus="eventBus"
@focus="onFocus"
@blur="onBlur"
Expand Down Expand Up @@ -61,7 +61,7 @@ import type {
import { isResourceLocatorValue } from 'n8n-workflow';
import type { INodeUi, IUpdateInformation, TargetItem } from '@/Interface';
import { workflowHelpers } from '@/mixins/workflowHelpers';
import { isValueExpression } from '@/utils';
import { isValueExpression, parseResourceMapperFieldName } from '@/utils';
import { useNDVStore } from '@/stores/ndv.store';
import { useEnvironmentsStore, useExternalSecretsStore } from '@/stores';
Expand Down Expand Up @@ -226,6 +226,9 @@ export default defineComponent({
...this.additionalExpressionData,
};
},
parsedParameterName() {
return parseResourceMapperFieldName(this.parameter?.name ?? '');
},
},
methods: {
onFocus() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,10 @@ function getParamType(field: ResourceMapperField): NodePropertyTypes {
return 'string';
}
function getParsedFieldName(fullName: string): string {
return parseResourceMapperFieldName(fullName) ?? fullName;
}
function onValueChanged(value: IUpdateInformation): void {
emit('fieldValueChanged', value);
}
Expand Down Expand Up @@ -344,7 +348,7 @@ defineExpose({
},
})
"
data-test-id="remove-field-button"
:data-test-id="`remove-field-button-${getParsedFieldName(field.name)}`"
@click="removeField(field.name)"
/>
</div>
Expand Down
57 changes: 5 additions & 52 deletions packages/editor-ui/src/components/__tests__/ResourceMapper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,11 @@ describe('ResourceMapper.vue', () => {
expect(
getByTestId('mapping-fields-container').querySelectorAll('.parameter-input').length,
).toBe(4);
expect(queryAllByTestId('remove-field-button').length).toBe(1);
expect(
getByTestId('mapping-fields-container').querySelectorAll(
'[data-test-id^="remove-field-button"]',
).length,
).toBe(1);
});

it('should render correct options based on saved schema', async () => {
Expand Down Expand Up @@ -291,55 +295,4 @@ describe('ResourceMapper.vue', () => {
await waitAllPromises();
expect(fetchFieldsSpy).not.toHaveBeenCalled();
});

it.skip('should delete fields from UI and parameter value when they are deleted', async () => {
const { getByTestId, emitted } = renderComponent({
props: {
node: {
parameters: {
columns: {
schema: null,
},
},
},
},
});
await waitAllPromises();
// Add some values so we can test if they are gone after deletion
const idInput = getByTestId('parameter-input-value["id"]').querySelector('input');
const firstNameInput = getByTestId('parameter-input-value["First name"]').querySelector(
'input',
);
const lastNameInput = getByTestId('parameter-input-value["Last name"]').querySelector('input');
const usernameInput = getByTestId('parameter-input-value["Username"]').querySelector('input');
const addressInput = getByTestId('parameter-input-value["Address"]').querySelector('input');
if (idInput && firstNameInput && lastNameInput && usernameInput && addressInput) {
await userEvent.type(idInput, '123');
await userEvent.type(firstNameInput, 'John');
await userEvent.type(lastNameInput, 'Doe');
await userEvent.type(usernameInput, 'johndoe');
await userEvent.type(addressInput, '123 Main St');
// All field values should be in parameter value
const valueBeforeRemove = getLatestValueChangeEvent(emitted());
expect(valueBeforeRemove[0].value.value).toHaveProperty('id');
expect(valueBeforeRemove[0].value.value).toHaveProperty('First name');
expect(valueBeforeRemove[0].value.value).toHaveProperty('Last name');
expect(valueBeforeRemove[0].value.value).toHaveProperty('Username');
expect(valueBeforeRemove[0].value.value).toHaveProperty('Address');
// Click on 'Remove all fields' option
await userEvent.click(getByTestId('columns-parameter-input-options-container'));
await userEvent.click(getByTestId('action-removeAllFields'));
// Should delete all non-mandatory fields:
// 1. From UI
expect(
getByTestId('resource-mapper-container').querySelectorAll('.parameter-item').length,
).toBe(3);
// 2. And their values from parameter value
const valueAfterRemove = getLatestValueChangeEvent(emitted());
expect(valueAfterRemove[0].value.value).not.toHaveProperty('Username');
expect(valueAfterRemove[0].value.value).not.toHaveProperty('Address');
} else {
throw new Error('Could not find input fields');
}
});
});
8 changes: 8 additions & 0 deletions packages/nodes-base/nodes/E2eTest/E2eTest.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,14 @@ export class E2eTest implements INodeType {
};

async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const operation = this.getNodeParameter('operation', 0);
// For resource mapper testing, return actual node values
if (operation === 'resourceMapper') {
const rmValue = this.getNodeParameter('resourceMapper.value', 0);
if (rmValue) {
return [[{ json: rmValue as INodeExecutionData }]];
}
}
return [returnData];
}
}
9 changes: 9 additions & 0 deletions packages/nodes-base/nodes/E2eTest/mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@ export const resourceMapperFields: ResourceMapperFields = {
display: true,
type: 'string',
},
{
id: 'age',
displayName: 'Age',
defaultMatch: false,
canBeUsedToMatch: false,
required: false,
display: true,
type: 'number',
},
],
};

Expand Down

0 comments on commit aaf87c3

Please sign in to comment.