mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
# Conflicts: # packages/editor-ui/src/components/Projects/ProjectMoveResourceModal.test.ts
238 lines
7.1 KiB
TypeScript
238 lines
7.1 KiB
TypeScript
import { createTestingPinia } from '@pinia/testing';
|
|
import userEvent from '@testing-library/user-event';
|
|
import { createComponentRenderer } from '@/__tests__/render';
|
|
import { createTestWorkflow } from '@/__tests__/mocks';
|
|
import { createProjectListItem } from '@/__tests__/data/projects';
|
|
import { getDropdownItems, mockedStore } from '@/__tests__/utils';
|
|
import type { MockedStore } from '@/__tests__/utils';
|
|
import { PROJECT_MOVE_RESOURCE_MODAL } from '@/constants';
|
|
import ProjectMoveResourceModal from '@/components/Projects/ProjectMoveResourceModal.vue';
|
|
import { useTelemetry } from '@/composables/useTelemetry';
|
|
import { useProjectsStore } from '@/stores/projects.store';
|
|
import { useWorkflowsStore } from '@/stores/workflows.store';
|
|
import { useCredentialsStore } from '@/stores/credentials.store';
|
|
|
|
const renderComponent = createComponentRenderer(ProjectMoveResourceModal, {
|
|
pinia: createTestingPinia(),
|
|
global: {
|
|
stubs: {
|
|
Modal: {
|
|
template:
|
|
'<div role="dialog"><slot name="header" /><slot name="content" /><slot name="footer" /></div>',
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
let telemetry: ReturnType<typeof useTelemetry>;
|
|
let projectsStore: MockedStore<typeof useProjectsStore>;
|
|
let workflowsStore: MockedStore<typeof useWorkflowsStore>;
|
|
let credentialsStore: MockedStore<typeof useCredentialsStore>;
|
|
|
|
describe('ProjectMoveResourceModal', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
telemetry = useTelemetry();
|
|
projectsStore = mockedStore(useProjectsStore);
|
|
workflowsStore = mockedStore(useWorkflowsStore);
|
|
credentialsStore = mockedStore(useCredentialsStore);
|
|
});
|
|
|
|
it('should send telemetry when mounted', async () => {
|
|
const telemetryTrackSpy = vi.spyOn(telemetry, 'track');
|
|
|
|
projectsStore.availableProjects = [createProjectListItem()];
|
|
workflowsStore.fetchWorkflow.mockResolvedValueOnce(createTestWorkflow());
|
|
|
|
const props = {
|
|
modalName: PROJECT_MOVE_RESOURCE_MODAL,
|
|
data: {
|
|
resourceType: 'workflow',
|
|
resourceTypeLabel: 'workflow',
|
|
resource: {
|
|
id: '1',
|
|
homeProject: {
|
|
id: '2',
|
|
name: 'My Project',
|
|
},
|
|
},
|
|
},
|
|
};
|
|
renderComponent({ props });
|
|
expect(telemetryTrackSpy).toHaveBeenCalledWith(
|
|
'User clicked to move a workflow',
|
|
expect.objectContaining({ workflow_id: '1' }),
|
|
);
|
|
});
|
|
|
|
it('should show no available projects message', async () => {
|
|
projectsStore.availableProjects = [];
|
|
workflowsStore.fetchWorkflow.mockResolvedValueOnce(createTestWorkflow());
|
|
|
|
const props = {
|
|
modalName: PROJECT_MOVE_RESOURCE_MODAL,
|
|
data: {
|
|
resourceType: 'workflow',
|
|
resourceTypeLabel: 'workflow',
|
|
resource: {
|
|
id: '1',
|
|
homeProject: {
|
|
id: '2',
|
|
name: 'My Project',
|
|
},
|
|
},
|
|
},
|
|
};
|
|
const { getByText } = renderComponent({ props });
|
|
expect(getByText(/Currently there are not any projects or users available/)).toBeVisible();
|
|
});
|
|
|
|
it('should not hide project select if filter has no result', async () => {
|
|
const projects = Array.from({ length: 5 }, createProjectListItem);
|
|
projectsStore.availableProjects = projects;
|
|
|
|
const props = {
|
|
modalName: PROJECT_MOVE_RESOURCE_MODAL,
|
|
data: {
|
|
resourceType: 'workflow',
|
|
resourceTypeLabel: 'Workflow',
|
|
resource: {
|
|
id: '1',
|
|
homeProject: {
|
|
id: projects[0].id,
|
|
name: projects[0].name,
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
const { getByTestId, getByRole } = renderComponent({ props });
|
|
|
|
const projectSelect = getByTestId('project-move-resource-modal-select');
|
|
const projectSelectInput: HTMLInputElement = getByRole('combobox');
|
|
expect(projectSelectInput).toBeVisible();
|
|
expect(projectSelect).toBeVisible();
|
|
|
|
const projectSelectDropdownItems = await getDropdownItems(projectSelect);
|
|
expect(projectSelectDropdownItems).toHaveLength(projects.length - 1);
|
|
|
|
await userEvent.click(projectSelectInput);
|
|
await userEvent.type(projectSelectInput, 'non-existing project');
|
|
|
|
expect(projectSelect).toBeVisible();
|
|
});
|
|
|
|
it('should not load workflow if the resource is a credential', async () => {
|
|
const telemetryTrackSpy = vi.spyOn(telemetry, 'track');
|
|
projectsStore.availableProjects = [createProjectListItem()];
|
|
|
|
const props = {
|
|
modalName: PROJECT_MOVE_RESOURCE_MODAL,
|
|
data: {
|
|
resourceType: 'credential',
|
|
resourceTypeLabel: 'credential',
|
|
resource: {
|
|
id: '1',
|
|
homeProject: {
|
|
id: '2',
|
|
name: 'My Project',
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
const { getByText } = renderComponent({ props });
|
|
expect(telemetryTrackSpy).toHaveBeenCalledWith(
|
|
'User clicked to move a credential',
|
|
expect.objectContaining({ credential_id: '1' }),
|
|
);
|
|
expect(workflowsStore.fetchWorkflow).not.toHaveBeenCalled();
|
|
expect(getByText(/Moving will remove any existing sharing for this credential/)).toBeVisible();
|
|
});
|
|
|
|
it('should send credential IDs when workflow moved with used credentials and checkbox checked', async () => {
|
|
const destinationProject = createProjectListItem();
|
|
const currentProjectId = '123';
|
|
const movedWorkflow = {
|
|
...createTestWorkflow(),
|
|
usedCredentials: [
|
|
{
|
|
id: '1',
|
|
name: 'PG Credential',
|
|
credentialType: 'postgres',
|
|
currentUserHasAccess: true,
|
|
},
|
|
{
|
|
id: '2',
|
|
name: 'Notion Credential',
|
|
credentialType: 'notion',
|
|
currentUserHasAccess: true,
|
|
},
|
|
],
|
|
};
|
|
|
|
projectsStore.currentProjectId = currentProjectId;
|
|
projectsStore.availableProjects = [destinationProject];
|
|
workflowsStore.fetchWorkflow.mockResolvedValueOnce(movedWorkflow);
|
|
credentialsStore.fetchAllCredentials.mockResolvedValueOnce([
|
|
{
|
|
id: '1',
|
|
name: 'PG Credential',
|
|
createdAt: '2021-01-01T00:00:00Z',
|
|
updatedAt: '2021-01-01T00:00:00Z',
|
|
type: 'postgres',
|
|
scopes: ['credential:share'],
|
|
isManaged: false,
|
|
},
|
|
{
|
|
id: '2',
|
|
name: 'Notion Credential',
|
|
createdAt: '2021-01-01T00:00:00Z',
|
|
updatedAt: '2021-01-01T00:00:00Z',
|
|
type: 'notion',
|
|
scopes: ['credential:share'],
|
|
isManaged: false,
|
|
},
|
|
{
|
|
id: '3',
|
|
name: 'Another Credential',
|
|
createdAt: '2021-01-01T00:00:00Z',
|
|
updatedAt: '2021-01-01T00:00:00Z',
|
|
type: 'another',
|
|
scopes: ['credential:share'],
|
|
isManaged: false,
|
|
},
|
|
]);
|
|
|
|
const props = {
|
|
modalName: PROJECT_MOVE_RESOURCE_MODAL,
|
|
data: {
|
|
resourceType: 'workflow',
|
|
resourceTypeLabel: 'workflow',
|
|
resource: movedWorkflow,
|
|
},
|
|
};
|
|
const { getByTestId, getByText } = renderComponent({ props });
|
|
expect(getByTestId('project-move-resource-modal-button')).toBeDisabled();
|
|
expect(getByText(/Moving will remove any existing sharing for this workflow/)).toBeVisible();
|
|
|
|
const projectSelect = getByTestId('project-move-resource-modal-select');
|
|
expect(projectSelect).toBeVisible();
|
|
|
|
const projectSelectDropdownItems = await getDropdownItems(projectSelect);
|
|
await userEvent.click(projectSelectDropdownItems[0]);
|
|
|
|
expect(getByTestId('project-move-resource-modal-button')).toBeEnabled();
|
|
|
|
await userEvent.click(getByTestId('project-move-resource-modal-checkbox-all'));
|
|
await userEvent.click(getByTestId('project-move-resource-modal-button'));
|
|
|
|
expect(projectsStore.moveResourceToProject).toHaveBeenCalledWith(
|
|
'workflow',
|
|
movedWorkflow.id,
|
|
destinationProject.id,
|
|
['1', '2'],
|
|
);
|
|
});
|
|
});
|