mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-25 20:54:07 -08:00
fix(editor): Add workflow scopes when initializing workflow (#10455)
Some checks are pending
Test Master / install-and-build (push) Waiting to run
Test Master / Unit tests (18.x) (push) Blocked by required conditions
Test Master / Unit tests (20.x) (push) Blocked by required conditions
Test Master / Unit tests (22.4) (push) Blocked by required conditions
Test Master / Lint (push) Blocked by required conditions
Test Master / Notify Slack on failure (push) Blocked by required conditions
Some checks are pending
Test Master / install-and-build (push) Waiting to run
Test Master / Unit tests (18.x) (push) Blocked by required conditions
Test Master / Unit tests (20.x) (push) Blocked by required conditions
Test Master / Unit tests (22.4) (push) Blocked by required conditions
Test Master / Lint (push) Blocked by required conditions
Test Master / Notify Slack on failure (push) Blocked by required conditions
Co-authored-by: Mutasem Aldmour <mutasem@n8n.io>
This commit is contained in:
parent
556699ac3d
commit
b857c2cda0
21
cypress/e2e/1858-PAY-can-use-context-menu.ts
Normal file
21
cypress/e2e/1858-PAY-can-use-context-menu.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
|
||||||
|
|
||||||
|
const WorkflowPage = new WorkflowPageClass();
|
||||||
|
|
||||||
|
describe('PAY-1858 context menu', () => {
|
||||||
|
it('can use context menu on saved workflow', () => {
|
||||||
|
WorkflowPage.actions.visit();
|
||||||
|
cy.createFixtureWorkflow('Test_workflow_filter.json', 'test');
|
||||||
|
|
||||||
|
WorkflowPage.getters.canvasNodes().should('have.length', 5);
|
||||||
|
WorkflowPage.actions.deleteNodeFromContextMenu('Then');
|
||||||
|
WorkflowPage.getters.canvasNodes().should('have.length', 4);
|
||||||
|
|
||||||
|
WorkflowPage.actions.hitSaveWorkflow();
|
||||||
|
|
||||||
|
cy.reload();
|
||||||
|
WorkflowPage.getters.canvasNodes().should('have.length', 4);
|
||||||
|
WorkflowPage.actions.deleteNodeFromContextMenu('Code');
|
||||||
|
WorkflowPage.getters.canvasNodes().should('have.length', 3);
|
||||||
|
});
|
||||||
|
});
|
|
@ -35,7 +35,8 @@ describe('Personal Settings', () => {
|
||||||
successToast().find('.el-notification__closeBtn').click();
|
successToast().find('.el-notification__closeBtn').click();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('not allow malicious values for personal data', () => {
|
// eslint-disable-next-line n8n-local-rules/no-skipped-tests
|
||||||
|
it.skip('not allow malicious values for personal data', () => {
|
||||||
cy.visit('/settings/personal');
|
cy.visit('/settings/personal');
|
||||||
INVALID_NAMES.forEach((name) => {
|
INVALID_NAMES.forEach((name) => {
|
||||||
cy.getByTestId('personal-data-form').find('input[name="firstName"]').clear().type(name);
|
cy.getByTestId('personal-data-form').find('input[name="firstName"]').clear().type(name);
|
||||||
|
|
|
@ -25,7 +25,7 @@ import {
|
||||||
SET_NODE_TYPE,
|
SET_NODE_TYPE,
|
||||||
STICKY_NODE_TYPE,
|
STICKY_NODE_TYPE,
|
||||||
} from '@/constants';
|
} from '@/constants';
|
||||||
import type { INodeUi } from '@/Interface';
|
import type { INodeUi, IWorkflowDb } from '@/Interface';
|
||||||
|
|
||||||
export const mockNode = ({
|
export const mockNode = ({
|
||||||
id = uuid(),
|
id = uuid(),
|
||||||
|
@ -147,6 +147,35 @@ export function createTestWorkflowObject({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createTestWorkflow({
|
||||||
|
id = uuid(),
|
||||||
|
name = 'Test Workflow',
|
||||||
|
nodes = [],
|
||||||
|
connections = {},
|
||||||
|
active = false,
|
||||||
|
settings = {
|
||||||
|
timezone: 'DEFAULT',
|
||||||
|
executionOrder: 'v1',
|
||||||
|
},
|
||||||
|
pinData = {},
|
||||||
|
...rest
|
||||||
|
}: Partial<IWorkflowDb> = {}): IWorkflowDb {
|
||||||
|
return {
|
||||||
|
createdAt: '',
|
||||||
|
updatedAt: '',
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
nodes,
|
||||||
|
connections,
|
||||||
|
active,
|
||||||
|
settings,
|
||||||
|
versionId: '1',
|
||||||
|
meta: {},
|
||||||
|
pinData,
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function createTestNode(node: Partial<INode> = {}): INode {
|
export function createTestNode(node: Partial<INode> = {}): INode {
|
||||||
return {
|
return {
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
|
|
|
@ -3,6 +3,10 @@ import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers';
|
||||||
import router from '@/router';
|
import router from '@/router';
|
||||||
import { createTestingPinia } from '@pinia/testing';
|
import { createTestingPinia } from '@pinia/testing';
|
||||||
import { setActivePinia } from 'pinia';
|
import { setActivePinia } from 'pinia';
|
||||||
|
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||||
|
import { useWorkflowsEEStore } from '@/stores/workflows.ee.store';
|
||||||
|
import { useTagsStore } from '@/stores/tags.store';
|
||||||
|
import { createTestWorkflow } from '@/__tests__/mocks';
|
||||||
|
|
||||||
const getDuplicateTestWorkflow = (): IWorkflowDataUpdate => ({
|
const getDuplicateTestWorkflow = (): IWorkflowDataUpdate => ({
|
||||||
name: 'Duplicate webhook test',
|
name: 'Duplicate webhook test',
|
||||||
|
@ -50,32 +54,23 @@ const getDuplicateTestWorkflow = (): IWorkflowDataUpdate => ({
|
||||||
connections: {},
|
connections: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
vi.mock('@/stores/workflows.store', () => ({
|
|
||||||
useWorkflowsStore: vi.fn(() => ({
|
|
||||||
workflowsById: {},
|
|
||||||
createNewWorkflow: vi.fn(() => {}),
|
|
||||||
addWorkflow: vi.fn(() => {}),
|
|
||||||
setActive: vi.fn(() => {}),
|
|
||||||
setWorkflowId: vi.fn(() => {}),
|
|
||||||
setWorkflowVersionId: vi.fn(() => {}),
|
|
||||||
setWorkflowName: vi.fn(() => {}),
|
|
||||||
setWorkflowSettings: vi.fn(() => {}),
|
|
||||||
setNodeValue: vi.fn(() => {}),
|
|
||||||
setWorkflowTagIds: vi.fn(() => {}),
|
|
||||||
getCurrentWorkflow: vi.fn(() => ({})),
|
|
||||||
})),
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('useWorkflowHelpers', () => {
|
describe('useWorkflowHelpers', () => {
|
||||||
|
let workflowsStore: ReturnType<typeof useWorkflowsStore>;
|
||||||
|
let workflowsEEStore: ReturnType<typeof useWorkflowsEEStore>;
|
||||||
|
let tagsStore: ReturnType<typeof useTagsStore>;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
setActivePinia(createTestingPinia());
|
||||||
|
workflowsStore = useWorkflowsStore();
|
||||||
|
workflowsEEStore = useWorkflowsEEStore();
|
||||||
|
tagsStore = useTagsStore();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
describe('saveAsNewWorkflow', () => {
|
describe('saveAsNewWorkflow', () => {
|
||||||
beforeAll(() => {
|
|
||||||
setActivePinia(createTestingPinia());
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
vi.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should respect `resetWebhookUrls: false` when duplicating workflows', async () => {
|
it('should respect `resetWebhookUrls: false` when duplicating workflows', async () => {
|
||||||
const workflow = getDuplicateTestWorkflow();
|
const workflow = getDuplicateTestWorkflow();
|
||||||
if (!workflow.nodes) {
|
if (!workflow.nodes) {
|
||||||
|
@ -120,4 +115,101 @@ describe('useWorkflowHelpers', () => {
|
||||||
expect(pathsPreSave).not.toEqual(pathsPostSave);
|
expect(pathsPreSave).not.toEqual(pathsPostSave);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('initState', () => {
|
||||||
|
it('should initialize workflow state with provided data', () => {
|
||||||
|
const { initState } = useWorkflowHelpers({ router });
|
||||||
|
|
||||||
|
const workflowData = createTestWorkflow({
|
||||||
|
id: '1',
|
||||||
|
name: 'Test Workflow',
|
||||||
|
active: true,
|
||||||
|
pinData: {},
|
||||||
|
meta: {},
|
||||||
|
scopes: ['workflow:create'],
|
||||||
|
usedCredentials: [],
|
||||||
|
sharedWithProjects: [],
|
||||||
|
tags: [],
|
||||||
|
});
|
||||||
|
const addWorkflowSpy = vi.spyOn(workflowsStore, 'addWorkflow');
|
||||||
|
const setActiveSpy = vi.spyOn(workflowsStore, 'setActive');
|
||||||
|
const setWorkflowIdSpy = vi.spyOn(workflowsStore, 'setWorkflowId');
|
||||||
|
const setWorkflowNameSpy = vi.spyOn(workflowsStore, 'setWorkflowName');
|
||||||
|
const setWorkflowSettingsSpy = vi.spyOn(workflowsStore, 'setWorkflowSettings');
|
||||||
|
const setWorkflowPinDataSpy = vi.spyOn(workflowsStore, 'setWorkflowPinData');
|
||||||
|
const setWorkflowVersionIdSpy = vi.spyOn(workflowsStore, 'setWorkflowVersionId');
|
||||||
|
const setWorkflowMetadataSpy = vi.spyOn(workflowsStore, 'setWorkflowMetadata');
|
||||||
|
const setWorkflowScopesSpy = vi.spyOn(workflowsStore, 'setWorkflowScopes');
|
||||||
|
const setUsedCredentialsSpy = vi.spyOn(workflowsStore, 'setUsedCredentials');
|
||||||
|
const setWorkflowSharedWithSpy = vi.spyOn(workflowsEEStore, 'setWorkflowSharedWith');
|
||||||
|
const setWorkflowTagIdsSpy = vi.spyOn(workflowsStore, 'setWorkflowTagIds');
|
||||||
|
const upsertTagsSpy = vi.spyOn(tagsStore, 'upsertTags');
|
||||||
|
|
||||||
|
initState(workflowData);
|
||||||
|
|
||||||
|
expect(addWorkflowSpy).toHaveBeenCalledWith(workflowData);
|
||||||
|
expect(setActiveSpy).toHaveBeenCalledWith(true);
|
||||||
|
expect(setWorkflowIdSpy).toHaveBeenCalledWith('1');
|
||||||
|
expect(setWorkflowNameSpy).toHaveBeenCalledWith({
|
||||||
|
newName: 'Test Workflow',
|
||||||
|
setStateDirty: false,
|
||||||
|
});
|
||||||
|
expect(setWorkflowSettingsSpy).toHaveBeenCalledWith({
|
||||||
|
executionOrder: 'v1',
|
||||||
|
timezone: 'DEFAULT',
|
||||||
|
});
|
||||||
|
expect(setWorkflowPinDataSpy).toHaveBeenCalledWith({});
|
||||||
|
expect(setWorkflowVersionIdSpy).toHaveBeenCalledWith('1');
|
||||||
|
expect(setWorkflowMetadataSpy).toHaveBeenCalledWith({});
|
||||||
|
expect(setWorkflowScopesSpy).toHaveBeenCalledWith(['workflow:create']);
|
||||||
|
expect(setUsedCredentialsSpy).toHaveBeenCalledWith([]);
|
||||||
|
expect(setWorkflowSharedWithSpy).toHaveBeenCalledWith({
|
||||||
|
workflowId: '1',
|
||||||
|
sharedWithProjects: [],
|
||||||
|
});
|
||||||
|
expect(setWorkflowTagIdsSpy).toHaveBeenCalledWith([]);
|
||||||
|
expect(upsertTagsSpy).toHaveBeenCalledWith([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle missing `usedCredentials` and `sharedWithProjects` gracefully', () => {
|
||||||
|
const { initState } = useWorkflowHelpers({ router });
|
||||||
|
|
||||||
|
const workflowData = createTestWorkflow({
|
||||||
|
id: '1',
|
||||||
|
name: 'Test Workflow',
|
||||||
|
active: true,
|
||||||
|
pinData: {},
|
||||||
|
meta: {},
|
||||||
|
scopes: [],
|
||||||
|
tags: [],
|
||||||
|
});
|
||||||
|
const setUsedCredentialsSpy = vi.spyOn(workflowsStore, 'setUsedCredentials');
|
||||||
|
const setWorkflowSharedWithSpy = vi.spyOn(workflowsEEStore, 'setWorkflowSharedWith');
|
||||||
|
|
||||||
|
initState(workflowData);
|
||||||
|
|
||||||
|
expect(setUsedCredentialsSpy).not.toHaveBeenCalled();
|
||||||
|
expect(setWorkflowSharedWithSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle missing `tags` gracefully', () => {
|
||||||
|
const { initState } = useWorkflowHelpers({ router });
|
||||||
|
|
||||||
|
const workflowData = createTestWorkflow({
|
||||||
|
id: '1',
|
||||||
|
name: 'Test Workflow',
|
||||||
|
active: true,
|
||||||
|
pinData: {},
|
||||||
|
meta: {},
|
||||||
|
scopes: [],
|
||||||
|
});
|
||||||
|
const setWorkflowTagIdsSpy = vi.spyOn(workflowsStore, 'setWorkflowTagIds');
|
||||||
|
const upsertTagsSpy = vi.spyOn(tagsStore, 'upsertTags');
|
||||||
|
|
||||||
|
initState(workflowData);
|
||||||
|
|
||||||
|
expect(setWorkflowTagIdsSpy).toHaveBeenCalledWith([]);
|
||||||
|
expect(upsertTagsSpy).toHaveBeenCalledWith([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1116,6 +1116,7 @@ export function useWorkflowHelpers(options: { router: ReturnType<typeof useRoute
|
||||||
workflowsStore.setWorkflowPinData(workflowData.pinData ?? {});
|
workflowsStore.setWorkflowPinData(workflowData.pinData ?? {});
|
||||||
workflowsStore.setWorkflowVersionId(workflowData.versionId);
|
workflowsStore.setWorkflowVersionId(workflowData.versionId);
|
||||||
workflowsStore.setWorkflowMetadata(workflowData.meta);
|
workflowsStore.setWorkflowMetadata(workflowData.meta);
|
||||||
|
workflowsStore.setWorkflowScopes(workflowData.scopes);
|
||||||
|
|
||||||
if (workflowData.usedCredentials) {
|
if (workflowData.usedCredentials) {
|
||||||
workflowsStore.setUsedCredentials(workflowData.usedCredentials);
|
workflowsStore.setUsedCredentials(workflowData.usedCredentials);
|
||||||
|
|
|
@ -699,6 +699,10 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setWorkflowScopes(scopes: IWorkflowDb['scopes']): void {
|
||||||
|
workflow.value.scopes = scopes;
|
||||||
|
}
|
||||||
|
|
||||||
function setWorkflowMetadata(metadata: WorkflowMetadata | undefined): void {
|
function setWorkflowMetadata(metadata: WorkflowMetadata | undefined): void {
|
||||||
workflow.value.meta = metadata;
|
workflow.value.meta = metadata;
|
||||||
}
|
}
|
||||||
|
@ -1634,6 +1638,7 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
|
||||||
setWorkflowTagIds,
|
setWorkflowTagIds,
|
||||||
addWorkflowTagIds,
|
addWorkflowTagIds,
|
||||||
removeWorkflowTagId,
|
removeWorkflowTagId,
|
||||||
|
setWorkflowScopes,
|
||||||
setWorkflowMetadata,
|
setWorkflowMetadata,
|
||||||
addToWorkflowMetadata,
|
addToWorkflowMetadata,
|
||||||
setWorkflow,
|
setWorkflow,
|
||||||
|
|
Loading…
Reference in a new issue