From ecd287564d91f0ae6d8ea40ad2b0d12c8219bf31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milorad=20FIlipovi=C4=87?= Date: Wed, 21 Aug 2024 10:42:08 +0200 Subject: [PATCH] feat(editor): Update `element-plus` to 2.4.3 (no-changelog) (#10281) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ --- cypress/e2e/11-inline-expression-editor.cy.ts | 15 + cypress/e2e/17-workflow-tags.cy.ts | 4 +- cypress/e2e/2-credentials.cy.ts | 4 +- cypress/pages/ndv.ts | 2 + cypress/utils/popper.ts | 2 +- packages/design-system/.storybook/preview.js | 2 +- packages/design-system/package.json | 2 +- .../__snapshots__/Checkbox.spec.ts.snap | 4 - .../__snapshots__/ColorPicker.spec.ts.snap | 2 + .../N8nDatatable/__tests__/Datatable.spec.ts | 2 + .../__snapshots__/Datatable.spec.ts.snap | 3 +- .../N8nSelect/__tests__/Select.spec.ts | 2 + .../__snapshots__/Select.spec.ts.snap | 3 +- packages/design-system/src/utils/index.ts | 1 + packages/design-system/src/utils/testUtils.ts | 18 ++ packages/editor-ui/src/__tests__/utils.ts | 8 +- .../components/ContextMenu/ContextMenu.vue | 8 +- .../ExpandableInput/ExpandableInputEdit.vue | 8 +- .../components/ExpressionParameterInput.vue | 10 +- .../src/components/NDVSubConnections.vue | 153 +++++----- .../Projects/ProjectSharing.test.ts | 14 +- .../ResourceLocator/ResourceLocator.vue | 263 +++++++++--------- packages/editor-ui/src/components/Sticky.vue | 10 +- .../editor-ui/src/components/TagsDropdown.vue | 28 +- .../__tests__/WorkflowLMChatModal.test.ts | 6 +- packages/editor-ui/src/plugins/directives.ts | 2 - .../__tests__/SettingsSourceControl.test.ts | 4 +- pnpm-lock.yaml | 44 +-- 28 files changed, 331 insertions(+), 293 deletions(-) create mode 100644 packages/design-system/src/utils/testUtils.ts diff --git a/cypress/e2e/11-inline-expression-editor.cy.ts b/cypress/e2e/11-inline-expression-editor.cy.ts index 143648ce1b..945c62821b 100644 --- a/cypress/e2e/11-inline-expression-editor.cy.ts +++ b/cypress/e2e/11-inline-expression-editor.cy.ts @@ -11,6 +11,21 @@ describe('Inline expression editor', () => { cy.on('uncaught:exception', (error) => error.name !== 'ExpressionError'); }); + describe('Basic UI functionality', () => { + it('should open and close inline expression preview', () => { + WorkflowPage.actions.zoomToFit(); + WorkflowPage.actions.openNode('Schedule'); + WorkflowPage.actions.openInlineExpressionEditor(); + WorkflowPage.getters.inlineExpressionEditorInput().clear(); + WorkflowPage.getters.inlineExpressionEditorInput().click().type('{{'); + WorkflowPage.getters.inlineExpressionEditorInput().type('123'); + WorkflowPage.getters.inlineExpressionEditorOutput().contains(/^123$/); + // click outside to close + ndv.getters.outputPanel().click(); + WorkflowPage.getters.inlineExpressionEditorOutput().should('not.exist'); + }); + }); + describe('Static data', () => { beforeEach(() => { WorkflowPage.actions.addNodeToCanvas('Hacker News'); diff --git a/cypress/e2e/17-workflow-tags.cy.ts b/cypress/e2e/17-workflow-tags.cy.ts index fc889aead2..26ea7cbe2c 100644 --- a/cypress/e2e/17-workflow-tags.cy.ts +++ b/cypress/e2e/17-workflow-tags.cy.ts @@ -65,7 +65,7 @@ describe('Workflow tags', () => { 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.workflowTagsContainer().click(); wf.getters.tagsInDropdown().filter('.selected').first().click(); cy.get('body').click(0, 0); wf.getters.workflowTags().click(); @@ -79,7 +79,7 @@ describe('Workflow tags', () => { wf.actions.addTags(TEST_TAGS); cy.get('body').click(0, 0); wf.getters.workflowTags().click(); - wf.getters.tagsDropdown().find('input:focus').type(NON_EXISTING_TAG); + wf.getters.workflowTagsInput().type(NON_EXISTING_TAG); getVisibleSelect() .find('li') diff --git a/cypress/e2e/2-credentials.cy.ts b/cypress/e2e/2-credentials.cy.ts index ffecd51959..9dbe6c6b5d 100644 --- a/cypress/e2e/2-credentials.cy.ts +++ b/cypress/e2e/2-credentials.cy.ts @@ -112,13 +112,13 @@ describe('Credentials', () => { workflowPage.getters.nodeCredentialsSelect().should('have.length', 2); workflowPage.getters.nodeCredentialsSelect().first().click(); - getVisibleSelect().find('li').last().click(); + getVisibleSelect().find('li').contains('Create New Credential').click(); // This one should show auth type selector credentialsModal.getters.credentialAuthTypeRadioButtons().should('have.length', 2); cy.get('body').type('{esc}'); workflowPage.getters.nodeCredentialsSelect().last().click(); - getVisibleSelect().find('li').last().click(); + getVisibleSelect().find('li').contains('Create New Credential').click(); // This one should not show auth type selector credentialsModal.getters.credentialsAuthTypeSelector().should('not.exist'); }); diff --git a/cypress/pages/ndv.ts b/cypress/pages/ndv.ts index 3bb9eb0fe0..8bd7ccf95f 100644 --- a/cypress/pages/ndv.ts +++ b/cypress/pages/ndv.ts @@ -138,6 +138,8 @@ export class NDV extends BasePage { cy.getByTestId(`fixed-collection-${paramName}`), schemaViewNode: () => cy.getByTestId('run-data-schema-node'), schemaViewNodeName: () => cy.getByTestId('run-data-schema-node-name'), + expressionExpanders: () => cy.getByTestId('expander'), + expressionModalOutput: () => cy.getByTestId('expression-modal-output'), }; actions = { diff --git a/cypress/utils/popper.ts b/cypress/utils/popper.ts index 5743c70f3e..43ef2997cf 100644 --- a/cypress/utils/popper.ts +++ b/cypress/utils/popper.ts @@ -3,7 +3,7 @@ export function getPopper() { } export function getVisiblePopper() { - return getPopper().filter(':visible'); + return getPopper().filter('[aria-hidden="false"]'); } export function getVisibleSelect() { diff --git a/packages/design-system/.storybook/preview.js b/packages/design-system/.storybook/preview.js index bd329cfaea..bb44f598ea 100644 --- a/packages/design-system/.storybook/preview.js +++ b/packages/design-system/.storybook/preview.js @@ -8,7 +8,7 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { fas } from '@fortawesome/free-solid-svg-icons'; import ElementPlus from 'element-plus'; -import lang from 'element-plus/lib/locale/lang/en'; +import lang from 'element-plus/dist/locale/en.mjs' import { N8nPlugin } from '../src/plugin'; diff --git a/packages/design-system/package.json b/packages/design-system/package.json index f6f0a128ab..0de4c11ce9 100644 --- a/packages/design-system/package.json +++ b/packages/design-system/package.json @@ -44,7 +44,7 @@ "@fortawesome/fontawesome-svg-core": "^1.2.36", "@fortawesome/free-solid-svg-icons": "^5.15.4", "@fortawesome/vue-fontawesome": "^3.0.3", - "element-plus": "^2.3.6", + "element-plus": "2.4.3", "markdown-it": "^13.0.2", "markdown-it-emoji": "^2.0.2", "markdown-it-link-attributes": "^4.0.1", diff --git a/packages/design-system/src/components/N8nCheckbox/__tests__/__snapshots__/Checkbox.spec.ts.snap b/packages/design-system/src/components/N8nCheckbox/__tests__/__snapshots__/Checkbox.spec.ts.snap index 9008ca6000..c6dd12ec37 100644 --- a/packages/design-system/src/components/N8nCheckbox/__tests__/__snapshots__/Checkbox.spec.ts.snap +++ b/packages/design-system/src/components/N8nCheckbox/__tests__/__snapshots__/Checkbox.spec.ts.snap @@ -10,7 +10,6 @@ exports[`components > N8nCheckbox > should render with both child and label 1`] class="el-checkbox__input" > N8nCheckbox > should render with child 1`] = ` class="el-checkbox__input" > @@ -106,7 +104,6 @@ exports[`components > N8nCheckbox > should render with label 1`] = ` class="el-checkbox__input" > N8nCheckbox > should render without label and child conten class="el-checkbox__input" > diff --git a/packages/design-system/src/components/N8nColorPicker/__tests__/__snapshots__/ColorPicker.spec.ts.snap b/packages/design-system/src/components/N8nColorPicker/__tests__/__snapshots__/ColorPicker.spec.ts.snap index d0714ea407..5289cc34aa 100644 --- a/packages/design-system/src/components/N8nColorPicker/__tests__/__snapshots__/ColorPicker.spec.ts.snap +++ b/packages/design-system/src/components/N8nColorPicker/__tests__/__snapshots__/ColorPicker.spec.ts.snap @@ -9,6 +9,7 @@ exports[`components > N8nColorPicker > should render with input 1`] = `
N8nColorPicker > should render without input 1`] = `
{ expect(wrapper.container.querySelectorAll('tbody tr td').length).toEqual( columns.length * rowsPerPage, ); + removeDynamicAttributes(wrapper.container); expect(wrapper.html()).toMatchSnapshot(); }); diff --git a/packages/design-system/src/components/N8nDatatable/__tests__/__snapshots__/Datatable.spec.ts.snap b/packages/design-system/src/components/N8nDatatable/__tests__/__snapshots__/Datatable.spec.ts.snap index 0d5d029f17..63c2e64694 100644 --- a/packages/design-system/src/components/N8nDatatable/__tests__/__snapshots__/Datatable.spec.ts.snap +++ b/packages/design-system/src/components/N8nDatatable/__tests__/__snapshots__/Datatable.spec.ts.snap @@ -113,7 +113,6 @@ exports[`components > N8nDatatable > should render correctly 1`] = `
-
@@ -121,7 +120,7 @@ exports[`components > N8nDatatable > should render correctly 1`] = `
- +
diff --git a/packages/design-system/src/components/N8nSelect/__tests__/Select.spec.ts b/packages/design-system/src/components/N8nSelect/__tests__/Select.spec.ts index 2ee22f4e25..170cfdaa3f 100644 --- a/packages/design-system/src/components/N8nSelect/__tests__/Select.spec.ts +++ b/packages/design-system/src/components/N8nSelect/__tests__/Select.spec.ts @@ -3,6 +3,7 @@ import { render, waitFor, within } from '@testing-library/vue'; import userEvent from '@testing-library/user-event'; import N8nSelect from '../Select.vue'; import N8nOption from '../../N8nOption/Option.vue'; +import { removeDynamicAttributes } from 'n8n-design-system/utils'; describe('components', () => { describe('N8nSelect', () => { @@ -21,6 +22,7 @@ describe('components', () => { ], }, }); + removeDynamicAttributes(wrapper.container); expect(wrapper.html()).toMatchSnapshot(); }); diff --git a/packages/design-system/src/components/N8nSelect/__tests__/__snapshots__/Select.spec.ts.snap b/packages/design-system/src/components/N8nSelect/__tests__/__snapshots__/Select.spec.ts.snap index 7277454cf3..c69860442a 100644 --- a/packages/design-system/src/components/N8nSelect/__tests__/__snapshots__/Select.spec.ts.snap +++ b/packages/design-system/src/components/N8nSelect/__tests__/__snapshots__/Select.spec.ts.snap @@ -6,7 +6,6 @@ exports[`components > N8nSelect > should render correctly 1`] = `
-
@@ -14,7 +13,7 @@ exports[`components > N8nSelect > should render correctly 1`] = `
- +
diff --git a/packages/design-system/src/utils/index.ts b/packages/design-system/src/utils/index.ts index 3f4ed339f0..be6ddc6375 100644 --- a/packages/design-system/src/utils/index.ts +++ b/packages/design-system/src/utils/index.ts @@ -4,3 +4,4 @@ export * from './markdown'; export * from './typeguards'; export * from './uid'; export * from './valueByPath'; +export * from './testUtils'; diff --git a/packages/design-system/src/utils/testUtils.ts b/packages/design-system/src/utils/testUtils.ts new file mode 100644 index 0000000000..e632d3e1bf --- /dev/null +++ b/packages/design-system/src/utils/testUtils.ts @@ -0,0 +1,18 @@ +const DYNAMIC_ATTRIBUTES = ['aria-controls']; + +/** + * Deletes dynamic attributes from the container children so snapshots can be tested. + * + * Background: + * Vue test utils use server rendering to render components (https://v1.test-utils.vuejs.org/api/render.html#render). + * Element UI in SSR mode adds dynamic attributes to the rendered HTML each time the test is run (https://element-plus.org/en-US/guide/ssr#provide-an-id). + * + * NOTE: Make sure to manually remove same attributes from the expected snapshot. + */ +// TODO: Find a way to inject static value for dynamic attributes in tests +export function removeDynamicAttributes(container: Element): void { + DYNAMIC_ATTRIBUTES.forEach((attribute) => { + const elements = container.querySelectorAll(`[${attribute}]`); + elements.forEach((element) => element.removeAttribute(attribute)); + }); +} diff --git a/packages/editor-ui/src/__tests__/utils.ts b/packages/editor-ui/src/__tests__/utils.ts index 8090227ee5..ccbcd13bd3 100644 --- a/packages/editor-ui/src/__tests__/utils.ts +++ b/packages/editor-ui/src/__tests__/utils.ts @@ -72,7 +72,7 @@ export const SETTINGS_STORE_DEFAULT_STATE: ISettingsState = { }; export const getDropdownItems = async (dropdownTriggerParent: HTMLElement) => { - await userEvent.click(within(dropdownTriggerParent).getByRole('textbox')); + await userEvent.click(within(dropdownTriggerParent).getByRole('combobox')); const selectTrigger = dropdownTriggerParent.querySelector( '.select-trigger[aria-describedby]', ) as HTMLElement; @@ -84,3 +84,9 @@ export const getDropdownItems = async (dropdownTriggerParent: HTMLElement) => { return selectDropdown.querySelectorAll('.el-select-dropdown__item'); }; + +export const getSelectedDropdownValue = async (items: NodeListOf) => { + const selectedItem = Array.from(items).find((item) => item.classList.contains('selected')); + expect(selectedItem).toBeInTheDocument(); + return selectedItem?.querySelector('p')?.textContent?.trim(); +}; diff --git a/packages/editor-ui/src/components/ContextMenu/ContextMenu.vue b/packages/editor-ui/src/components/ContextMenu/ContextMenu.vue index 13bfcf9c75..0fd54b0a73 100644 --- a/packages/editor-ui/src/components/ContextMenu/ContextMenu.vue +++ b/packages/editor-ui/src/components/ContextMenu/ContextMenu.vue @@ -2,11 +2,13 @@ import { type ContextMenuAction, useContextMenu } from '@/composables/useContextMenu'; import { N8nActionDropdown } from 'n8n-design-system'; import { watch, ref } from 'vue'; +import { onClickOutside } from '@vueuse/core'; const contextMenu = useContextMenu(); const { position, isOpen, actions, target } = contextMenu; const dropdown = ref>(); const emit = defineEmits<{ action: [action: ContextMenuAction, nodeIds: string[]] }>(); +const container = ref(); watch( isOpen, @@ -26,7 +28,7 @@ function onActionSelect(item: string) { emit('action', action, contextMenu.targetNodeIds.value); } -function onClickOutside(event: MouseEvent) { +function closeMenu(event: MouseEvent) { event.preventDefault(); event.stopPropagation(); contextMenu.close(); @@ -37,12 +39,14 @@ function onVisibleChange(open: boolean) { contextMenu.close(); } } + +onClickOutside(container, closeMenu);