mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-25 20:54:07 -08:00
test: Add e2e workflow tags (no-changelog) (#5411)
* 🧪 Add workflow tags tests * ⚡ Create `openTagManagerModal` * ⚡ Add wait to prevent detached DOM element * ⚡ Add wait to mirror other tests
This commit is contained in:
parent
a07de049a2
commit
e0c4c25227
96
cypress/e2e/17-workflow-tags.cy.ts
Normal file
96
cypress/e2e/17-workflow-tags.cy.ts
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
import { WorkflowPage } from '../pages';
|
||||||
|
|
||||||
|
const wf = new WorkflowPage();
|
||||||
|
|
||||||
|
const TEST_TAGS = ['Tag 1', 'Tag 2', 'Tag 3'];
|
||||||
|
|
||||||
|
describe('Workflow tags', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.resetAll();
|
||||||
|
cy.skipSetup();
|
||||||
|
wf.actions.visit();
|
||||||
|
cy.waitForLoad();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create and attach tags inline', () => {
|
||||||
|
wf.getters.createTagButton().click();
|
||||||
|
wf.actions.addTags(TEST_TAGS);
|
||||||
|
wf.getters.tagPills().should('have.length', TEST_TAGS.length);
|
||||||
|
wf.getters.nthTagPill(1).click();
|
||||||
|
wf.actions.addTags('Tag 4');
|
||||||
|
wf.getters.tagPills().should('have.length', TEST_TAGS.length + 1);
|
||||||
|
wf.getters.isWorkflowSaved();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create tags via modal', () => {
|
||||||
|
wf.actions.openTagManagerModal();
|
||||||
|
|
||||||
|
const [first, second] = TEST_TAGS;
|
||||||
|
|
||||||
|
cy.contains('Create a tag').click();
|
||||||
|
cy.getByTestId('tags-table').find('input').type(first).type('{enter}');
|
||||||
|
cy.contains('Add new').click();
|
||||||
|
cy.wait(300);
|
||||||
|
cy.getByTestId('tags-table').find('input').type(second).type('{enter}');
|
||||||
|
cy.contains('Done').click();
|
||||||
|
|
||||||
|
wf.getters.createTagButton().click();
|
||||||
|
wf.getters.tagsInDropdown().should('have.length', 2); // two stored
|
||||||
|
wf.getters.tagPills().should('have.length', 0); // none attached
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete a tag via modal', () => {
|
||||||
|
wf.actions.openTagManagerModal();
|
||||||
|
|
||||||
|
const [first] = TEST_TAGS;
|
||||||
|
|
||||||
|
cy.contains('Create a tag').click();
|
||||||
|
cy.getByTestId('tags-table').find('input').type(first).type('{enter}');
|
||||||
|
cy.getByTestId('delete-tag-button').click({ force: true });
|
||||||
|
cy.wait(300);
|
||||||
|
cy.contains('Delete tag').click();
|
||||||
|
cy.contains('Done').click();
|
||||||
|
wf.getters.createTagButton().click();
|
||||||
|
wf.getters.tagsInDropdown().should('have.length', 0); // none stored
|
||||||
|
wf.getters.tagPills().should('have.length', 0); // none attached
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update a tag via modal', () => {
|
||||||
|
wf.actions.openTagManagerModal();
|
||||||
|
|
||||||
|
const [first] = TEST_TAGS;
|
||||||
|
|
||||||
|
cy.contains('Create a tag').click();
|
||||||
|
cy.getByTestId('tags-table').find('input').type(first).type('{enter}');
|
||||||
|
cy.getByTestId('edit-tag-button').click({ force: true });
|
||||||
|
cy.wait(300);
|
||||||
|
cy.getByTestId('tags-table')
|
||||||
|
.find('.el-input--large')
|
||||||
|
.should('be.visible')
|
||||||
|
.type(' Updated')
|
||||||
|
.type('{enter}');
|
||||||
|
cy.contains('Done').click();
|
||||||
|
wf.getters.createTagButton().click();
|
||||||
|
wf.getters.tagsInDropdown().should('have.length', 1); // one stored
|
||||||
|
wf.getters.tagsInDropdown().contains('Updated').should('exist');
|
||||||
|
wf.getters.tagPills().should('have.length', 0); // none attached
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should detach a tag inline by clicking on X on tag pill', () => {
|
||||||
|
wf.getters.createTagButton().click();
|
||||||
|
wf.actions.addTags(TEST_TAGS);
|
||||||
|
wf.getters.nthTagPill(1).click();
|
||||||
|
wf.getters.tagsDropdown().find('.el-tag__close').first().click();
|
||||||
|
cy.get('body').type('{enter}');
|
||||||
|
wf.getters.tagPills().should('have.length', TEST_TAGS.length - 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should detach a tag inline by clicking on dropdown list item', () => {
|
||||||
|
wf.getters.createTagButton().click();
|
||||||
|
wf.actions.addTags(TEST_TAGS);
|
||||||
|
wf.getters.nthTagPill(1).click();
|
||||||
|
wf.getters.tagsDropdown().find('li.selected').first().click();
|
||||||
|
cy.get('body').type('{enter}');
|
||||||
|
wf.getters.tagPills().should('have.length', TEST_TAGS.length - 1);
|
||||||
|
});
|
||||||
|
});
|
|
@ -7,7 +7,6 @@ import {
|
||||||
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
|
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
|
||||||
|
|
||||||
const NEW_WORKFLOW_NAME = 'Something else';
|
const NEW_WORKFLOW_NAME = 'Something else';
|
||||||
const TEST_WF_TAGS = ['Tag 1', 'Tag 2', 'Tag 3'];
|
|
||||||
const IMPORT_WORKFLOW_URL = 'https://www.jsonkeeper.com/b/FNB0#.json';
|
const IMPORT_WORKFLOW_URL = 'https://www.jsonkeeper.com/b/FNB0#.json';
|
||||||
const DUPLICATE_WORKFLOW_NAME = 'Duplicated workflow';
|
const DUPLICATE_WORKFLOW_NAME = 'Duplicated workflow';
|
||||||
const DUPLICATE_WORKFLOW_TAG = 'Duplicate';
|
const DUPLICATE_WORKFLOW_TAG = 'Duplicate';
|
||||||
|
@ -66,40 +65,6 @@ describe('Workflow Actions', () => {
|
||||||
.should('eq', NEW_WORKFLOW_NAME);
|
.should('eq', NEW_WORKFLOW_NAME);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add tags', () => {
|
|
||||||
WorkflowPage.getters.newTagLink().click();
|
|
||||||
WorkflowPage.actions.addTags(TEST_WF_TAGS);
|
|
||||||
WorkflowPage.getters.isWorkflowSaved();
|
|
||||||
WorkflowPage.getters.workflowTagElements().should('have.length', TEST_WF_TAGS.length);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should add more tags', () => {
|
|
||||||
WorkflowPage.getters.newTagLink().click();
|
|
||||||
WorkflowPage.actions.addTags(TEST_WF_TAGS);
|
|
||||||
WorkflowPage.getters.isWorkflowSaved();
|
|
||||||
WorkflowPage.getters.firstWorkflowTagElement().click();
|
|
||||||
WorkflowPage.actions.addTags(['Another one']);
|
|
||||||
WorkflowPage.getters.workflowTagElements().should('have.length', TEST_WF_TAGS.length + 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should remove tags by clicking X in tag', () => {
|
|
||||||
WorkflowPage.getters.newTagLink().click();
|
|
||||||
WorkflowPage.actions.addTags(TEST_WF_TAGS);
|
|
||||||
WorkflowPage.getters.firstWorkflowTagElement().click();
|
|
||||||
WorkflowPage.getters.workflowTagsContainer().find('.el-tag__close').first().click();
|
|
||||||
cy.get('body').type('{enter}');
|
|
||||||
WorkflowPage.getters.workflowTagElements().should('have.length', TEST_WF_TAGS.length - 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should remove tags from dropdown', () => {
|
|
||||||
WorkflowPage.getters.newTagLink().click();
|
|
||||||
WorkflowPage.actions.addTags(TEST_WF_TAGS);
|
|
||||||
WorkflowPage.getters.firstWorkflowTagElement().click();
|
|
||||||
WorkflowPage.getters.workflowTagsDropdown().find('li.selected').first().click();
|
|
||||||
cy.get('body').type('{enter}');
|
|
||||||
WorkflowPage.getters.workflowTagElements().should('have.length', TEST_WF_TAGS.length - 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should copy nodes', () => {
|
it('should copy nodes', () => {
|
||||||
WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME);
|
WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME);
|
||||||
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
|
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
|
||||||
|
|
|
@ -12,11 +12,12 @@ export class WorkflowPage extends BasePage {
|
||||||
workflowTagsContainer: () => cy.getByTestId('workflow-tags-container'),
|
workflowTagsContainer: () => cy.getByTestId('workflow-tags-container'),
|
||||||
workflowTagsInput: () =>
|
workflowTagsInput: () =>
|
||||||
this.getters.workflowTagsContainer().then(($el) => cy.wrap($el.find('input').first())),
|
this.getters.workflowTagsContainer().then(($el) => cy.wrap($el.find('input').first())),
|
||||||
workflowTagElements: () => cy.get('[data-test-id="workflow-tags-container"] span.tags > span'),
|
tagPills: () => cy.get('[data-test-id="workflow-tags-container"] span.tags > span'),
|
||||||
firstWorkflowTagElement: () =>
|
nthTagPill: (n: number) =>
|
||||||
cy.get('[data-test-id="workflow-tags-container"] span.tags > span:nth-child(1)'),
|
cy.get(`[data-test-id="workflow-tags-container"] span.tags > span:nth-child(${n})`),
|
||||||
workflowTagsDropdown: () => cy.getByTestId('workflow-tags-dropdown'),
|
tagsDropdown: () => cy.getByTestId('workflow-tags-dropdown'),
|
||||||
newTagLink: () => cy.getByTestId('new-tag-link'),
|
tagsInDropdown: () => cy.getByTestId('workflow-tags-dropdown').find('li').filter('.tag'),
|
||||||
|
createTagButton: () => cy.getByTestId('new-tag-link'),
|
||||||
saveButton: () => cy.getByTestId('workflow-save-button'),
|
saveButton: () => cy.getByTestId('workflow-save-button'),
|
||||||
nodeCreatorSearchBar: () => cy.getByTestId('node-creator-search-bar'),
|
nodeCreatorSearchBar: () => cy.getByTestId('node-creator-search-bar'),
|
||||||
nodeCreatorPlusButton: () => cy.getByTestId('node-creator-plus-button'),
|
nodeCreatorPlusButton: () => cy.getByTestId('node-creator-plus-button'),
|
||||||
|
@ -95,9 +96,13 @@ export class WorkflowPage extends BasePage {
|
||||||
ndvParameters: () => cy.getByTestId('parameter-item'),
|
ndvParameters: () => cy.getByTestId('parameter-item'),
|
||||||
nodeCredentialsLabel: () => cy.getByTestId('credentials-label'),
|
nodeCredentialsLabel: () => cy.getByTestId('credentials-label'),
|
||||||
getConnectionBetweenNodes: (sourceNodeName: string, targetNodeName: string) =>
|
getConnectionBetweenNodes: (sourceNodeName: string, targetNodeName: string) =>
|
||||||
cy.get(`.jtk-connector[data-source-node="${sourceNodeName}"][data-target-node="${targetNodeName}"]`),
|
cy.get(
|
||||||
|
`.jtk-connector[data-source-node="${sourceNodeName}"][data-target-node="${targetNodeName}"]`,
|
||||||
|
),
|
||||||
getConnectionActionsBetweenNodes: (sourceNodeName: string, targetNodeName: string) =>
|
getConnectionActionsBetweenNodes: (sourceNodeName: string, targetNodeName: string) =>
|
||||||
cy.get(`.connection-actions[data-source-node="${sourceNodeName}"][data-target-node="${targetNodeName}"]`),
|
cy.get(
|
||||||
|
`.connection-actions[data-source-node="${sourceNodeName}"][data-target-node="${targetNodeName}"]`,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
actions = {
|
actions = {
|
||||||
visit: () => {
|
visit: () => {
|
||||||
|
@ -132,6 +137,10 @@ export class WorkflowPage extends BasePage {
|
||||||
cy.contains('Expression').invoke('show').click();
|
cy.contains('Expression').invoke('show').click();
|
||||||
cy.getByTestId('expander').invoke('show').click();
|
cy.getByTestId('expander').invoke('show').click();
|
||||||
},
|
},
|
||||||
|
openTagManagerModal: () => {
|
||||||
|
this.getters.createTagButton().click();
|
||||||
|
this.getters.tagsDropdown().find('li.manage-tags').first().click();
|
||||||
|
},
|
||||||
openInlineExpressionEditor: () => {
|
openInlineExpressionEditor: () => {
|
||||||
cy.contains('Expression').invoke('show').click();
|
cy.contains('Expression').invoke('show').click();
|
||||||
this.getters.inlineExpressionEditorInput().click();
|
this.getters.inlineExpressionEditorInput().click();
|
||||||
|
@ -161,7 +170,9 @@ export class WorkflowPage extends BasePage {
|
||||||
cy.get('body').type(newName);
|
cy.get('body').type(newName);
|
||||||
cy.get('body').type('{enter}');
|
cy.get('body').type('{enter}');
|
||||||
},
|
},
|
||||||
addTags: (tags: string[]) => {
|
addTags: (tags: string | string[]) => {
|
||||||
|
if (!Array.isArray(tags)) tags = [tags];
|
||||||
|
|
||||||
tags.forEach((tag) => {
|
tags.forEach((tag) => {
|
||||||
this.getters.workflowTagsInput().type(tag);
|
this.getters.workflowTagsInput().type(tag);
|
||||||
this.getters.workflowTagsInput().type('{enter}');
|
this.getters.workflowTagsInput().type('{enter}');
|
||||||
|
@ -200,12 +211,24 @@ export class WorkflowPage extends BasePage {
|
||||||
},
|
},
|
||||||
addNodeBetweenNodes: (sourceNodeName: string, targetNodeName: string, newNodeName: string) => {
|
addNodeBetweenNodes: (sourceNodeName: string, targetNodeName: string, newNodeName: string) => {
|
||||||
this.getters.getConnectionBetweenNodes(sourceNodeName, targetNodeName).first().realHover();
|
this.getters.getConnectionBetweenNodes(sourceNodeName, targetNodeName).first().realHover();
|
||||||
this.getters.getConnectionActionsBetweenNodes(sourceNodeName, targetNodeName).find('.add').first().click({ force: true });
|
this.getters
|
||||||
|
.getConnectionActionsBetweenNodes(sourceNodeName, targetNodeName)
|
||||||
|
.find('.add')
|
||||||
|
.first()
|
||||||
|
.click({ force: true });
|
||||||
this.actions.addNodeToCanvas(newNodeName, false);
|
this.actions.addNodeToCanvas(newNodeName, false);
|
||||||
},
|
},
|
||||||
deleteNodeBetweenNodes: (sourceNodeName: string, targetNodeName: string, newNodeName: string) => {
|
deleteNodeBetweenNodes: (
|
||||||
|
sourceNodeName: string,
|
||||||
|
targetNodeName: string,
|
||||||
|
newNodeName: string,
|
||||||
|
) => {
|
||||||
this.getters.getConnectionBetweenNodes(sourceNodeName, targetNodeName).first().realHover();
|
this.getters.getConnectionBetweenNodes(sourceNodeName, targetNodeName).first().realHover();
|
||||||
this.getters.getConnectionActionsBetweenNodes(sourceNodeName, targetNodeName).find('.delete').first().click({ force: true });
|
this.getters
|
||||||
|
.getConnectionActionsBetweenNodes(sourceNodeName, targetNodeName)
|
||||||
|
.find('.delete')
|
||||||
|
.first()
|
||||||
|
.click({ force: true });
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,12 +90,14 @@
|
||||||
:title="$locale.baseText('tagsTable.editTag')"
|
:title="$locale.baseText('tagsTable.editTag')"
|
||||||
@click.stop="enableUpdate(scope.row)"
|
@click.stop="enableUpdate(scope.row)"
|
||||||
icon="pen"
|
icon="pen"
|
||||||
|
data-test-id="edit-tag-button"
|
||||||
/>
|
/>
|
||||||
<n8n-icon-button
|
<n8n-icon-button
|
||||||
v-if="scope.row.canDelete"
|
v-if="scope.row.canDelete"
|
||||||
:title="$locale.baseText('tagsTable.deleteTag')"
|
:title="$locale.baseText('tagsTable.deleteTag')"
|
||||||
@click.stop="enableDelete(scope.row)"
|
@click.stop="enableDelete(scope.row)"
|
||||||
icon="trash"
|
icon="trash"
|
||||||
|
data-test-id="delete-tag-button"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
@cancelOperation="cancelOperation"
|
@cancelOperation="cancelOperation"
|
||||||
@applyOperation="applyOperation"
|
@applyOperation="applyOperation"
|
||||||
ref="tagsTable"
|
ref="tagsTable"
|
||||||
|
data-test-id="tags-table"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
Loading…
Reference in a new issue