mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
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: Csaba Tuncsik <csaba.tuncsik@gmail.com>
251 lines
7.4 KiB
TypeScript
251 lines
7.4 KiB
TypeScript
import { createTestingPinia } from '@pinia/testing';
|
|
import { setActivePinia } from 'pinia';
|
|
import { useProjectsStore } from '@/stores/projects.store';
|
|
import { useSourceControlStore } from '@/stores/sourceControl.store';
|
|
import { mockedStore } from '@/__tests__/utils';
|
|
import type router from 'vue-router';
|
|
import { flushPromises } from '@vue/test-utils';
|
|
import { useToast } from '@/composables/useToast';
|
|
import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper';
|
|
import { useSettingsStore } from '@/stores/settings.store';
|
|
import { useCloudPlanStore } from '@/stores/cloudPlan.store';
|
|
import type { CloudPlanState } from '@/Interface';
|
|
|
|
import { VIEWS } from '@/constants';
|
|
import type { Project, ProjectListItem } from '@/types/projects.types';
|
|
|
|
import { useGlobalEntityCreation } from './useGlobalEntityCreation';
|
|
|
|
vi.mock('@/composables/usePageRedirectionHelper', () => {
|
|
const goToUpgrade = vi.fn();
|
|
return {
|
|
usePageRedirectionHelper: () => ({
|
|
goToUpgrade,
|
|
}),
|
|
};
|
|
});
|
|
|
|
vi.mock('@/composables/useToast', () => {
|
|
const showMessage = vi.fn();
|
|
const showError = vi.fn();
|
|
return {
|
|
useToast: () => {
|
|
return {
|
|
showMessage,
|
|
showError,
|
|
};
|
|
},
|
|
};
|
|
});
|
|
|
|
const routerPushMock = vi.fn();
|
|
vi.mock('vue-router', async (importOriginal) => {
|
|
const { RouterLink, useRoute } = await importOriginal<typeof router>();
|
|
return {
|
|
RouterLink,
|
|
useRoute,
|
|
useRouter: () => ({
|
|
push: routerPushMock,
|
|
}),
|
|
};
|
|
});
|
|
|
|
beforeEach(() => {
|
|
setActivePinia(createTestingPinia());
|
|
routerPushMock.mockReset();
|
|
});
|
|
|
|
describe('useGlobalEntityCreation', () => {
|
|
it('should not contain projects for community', () => {
|
|
const projectsStore = mockedStore(useProjectsStore);
|
|
|
|
const personalProjectId = 'personal-project';
|
|
projectsStore.isTeamProjectFeatureEnabled = false;
|
|
projectsStore.personalProject = { id: personalProjectId } as Project;
|
|
const { menu } = useGlobalEntityCreation();
|
|
|
|
expect(menu.value[0]).toStrictEqual(
|
|
expect.objectContaining({
|
|
route: { name: VIEWS.NEW_WORKFLOW, query: { projectId: personalProjectId } },
|
|
}),
|
|
);
|
|
|
|
expect(menu.value[1]).toStrictEqual(
|
|
expect.objectContaining({
|
|
route: {
|
|
name: VIEWS.CREDENTIALS,
|
|
params: { projectId: personalProjectId, credentialId: 'create' },
|
|
},
|
|
}),
|
|
);
|
|
});
|
|
|
|
describe('single project', () => {
|
|
const currentProjectId = 'current-project';
|
|
|
|
it('should use currentProject', () => {
|
|
const projectsStore = mockedStore(useProjectsStore);
|
|
|
|
projectsStore.isTeamProjectFeatureEnabled = true;
|
|
projectsStore.currentProject = { id: currentProjectId } as Project;
|
|
|
|
const { menu } = useGlobalEntityCreation(false);
|
|
|
|
expect(menu.value[0]).toStrictEqual(
|
|
expect.objectContaining({
|
|
route: { name: VIEWS.NEW_WORKFLOW, query: { projectId: currentProjectId } },
|
|
}),
|
|
);
|
|
|
|
expect(menu.value[1]).toStrictEqual(
|
|
expect.objectContaining({
|
|
route: {
|
|
name: VIEWS.PROJECTS_CREDENTIALS,
|
|
params: { projectId: currentProjectId, credentialId: 'create' },
|
|
},
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('should be disabled in readOnly', () => {
|
|
const projectsStore = mockedStore(useProjectsStore);
|
|
|
|
projectsStore.isTeamProjectFeatureEnabled = true;
|
|
projectsStore.currentProject = { id: currentProjectId } as Project;
|
|
|
|
const sourceControl = mockedStore(useSourceControlStore);
|
|
sourceControl.preferences.branchReadOnly = true;
|
|
|
|
const { menu } = useGlobalEntityCreation(false);
|
|
|
|
expect(menu.value[0]).toStrictEqual(
|
|
expect.objectContaining({
|
|
disabled: true,
|
|
}),
|
|
);
|
|
|
|
expect(menu.value[1]).toStrictEqual(
|
|
expect.objectContaining({
|
|
disabled: true,
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('should be disabled based in scopes', () => {
|
|
const projectsStore = mockedStore(useProjectsStore);
|
|
|
|
projectsStore.isTeamProjectFeatureEnabled = true;
|
|
projectsStore.currentProject = { id: currentProjectId, scopes: [] } as unknown as Project;
|
|
|
|
const { menu } = useGlobalEntityCreation(false);
|
|
|
|
expect(menu.value[0]).toStrictEqual(
|
|
expect.objectContaining({
|
|
disabled: true,
|
|
}),
|
|
);
|
|
|
|
expect(menu.value[1]).toStrictEqual(
|
|
expect.objectContaining({
|
|
disabled: true,
|
|
}),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('global', () => {
|
|
it('should show personal + all team projects', () => {
|
|
const projectsStore = mockedStore(useProjectsStore);
|
|
projectsStore.teamProjectsLimit = -1;
|
|
|
|
const personalProjectId = 'personal-project';
|
|
projectsStore.isTeamProjectFeatureEnabled = true;
|
|
projectsStore.personalProject = { id: personalProjectId } as Project;
|
|
projectsStore.myProjects = [
|
|
{ id: '1', name: '1', type: 'team' },
|
|
{ id: '2', name: '2', type: 'public' },
|
|
{ id: '3', name: '3', type: 'team' },
|
|
] as ProjectListItem[];
|
|
|
|
const { menu } = useGlobalEntityCreation(true);
|
|
|
|
expect(menu.value[0].submenu?.length).toBe(4);
|
|
expect(menu.value[1].submenu?.length).toBe(4);
|
|
});
|
|
});
|
|
|
|
describe('handleSelect()', () => {
|
|
it('should only handle create-project', () => {
|
|
const projectsStore = mockedStore(useProjectsStore);
|
|
projectsStore.isTeamProjectFeatureEnabled = true;
|
|
const { handleSelect } = useGlobalEntityCreation(true);
|
|
handleSelect('dummy');
|
|
expect(projectsStore.createProject).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('creates a new project', async () => {
|
|
const toast = useToast();
|
|
const projectsStore = mockedStore(useProjectsStore);
|
|
projectsStore.isTeamProjectFeatureEnabled = true;
|
|
projectsStore.canCreateProjects = true;
|
|
projectsStore.createProject.mockResolvedValueOnce({ name: 'test', id: '1' } as Project);
|
|
|
|
const { handleSelect } = useGlobalEntityCreation(true);
|
|
|
|
handleSelect('create-project');
|
|
await flushPromises();
|
|
|
|
expect(projectsStore.createProject).toHaveBeenCalled();
|
|
expect(routerPushMock).toHaveBeenCalled();
|
|
expect(toast.showMessage).toHaveBeenCalled();
|
|
});
|
|
|
|
it('handles create project error', async () => {
|
|
const toast = useToast();
|
|
const projectsStore = mockedStore(useProjectsStore);
|
|
projectsStore.isTeamProjectFeatureEnabled = true;
|
|
projectsStore.canCreateProjects = true;
|
|
projectsStore.createProject.mockRejectedValueOnce(new Error('error'));
|
|
|
|
const { handleSelect } = useGlobalEntityCreation(true);
|
|
|
|
handleSelect('create-project');
|
|
await flushPromises();
|
|
expect(toast.showError).toHaveBeenCalled();
|
|
});
|
|
|
|
it('redirects when project limit has been reached', () => {
|
|
const projectsStore = mockedStore(useProjectsStore);
|
|
projectsStore.canCreateProjects = false;
|
|
projectsStore.isTeamProjectFeatureEnabled = true;
|
|
const redirect = usePageRedirectionHelper();
|
|
|
|
const { handleSelect } = useGlobalEntityCreation(true);
|
|
|
|
handleSelect('create-project');
|
|
expect(redirect.goToUpgrade).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
it('should show plan and limit according to deployment type', () => {
|
|
const settingsStore = mockedStore(useSettingsStore);
|
|
|
|
const cloudPlanStore = mockedStore(useCloudPlanStore);
|
|
cloudPlanStore.currentPlanData = { displayName: 'Pro' } as CloudPlanState['data'];
|
|
const projectsStore = mockedStore(useProjectsStore);
|
|
projectsStore.isTeamProjectFeatureEnabled = true;
|
|
projectsStore.teamProjectsLimit = 10;
|
|
|
|
settingsStore.isCloudDeployment = true;
|
|
const { projectsLimitReachedMessage } = useGlobalEntityCreation(true);
|
|
expect(projectsLimitReachedMessage.value).toContain(
|
|
'You have reached the Pro plan limit of 10.',
|
|
);
|
|
|
|
settingsStore.isCloudDeployment = false;
|
|
expect(projectsLimitReachedMessage.value).toContain(
|
|
'Upgrade to unlock projects for more granular control over sharing, access and organisation of workflows',
|
|
);
|
|
});
|
|
});
|