feat(editor): Migrate Design System and Editor UI to Vue 3 (#6476)
* feat: remove vue-fragment (no-changelog) * feat: partial design-system migration * feat: migrate info-accordion and info-tip components * feat: migrate several components to vue 3 * feat: migrated several components * feat: migrate several components * feat: migrate several components * feat: migrate several components * feat: re-exported all design system components * fix: fix design for popper components * fix: editor kind of working, lots of issues to fix * fix: fix several vue 3 migration issues * fix: replace @change with @update:modelValue in several places * fix: fix translation linking * fix: fix inline-edit input * fix: fix ndv and dialog design * fix: update parameter input event bindings * fix: rename deprecated lifecycle methods * fix: fix json view mapping * build: update lock file * fix(editor): revisit last conflict with master and fix issues * fix(editor): revisit last conflict with master and fix issues * fix: fix expression editor bug causing code mirror to no longer be reactive * fix: fix resource locator bug * fix: fix vue-agile integration * fix: remove global import for vue-agile * fix: replace element-plus buttons with n8n-buttons everywhere * fix(editor): Fix various element-plus styles (#6571) * fix(editor): Fix various element-plus styles Signed-off-by: Oleg Ivaniv <me@olegivaniv.com> * Remove debugging code Signed-off-by: Oleg Ivaniv <me@olegivaniv.com> * Address PR comments Signed-off-by: Oleg Ivaniv <me@olegivaniv.com> --------- Signed-off-by: Oleg Ivaniv <me@olegivaniv.com> * fix(editor): Fix loading in production mode [Vue 3] (#6578) Signed-off-by: Oleg Ivaniv <me@olegivaniv.com> * fix(editor): First round of e2e tests fixes with Vue 3 (#6579) * fix(editor): Fix broken smoke and workflow list e2e tests * ✔️ Fix failing canvas action tests. Updating some selectors used in credentials and workflow tests * feat: add vue 3 eslint rules and fix issues * fix: fix tags-dropdown * fix: fix white-space issues caused by i18n-t * fix: rename non-generic click events * fix: fix search in resources list layout * fix: fix datatable paginator * fix: fix popper select caret and dropdown size * fix: add width to action-dropdown * fix: fix workflow settings icon not being hidden * fix: refactor newly added code * fix: fix merge issue * fix: fix ndv credentials watcher * fix: fix workflow saving and grabber notch * fix: fix nodes list panel transition * fix: fix node title visibility * fix: fix data unpinning * fix: fix value access * fix: show input panel only if trigger panel enabled or not trigger node * fix: fix tags dropdown and executions status spcing * fix(editor): Prevent execution list to load back when leaving the route (#6697) fix(editor): prevent execution list to load back when leaving the route * fix: fix drawer visibility * fix: fix expression toggle padding * fix: fix expressions editor styling * chore: prepare for testing * fix: fix styling for el-button without patching * test: fix unit tests in design-system * test: fix most unit tests * fix: remove import cycle. * fix: fix personalization modal tests * fix further resource mapper test adjustments * fix: fix multiple tests and n8n-route attr duplication * fix: fix source control tets * fix: fixed remaining unit tests * fix: fix workflows and credentials e2e tests * fix: fix localizeNodeNames * fix: update ndv e2e tests * fix: fix popper left placement arrow * fix: fix 5-ndv e2e tests * fix: fix 6-code-node e2e tests * fix(editor): Drop click outside directive from NodeCreator (#6716) * fix(editor): Drop click outside directive from NodeCreator * fix(editor): make sure mouseup outside is unbound at least before the component is unmounted * fix: fix 10-settings-log-streaming e2e tests * fix: fix node redrawing * fix: fix tooltip buttons styling * fix: fix varous e2e suites * fix: fix 15-scheduler-node e2e suite * fix: fix route watcher * fix: fixed param name update and credential edit * feat: update event names * refactor: Remove deprecated `$data` (#6576) Co-authored-by: Alex Grozav <alex@grozav.com> * fix: fix 17-sharing e2e suite * fix: fix tags dropdown * fix: fix tags manager * fix(editor): move :deep selectors to a separate scoped style block * fix: fix sticky component and inline text edit * fix: update e2e tests * fix: remove button override references * fix(editor): Adjust spacing in templates for Vue 3 (#6744) * fix(editor): Adjust spacing in templates * fix: Undo unneeded change * fix: Undo unneeded change * fix(editor): Adjust NDV height for Vue 3 (#6742) fix(editor): Adjust NDV height * fix(editor): Restore collapsed sidebar items for Vue 3 (#6743) fix(editor): Restore collapsed sidebar items * fix: fix linting issues * fix: fix design-system deps * fix: post-merge fixes * fix: update tests * fix: increase timeout for executionslist tets * chore: fix linting issue * fix: fix 14-mapping e2e tests in ci * fix: re-enable tests * fix: fix workflow duplication e2e tests after tags update * fix(editor): Change component prop to be typed * fix: fix tags dropdown in duplicate wf modal * fix: fix focus behaviour in tags selector * fix: fix tag creation * fix: fix log streaming e2e race condition * fix(editor): Fix Vue 3 linting issues (#6748) * fix(editor): Fix Vue 3 linting issues Signed-off-by: Oleg Ivaniv <me@olegivaniv.com> * fix MainSidebar linter issues * revert pnpm lock * update pnpm lock file --------- Signed-off-by: Oleg Ivaniv <me@olegivaniv.com> Co-authored-by: Alex Grozav <alex@grozav.com> * fix(editor): Some css fixes for vue3 branch (#6749) * ✨ Fixing filter button height * ✨ Update input modal button position * ✨ Updating tags styling * ✨ Fix event logging settings spacing * 👕 Fixing lint errors * fix: fix linting issues * Revert to `// eslint-disable-next-line @typescript-eslint/no-misused-promises` disabling of mixins init Signed-off-by: Oleg Ivaniv <me@olegivaniv.com> * fix: fix css issue * fix(editor): Lint fix * fix(editor): Fix settings initialisation (#6750) Signed-off-by: Oleg Ivaniv <me@olegivaniv.com> * fix: fix initial settings loading * fix: replace realClick with click force * fix: fix randomly failing mapping e2e tests * fix(editor): Fix menu item event handling * fix: fix resource filters dropdown events (#6752) * fix: fix resource filters dropdown events * fix: remove teleported:false * fix: fix event selection event naming (#6753) * fix: removed console.log (#6754) * fix: rever await nextTick changes * fix: redo linting changes * fix(editor): Redraw node connections if adding more than one node to canvas (#6755) * fix(editor): Redraw node connections if adding more than one node to canvas Signed-off-by: Oleg Ivaniv <me@olegivaniv.com> * Update position before connection two nodes * Lint fix --------- Signed-off-by: Oleg Ivaniv <me@olegivaniv.com> Co-authored-by: Alex Grozav <alex@grozav.com> * fix(editor): Fix `ResourceMapper` unit tests (#6758) * ✔️ Fix matching columns test * ✔️ Fix multiple matching columns test * ✔️ Removing `skip` from the last test * fix: Allow pasting a big workflow (#6760) * fix: pasting a big workflow * chore: update comment * refactor: move try/catch to function * refactor: move try/catch to function * fix(editor): Fix modal layer width * fix: fix position changes * fix: undo it.only * fix: make undo/redo multiple steps more verbose * fix: Fix value survey styles (#6764) * fix: fix value survey styles * fix: lint * Revert "fix: lint" 72869c431f1448861df021be041b61c62f1e3118 * fix: lint * fix(editor): Fix collapsed sub menu * fix: Fix drawer animation (#6767) fix: drawer animation * fix(editor): Fix source control buttons (#6769) * fix(editor): Fix App loading & auth (#6768) * fix(editor): Fix App loading & auth Signed-off-by: Oleg Ivaniv <me@olegivaniv.com> * Await promises Signed-off-by: Oleg Ivaniv <me@olegivaniv.com> * Fix eslint error Signed-off-by: Oleg Ivaniv <me@olegivaniv.com> --------- Signed-off-by: Oleg Ivaniv <me@olegivaniv.com> --------- Signed-off-by: Oleg Ivaniv <me@olegivaniv.com> Co-authored-by: Csaba Tuncsik <csaba@n8n.io> Co-authored-by: OlegIvaniv <me@olegivaniv.com> Co-authored-by: Milorad FIlipović <milorad@n8n.io> Co-authored-by: Iván Ovejero <ivov.src@gmail.com> Co-authored-by: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import { PiniaVuePlugin } from 'pinia';
|
||||
import { render, within } from '@testing-library/vue';
|
||||
import { within } from '@testing-library/vue';
|
||||
import { merge } from 'lodash-es';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
@@ -10,53 +9,52 @@ import { createTestingPinia } from '@pinia/testing';
|
||||
import BannerStack from '@/components/banners/BannerStack.vue';
|
||||
import { useUIStore } from '@/stores/ui.store';
|
||||
import { useUsersStore } from '@/stores/users.store';
|
||||
import type { RenderOptions } from '@/__tests__/render';
|
||||
import { createComponentRenderer } from '@/__tests__/render';
|
||||
|
||||
let uiStore: ReturnType<typeof useUIStore>;
|
||||
let usersStore: ReturnType<typeof useUsersStore>;
|
||||
|
||||
const DEFAULT_SETUP = {
|
||||
pinia: createTestingPinia({
|
||||
initialState: {
|
||||
[STORES.SETTINGS]: {
|
||||
settings: merge({}, SETTINGS_STORE_DEFAULT_STATE.settings),
|
||||
},
|
||||
[STORES.UI]: {
|
||||
banners: {
|
||||
V1: { dismissed: false },
|
||||
TRIAL: { dismissed: false },
|
||||
TRIAL_OVER: { dismissed: false },
|
||||
const initialState = {
|
||||
[STORES.SETTINGS]: {
|
||||
settings: merge({}, SETTINGS_STORE_DEFAULT_STATE.settings),
|
||||
},
|
||||
[STORES.UI]: {
|
||||
banners: {
|
||||
V1: { dismissed: false },
|
||||
TRIAL: { dismissed: false },
|
||||
TRIAL_OVER: { dismissed: false },
|
||||
},
|
||||
},
|
||||
[STORES.USERS]: {
|
||||
currentUserId: 'aaa-bbb',
|
||||
users: {
|
||||
'aaa-bbb': {
|
||||
id: 'aaa-bbb',
|
||||
globalRole: {
|
||||
id: '1',
|
||||
name: 'owner',
|
||||
scope: 'global',
|
||||
},
|
||||
},
|
||||
[STORES.USERS]: {
|
||||
currentUserId: 'aaa-bbb',
|
||||
users: {
|
||||
'aaa-bbb': {
|
||||
id: 'aaa-bbb',
|
||||
globalRole: {
|
||||
id: '1',
|
||||
name: 'owner',
|
||||
scope: 'global',
|
||||
},
|
||||
},
|
||||
'bbb-bbb': {
|
||||
id: 'bbb-bbb',
|
||||
globalRoleId: 2,
|
||||
globalRole: {
|
||||
id: '2',
|
||||
name: 'member',
|
||||
scope: 'global',
|
||||
},
|
||||
},
|
||||
'bbb-bbb': {
|
||||
id: 'bbb-bbb',
|
||||
globalRoleId: 2,
|
||||
globalRole: {
|
||||
id: '2',
|
||||
name: 'member',
|
||||
scope: 'global',
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
const renderComponent = (renderOptions: Parameters<typeof render>[1] = {}) =>
|
||||
render(BannerStack, merge(DEFAULT_SETUP, renderOptions), (vue) => {
|
||||
vue.use(PiniaVuePlugin);
|
||||
});
|
||||
const defaultRenderOptions: RenderOptions = {
|
||||
pinia: createTestingPinia({ initialState }),
|
||||
};
|
||||
|
||||
const renderComponent = createComponentRenderer(BannerStack, defaultRenderOptions);
|
||||
|
||||
describe('BannerStack', () => {
|
||||
beforeEach(() => {
|
||||
@@ -82,19 +80,17 @@ describe('BannerStack', () => {
|
||||
it('should not render dismissed banners', async () => {
|
||||
const { getByTestId } = renderComponent({
|
||||
pinia: createTestingPinia({
|
||||
initialState: merge(
|
||||
{
|
||||
[STORES.UI]: {
|
||||
banners: {
|
||||
V1: { dismissed: true },
|
||||
TRIAL: { dismissed: true },
|
||||
},
|
||||
initialState: merge(initialState, {
|
||||
[STORES.UI]: {
|
||||
banners: {
|
||||
V1: { dismissed: true },
|
||||
TRIAL: { dismissed: true },
|
||||
},
|
||||
},
|
||||
DEFAULT_SETUP.pinia,
|
||||
),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
const bannerStack = getByTestId('banner-stack');
|
||||
expect(bannerStack).toBeInTheDocument();
|
||||
|
||||
@@ -117,7 +113,7 @@ describe('BannerStack', () => {
|
||||
it('should permanently dismiss banner on click', async () => {
|
||||
const { getByTestId } = renderComponent({
|
||||
pinia: createTestingPinia({
|
||||
initialState: merge(DEFAULT_SETUP.pinia, {
|
||||
initialState: merge(initialState, {
|
||||
[STORES.UI]: {
|
||||
banners: {
|
||||
V1: { dismissed: false },
|
||||
@@ -139,7 +135,7 @@ describe('BannerStack', () => {
|
||||
it('should not render permanent dismiss link if user is not owner', async () => {
|
||||
const { queryByTestId } = renderComponent({
|
||||
pinia: createTestingPinia({
|
||||
initialState: merge(DEFAULT_SETUP.pinia, {
|
||||
initialState: merge(initialState, {
|
||||
[STORES.USERS]: {
|
||||
currentUserId: 'bbb-bbb',
|
||||
},
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { PiniaVuePlugin } from 'pinia';
|
||||
import { render } from '@testing-library/vue';
|
||||
import { merge } from 'lodash-es';
|
||||
|
||||
import { SETTINGS_STORE_DEFAULT_STATE } from '@/__tests__/utils';
|
||||
@@ -7,6 +5,7 @@ import { STORES } from '@/constants';
|
||||
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import CopyInput from '@/components/CopyInput.vue';
|
||||
import { createComponentRenderer } from '@/__tests__/render';
|
||||
|
||||
const DEFAULT_SETUP = {
|
||||
pinia: createTestingPinia({
|
||||
@@ -22,10 +21,7 @@ const DEFAULT_SETUP = {
|
||||
},
|
||||
};
|
||||
|
||||
const renderComponent = (renderOptions: Parameters<typeof render>[1] = {}) =>
|
||||
render(CopyInput, merge(DEFAULT_SETUP, renderOptions), (vue) => {
|
||||
vue.use(PiniaVuePlugin);
|
||||
});
|
||||
const renderComponent = createComponentRenderer(CopyInput, DEFAULT_SETUP);
|
||||
|
||||
describe('BannerStack', () => {
|
||||
afterEach(() => {
|
||||
|
||||
@@ -1,29 +1,14 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import Vue from 'vue';
|
||||
import { PiniaVuePlugin } from 'pinia';
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import type { RenderOptions } from '@testing-library/vue';
|
||||
import { render } from '@testing-library/vue';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import ExecutionFilter from '@/components/ExecutionFilter.vue';
|
||||
import { STORES } from '@/constants';
|
||||
import { i18nInstance } from '@/plugins/i18n';
|
||||
import type { IWorkflowShortResponse, ExecutionFilterType } from '@/Interface';
|
||||
import { useTelemetry } from '@/composables';
|
||||
|
||||
vi.mock('@/composables', () => {
|
||||
const track = vi.fn();
|
||||
return {
|
||||
useTelemetry: () => ({
|
||||
track,
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
let telemetry: ReturnType<typeof useTelemetry>;
|
||||
|
||||
Vue.use(PiniaVuePlugin);
|
||||
import { createComponentRenderer } from '@/__tests__/render';
|
||||
import * as telemetryModule from '@/composables/useTelemetry';
|
||||
import type { Telemetry } from '@/plugins/telemetry';
|
||||
import { merge } from 'lodash-es';
|
||||
|
||||
const defaultFilterState: ExecutionFilterType = {
|
||||
status: 'all',
|
||||
@@ -65,13 +50,36 @@ const initialState = {
|
||||
},
|
||||
};
|
||||
|
||||
const renderOptions: RenderOptions<ExecutionFilter> = {
|
||||
i18n: i18nInstance,
|
||||
};
|
||||
const renderComponent = createComponentRenderer(ExecutionFilter, {
|
||||
props: {
|
||||
teleported: false,
|
||||
},
|
||||
});
|
||||
|
||||
describe('ExecutionFilter', () => {
|
||||
beforeEach(() => {
|
||||
telemetry = useTelemetry();
|
||||
afterAll(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
test('telemetry sent only once after component is mounted', async () => {
|
||||
const track = vi.fn();
|
||||
const spy = vi.spyOn(telemetryModule, 'useTelemetry');
|
||||
spy.mockImplementation(
|
||||
() =>
|
||||
({
|
||||
track,
|
||||
} as unknown as Telemetry),
|
||||
);
|
||||
|
||||
const { getByTestId } = renderComponent({
|
||||
pinia: createTestingPinia({ initialState }),
|
||||
});
|
||||
const customDataKeyInput = getByTestId('execution-filter-saved-data-key-input');
|
||||
|
||||
await userEvent.type(customDataKeyInput, 'test');
|
||||
await userEvent.type(customDataKeyInput, 'key');
|
||||
|
||||
expect(track).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test.each([
|
||||
@@ -86,30 +94,49 @@ describe('ExecutionFilter', () => {
|
||||
])(
|
||||
'renders in %s environment on %s deployment with advancedExecutionFilters %s and workflows %s',
|
||||
async (environment, deployment, advancedExecutionFilters, workflows) => {
|
||||
initialState[STORES.SETTINGS].settings.license.environment = environment;
|
||||
initialState[STORES.SETTINGS].settings.deployment.type = deployment;
|
||||
initialState[STORES.SETTINGS].settings.enterprise.advancedExecutionFilters =
|
||||
advancedExecutionFilters;
|
||||
|
||||
renderOptions.pinia = createTestingPinia({ initialState });
|
||||
renderOptions.props = { workflows };
|
||||
|
||||
const { getByTestId, queryByTestId } = render(ExecutionFilter, renderOptions);
|
||||
const { html, getByTestId, queryByTestId, queryAllByTestId } = renderComponent({
|
||||
props: { workflows },
|
||||
pinia: createTestingPinia({
|
||||
initialState: merge(initialState, {
|
||||
[STORES.SETTINGS]: {
|
||||
settings: {
|
||||
license: {
|
||||
environment,
|
||||
},
|
||||
deployment: {
|
||||
type: deployment,
|
||||
},
|
||||
enterprise: {
|
||||
advancedExecutionFilters,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
await userEvent.click(getByTestId('executions-filter-button'));
|
||||
await userEvent.hover(getByTestId('execution-filter-saved-data-key-input'));
|
||||
|
||||
if (advancedExecutionFilters) {
|
||||
expect(queryByTestId('executions-filter-view-plans-link')).not.toBeInTheDocument();
|
||||
expect(queryByTestId('executions-filter-view-plans-link')).not.toBeVisible();
|
||||
}
|
||||
|
||||
expect(queryByTestId('executions-filter-reset-button')).not.toBeInTheDocument();
|
||||
expect(!!queryByTestId('executions-filter-workflows-select')).toBe(!!workflows?.length);
|
||||
|
||||
const select = queryByTestId('executions-filter-workflows-select');
|
||||
if (workflows && workflows.length > 0) {
|
||||
expect(select).toBeVisible();
|
||||
} else {
|
||||
expect(select).not.toBeInTheDocument();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
test('state change', async () => {
|
||||
const { getByTestId, queryByTestId, emitted } = render(ExecutionFilter, renderOptions);
|
||||
const { html, getByTestId, queryByTestId, emitted } = renderComponent({
|
||||
pinia: createTestingPinia({ initialState }),
|
||||
});
|
||||
|
||||
const filterChangedEvent = emitted().filterChanged;
|
||||
expect(filterChangedEvent).toHaveLength(1);
|
||||
@@ -123,6 +150,7 @@ describe('ExecutionFilter', () => {
|
||||
expect(getByTestId('execution-filter-form')).toBeVisible();
|
||||
|
||||
await userEvent.click(getByTestId('executions-filter-status-select'));
|
||||
|
||||
await userEvent.click(getByTestId('executions-filter-status-select').querySelectorAll('li')[1]);
|
||||
|
||||
expect(emitted().filterChanged).toHaveLength(2);
|
||||
@@ -136,14 +164,4 @@ describe('ExecutionFilter', () => {
|
||||
expect(queryByTestId('executions-filter-reset-button')).not.toBeInTheDocument();
|
||||
expect(queryByTestId('execution-filter-badge')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('telemetry sent only once after component is mounted', async () => {
|
||||
const { getByTestId } = render(ExecutionFilter, renderOptions);
|
||||
const customDataKeyInput = getByTestId('execution-filter-saved-data-key-input');
|
||||
|
||||
await userEvent.type(customDataKeyInput, 'test');
|
||||
await userEvent.type(customDataKeyInput, 'key');
|
||||
|
||||
expect(telemetry.track).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import { vi, describe, it, expect } from 'vitest';
|
||||
import { merge } from 'lodash-es';
|
||||
import { PiniaVuePlugin } from 'pinia';
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import { render } from '@testing-library/vue';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { STORES } from '@/constants';
|
||||
import ExecutionsList from '@/components/ExecutionsList.vue';
|
||||
import { i18nInstance } from '@/plugins/i18n';
|
||||
import type { IWorkflowDb } from '@/Interface';
|
||||
import type { IExecutionsSummary } from 'n8n-workflow';
|
||||
import { retry, SETTINGS_STORE_DEFAULT_STATE, waitAllPromises } from '@/__tests__/utils';
|
||||
import { useWorkflowsStore } from '@/stores';
|
||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||
import type { RenderOptions } from '@/__tests__/render';
|
||||
import { createComponentRenderer } from '@/__tests__/render';
|
||||
|
||||
let pinia: ReturnType<typeof createTestingPinia>;
|
||||
|
||||
@@ -65,28 +64,19 @@ const generateExecutionsData = () =>
|
||||
estimated: false,
|
||||
}));
|
||||
|
||||
const renderComponent = async () => {
|
||||
const renderResult = render(
|
||||
ExecutionsList,
|
||||
{
|
||||
pinia,
|
||||
propsData: {
|
||||
autoRefreshEnabled: false,
|
||||
},
|
||||
i18n: i18nInstance,
|
||||
const defaultRenderOptions: RenderOptions = {
|
||||
props: {
|
||||
autoRefreshEnabled: false,
|
||||
},
|
||||
global: {
|
||||
stubs: {
|
||||
stubs: ['font-awesome-icon'],
|
||||
},
|
||||
(vue) => {
|
||||
vue.use(PiniaVuePlugin);
|
||||
vue.prototype.$telemetry = {
|
||||
track: () => {},
|
||||
};
|
||||
},
|
||||
);
|
||||
await waitAllPromises();
|
||||
return renderResult;
|
||||
},
|
||||
};
|
||||
|
||||
const renderComponent = createComponentRenderer(ExecutionsList, defaultRenderOptions);
|
||||
|
||||
describe('ExecutionsList.vue', () => {
|
||||
let workflowsStore: ReturnType<typeof useWorkflowsStore>;
|
||||
let workflowsData: IWorkflowDb[];
|
||||
@@ -123,7 +113,13 @@ describe('ExecutionsList.vue', () => {
|
||||
results: [],
|
||||
estimated: false,
|
||||
});
|
||||
const { queryAllByTestId, queryByTestId, getByTestId } = await renderComponent();
|
||||
const { queryAllByTestId, queryByTestId, getByTestId } = renderComponent({
|
||||
global: {
|
||||
plugins: [pinia],
|
||||
},
|
||||
});
|
||||
await waitAllPromises();
|
||||
|
||||
await userEvent.click(getByTestId('execution-auto-refresh-checkbox'));
|
||||
|
||||
expect(queryAllByTestId('select-execution-checkbox').length).toBe(0);
|
||||
@@ -132,58 +128,67 @@ describe('ExecutionsList.vue', () => {
|
||||
expect(getByTestId('execution-list-empty')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should handle selection flow when loading more items', async () => {
|
||||
const storeSpy = vi
|
||||
.spyOn(workflowsStore, 'getPastExecutions')
|
||||
.mockResolvedValueOnce(executionsData[0])
|
||||
.mockResolvedValueOnce(executionsData[1]);
|
||||
it(
|
||||
'should handle selection flow when loading more items',
|
||||
async () => {
|
||||
const storeSpy = vi
|
||||
.spyOn(workflowsStore, 'getPastExecutions')
|
||||
.mockResolvedValueOnce(executionsData[0])
|
||||
.mockResolvedValueOnce(executionsData[1]);
|
||||
|
||||
const { getByTestId, getAllByTestId, queryByTestId } = await renderComponent();
|
||||
const { getByTestId, getAllByTestId, queryByTestId } = renderComponent({
|
||||
global: {
|
||||
plugins: [pinia],
|
||||
},
|
||||
});
|
||||
await waitAllPromises();
|
||||
|
||||
expect(storeSpy).toHaveBeenCalledTimes(1);
|
||||
expect(storeSpy).toHaveBeenCalledTimes(1);
|
||||
|
||||
await userEvent.click(getByTestId('select-visible-executions-checkbox'));
|
||||
await userEvent.click(getByTestId('select-visible-executions-checkbox'));
|
||||
|
||||
await retry(() =>
|
||||
await retry(() =>
|
||||
expect(
|
||||
getAllByTestId('select-execution-checkbox').filter((el) =>
|
||||
el.contains(el.querySelector(':checked')),
|
||||
).length,
|
||||
).toBe(10),
|
||||
);
|
||||
expect(getByTestId('select-all-executions-checkbox')).toBeInTheDocument();
|
||||
expect(getByTestId('selected-executions-info').textContent).toContain(10);
|
||||
|
||||
await userEvent.click(getByTestId('load-more-button'));
|
||||
|
||||
expect(storeSpy).toHaveBeenCalledTimes(2);
|
||||
expect(getAllByTestId('select-execution-checkbox').length).toBe(20);
|
||||
expect(
|
||||
getAllByTestId('select-execution-checkbox').filter((el) =>
|
||||
el.contains(el.querySelector(':checked')),
|
||||
).length,
|
||||
).toBe(10),
|
||||
);
|
||||
expect(getByTestId('select-all-executions-checkbox')).toBeInTheDocument();
|
||||
expect(getByTestId('selected-executions-info').textContent).toContain(10);
|
||||
).toBe(10);
|
||||
|
||||
await userEvent.click(getByTestId('load-more-button'));
|
||||
await userEvent.click(getByTestId('select-all-executions-checkbox'));
|
||||
expect(getAllByTestId('select-execution-checkbox').length).toBe(20);
|
||||
expect(
|
||||
getAllByTestId('select-execution-checkbox').filter((el) =>
|
||||
el.contains(el.querySelector(':checked')),
|
||||
).length,
|
||||
).toBe(20);
|
||||
expect(getByTestId('selected-executions-info').textContent).toContain(20);
|
||||
|
||||
expect(storeSpy).toHaveBeenCalledTimes(2);
|
||||
expect(getAllByTestId('select-execution-checkbox').length).toBe(20);
|
||||
expect(
|
||||
getAllByTestId('select-execution-checkbox').filter((el) =>
|
||||
el.contains(el.querySelector(':checked')),
|
||||
).length,
|
||||
).toBe(10);
|
||||
|
||||
await userEvent.click(getByTestId('select-all-executions-checkbox'));
|
||||
expect(getAllByTestId('select-execution-checkbox').length).toBe(20);
|
||||
expect(
|
||||
getAllByTestId('select-execution-checkbox').filter((el) =>
|
||||
el.contains(el.querySelector(':checked')),
|
||||
).length,
|
||||
).toBe(20);
|
||||
expect(getByTestId('selected-executions-info').textContent).toContain(20);
|
||||
|
||||
await userEvent.click(getAllByTestId('select-execution-checkbox')[2]);
|
||||
expect(getAllByTestId('select-execution-checkbox').length).toBe(20);
|
||||
expect(
|
||||
getAllByTestId('select-execution-checkbox').filter((el) =>
|
||||
el.contains(el.querySelector(':checked')),
|
||||
).length,
|
||||
).toBe(19);
|
||||
expect(getByTestId('selected-executions-info').textContent).toContain(19);
|
||||
expect(getByTestId('select-visible-executions-checkbox')).toBeInTheDocument();
|
||||
expect(queryByTestId('select-all-executions-checkbox')).not.toBeInTheDocument();
|
||||
});
|
||||
await userEvent.click(getAllByTestId('select-execution-checkbox')[2]);
|
||||
expect(getAllByTestId('select-execution-checkbox').length).toBe(20);
|
||||
expect(
|
||||
getAllByTestId('select-execution-checkbox').filter((el) =>
|
||||
el.contains(el.querySelector(':checked')),
|
||||
).length,
|
||||
).toBe(19);
|
||||
expect(getByTestId('selected-executions-info').textContent).toContain(19);
|
||||
expect(getByTestId('select-visible-executions-checkbox')).toBeInTheDocument();
|
||||
expect(queryByTestId('select-all-executions-checkbox')).not.toBeInTheDocument();
|
||||
},
|
||||
{ timeout: 10000 },
|
||||
);
|
||||
|
||||
it('should show "retry" data when appropriate', async () => {
|
||||
vi.spyOn(workflowsStore, 'getPastExecutions').mockResolvedValue(executionsData[0]);
|
||||
@@ -192,7 +197,12 @@ describe('ExecutionsList.vue', () => {
|
||||
(execution) => !execution.retryOf && execution.retrySuccessId,
|
||||
);
|
||||
|
||||
const { queryAllByText } = await renderComponent();
|
||||
const { queryAllByText } = renderComponent({
|
||||
global: {
|
||||
plugins: [pinia],
|
||||
},
|
||||
});
|
||||
await waitAllPromises();
|
||||
|
||||
expect(queryAllByText(/Retry of/).length).toBe(retryOf.length);
|
||||
expect(queryAllByText(/Success retry/).length).toBe(retrySuccessId.length);
|
||||
|
||||
@@ -1,34 +1,22 @@
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { render, waitFor } from '@testing-library/vue';
|
||||
import { waitFor } from '@testing-library/vue';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { PiniaVuePlugin } from 'pinia';
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import { merge } from 'lodash-es';
|
||||
import { SOURCE_CONTROL_PULL_MODAL_KEY, STORES } from '@/constants';
|
||||
import { i18nInstance } from '@/plugins/i18n';
|
||||
import { SETTINGS_STORE_DEFAULT_STATE } from '@/__tests__/utils';
|
||||
import MainSidebarSourceControl from '@/components/MainSidebarSourceControl.vue';
|
||||
import { useSourceControlStore, useUIStore } from '@/stores';
|
||||
import { useSourceControlStore } from '@/stores/sourceControl.store';
|
||||
import { useUIStore } from '@/stores/ui.store';
|
||||
import { useUsersStore } from '@/stores/users.store';
|
||||
import { createComponentRenderer } from '@/__tests__/render';
|
||||
|
||||
let pinia: ReturnType<typeof createTestingPinia>;
|
||||
let sourceControlStore: ReturnType<typeof useSourceControlStore>;
|
||||
let uiStore: ReturnType<typeof useUIStore>;
|
||||
let usersStore: ReturnType<typeof useUsersStore>;
|
||||
|
||||
const renderComponent = (renderOptions: Parameters<typeof render>[1] = {}) => {
|
||||
return render(
|
||||
MainSidebarSourceControl,
|
||||
{
|
||||
pinia,
|
||||
i18n: i18nInstance,
|
||||
...renderOptions,
|
||||
},
|
||||
(vue) => {
|
||||
vue.use(PiniaVuePlugin);
|
||||
},
|
||||
);
|
||||
};
|
||||
const renderComponent = createComponentRenderer(MainSidebarSourceControl);
|
||||
|
||||
describe('MainSidebarSourceControl', () => {
|
||||
beforeEach(() => {
|
||||
@@ -51,12 +39,12 @@ describe('MainSidebarSourceControl', () => {
|
||||
|
||||
it('should render nothing when not instance owner', async () => {
|
||||
vi.spyOn(usersStore, 'isInstanceOwner', 'get').mockReturnValue(false);
|
||||
const { container } = renderComponent({ props: { isCollapsed: false } });
|
||||
const { container } = renderComponent({ pinia, props: { isCollapsed: false } });
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it('should render empty content when instance owner but not connected', async () => {
|
||||
const { getByTestId } = renderComponent({ props: { isCollapsed: false } });
|
||||
const { getByTestId } = renderComponent({ pinia, props: { isCollapsed: false } });
|
||||
expect(getByTestId('main-sidebar-source-control')).toBeInTheDocument();
|
||||
expect(getByTestId('main-sidebar-source-control')).toBeEmptyDOMElement();
|
||||
});
|
||||
@@ -75,7 +63,10 @@ describe('MainSidebarSourceControl', () => {
|
||||
});
|
||||
|
||||
it('should render the appropriate content', async () => {
|
||||
const { getByTestId, queryByTestId } = renderComponent({ props: { isCollapsed: false } });
|
||||
const { getByTestId, queryByTestId } = renderComponent({
|
||||
pinia,
|
||||
props: { isCollapsed: false },
|
||||
});
|
||||
expect(getByTestId('main-sidebar-source-control-connected')).toBeInTheDocument();
|
||||
expect(queryByTestId('main-sidebar-source-control-setup')).not.toBeInTheDocument();
|
||||
});
|
||||
@@ -84,7 +75,10 @@ describe('MainSidebarSourceControl', () => {
|
||||
vi.spyOn(sourceControlStore, 'pullWorkfolder').mockRejectedValueOnce({
|
||||
response: { status: 400 },
|
||||
});
|
||||
const { getAllByRole, getByRole } = renderComponent({ props: { isCollapsed: false } });
|
||||
const { getAllByRole, getByRole } = renderComponent({
|
||||
pinia,
|
||||
props: { isCollapsed: false },
|
||||
});
|
||||
|
||||
await userEvent.click(getAllByRole('button')[0]);
|
||||
await waitFor(() => expect(getByRole('alert')).toBeInTheDocument());
|
||||
@@ -97,7 +91,10 @@ describe('MainSidebarSourceControl', () => {
|
||||
});
|
||||
const openModalSpy = vi.spyOn(uiStore, 'openModalWithData');
|
||||
|
||||
const { getAllByRole, getByRole } = renderComponent({ props: { isCollapsed: false } });
|
||||
const { getAllByRole, getByRole } = renderComponent({
|
||||
pinia,
|
||||
props: { isCollapsed: false },
|
||||
});
|
||||
|
||||
await userEvent.click(getAllByRole('button')[0]);
|
||||
await waitFor(() =>
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
import { PiniaVuePlugin } from 'pinia';
|
||||
import { createLocalVue, mount } from '@vue/test-utils';
|
||||
import PersonalizationModal from '@/components/PersonalizationModal.vue';
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import { PERSONALIZATION_MODAL_KEY } from '@/constants';
|
||||
import { PERSONALIZATION_MODAL_KEY, STORES } from '@/constants';
|
||||
import { retry } from '@/__tests__/utils';
|
||||
import { createComponentRenderer } from '@/__tests__/render';
|
||||
import { fireEvent } from '@testing-library/vue';
|
||||
|
||||
describe('PersonalizationModal.vue', () => {
|
||||
const pinia = createTestingPinia({
|
||||
const renderComponent = createComponentRenderer(PersonalizationModal, {
|
||||
props: {
|
||||
teleported: false,
|
||||
appendToBody: false,
|
||||
},
|
||||
pinia: createTestingPinia({
|
||||
initialState: {
|
||||
ui: {
|
||||
[STORES.UI]: {
|
||||
modals: {
|
||||
[PERSONALIZATION_MODAL_KEY]: { open: true },
|
||||
},
|
||||
},
|
||||
settings: {
|
||||
[STORES.SETTINGS]: {
|
||||
settings: {
|
||||
templates: {
|
||||
host: '',
|
||||
@@ -21,41 +25,39 @@ describe('PersonalizationModal.vue', () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(PiniaVuePlugin);
|
||||
}),
|
||||
});
|
||||
|
||||
describe('PersonalizationModal.vue', () => {
|
||||
it('should render correctly', async () => {
|
||||
const wrapper = mount(PersonalizationModal, {
|
||||
localVue,
|
||||
pinia,
|
||||
});
|
||||
const wrapper = renderComponent();
|
||||
|
||||
await retry(() => expect(wrapper.find('.modal-content').exists()).toBe(true));
|
||||
await retry(() =>
|
||||
expect(wrapper.container.querySelector('.modal-content')).toBeInTheDocument(),
|
||||
);
|
||||
|
||||
expect(wrapper.findAll('.n8n-select').length).toEqual(5);
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
expect(wrapper.container.querySelectorAll('.n8n-select').length).toEqual(5);
|
||||
});
|
||||
|
||||
it('should display new option when role is "Devops", "Engineering", "IT", or "Sales and marketing"', async () => {
|
||||
const wrapper = mount(PersonalizationModal, {
|
||||
localVue,
|
||||
pinia,
|
||||
});
|
||||
const wrapper = renderComponent();
|
||||
|
||||
await retry(() => expect(wrapper.find('.modal-content').exists()).toBe(true));
|
||||
await retry(() =>
|
||||
expect(wrapper.container.querySelector('.modal-content')).toBeInTheDocument(),
|
||||
);
|
||||
|
||||
for (const index of [3, 4, 5, 6]) {
|
||||
await wrapper.find('.n8n-select[name="role"]').trigger('click');
|
||||
await wrapper
|
||||
.find('.n8n-select[name="role"]')
|
||||
.findAll('.el-select-dropdown__item')
|
||||
.at(index)
|
||||
.trigger('click');
|
||||
const select = wrapper.container.querySelectorAll('.n8n-select')[1]!;
|
||||
|
||||
await fireEvent.click(select);
|
||||
|
||||
const item = select.querySelectorAll('.el-select-dropdown__item')[index];
|
||||
|
||||
await fireEvent.click(item);
|
||||
|
||||
await retry(() => {
|
||||
expect(wrapper.findAll('.n8n-select').length).toEqual(6);
|
||||
expect(wrapper.find('.n8n-select[name^="automationGoal"]').exists()).toBe(true);
|
||||
expect(wrapper.container.querySelectorAll('.n8n-select').length).toEqual(6);
|
||||
expect(wrapper.container.querySelector('[name^="automationGoal"]')).toBeInTheDocument();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import { PiniaVuePlugin } from 'pinia';
|
||||
import { render, within } from '@testing-library/vue';
|
||||
import { merge } from 'lodash-es';
|
||||
import {
|
||||
DEFAULT_SETUP,
|
||||
MAPPING_COLUMNS_RESPONSE,
|
||||
@@ -12,15 +9,13 @@ import { waitAllPromises } from '@/__tests__/utils';
|
||||
import * as workflowHelpers from '@/mixins/workflowHelpers';
|
||||
import ResourceMapper from '@/components/ResourceMapper/ResourceMapper.vue';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { createComponentRenderer } from '@/__tests__/render';
|
||||
import type { SpyInstance } from 'vitest';
|
||||
|
||||
let nodeTypeStore: ReturnType<typeof useNodeTypesStore>;
|
||||
let fetchFieldsSpy: SpyInstance, resolveParameterSpy: SpyInstance;
|
||||
|
||||
const renderComponent = (renderOptions: Parameters<typeof render>[1] = {}) =>
|
||||
render(ResourceMapper, merge(DEFAULT_SETUP, renderOptions), (vue) => {
|
||||
vue.use(PiniaVuePlugin);
|
||||
});
|
||||
const renderComponent = createComponentRenderer(ResourceMapper, DEFAULT_SETUP);
|
||||
|
||||
describe('ResourceMapper.vue', () => {
|
||||
beforeAll(() => {
|
||||
@@ -50,18 +45,21 @@ describe('ResourceMapper.vue', () => {
|
||||
).toBe(MAPPING_COLUMNS_RESPONSE.fields.length);
|
||||
});
|
||||
|
||||
it('renders add mode properly', async () => {
|
||||
const { getByTestId, queryByTestId } = renderComponent({
|
||||
props: {
|
||||
parameter: {
|
||||
typeOptions: {
|
||||
resourceMapper: {
|
||||
mode: 'add',
|
||||
it('renders add mode properly', async () => {
|
||||
const { getByTestId, queryByTestId } = renderComponent(
|
||||
{
|
||||
props: {
|
||||
parameter: {
|
||||
typeOptions: {
|
||||
resourceMapper: {
|
||||
mode: 'add',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
{ merge: true },
|
||||
);
|
||||
await waitAllPromises();
|
||||
expect(getByTestId('resource-mapper-container')).toBeInTheDocument();
|
||||
// This mode doesn't render matching column selector
|
||||
@@ -69,113 +67,124 @@ describe('ResourceMapper.vue', () => {
|
||||
});
|
||||
|
||||
it('renders multi-key match selector properly', async () => {
|
||||
const { container, getByTestId } = renderComponent({
|
||||
props: {
|
||||
parameter: {
|
||||
typeOptions: {
|
||||
resourceMapper: {
|
||||
mode: 'upsert',
|
||||
multiKeyMatch: true,
|
||||
const { container, getByTestId } = renderComponent(
|
||||
{
|
||||
props: {
|
||||
parameter: {
|
||||
typeOptions: {
|
||||
resourceMapper: {
|
||||
mode: 'upsert',
|
||||
multiKeyMatch: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
{ merge: true },
|
||||
);
|
||||
await waitAllPromises();
|
||||
expect(getByTestId('resource-mapper-container')).toBeInTheDocument();
|
||||
expect(container.querySelector('.el-select__tags')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not render mapping mode selector if it is disabled', async () => {
|
||||
const { getByTestId, queryByTestId } = renderComponent({
|
||||
props: {
|
||||
parameter: {
|
||||
typeOptions: {
|
||||
resourceMapper: {
|
||||
supportAutoMap: false,
|
||||
const { getByTestId, queryByTestId } = renderComponent(
|
||||
{
|
||||
props: {
|
||||
parameter: {
|
||||
typeOptions: {
|
||||
resourceMapper: {
|
||||
supportAutoMap: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
{ merge: true },
|
||||
);
|
||||
await waitAllPromises();
|
||||
expect(getByTestId('resource-mapper-container')).toBeInTheDocument();
|
||||
expect(queryByTestId('mapping-mode-select')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders field on top of the list when they are selected for matching', async () => {
|
||||
const { container, getByTestId } = renderComponent({
|
||||
props: {
|
||||
parameter: {
|
||||
typeOptions: {
|
||||
resourceMapper: {
|
||||
supportAutoMap: true,
|
||||
mode: 'upsert',
|
||||
multiKeyMatch: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
await waitAllPromises();
|
||||
expect(getByTestId('resource-mapper-container')).toBeInTheDocument();
|
||||
// Id should be the first field in the list
|
||||
expect(container.querySelector('.parameter-item')).toContainHTML('id (using to match)');
|
||||
// // Select Last Name as matching column
|
||||
await userEvent.click(getByTestId('matching-column-select'));
|
||||
const matchingColumnDropdown = getByTestId('matching-column-select');
|
||||
await userEvent.click(within(matchingColumnDropdown).getByText('Last Name'));
|
||||
// // Now, last name should be the first field in the list
|
||||
expect(container.querySelector('.parameter-item')).toContainHTML('Last Name (using to match)');
|
||||
});
|
||||
|
||||
it('renders selected matching columns properly when multiple key matching is enabled', async () => {
|
||||
const { getByTestId, getByText, queryByText } = renderComponent({
|
||||
props: {
|
||||
parameter: {
|
||||
typeOptions: {
|
||||
resourceMapper: {
|
||||
supportAutoMap: true,
|
||||
mode: 'upsert',
|
||||
multiKeyMatch: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
await waitAllPromises();
|
||||
expect(getByTestId('resource-mapper-container')).toBeInTheDocument();
|
||||
const matchingColumnDropdown = getByTestId('matching-column-select');
|
||||
await userEvent.click(matchingColumnDropdown);
|
||||
await userEvent.click(within(matchingColumnDropdown).getByText('Username'));
|
||||
// Both matching columns should be rendered in the dropdown
|
||||
expect(getByTestId('matching-column-select')).toContainHTML(
|
||||
'<span class="el-select__tags-text">id</span>',
|
||||
);
|
||||
expect(getByTestId('matching-column-select')).toContainHTML(
|
||||
'<span class="el-select__tags-text">Username</span>',
|
||||
);
|
||||
// All selected columns should have correct labels
|
||||
expect(getByText('id (using to match)')).toBeInTheDocument();
|
||||
expect(getByText('Username (using to match)')).toBeInTheDocument();
|
||||
expect(queryByText('First Name (using to match)')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('uses field words defined in node definition', async () => {
|
||||
const { getByText } = renderComponent({
|
||||
props: {
|
||||
parameter: {
|
||||
typeOptions: {
|
||||
resourceMapper: {
|
||||
fieldWords: {
|
||||
singular: 'foo',
|
||||
plural: 'foos',
|
||||
const { container, getByTestId } = renderComponent(
|
||||
{
|
||||
props: {
|
||||
parameter: {
|
||||
typeOptions: {
|
||||
resourceMapper: {
|
||||
supportAutoMap: true,
|
||||
mode: 'upsert',
|
||||
multiKeyMatch: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
{ merge: true },
|
||||
);
|
||||
await waitAllPromises();
|
||||
expect(getByTestId('resource-mapper-container')).toBeInTheDocument();
|
||||
// Id should be the first field in the list
|
||||
expect(container.querySelector('.parameter-item')).toContainHTML('id (using to match)');
|
||||
// Select Last Name as matching column
|
||||
await userEvent.click(getByTestId('matching-column-option-Last name'));
|
||||
// Now, last name should be the first field in the list
|
||||
expect(container.querySelector('.parameter-item div.title')).toHaveTextContent(
|
||||
'Last name (using to match)',
|
||||
);
|
||||
});
|
||||
|
||||
it('renders selected matching columns properly when multiple key matching is enabled', async () => {
|
||||
const { getByTestId, getAllByText, queryByText } = renderComponent(
|
||||
{
|
||||
props: {
|
||||
parameter: {
|
||||
typeOptions: {
|
||||
resourceMapper: {
|
||||
supportAutoMap: true,
|
||||
mode: 'upsert',
|
||||
multiKeyMatch: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{ merge: true },
|
||||
);
|
||||
await waitAllPromises();
|
||||
expect(getByTestId('resource-mapper-container')).toBeInTheDocument();
|
||||
await userEvent.click(getByTestId('matching-column-option-Username'));
|
||||
|
||||
// Both matching columns (id and Username) should be rendered in the dropdown
|
||||
expect(
|
||||
getByTestId('matching-column-select').querySelector('.el-select > div'),
|
||||
).toHaveTextContent('idUsername');
|
||||
// All selected columns should have correct labels
|
||||
expect(getAllByText('id (using to match)')[0]).toBeInTheDocument();
|
||||
expect(getAllByText('Username (using to match)')[0]).toBeInTheDocument();
|
||||
expect(queryByText('First Name (using to match)')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('uses field words defined in node definition', async () => {
|
||||
const { getByText } = renderComponent(
|
||||
{
|
||||
props: {
|
||||
parameter: {
|
||||
typeOptions: {
|
||||
resourceMapper: {
|
||||
fieldWords: {
|
||||
singular: 'foo',
|
||||
plural: 'foos',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{ merge: true },
|
||||
);
|
||||
await waitAllPromises();
|
||||
expect(getByText('Set the value for each foo')).toBeInTheDocument();
|
||||
expect(
|
||||
@@ -186,24 +195,27 @@ describe('ResourceMapper.vue', () => {
|
||||
});
|
||||
|
||||
it('should render correct fields based on saved schema', async () => {
|
||||
const { getByTestId, queryAllByTestId } = renderComponent({
|
||||
props: {
|
||||
node: {
|
||||
parameters: {
|
||||
columns: {
|
||||
schema: UPDATED_SCHEMA,
|
||||
const { getByTestId, queryAllByTestId } = renderComponent(
|
||||
{
|
||||
props: {
|
||||
node: {
|
||||
parameters: {
|
||||
columns: {
|
||||
schema: UPDATED_SCHEMA,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
parameter: {
|
||||
typeOptions: {
|
||||
resourceMapper: {
|
||||
mode: 'add',
|
||||
parameter: {
|
||||
typeOptions: {
|
||||
resourceMapper: {
|
||||
mode: 'add',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
{ merge: true },
|
||||
);
|
||||
await waitAllPromises();
|
||||
// There should be 4 fields rendered and only 1 of them should have remove button
|
||||
expect(
|
||||
@@ -213,24 +225,27 @@ describe('ResourceMapper.vue', () => {
|
||||
});
|
||||
|
||||
it('should render correct options based on saved schema', async () => {
|
||||
const { getByTestId } = renderComponent({
|
||||
props: {
|
||||
node: {
|
||||
parameters: {
|
||||
columns: {
|
||||
schema: UPDATED_SCHEMA,
|
||||
const { getByTestId } = renderComponent(
|
||||
{
|
||||
props: {
|
||||
node: {
|
||||
parameters: {
|
||||
columns: {
|
||||
schema: UPDATED_SCHEMA,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
parameter: {
|
||||
typeOptions: {
|
||||
resourceMapper: {
|
||||
mode: 'add',
|
||||
parameter: {
|
||||
typeOptions: {
|
||||
resourceMapper: {
|
||||
mode: 'add',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
{ merge: true },
|
||||
);
|
||||
await waitAllPromises();
|
||||
// Should have one option in the bottom dropdown for one removed field
|
||||
expect(getByTestId('add-fields-select').querySelectorAll('li').length).toBe(1);
|
||||
|
||||
@@ -1,150 +1,33 @@
|
||||
import type Vue from 'vue';
|
||||
import { defineComponent } from 'vue';
|
||||
import { PiniaVuePlugin } from 'pinia';
|
||||
import { render, waitFor } from '@testing-library/vue';
|
||||
import { waitFor } from '@testing-library/vue';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import { merge } from 'lodash-es';
|
||||
import RunData from '@/components/RunData.vue';
|
||||
import { STORES, VIEWS } from '@/constants';
|
||||
import { useSSOStore } from '@/stores/sso.store';
|
||||
import { SETTINGS_STORE_DEFAULT_STATE } from '@/__tests__/utils';
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { genericHelpers } from '@/mixins/genericHelpers';
|
||||
import { pinData } from '@/mixins/pinData';
|
||||
import { useNDVStore, useWorkflowsStore } from '@/stores';
|
||||
import { createComponentRenderer } from '@/__tests__/render';
|
||||
|
||||
let pinia: ReturnType<typeof createTestingPinia>;
|
||||
let ssoStore: ReturnType<typeof useSSOStore>;
|
||||
let workflowsStore: ReturnType<typeof useWorkflowsStore>;
|
||||
let ndvStore: ReturnType<typeof useNDVStore>;
|
||||
|
||||
function TelemetryPlugin(vue: typeof Vue): void {
|
||||
Object.defineProperty(vue, '$telemetry', {
|
||||
get() {
|
||||
return {
|
||||
track: () => {},
|
||||
};
|
||||
const renderComponent = createComponentRenderer(RunData, {
|
||||
props: {
|
||||
nodeUi: {
|
||||
name: 'Test Node',
|
||||
},
|
||||
});
|
||||
Object.defineProperty(vue.prototype, '$telemetry', {
|
||||
get() {
|
||||
return {
|
||||
track: () => {},
|
||||
};
|
||||
},
|
||||
global: {
|
||||
mocks: {
|
||||
$route: {
|
||||
name: VIEWS.WORKFLOW,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const nodeHelpers = defineComponent({
|
||||
methods: {
|
||||
getNodeInputData: vi.fn().mockReturnValue([
|
||||
{
|
||||
json: {
|
||||
id: 1,
|
||||
name: 'Test 1',
|
||||
json: {
|
||||
data: 'Json data 1',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
json: {
|
||||
id: 2,
|
||||
name: 'Test 2',
|
||||
json: {
|
||||
data: 'Json data 2',
|
||||
},
|
||||
},
|
||||
},
|
||||
]),
|
||||
},
|
||||
});
|
||||
|
||||
const renderComponent = (renderOptions: Parameters<typeof render>[1] = {}) =>
|
||||
render(
|
||||
RunData,
|
||||
merge(
|
||||
{
|
||||
pinia,
|
||||
mocks: {
|
||||
$route: {
|
||||
name: VIEWS.WORKFLOW,
|
||||
},
|
||||
},
|
||||
mixins: [externalHooks, genericHelpers, nodeHelpers, pinData],
|
||||
},
|
||||
renderOptions,
|
||||
),
|
||||
(vue) => {
|
||||
vue.use(TelemetryPlugin);
|
||||
vue.use(PiniaVuePlugin);
|
||||
},
|
||||
);
|
||||
|
||||
describe('RunData', () => {
|
||||
beforeEach(() => {
|
||||
pinia = createTestingPinia({
|
||||
initialState: {
|
||||
[STORES.SETTINGS]: {
|
||||
settings: merge({}, SETTINGS_STORE_DEFAULT_STATE.settings),
|
||||
},
|
||||
},
|
||||
});
|
||||
ssoStore = useSSOStore();
|
||||
workflowsStore = useWorkflowsStore();
|
||||
ndvStore = useNDVStore();
|
||||
|
||||
vi.spyOn(workflowsStore, 'getWorkflowExecution', 'get').mockReturnValue({
|
||||
id: '1',
|
||||
finished: true,
|
||||
mode: 'trigger',
|
||||
startedAt: new Date(),
|
||||
workflowData: {
|
||||
id: '1',
|
||||
name: 'Test Workflow',
|
||||
versionId: '1',
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
active: false,
|
||||
nodes: [],
|
||||
connections: {},
|
||||
},
|
||||
data: {
|
||||
resultData: {
|
||||
runData: {
|
||||
'Test Node': [
|
||||
{
|
||||
startTime: new Date().getTime(),
|
||||
executionTime: new Date().getTime(),
|
||||
data: {},
|
||||
source: [null],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should render data correctly even when "item.json" has another "json" key', async () => {
|
||||
vi.spyOn(ndvStore, 'getPanelDisplayMode').mockReturnValue('schema');
|
||||
vi.spyOn(ndvStore, 'activeNode', 'get').mockReturnValue({
|
||||
id: '1',
|
||||
typeVersion: 1,
|
||||
name: 'Test Node',
|
||||
position: [0, 0],
|
||||
type: 'test',
|
||||
parameters: {},
|
||||
});
|
||||
|
||||
const { getByText, getAllByTestId, getByTestId } = renderComponent({
|
||||
const { html, getByText, getAllByTestId, getByTestId } = renderComponent({
|
||||
props: {
|
||||
nodeUi: {
|
||||
id: '1',
|
||||
name: 'Test Node',
|
||||
position: [0, 0],
|
||||
},
|
||||
@@ -154,10 +37,90 @@ describe('RunData', () => {
|
||||
mappingEnabled: true,
|
||||
distanceFromActive: 0,
|
||||
},
|
||||
pinia: createTestingPinia({
|
||||
initialState: {
|
||||
[STORES.SETTINGS]: {
|
||||
settings: merge({}, SETTINGS_STORE_DEFAULT_STATE.settings),
|
||||
},
|
||||
[STORES.NDV]: {
|
||||
output: {
|
||||
displayMode: 'schema',
|
||||
},
|
||||
activeNodeName: 'Test Node',
|
||||
},
|
||||
[STORES.WORKFLOWS]: {
|
||||
workflow: {
|
||||
nodes: [
|
||||
{
|
||||
id: '1',
|
||||
typeVersion: 1,
|
||||
name: 'Test Node',
|
||||
position: [0, 0],
|
||||
type: 'test',
|
||||
parameters: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
workflowExecutionData: {
|
||||
id: '1',
|
||||
finished: true,
|
||||
mode: 'trigger',
|
||||
startedAt: new Date(),
|
||||
workflowData: {
|
||||
id: '1',
|
||||
name: 'Test Workflow',
|
||||
versionId: '1',
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
active: false,
|
||||
nodes: [],
|
||||
connections: {},
|
||||
},
|
||||
data: {
|
||||
resultData: {
|
||||
runData: {
|
||||
'Test Node': [
|
||||
{
|
||||
startTime: new Date().getTime(),
|
||||
executionTime: new Date().getTime(),
|
||||
data: {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
json: {
|
||||
id: 1,
|
||||
name: 'Test 1',
|
||||
json: {
|
||||
data: 'Json data 1',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
json: {
|
||||
id: 2,
|
||||
name: 'Test 2',
|
||||
json: {
|
||||
data: 'Json data 2',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
source: [null],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
await userEvent.click(getByTestId('ndv-pin-data'));
|
||||
await waitFor(() => getAllByTestId('run-data-schema-item'));
|
||||
await waitFor(() => getAllByTestId('run-data-schema-item'), { timeout: 1000 });
|
||||
expect(getByText('Test 1')).toBeInTheDocument();
|
||||
expect(getByText('Json data 1')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -1,44 +1,40 @@
|
||||
import Vue from 'vue';
|
||||
import { PiniaVuePlugin } from 'pinia';
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import { render, screen, cleanup } from '@testing-library/vue';
|
||||
import { screen, cleanup } from '@testing-library/vue';
|
||||
import RunDataJson from '@/components/RunDataJson.vue';
|
||||
import { createComponentRenderer } from '@/__tests__/render';
|
||||
|
||||
Vue.use(PiniaVuePlugin);
|
||||
|
||||
describe('RunDataJson.vue', () => {
|
||||
const DEFAULT_SETUP = {
|
||||
pinia: createTestingPinia(),
|
||||
props: {
|
||||
mappingEnabled: true,
|
||||
editMode: { enabled: false },
|
||||
inputData: [
|
||||
{
|
||||
json: {
|
||||
list: [1, 2, 3],
|
||||
record: { name: 'Joe' },
|
||||
myNumber: 123,
|
||||
myStringNumber: '456',
|
||||
myStringText: 'abc',
|
||||
nil: null,
|
||||
d: undefined,
|
||||
},
|
||||
const renderComponent = createComponentRenderer(RunDataJson, {
|
||||
props: {
|
||||
mappingEnabled: true,
|
||||
editMode: { enabled: false },
|
||||
inputData: [
|
||||
{
|
||||
json: {
|
||||
list: [1, 2, 3],
|
||||
record: { name: 'Joe' },
|
||||
myNumber: 123,
|
||||
myStringNumber: '456',
|
||||
myStringText: 'abc',
|
||||
nil: null,
|
||||
d: undefined,
|
||||
},
|
||||
],
|
||||
node: {
|
||||
parameters: {
|
||||
keepOnlySet: false,
|
||||
values: {},
|
||||
options: {},
|
||||
},
|
||||
id: '820ea733-d8a6-4379-8e73-88a2347ea003',
|
||||
name: 'Set',
|
||||
type: 'n8n-nodes-base.set',
|
||||
typeVersion: 1,
|
||||
position: [380, 1060],
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
node: {
|
||||
parameters: {
|
||||
keepOnlySet: false,
|
||||
values: {},
|
||||
options: {},
|
||||
},
|
||||
id: '820ea733-d8a6-4379-8e73-88a2347ea003',
|
||||
name: 'Set',
|
||||
type: 'n8n-nodes-base.set',
|
||||
typeVersion: 1,
|
||||
position: [380, 1060],
|
||||
disabled: false,
|
||||
},
|
||||
},
|
||||
global: {
|
||||
mocks: {
|
||||
$locale: {
|
||||
baseText() {
|
||||
@@ -49,13 +45,17 @@ describe('RunDataJson.vue', () => {
|
||||
getters: {},
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
describe('RunDataJson.vue', () => {
|
||||
beforeEach(cleanup);
|
||||
|
||||
it('renders json values properly', () => {
|
||||
const { container } = render(RunDataJson, DEFAULT_SETUP, (vue) => {
|
||||
vue.use(PiniaVuePlugin);
|
||||
const { container } = renderComponent({
|
||||
global: {
|
||||
plugins: [createTestingPinia()],
|
||||
},
|
||||
});
|
||||
expect(container).toMatchSnapshot();
|
||||
|
||||
|
||||
@@ -1,82 +1,86 @@
|
||||
import { PiniaVuePlugin } from 'pinia';
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import { render, cleanup } from '@testing-library/vue';
|
||||
import { cleanup } from '@testing-library/vue';
|
||||
import RunDataJsonSchema from '@/components/RunDataSchema.vue';
|
||||
import { STORES } from '@/constants';
|
||||
import { createComponentRenderer } from '@/__tests__/render';
|
||||
|
||||
describe('RunDataJsonSchema.vue', () => {
|
||||
const renderOptions = {
|
||||
pinia: createTestingPinia({
|
||||
initialState: {
|
||||
[STORES.SETTINGS]: {
|
||||
settings: {
|
||||
templates: {
|
||||
enabled: true,
|
||||
host: 'https://api.n8n.io/api/',
|
||||
const renderComponent = createComponentRenderer(RunDataJsonSchema, {
|
||||
global: {
|
||||
stubs: ['font-awesome-icon'],
|
||||
plugins: [
|
||||
createTestingPinia({
|
||||
initialState: {
|
||||
[STORES.SETTINGS]: {
|
||||
settings: {
|
||||
templates: {
|
||||
enabled: true,
|
||||
host: 'https://api.n8n.io/api/',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
props: {
|
||||
mappingEnabled: true,
|
||||
distanceFromActive: 1,
|
||||
runIndex: 1,
|
||||
totalRuns: 2,
|
||||
paneType: 'input',
|
||||
node: {
|
||||
parameters: {
|
||||
keepOnlySet: false,
|
||||
values: {},
|
||||
options: {},
|
||||
},
|
||||
}),
|
||||
stubs: ['font-awesome-icon'],
|
||||
props: {
|
||||
mappingEnabled: true,
|
||||
distanceFromActive: 1,
|
||||
runIndex: 1,
|
||||
totalRuns: 2,
|
||||
paneType: 'input',
|
||||
node: {
|
||||
parameters: {
|
||||
keepOnlySet: false,
|
||||
values: {},
|
||||
options: {},
|
||||
},
|
||||
id: '820ea733-d8a6-4379-8e73-88a2347ea003',
|
||||
name: 'Set',
|
||||
type: 'n8n-nodes-base.set',
|
||||
typeVersion: 1,
|
||||
position: [380, 1060],
|
||||
disabled: false,
|
||||
},
|
||||
data: [{}],
|
||||
id: '820ea733-d8a6-4379-8e73-88a2347ea003',
|
||||
name: 'Set',
|
||||
type: 'n8n-nodes-base.set',
|
||||
typeVersion: 1,
|
||||
position: [380, 1060],
|
||||
disabled: false,
|
||||
},
|
||||
};
|
||||
data: [{}],
|
||||
},
|
||||
});
|
||||
|
||||
describe('RunDataJsonSchema.vue', () => {
|
||||
beforeEach(cleanup);
|
||||
|
||||
it('renders schema for empty data', () => {
|
||||
const { container } = render(RunDataJsonSchema, renderOptions, (vue) => {
|
||||
vue.use(PiniaVuePlugin);
|
||||
});
|
||||
const { container } = renderComponent();
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders schema for data', () => {
|
||||
renderOptions.props.data = [
|
||||
{ name: 'John', age: 22, hobbies: ['surfing', 'traveling'] },
|
||||
{ name: 'Joe', age: 33, hobbies: ['skateboarding', 'gaming'] },
|
||||
];
|
||||
const { container } = render(RunDataJsonSchema, renderOptions, (vue) => {
|
||||
vue.use(PiniaVuePlugin);
|
||||
const { container } = renderComponent({
|
||||
props: {
|
||||
data: [
|
||||
{ name: 'John', age: 22, hobbies: ['surfing', 'traveling'] },
|
||||
{ name: 'Joe', age: 33, hobbies: ['skateboarding', 'gaming'] },
|
||||
],
|
||||
},
|
||||
});
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders schema with spaces and dots', () => {
|
||||
renderOptions.props.data = [
|
||||
{
|
||||
'hello world': [
|
||||
const { container } = renderComponent({
|
||||
props: {
|
||||
data: [
|
||||
{
|
||||
test: {
|
||||
'more to think about': 1,
|
||||
},
|
||||
'test.how': 'ignore',
|
||||
'hello world': [
|
||||
{
|
||||
test: {
|
||||
'more to think about': 1,
|
||||
},
|
||||
'test.how': 'ignore',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
const { container } = render(RunDataJsonSchema, renderOptions, (vue) => {
|
||||
vue.use(PiniaVuePlugin);
|
||||
});
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { render } from '@testing-library/vue';
|
||||
import { PiniaVuePlugin } from 'pinia';
|
||||
import { SETTINGS_STORE_DEFAULT_STATE, waitAllPromises } from '@/__tests__/utils';
|
||||
import { STORES } from '@/constants';
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
@@ -7,6 +5,7 @@ import { createTestingPinia } from '@pinia/testing';
|
||||
import SqlEditor from '@/components/SqlEditor/SqlEditor.vue';
|
||||
import { expressionManager } from '@/mixins/expressionManager';
|
||||
import type { TargetItem } from '@/Interface';
|
||||
import { renderComponent } from '@/__tests__/render';
|
||||
|
||||
const EXPRESSION_OUTPUT_TEST_ID = 'inline-expression-editor-output';
|
||||
|
||||
@@ -19,24 +18,23 @@ const RESOLVABLES: { [key: string]: string | number | boolean } = {
|
||||
};
|
||||
|
||||
const DEFAULT_SETUP = {
|
||||
pinia: createTestingPinia({
|
||||
initialState: {
|
||||
[STORES.SETTINGS]: {
|
||||
settings: SETTINGS_STORE_DEFAULT_STATE.settings,
|
||||
},
|
||||
},
|
||||
}),
|
||||
props: {
|
||||
dialect: 'PostgreSQL',
|
||||
isReadOnly: false,
|
||||
},
|
||||
global: {
|
||||
plugins: [
|
||||
createTestingPinia({
|
||||
initialState: {
|
||||
[STORES.SETTINGS]: {
|
||||
settings: SETTINGS_STORE_DEFAULT_STATE.settings,
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const renderComponent = (renderOptions: Parameters<typeof render>[1] = {}) =>
|
||||
render(SqlEditor, { ...DEFAULT_SETUP, ...renderOptions }, (vue) => {
|
||||
vue.use(PiniaVuePlugin);
|
||||
});
|
||||
|
||||
describe('SQL Editor Preview Tests', () => {
|
||||
beforeEach(() => {
|
||||
vi.spyOn(expressionManager.methods, 'resolve').mockImplementation(
|
||||
@@ -51,9 +49,11 @@ describe('SQL Editor Preview Tests', () => {
|
||||
});
|
||||
|
||||
it('renders basic query', async () => {
|
||||
const { getByTestId } = renderComponent({
|
||||
const { getByTestId } = renderComponent(SqlEditor, {
|
||||
...DEFAULT_SETUP,
|
||||
props: {
|
||||
query: 'SELECT * FROM users',
|
||||
...DEFAULT_SETUP.props,
|
||||
modelValue: 'SELECT * FROM users',
|
||||
},
|
||||
});
|
||||
await waitAllPromises();
|
||||
@@ -61,9 +61,11 @@ describe('SQL Editor Preview Tests', () => {
|
||||
});
|
||||
|
||||
it('renders basic query with expression', async () => {
|
||||
const { getByTestId } = renderComponent({
|
||||
const { getByTestId } = renderComponent(SqlEditor, {
|
||||
...DEFAULT_SETUP,
|
||||
props: {
|
||||
query: 'SELECT * FROM {{ $json.table }}',
|
||||
...DEFAULT_SETUP.props,
|
||||
modelValue: 'SELECT * FROM {{ $json.table }}',
|
||||
},
|
||||
});
|
||||
await waitAllPromises();
|
||||
@@ -71,9 +73,11 @@ describe('SQL Editor Preview Tests', () => {
|
||||
});
|
||||
|
||||
it('renders resolved expressions with dot between resolvables', async () => {
|
||||
const { getByTestId } = renderComponent({
|
||||
const { getByTestId } = renderComponent(SqlEditor, {
|
||||
...DEFAULT_SETUP,
|
||||
props: {
|
||||
query: 'SELECT * FROM {{ $json.schema }}.{{ $json.table }}',
|
||||
...DEFAULT_SETUP.props,
|
||||
modelValue: 'SELECT * FROM {{ $json.schema }}.{{ $json.table }}',
|
||||
},
|
||||
});
|
||||
await waitAllPromises();
|
||||
@@ -81,9 +85,11 @@ describe('SQL Editor Preview Tests', () => {
|
||||
});
|
||||
|
||||
it('renders resolved expressions which resolve to 0', async () => {
|
||||
const { getByTestId } = renderComponent({
|
||||
const { getByTestId } = renderComponent(SqlEditor, {
|
||||
...DEFAULT_SETUP,
|
||||
props: {
|
||||
query:
|
||||
...DEFAULT_SETUP.props,
|
||||
modelValue:
|
||||
'SELECT * FROM {{ $json.schema }}.{{ $json.table }} WHERE {{ $json.id }} > {{ $json.limit - 10 }}',
|
||||
},
|
||||
});
|
||||
@@ -94,9 +100,11 @@ describe('SQL Editor Preview Tests', () => {
|
||||
});
|
||||
|
||||
it('keeps query formatting in rendered output', async () => {
|
||||
const { getByTestId } = renderComponent({
|
||||
const { getByTestId } = renderComponent(SqlEditor, {
|
||||
...DEFAULT_SETUP,
|
||||
props: {
|
||||
query:
|
||||
...DEFAULT_SETUP.props,
|
||||
modelValue:
|
||||
'SELECT * FROM {{ $json.schema }}.{{ $json.table }}\n WHERE id > {{ $json.limit - 10 }}\n AND active = {{ $json.active }};',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { PiniaVuePlugin } from 'pinia';
|
||||
import { render } from '@testing-library/vue';
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import { merge } from 'lodash-es';
|
||||
import SSOLogin from '@/components/SSOLogin.vue';
|
||||
@@ -7,28 +5,20 @@ import { STORES } from '@/constants';
|
||||
import { useSSOStore } from '@/stores/sso.store';
|
||||
import { SETTINGS_STORE_DEFAULT_STATE } from '@/__tests__/utils';
|
||||
import { afterEach } from 'vitest';
|
||||
import { createComponentRenderer } from '@/__tests__/render';
|
||||
|
||||
let pinia: ReturnType<typeof createTestingPinia>;
|
||||
let ssoStore: ReturnType<typeof useSSOStore>;
|
||||
|
||||
const renderComponent = (renderOptions: Parameters<typeof render>[1] = {}) =>
|
||||
render(
|
||||
SSOLogin,
|
||||
merge(
|
||||
{
|
||||
pinia,
|
||||
stubs: {
|
||||
'n8n-button': {
|
||||
template: '<button data-test-id="sso-button"></button>',
|
||||
},
|
||||
},
|
||||
const renderComponent = createComponentRenderer(SSOLogin, {
|
||||
global: {
|
||||
stubs: {
|
||||
'n8n-button': {
|
||||
template: '<button data-test-id="sso-button"></button>',
|
||||
},
|
||||
renderOptions,
|
||||
),
|
||||
(vue) => {
|
||||
vue.use(PiniaVuePlugin);
|
||||
},
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
describe('SSOLogin', () => {
|
||||
beforeEach(() => {
|
||||
@@ -47,13 +37,13 @@ describe('SSOLogin', () => {
|
||||
});
|
||||
|
||||
it('should not render button if conditions are not met', () => {
|
||||
const { queryByRole } = renderComponent();
|
||||
const { queryByRole } = renderComponent({ pinia });
|
||||
expect(queryByRole('button')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render button if the store returns true for the conditions', () => {
|
||||
vi.spyOn(ssoStore, 'showSsoLoginButton', 'get').mockReturnValue(true);
|
||||
const { queryByRole } = renderComponent();
|
||||
const { queryByRole } = renderComponent({ pinia });
|
||||
expect(queryByRole('button')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,24 +1,38 @@
|
||||
import VariablesRow from '../VariablesRow.vue';
|
||||
import type { EnvironmentVariable } from '@/Interface';
|
||||
import { fireEvent } from '@testing-library/vue';
|
||||
import { createPinia, setActivePinia } from 'pinia';
|
||||
import { setupServer } from '@/__tests__/server';
|
||||
import { afterAll, beforeAll } from 'vitest';
|
||||
import { useSettingsStore, useUsersStore } from '@/stores';
|
||||
import { renderComponent } from '@/__tests__/utils';
|
||||
import { createComponentRenderer } from '@/__tests__/render';
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import { STORES } from '@/constants';
|
||||
|
||||
const renderComponent = createComponentRenderer(VariablesRow, {
|
||||
pinia: createTestingPinia({
|
||||
initialState: {
|
||||
[STORES.SETTINGS]: {
|
||||
settings: {
|
||||
enterprise: {
|
||||
variables: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
global: {
|
||||
stubs: ['n8n-tooltip'],
|
||||
},
|
||||
});
|
||||
|
||||
describe('VariablesRow', () => {
|
||||
let server: ReturnType<typeof setupServer>;
|
||||
let pinia: ReturnType<typeof createPinia>;
|
||||
|
||||
beforeAll(() => {
|
||||
server = setupServer();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
pinia = createPinia();
|
||||
setActivePinia(pinia);
|
||||
|
||||
await useSettingsStore().getSettings();
|
||||
await useUsersStore().loginWithCookie();
|
||||
});
|
||||
@@ -27,8 +41,6 @@ describe('VariablesRow', () => {
|
||||
server.shutdown();
|
||||
});
|
||||
|
||||
const stubs = ['n8n-tooltip'];
|
||||
|
||||
const environmentVariable: EnvironmentVariable = {
|
||||
id: 1,
|
||||
key: 'key',
|
||||
@@ -36,25 +48,20 @@ describe('VariablesRow', () => {
|
||||
};
|
||||
|
||||
it('should render correctly', () => {
|
||||
const wrapper = renderComponent(VariablesRow, {
|
||||
const wrapper = renderComponent({
|
||||
props: {
|
||||
data: environmentVariable,
|
||||
},
|
||||
stubs,
|
||||
pinia,
|
||||
});
|
||||
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
expect(wrapper.container.querySelectorAll('td')).toHaveLength(4);
|
||||
});
|
||||
|
||||
it('should show edit and delete buttons on hover', async () => {
|
||||
const wrapper = renderComponent(VariablesRow, {
|
||||
const wrapper = renderComponent({
|
||||
props: {
|
||||
data: environmentVariable,
|
||||
},
|
||||
stubs,
|
||||
pinia,
|
||||
});
|
||||
|
||||
await fireEvent.mouseEnter(wrapper.container);
|
||||
@@ -64,13 +71,11 @@ describe('VariablesRow', () => {
|
||||
});
|
||||
|
||||
it('should show key and value inputs in edit mode', async () => {
|
||||
const wrapper = renderComponent(VariablesRow, {
|
||||
const wrapper = renderComponent({
|
||||
props: {
|
||||
data: environmentVariable,
|
||||
editing: true,
|
||||
},
|
||||
stubs,
|
||||
pinia,
|
||||
});
|
||||
|
||||
await fireEvent.mouseEnter(wrapper.container);
|
||||
@@ -83,18 +88,14 @@ describe('VariablesRow', () => {
|
||||
expect(wrapper.getByTestId('variable-row-value-input').querySelector('input')).toHaveValue(
|
||||
environmentVariable.value,
|
||||
);
|
||||
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should show cancel and save buttons in edit mode', async () => {
|
||||
const wrapper = renderComponent(VariablesRow, {
|
||||
const wrapper = renderComponent({
|
||||
props: {
|
||||
data: environmentVariable,
|
||||
editing: true,
|
||||
},
|
||||
stubs,
|
||||
pinia,
|
||||
});
|
||||
|
||||
await fireEvent.mouseEnter(wrapper.container);
|
||||
|
||||
@@ -1,284 +0,0 @@
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`PersonalizationModal.vue > should render correctly 1`] = `
|
||||
"<transition-stub name=\\"dialog-fade\\" data-test-id=\\"personalization-form\\" class=\\"dialog-wrapper\\" style=\\"z-index: 2001;\\">
|
||||
<div class=\\"el-dialog__wrapper\\">
|
||||
<div role=\\"dialog\\" aria-modal=\\"true\\" aria-label=\\"dialog\\" class=\\"el-dialog\\" style=\\"margin-top: 15vh; width: 460px;\\">
|
||||
<div class=\\"el-dialog__header\\">
|
||||
<div class=\\"centerTitle\\">
|
||||
<div>
|
||||
<h1 class=\\"n8n-heading size-xlarge regular\\">Customize n8n to you</h1>
|
||||
</div>
|
||||
<div class=\\"subtitle\\">
|
||||
<h3 class=\\"n8n-heading text-light size-small regular\\">These questions help us tailor n8n to you</h3>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
<div class=\\"el-dialog__body\\">
|
||||
<div class=\\"modal-content\\">
|
||||
<div class=\\"container\\">
|
||||
<div>
|
||||
<div class=\\"grid\\">
|
||||
<div class=\\"\\">
|
||||
<div data-test-id=\\"companyType\\" class=\\"container\\"><label for=\\"companyType\\" class=\\"n8n-input-label inputLabel heading medium\\">
|
||||
<div class=\\"title\\"><span class=\\"n8n-text size-medium bold\\"> What best describes your company? <!----></span></div>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
</label>
|
||||
<div class=\\"\\">
|
||||
<div class=\\"n8n-select container\\" name=\\"companyType\\">
|
||||
<!---->
|
||||
<div class=\\"el-select el-select--large\\">
|
||||
<!---->
|
||||
<div class=\\"el-input el-input--large el-input--suffix\\">
|
||||
<!----><input type=\\"text\\" readonly=\\"readonly\\" autocomplete=\\"off\\" placeholder=\\"Select...\\" class=\\"el-input__inner\\">
|
||||
<!----><span class=\\"el-input__suffix\\"><span class=\\"el-input__suffix-inner\\"><i class=\\"el-select__caret el-input__icon el-icon-arrow-up\\"></i><!----><!----><!----><!----><!----></span>
|
||||
<!----></span>
|
||||
<!---->
|
||||
<!---->
|
||||
</div>
|
||||
<transition-stub name=\\"el-zoom-in-top\\">
|
||||
<div class=\\"el-select-dropdown el-popper\\" style=\\"display: none;\\">
|
||||
<div class=\\"el-scrollbar\\" style=\\"\\">
|
||||
<div class=\\"el-select-dropdown__wrap el-scrollbar__wrap el-scrollbar__wrap--hidden-default\\">
|
||||
<ul class=\\"el-scrollbar__view el-select-dropdown__list\\">
|
||||
<!---->
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Software as a service</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Ecommerce</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Marketing agency / consultancy</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Systems integrator / Automation agency</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Education</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Other</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>I'm not using n8n for work</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class=\\"el-scrollbar__bar is-horizontal\\">
|
||||
<div class=\\"el-scrollbar__thumb\\" style=\\"transform: translateX(0%); webkit-transform: translateX(0%);\\"></div>
|
||||
</div>
|
||||
<div class=\\"el-scrollbar__bar is-vertical\\">
|
||||
<div class=\\"el-scrollbar__thumb\\" style=\\"transform: translateY(0%); webkit-transform: translateY(0%);\\"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
</transition-stub>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
<div class=\\"\\">
|
||||
<div data-test-id=\\"role\\" class=\\"container\\"><label for=\\"role\\" class=\\"n8n-input-label inputLabel heading medium\\">
|
||||
<div class=\\"title\\"><span class=\\"n8n-text size-medium bold\\"> Which role best describes you? <!----></span></div>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
</label>
|
||||
<div class=\\"\\">
|
||||
<div class=\\"n8n-select container\\" name=\\"role\\">
|
||||
<!---->
|
||||
<div class=\\"el-select el-select--large\\">
|
||||
<!---->
|
||||
<div class=\\"el-input el-input--large el-input--suffix\\">
|
||||
<!----><input type=\\"text\\" readonly=\\"readonly\\" autocomplete=\\"off\\" placeholder=\\"Select...\\" class=\\"el-input__inner\\">
|
||||
<!----><span class=\\"el-input__suffix\\"><span class=\\"el-input__suffix-inner\\"><i class=\\"el-select__caret el-input__icon el-icon-arrow-up\\"></i><!----><!----><!----><!----><!----></span>
|
||||
<!----></span>
|
||||
<!---->
|
||||
<!---->
|
||||
</div>
|
||||
<transition-stub name=\\"el-zoom-in-top\\">
|
||||
<div class=\\"el-select-dropdown el-popper\\" style=\\"display: none;\\">
|
||||
<div class=\\"el-scrollbar\\" style=\\"\\">
|
||||
<div class=\\"el-select-dropdown__wrap el-scrollbar__wrap el-scrollbar__wrap--hidden-default\\">
|
||||
<ul class=\\"el-scrollbar__view el-select-dropdown__list\\">
|
||||
<!---->
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Business Owner</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Customer support</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Data Science</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Devops</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>IT</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Engineering</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Sales and Marketing</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Security</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Other (please specify)</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class=\\"el-scrollbar__bar is-horizontal\\">
|
||||
<div class=\\"el-scrollbar__thumb\\" style=\\"transform: translateX(0%); webkit-transform: translateX(0%);\\"></div>
|
||||
</div>
|
||||
<div class=\\"el-scrollbar__bar is-vertical\\">
|
||||
<div class=\\"el-scrollbar__thumb\\" style=\\"transform: translateY(0%); webkit-transform: translateY(0%);\\"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
</transition-stub>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
<div class=\\"\\">
|
||||
<div data-test-id=\\"automationBeneficiary\\" class=\\"container\\"><label for=\\"automationBeneficiary\\" class=\\"n8n-input-label inputLabel heading medium\\">
|
||||
<div class=\\"title\\"><span class=\\"n8n-text size-medium bold\\"> Who will your automations mainly be for? <!----></span></div>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
</label>
|
||||
<div class=\\"\\">
|
||||
<div class=\\"n8n-select container\\" name=\\"automationBeneficiary\\">
|
||||
<!---->
|
||||
<div class=\\"el-select el-select--large\\">
|
||||
<!---->
|
||||
<div class=\\"el-input el-input--large el-input--suffix\\">
|
||||
<!----><input type=\\"text\\" readonly=\\"readonly\\" autocomplete=\\"off\\" placeholder=\\"Select...\\" class=\\"el-input__inner\\">
|
||||
<!----><span class=\\"el-input__suffix\\"><span class=\\"el-input__suffix-inner\\"><i class=\\"el-select__caret el-input__icon el-icon-arrow-up\\"></i><!----><!----><!----><!----><!----></span>
|
||||
<!----></span>
|
||||
<!---->
|
||||
<!---->
|
||||
</div>
|
||||
<transition-stub name=\\"el-zoom-in-top\\">
|
||||
<div class=\\"el-select-dropdown el-popper\\" style=\\"display: none;\\">
|
||||
<div class=\\"el-scrollbar\\" style=\\"\\">
|
||||
<div class=\\"el-select-dropdown__wrap el-scrollbar__wrap el-scrollbar__wrap--hidden-default\\">
|
||||
<ul class=\\"el-scrollbar__view el-select-dropdown__list\\">
|
||||
<!---->
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Myself</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>My team</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Other teams</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class=\\"el-scrollbar__bar is-horizontal\\">
|
||||
<div class=\\"el-scrollbar__thumb\\" style=\\"transform: translateX(0%); webkit-transform: translateX(0%);\\"></div>
|
||||
</div>
|
||||
<div class=\\"el-scrollbar__bar is-vertical\\">
|
||||
<div class=\\"el-scrollbar__thumb\\" style=\\"transform: translateY(0%); webkit-transform: translateY(0%);\\"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
</transition-stub>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
<div class=\\"\\">
|
||||
<div data-test-id=\\"companySize\\" class=\\"container\\"><label for=\\"companySize\\" class=\\"n8n-input-label inputLabel heading medium\\">
|
||||
<div class=\\"title\\"><span class=\\"n8n-text size-medium bold\\"> How big is your company? <!----></span></div>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
</label>
|
||||
<div class=\\"\\">
|
||||
<div class=\\"n8n-select container\\" name=\\"companySize\\">
|
||||
<!---->
|
||||
<div class=\\"el-select el-select--large\\">
|
||||
<!---->
|
||||
<div class=\\"el-input el-input--large el-input--suffix\\">
|
||||
<!----><input type=\\"text\\" readonly=\\"readonly\\" autocomplete=\\"off\\" placeholder=\\"Select...\\" class=\\"el-input__inner\\">
|
||||
<!----><span class=\\"el-input__suffix\\"><span class=\\"el-input__suffix-inner\\"><i class=\\"el-select__caret el-input__icon el-icon-arrow-up\\"></i><!----><!----><!----><!----><!----></span>
|
||||
<!----></span>
|
||||
<!---->
|
||||
<!---->
|
||||
</div>
|
||||
<transition-stub name=\\"el-zoom-in-top\\">
|
||||
<div class=\\"el-select-dropdown el-popper\\" style=\\"display: none;\\">
|
||||
<div class=\\"el-scrollbar\\" style=\\"\\">
|
||||
<div class=\\"el-select-dropdown__wrap el-scrollbar__wrap el-scrollbar__wrap--hidden-default\\">
|
||||
<ul class=\\"el-scrollbar__view el-select-dropdown__list\\">
|
||||
<!---->
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Less than 20 people</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>20-99 people</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>100-499 people</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>500-999 people</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>1000+ people</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>I'm not using n8n for work</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class=\\"el-scrollbar__bar is-horizontal\\">
|
||||
<div class=\\"el-scrollbar__thumb\\" style=\\"transform: translateX(0%); webkit-transform: translateX(0%);\\"></div>
|
||||
</div>
|
||||
<div class=\\"el-scrollbar__bar is-vertical\\">
|
||||
<div class=\\"el-scrollbar__thumb\\" style=\\"transform: translateY(0%); webkit-transform: translateY(0%);\\"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
</transition-stub>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
<div class=\\"\\">
|
||||
<div data-test-id=\\"reportedSource\\" class=\\"container\\"><label for=\\"reportedSource\\" class=\\"n8n-input-label inputLabel heading medium\\">
|
||||
<div class=\\"title\\"><span class=\\"n8n-text size-medium bold\\"> How did you hear about n8n? <!----></span></div>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
</label>
|
||||
<div class=\\"\\">
|
||||
<div class=\\"n8n-select container\\" name=\\"reportedSource\\">
|
||||
<!---->
|
||||
<div class=\\"el-select el-select--large\\">
|
||||
<!---->
|
||||
<div class=\\"el-input el-input--large el-input--suffix\\">
|
||||
<!----><input type=\\"text\\" readonly=\\"readonly\\" autocomplete=\\"off\\" placeholder=\\"Select...\\" class=\\"el-input__inner\\">
|
||||
<!----><span class=\\"el-input__suffix\\"><span class=\\"el-input__suffix-inner\\"><i class=\\"el-select__caret el-input__icon el-icon-arrow-up\\"></i><!----><!----><!----><!----><!----></span>
|
||||
<!----></span>
|
||||
<!---->
|
||||
<!---->
|
||||
</div>
|
||||
<transition-stub name=\\"el-zoom-in-top\\">
|
||||
<div class=\\"el-select-dropdown el-popper\\" style=\\"display: none;\\">
|
||||
<div class=\\"el-scrollbar\\" style=\\"\\">
|
||||
<div class=\\"el-select-dropdown__wrap el-scrollbar__wrap el-scrollbar__wrap--hidden-default\\">
|
||||
<ul class=\\"el-scrollbar__view el-select-dropdown__list\\">
|
||||
<!---->
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Google</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Twitter</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>LinkedIn</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>YouTube</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Friend / Word of mouth</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Podcast</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Event</span></li>
|
||||
<li class=\\"el-select-dropdown__item\\"><span>Other (please specify)</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class=\\"el-scrollbar__bar is-horizontal\\">
|
||||
<div class=\\"el-scrollbar__thumb\\" style=\\"transform: translateX(0%); webkit-transform: translateX(0%);\\"></div>
|
||||
</div>
|
||||
<div class=\\"el-scrollbar__bar is-vertical\\">
|
||||
<div class=\\"el-scrollbar__thumb\\" style=\\"transform: translateY(0%); webkit-transform: translateY(0%);\\"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
</transition-stub>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class=\\"footer\\">
|
||||
<div><button aria-live=\\"polite\\" class=\\"button button primary medium float-right\\">
|
||||
<!----><span>Get started</span></button></div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
</transition-stub>"
|
||||
`;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,7 @@ exports[`RunDataJsonSchema.vue > renders schema for data 1`] = `
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
|
||||
<div
|
||||
class="schema"
|
||||
>
|
||||
@@ -15,13 +16,14 @@ exports[`RunDataJsonSchema.vue > renders schema for data 1`] = `
|
||||
class="item"
|
||||
data-test-id="run-data-schema-item"
|
||||
>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<div
|
||||
class="sub"
|
||||
>
|
||||
|
||||
<div
|
||||
class="item"
|
||||
data-test-id="run-data-schema-item"
|
||||
@@ -39,11 +41,23 @@ exports[`RunDataJsonSchema.vue > renders schema for data 1`] = `
|
||||
data-target="mappable"
|
||||
data-value="{{ $json.name }}"
|
||||
>
|
||||
<font-awesome-icon-stub
|
||||
icon="font"
|
||||
size="sm"
|
||||
/>
|
||||
<!---->
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="svg-inline--fa fa-font fa-w-14 fa-sm"
|
||||
data-icon="font"
|
||||
data-prefix="fas"
|
||||
focusable="false"
|
||||
role="img"
|
||||
viewBox="0 0 448 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
class=""
|
||||
d="M432 416h-23.41L277.88 53.69A32 32 0 0 0 247.58 32h-47.16a32 32 0 0 0-30.3 21.69L39.41 416H16a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h128a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16h-19.58l23.3-64h152.56l23.3 64H304a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h128a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zM176.85 272L224 142.51 271.15 272z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
<!--v-if-->
|
||||
<span
|
||||
class=""
|
||||
>
|
||||
@@ -56,9 +70,9 @@ exports[`RunDataJsonSchema.vue > renders schema for data 1`] = `
|
||||
>
|
||||
John
|
||||
</span>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
</div>
|
||||
<div
|
||||
class="item"
|
||||
@@ -77,11 +91,23 @@ exports[`RunDataJsonSchema.vue > renders schema for data 1`] = `
|
||||
data-target="mappable"
|
||||
data-value="{{ $json.age }}"
|
||||
>
|
||||
<font-awesome-icon-stub
|
||||
icon="hashtag"
|
||||
size="sm"
|
||||
/>
|
||||
<!---->
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="svg-inline--fa fa-hashtag fa-w-14 fa-sm"
|
||||
data-icon="hashtag"
|
||||
data-prefix="fas"
|
||||
focusable="false"
|
||||
role="img"
|
||||
viewBox="0 0 448 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
class=""
|
||||
d="M440.667 182.109l7.143-40c1.313-7.355-4.342-14.109-11.813-14.109h-74.81l14.623-81.891C377.123 38.754 371.468 32 363.997 32h-40.632a12 12 0 0 0-11.813 9.891L296.175 128H197.54l14.623-81.891C213.477 38.754 207.822 32 200.35 32h-40.632a12 12 0 0 0-11.813 9.891L132.528 128H53.432a12 12 0 0 0-11.813 9.891l-7.143 40C33.163 185.246 38.818 192 46.289 192h74.81L98.242 320H19.146a12 12 0 0 0-11.813 9.891l-7.143 40C-1.123 377.246 4.532 384 12.003 384h74.81L72.19 465.891C70.877 473.246 76.532 480 84.003 480h40.632a12 12 0 0 0 11.813-9.891L151.826 384h98.634l-14.623 81.891C234.523 473.246 240.178 480 247.65 480h40.632a12 12 0 0 0 11.813-9.891L315.472 384h79.096a12 12 0 0 0 11.813-9.891l7.143-40c1.313-7.355-4.342-14.109-11.813-14.109h-74.81l22.857-128h79.096a12 12 0 0 0 11.813-9.891zM261.889 320h-98.634l22.857-128h98.634l-22.857 128z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
<!--v-if-->
|
||||
<span
|
||||
class=""
|
||||
>
|
||||
@@ -94,9 +120,9 @@ exports[`RunDataJsonSchema.vue > renders schema for data 1`] = `
|
||||
>
|
||||
22
|
||||
</span>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
</div>
|
||||
<div
|
||||
class="item"
|
||||
@@ -115,11 +141,23 @@ exports[`RunDataJsonSchema.vue > renders schema for data 1`] = `
|
||||
data-target="mappable"
|
||||
data-value="{{ $json.hobbies }}"
|
||||
>
|
||||
<font-awesome-icon-stub
|
||||
icon="list"
|
||||
size="sm"
|
||||
/>
|
||||
<!---->
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="svg-inline--fa fa-list fa-w-16 fa-sm"
|
||||
data-icon="list"
|
||||
data-prefix="fas"
|
||||
focusable="false"
|
||||
role="img"
|
||||
viewBox="0 0 512 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
class=""
|
||||
d="M80 368H16a16 16 0 0 0-16 16v64a16 16 0 0 0 16 16h64a16 16 0 0 0 16-16v-64a16 16 0 0 0-16-16zm0-320H16A16 16 0 0 0 0 64v64a16 16 0 0 0 16 16h64a16 16 0 0 0 16-16V64a16 16 0 0 0-16-16zm0 160H16a16 16 0 0 0-16 16v64a16 16 0 0 0 16 16h64a16 16 0 0 0 16-16v-64a16 16 0 0 0-16-16zm416 176H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zm0-320H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16V80a16 16 0 0 0-16-16zm0 160H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
<!--v-if-->
|
||||
<span
|
||||
class=""
|
||||
>
|
||||
@@ -127,9 +165,8 @@ exports[`RunDataJsonSchema.vue > renders schema for data 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<!---->
|
||||
<!--v-if-->
|
||||
<input
|
||||
checked="checked"
|
||||
id="input_array-0-2"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -137,13 +174,27 @@ exports[`RunDataJsonSchema.vue > renders schema for data 1`] = `
|
||||
class="toggle"
|
||||
for="input_array-0-2"
|
||||
>
|
||||
<font-awesome-icon-stub
|
||||
icon="angle-up"
|
||||
/>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="svg-inline--fa fa-angle-up fa-w-10"
|
||||
data-icon="angle-up"
|
||||
data-prefix="fas"
|
||||
focusable="false"
|
||||
role="img"
|
||||
viewBox="0 0 320 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
class=""
|
||||
d="M177 159.7l136 136c9.4 9.4 9.4 24.6 0 33.9l-22.6 22.6c-9.4 9.4-24.6 9.4-33.9 0L160 255.9l-96.4 96.4c-9.4 9.4-24.6 9.4-33.9 0L7 329.7c-9.4-9.4-9.4-24.6 0-33.9l136-136c9.4-9.5 24.6-9.5 34-.1z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
</label>
|
||||
<div
|
||||
class="sub"
|
||||
>
|
||||
|
||||
<div
|
||||
class="item"
|
||||
data-test-id="run-data-schema-item"
|
||||
@@ -161,10 +212,22 @@ exports[`RunDataJsonSchema.vue > renders schema for data 1`] = `
|
||||
data-target="mappable"
|
||||
data-value="{{ $json.hobbies[0] }}"
|
||||
>
|
||||
<font-awesome-icon-stub
|
||||
icon="font"
|
||||
size="sm"
|
||||
/>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="svg-inline--fa fa-font fa-w-14 fa-sm"
|
||||
data-icon="font"
|
||||
data-prefix="fas"
|
||||
focusable="false"
|
||||
role="img"
|
||||
viewBox="0 0 448 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
class=""
|
||||
d="M432 416h-23.41L277.88 53.69A32 32 0 0 0 247.58 32h-47.16a32 32 0 0 0-30.3 21.69L39.41 416H16a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h128a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16h-19.58l23.3-64h152.56l23.3 64H304a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h128a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zM176.85 272L224 142.51 271.15 272z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
<span>
|
||||
hobbies
|
||||
</span>
|
||||
@@ -180,9 +243,9 @@ exports[`RunDataJsonSchema.vue > renders schema for data 1`] = `
|
||||
>
|
||||
surfing
|
||||
</span>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
</div>
|
||||
<div
|
||||
class="item"
|
||||
@@ -201,10 +264,22 @@ exports[`RunDataJsonSchema.vue > renders schema for data 1`] = `
|
||||
data-target="mappable"
|
||||
data-value="{{ $json.hobbies[1] }}"
|
||||
>
|
||||
<font-awesome-icon-stub
|
||||
icon="font"
|
||||
size="sm"
|
||||
/>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="svg-inline--fa fa-font fa-w-14 fa-sm"
|
||||
data-icon="font"
|
||||
data-prefix="fas"
|
||||
focusable="false"
|
||||
role="img"
|
||||
viewBox="0 0 448 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
class=""
|
||||
d="M432 416h-23.41L277.88 53.69A32 32 0 0 0 247.58 32h-47.16a32 32 0 0 0-30.3 21.69L39.41 416H16a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h128a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16h-19.58l23.3-64h152.56l23.3 64H304a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h128a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zM176.85 272L224 142.51 271.15 272z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
<span>
|
||||
hobbies
|
||||
</span>
|
||||
@@ -220,19 +295,20 @@ exports[`RunDataJsonSchema.vue > renders schema for data 1`] = `
|
||||
>
|
||||
traveling
|
||||
</span>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="teleporter hidden"
|
||||
data-v-d4e6e290=""
|
||||
/>
|
||||
|
||||
<!--teleport start-->
|
||||
<!--teleport end-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -250,15 +326,31 @@ exports[`RunDataJsonSchema.vue > renders schema for empty data 1`] = `
|
||||
class="iconText"
|
||||
>
|
||||
<span
|
||||
class="n8n-icon n8n-text compact size-medium regular"
|
||||
class="n8n-text compact size-medium regular n8n-icon n8n-icon"
|
||||
>
|
||||
<font-awesome-icon-stub
|
||||
class="medium"
|
||||
icon="info-circle"
|
||||
/>
|
||||
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="svg-inline--fa fa-info-circle fa-w-16 medium"
|
||||
data-icon="info-circle"
|
||||
data-prefix="fas"
|
||||
focusable="false"
|
||||
role="img"
|
||||
viewBox="0 0 512 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
class=""
|
||||
d="M256 8C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm0 110c23.196 0 42 18.804 42 42s-18.804 42-42 42-42-18.804-42-42 18.804-42 42-42zm56 254c0 6.627-5.373 12-12 12h-88c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h12v-64h-12c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h64c6.627 0 12 5.373 12 12v100h12c6.627 0 12 5.373 12 12v24z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
</span>
|
||||
<span>
|
||||
|
||||
No data to show - item(s) exist, but they’re empty
|
||||
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
@@ -274,6 +366,7 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
|
||||
<div
|
||||
class="schema"
|
||||
>
|
||||
@@ -281,13 +374,14 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
|
||||
class="item"
|
||||
data-test-id="run-data-schema-item"
|
||||
>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<div
|
||||
class="sub"
|
||||
>
|
||||
|
||||
<div
|
||||
class="item"
|
||||
data-test-id="run-data-schema-item"
|
||||
@@ -305,11 +399,23 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
|
||||
data-target="mappable"
|
||||
data-value="{{ $json['hello world'] }}"
|
||||
>
|
||||
<font-awesome-icon-stub
|
||||
icon="list"
|
||||
size="sm"
|
||||
/>
|
||||
<!---->
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="svg-inline--fa fa-list fa-w-16 fa-sm"
|
||||
data-icon="list"
|
||||
data-prefix="fas"
|
||||
focusable="false"
|
||||
role="img"
|
||||
viewBox="0 0 512 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
class=""
|
||||
d="M80 368H16a16 16 0 0 0-16 16v64a16 16 0 0 0 16 16h64a16 16 0 0 0 16-16v-64a16 16 0 0 0-16-16zm0-320H16A16 16 0 0 0 0 64v64a16 16 0 0 0 16 16h64a16 16 0 0 0 16-16V64a16 16 0 0 0-16-16zm0 160H16a16 16 0 0 0-16 16v64a16 16 0 0 0 16 16h64a16 16 0 0 0 16-16v-64a16 16 0 0 0-16-16zm416 176H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zm0-320H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16V80a16 16 0 0 0-16-16zm0 160H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
<!--v-if-->
|
||||
<span
|
||||
class=""
|
||||
>
|
||||
@@ -317,9 +423,8 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<!---->
|
||||
<!--v-if-->
|
||||
<input
|
||||
checked="checked"
|
||||
id="input_array-0-0"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -327,13 +432,27 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
|
||||
class="toggle"
|
||||
for="input_array-0-0"
|
||||
>
|
||||
<font-awesome-icon-stub
|
||||
icon="angle-up"
|
||||
/>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="svg-inline--fa fa-angle-up fa-w-10"
|
||||
data-icon="angle-up"
|
||||
data-prefix="fas"
|
||||
focusable="false"
|
||||
role="img"
|
||||
viewBox="0 0 320 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
class=""
|
||||
d="M177 159.7l136 136c9.4 9.4 9.4 24.6 0 33.9l-22.6 22.6c-9.4 9.4-24.6 9.4-33.9 0L160 255.9l-96.4 96.4c-9.4 9.4-24.6 9.4-33.9 0L7 329.7c-9.4-9.4-9.4-24.6 0-33.9l136-136c9.4-9.5 24.6-9.5 34-.1z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
</label>
|
||||
<div
|
||||
class="sub"
|
||||
>
|
||||
|
||||
<div
|
||||
class="item"
|
||||
data-test-id="run-data-schema-item"
|
||||
@@ -351,10 +470,22 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
|
||||
data-target="mappable"
|
||||
data-value="{{ $json['hello world'][0] }}"
|
||||
>
|
||||
<font-awesome-icon-stub
|
||||
icon="cube"
|
||||
size="sm"
|
||||
/>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="svg-inline--fa fa-cube fa-w-16 fa-sm"
|
||||
data-icon="cube"
|
||||
data-prefix="fas"
|
||||
focusable="false"
|
||||
role="img"
|
||||
viewBox="0 0 512 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
class=""
|
||||
d="M239.1 6.3l-208 78c-18.7 7-31.1 25-31.1 45v225.1c0 18.2 10.3 34.8 26.5 42.9l208 104c13.5 6.8 29.4 6.8 42.9 0l208-104c16.3-8.1 26.5-24.8 26.5-42.9V129.3c0-20-12.4-37.9-31.1-44.9l-208-78C262 2.2 250 2.2 239.1 6.3zM256 68.4l192 72v1.1l-192 78-192-78v-1.1l192-72zm32 356V275.5l160-65v133.9l-160 80z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
<span>
|
||||
hello world
|
||||
</span>
|
||||
@@ -365,9 +496,8 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<!---->
|
||||
<!--v-if-->
|
||||
<input
|
||||
checked="checked"
|
||||
id="input_object-1-0"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -375,13 +505,27 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
|
||||
class="toggle"
|
||||
for="input_object-1-0"
|
||||
>
|
||||
<font-awesome-icon-stub
|
||||
icon="angle-up"
|
||||
/>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="svg-inline--fa fa-angle-up fa-w-10"
|
||||
data-icon="angle-up"
|
||||
data-prefix="fas"
|
||||
focusable="false"
|
||||
role="img"
|
||||
viewBox="0 0 320 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
class=""
|
||||
d="M177 159.7l136 136c9.4 9.4 9.4 24.6 0 33.9l-22.6 22.6c-9.4 9.4-24.6 9.4-33.9 0L160 255.9l-96.4 96.4c-9.4 9.4-24.6 9.4-33.9 0L7 329.7c-9.4-9.4-9.4-24.6 0-33.9l136-136c9.4-9.5 24.6-9.5 34-.1z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
</label>
|
||||
<div
|
||||
class="sub"
|
||||
>
|
||||
|
||||
<div
|
||||
class="item"
|
||||
data-test-id="run-data-schema-item"
|
||||
@@ -399,11 +543,23 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
|
||||
data-target="mappable"
|
||||
data-value="{{ $json['hello world'][0].test }}"
|
||||
>
|
||||
<font-awesome-icon-stub
|
||||
icon="cube"
|
||||
size="sm"
|
||||
/>
|
||||
<!---->
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="svg-inline--fa fa-cube fa-w-16 fa-sm"
|
||||
data-icon="cube"
|
||||
data-prefix="fas"
|
||||
focusable="false"
|
||||
role="img"
|
||||
viewBox="0 0 512 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
class=""
|
||||
d="M239.1 6.3l-208 78c-18.7 7-31.1 25-31.1 45v225.1c0 18.2 10.3 34.8 26.5 42.9l208 104c13.5 6.8 29.4 6.8 42.9 0l208-104c16.3-8.1 26.5-24.8 26.5-42.9V129.3c0-20-12.4-37.9-31.1-44.9l-208-78C262 2.2 250 2.2 239.1 6.3zM256 68.4l192 72v1.1l-192 78-192-78v-1.1l192-72zm32 356V275.5l160-65v133.9l-160 80z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
<!--v-if-->
|
||||
<span
|
||||
class=""
|
||||
>
|
||||
@@ -411,9 +567,8 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<!---->
|
||||
<!--v-if-->
|
||||
<input
|
||||
checked="checked"
|
||||
id="input_object-2-0"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -421,13 +576,27 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
|
||||
class="toggle"
|
||||
for="input_object-2-0"
|
||||
>
|
||||
<font-awesome-icon-stub
|
||||
icon="angle-up"
|
||||
/>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="svg-inline--fa fa-angle-up fa-w-10"
|
||||
data-icon="angle-up"
|
||||
data-prefix="fas"
|
||||
focusable="false"
|
||||
role="img"
|
||||
viewBox="0 0 320 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
class=""
|
||||
d="M177 159.7l136 136c9.4 9.4 9.4 24.6 0 33.9l-22.6 22.6c-9.4 9.4-24.6 9.4-33.9 0L160 255.9l-96.4 96.4c-9.4 9.4-24.6 9.4-33.9 0L7 329.7c-9.4-9.4-9.4-24.6 0-33.9l136-136c9.4-9.5 24.6-9.5 34-.1z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
</label>
|
||||
<div
|
||||
class="sub"
|
||||
>
|
||||
|
||||
<div
|
||||
class="item"
|
||||
data-test-id="run-data-schema-item"
|
||||
@@ -445,11 +614,23 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
|
||||
data-target="mappable"
|
||||
data-value="{{ $json['hello world'][0].test['more to think about'] }}"
|
||||
>
|
||||
<font-awesome-icon-stub
|
||||
icon="hashtag"
|
||||
size="sm"
|
||||
/>
|
||||
<!---->
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="svg-inline--fa fa-hashtag fa-w-14 fa-sm"
|
||||
data-icon="hashtag"
|
||||
data-prefix="fas"
|
||||
focusable="false"
|
||||
role="img"
|
||||
viewBox="0 0 448 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
class=""
|
||||
d="M440.667 182.109l7.143-40c1.313-7.355-4.342-14.109-11.813-14.109h-74.81l14.623-81.891C377.123 38.754 371.468 32 363.997 32h-40.632a12 12 0 0 0-11.813 9.891L296.175 128H197.54l14.623-81.891C213.477 38.754 207.822 32 200.35 32h-40.632a12 12 0 0 0-11.813 9.891L132.528 128H53.432a12 12 0 0 0-11.813 9.891l-7.143 40C33.163 185.246 38.818 192 46.289 192h74.81L98.242 320H19.146a12 12 0 0 0-11.813 9.891l-7.143 40C-1.123 377.246 4.532 384 12.003 384h74.81L72.19 465.891C70.877 473.246 76.532 480 84.003 480h40.632a12 12 0 0 0 11.813-9.891L151.826 384h98.634l-14.623 81.891C234.523 473.246 240.178 480 247.65 480h40.632a12 12 0 0 0 11.813-9.891L315.472 384h79.096a12 12 0 0 0 11.813-9.891l7.143-40c1.313-7.355-4.342-14.109-11.813-14.109h-74.81l22.857-128h79.096a12 12 0 0 0 11.813-9.891zM261.889 320h-98.634l22.857-128h98.634l-22.857 128z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
<!--v-if-->
|
||||
<span
|
||||
class=""
|
||||
>
|
||||
@@ -462,10 +643,11 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
|
||||
>
|
||||
1
|
||||
</span>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -485,11 +667,23 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
|
||||
data-target="mappable"
|
||||
data-value="{{ $json['hello world'][0]['test.how'] }}"
|
||||
>
|
||||
<font-awesome-icon-stub
|
||||
icon="font"
|
||||
size="sm"
|
||||
/>
|
||||
<!---->
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="svg-inline--fa fa-font fa-w-14 fa-sm"
|
||||
data-icon="font"
|
||||
data-prefix="fas"
|
||||
focusable="false"
|
||||
role="img"
|
||||
viewBox="0 0 448 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
class=""
|
||||
d="M432 416h-23.41L277.88 53.69A32 32 0 0 0 247.58 32h-47.16a32 32 0 0 0-30.3 21.69L39.41 416H16a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h128a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16h-19.58l23.3-64h152.56l23.3 64H304a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h128a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zM176.85 272L224 142.51 271.15 272z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
<!--v-if-->
|
||||
<span
|
||||
class=""
|
||||
>
|
||||
@@ -502,21 +696,23 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
|
||||
>
|
||||
ignore
|
||||
</span>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="teleporter hidden"
|
||||
data-v-d4e6e290=""
|
||||
/>
|
||||
|
||||
<!--teleport start-->
|
||||
<!--teleport end-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`VariablesRow > should render correctly 1`] = `
|
||||
"<tr data-test-id=\\"variables-row\\" class=\\"variablesRow\\">
|
||||
<td class=\\"variables-key-column\\">
|
||||
<div><span>key</span></div>
|
||||
</td>
|
||||
<td class=\\"variables-value-column\\">
|
||||
<div><span>value</span></div>
|
||||
</td>
|
||||
<td class=\\"variables-usage-column\\">
|
||||
<div>
|
||||
<n8n-tooltip-stub justifybuttons=\\"flex-end\\" buttons=\\"\\" placement=\\"top\\"><span class=\\"usageSyntax\\">$vars.key</span></n8n-tooltip-stub>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class=\\"buttons hoverButtons\\">
|
||||
<n8n-tooltip-stub justifybuttons=\\"flex-end\\" buttons=\\"\\" placement=\\"top\\">
|
||||
<div><button disabled=\\"disabled\\" aria-disabled=\\"true\\" aria-live=\\"polite\\" class=\\"mr-xs button button tertiary medium disabled\\" data-test-id=\\"variable-row-edit-button\\">
|
||||
<!----><span> Edit </span></button></div>
|
||||
</n8n-tooltip-stub>
|
||||
<n8n-tooltip-stub justifybuttons=\\"flex-end\\" buttons=\\"\\" placement=\\"top\\">
|
||||
<div><button disabled=\\"disabled\\" aria-disabled=\\"true\\" aria-live=\\"polite\\" class=\\"button button tertiary medium disabled\\" data-test-id=\\"variable-row-delete-button\\">
|
||||
<!----><span> Delete </span></button></div>
|
||||
</n8n-tooltip-stub>
|
||||
</div>
|
||||
</td>
|
||||
</tr>"
|
||||
`;
|
||||
|
||||
exports[`VariablesRow > should show key and value inputs in edit mode 1`] = `
|
||||
"<tr data-test-id=\\"variables-row\\" class=\\"variablesRow\\">
|
||||
<td class=\\"variables-key-column\\">
|
||||
<div>
|
||||
<div data-test-id=\\"variable-row-key-input\\" class=\\"container\\">
|
||||
<!---->
|
||||
<div class=\\"\\">
|
||||
<div class=\\"el-input el-input--large n8n-input\\">
|
||||
<!----><input type=\\"text\\" autocomplete=\\"off\\" name=\\"key\\" placeholder=\\"Enter a name\\" class=\\"el-input__inner\\">
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class=\\"variables-value-column\\">
|
||||
<div>
|
||||
<div data-test-id=\\"variable-row-value-input\\" class=\\"container\\">
|
||||
<!---->
|
||||
<div class=\\"\\">
|
||||
<div class=\\"el-input el-input--large n8n-input\\">
|
||||
<!----><input type=\\"text\\" autocomplete=\\"off\\" name=\\"value\\" placeholder=\\"Enter a value\\" class=\\"el-input__inner\\">
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class=\\"variables-usage-column\\">
|
||||
<div>
|
||||
<n8n-tooltip-stub justifybuttons=\\"flex-end\\" buttons=\\"\\" placement=\\"top\\"><span class=\\"usageSyntax\\">$vars.key</span></n8n-tooltip-stub>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class=\\"buttons\\"><button aria-live=\\"polite\\" class=\\"mr-xs button button tertiary medium\\" data-test-id=\\"variable-row-cancel-button\\">
|
||||
<!----><span> Cancel </span></button><button aria-live=\\"polite\\" class=\\"button button primary medium\\" data-test-id=\\"variable-row-save-button\\">
|
||||
<!----><span> Save </span></button></div>
|
||||
</td>
|
||||
</tr>"
|
||||
`;
|
||||
@@ -101,6 +101,7 @@ export const DEFAULT_SETUP = {
|
||||
dependentParametersValues: 'gid=0',
|
||||
inputSize: 'small',
|
||||
labelSize: 'small',
|
||||
teleported: false,
|
||||
node: {
|
||||
parameters: NODE_PARAMETER_VALUES,
|
||||
id: 'f63efb2d-3cc5-4500-89f9-b39aab19baf5',
|
||||
|
||||
Reference in New Issue
Block a user