From 939e45cab9e979949b6cd22a08581ae102fd112a Mon Sep 17 00:00:00 2001 From: Stephen Smith Date: Fri, 28 Jun 2024 11:22:30 -0400 Subject: [PATCH] 21764: Consolidate tree node extraction to be reused for tests, add TreePicker unit tests Arvados-DCO-1.1-Signed-off-by: Stephen Smith --- .../workbench2/src/store/processes/process.ts | 5 + .../store/tree-picker/tree-picker-actions.ts | 44 +++-- .../tree-picker/tree-picker.test.tsx | 151 ++++++++++++++++++ 3 files changed, 175 insertions(+), 25 deletions(-) create mode 100644 services/workbench2/src/views-components/tree-picker/tree-picker.test.tsx diff --git a/services/workbench2/src/store/processes/process.ts b/services/workbench2/src/store/processes/process.ts index a31fd9eac8..481fcb863c 100644 --- a/services/workbench2/src/store/processes/process.ts +++ b/services/workbench2/src/store/processes/process.ts @@ -30,6 +30,11 @@ export enum ProcessStatus { CANCELLING = 'Cancelling', } +/** + * Gets a process from the store using container request uuid + * @param uuid container request associated with process + * @returns a Process object with containerRequest and optional container or undefined + */ export const getProcess = (uuid: string) => (resources: ResourcesState): Process | undefined => { if (extractUuidKind(uuid) === ResourceKind.CONTAINER_REQUEST) { const containerRequest = getResource(uuid)(resources); diff --git a/services/workbench2/src/store/tree-picker/tree-picker-actions.ts b/services/workbench2/src/store/tree-picker/tree-picker-actions.ts index 883847d854..4dc995338b 100644 --- a/services/workbench2/src/store/tree-picker/tree-picker-actions.ts +++ b/services/workbench2/src/store/tree-picker/tree-picker-actions.ts @@ -138,6 +138,23 @@ export const receiveTreePickerData = (params: ReceiveTreePickerDataParams) dispatch(treePickerActions.EXPAND_TREE_PICKER_NODE({ id, pickerId })); }; +export const extractGroupContentsNodeData = (expandableCollections: boolean) => (item: GroupContentsResource) => ( + item.uuid === "more-items-available" + ? { + id: item.uuid, + value: item, + status: TreeNodeStatus.LOADED + } + : { + id: item.uuid, + value: item, + status: item.kind === ResourceKind.PROJECT + ? TreeNodeStatus.INITIAL + : item.kind === ResourceKind.COLLECTION && expandableCollections + ? TreeNodeStatus.INITIAL + : TreeNodeStatus.LOADED + } +); interface LoadProjectParamsWithId extends LoadProjectParams { id: string; pickerId: string; @@ -222,22 +239,7 @@ export const loadProject = (params: LoadProjectParamsWithId) => return true; }), - extractNodeData: item => ( - item.uuid === "more-items-available" ? - { - id: item.uuid, - value: item, - status: TreeNodeStatus.LOADED - } - : { - id: item.uuid, - value: item, - status: item.kind === ResourceKind.PROJECT - ? TreeNodeStatus.INITIAL - : includeDirectories || includeFiles - ? TreeNodeStatus.INITIAL - : TreeNodeStatus.LOADED - }), + extractNodeData: extractGroupContentsNodeData(includeDirectories || includeFiles), })); } catch(e) { console.error("Failed to load project into tree picker:", e);; @@ -528,15 +530,7 @@ export const loadFavoritesProject = (params: LoadFavoritesProjectParams, return true; }), - extractNodeData: item => ({ - id: item.uuid, - value: item, - status: item.kind === ResourceKind.PROJECT - ? TreeNodeStatus.INITIAL - : includeDirectories || includeFiles - ? TreeNodeStatus.INITIAL - : TreeNodeStatus.LOADED - }), + extractNodeData: extractGroupContentsNodeData(includeDirectories || includeFiles), })); } }; diff --git a/services/workbench2/src/views-components/tree-picker/tree-picker.test.tsx b/services/workbench2/src/views-components/tree-picker/tree-picker.test.tsx new file mode 100644 index 0000000000..1d37123eb2 --- /dev/null +++ b/services/workbench2/src/views-components/tree-picker/tree-picker.test.tsx @@ -0,0 +1,151 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import React from "react"; +import Axios from "axios"; +import Adapter from "enzyme-adapter-react-16"; +import { configure, mount } from "enzyme"; +import { mockConfig } from "common/config"; +import { ServiceRepository, createServices } from "services/services"; +import { createBrowserHistory } from "history"; +import { ApiActions } from "services/api/api-actions"; +import { Provider } from "react-redux"; +import { configureStore } from "store/store"; +import { TreePicker } from "./tree-picker"; +import { initUserProject, receiveTreePickerData, extractGroupContentsNodeData } from "store/tree-picker/tree-picker-actions"; +import { authActions } from "store/auth/auth-action"; +import { ResourceKind } from "models/resource"; +import { updateResources } from "store/resources/resources-actions"; + +configure({ adapter: new Adapter() }); + +describe('', () => { + let store; + let services: ServiceRepository; + const axiosInst = Axios.create({ headers: {} }); + const config: any = {}; + const actions: ApiActions = { + progressFn: (id: string, working: boolean) => { }, + errorFn: (id: string, message: string) => { } + }; + const TEST_PICKER_ID = 'testPickerId'; + const fakeUser = { + email: "test@test.com", + firstName: "John", + lastName: "Doe", + uuid: "zzzzz-tpzed-xurymjxw79nv3jz", + ownerUuid: "ownerUuid", + username: "username", + prefs: {}, + isAdmin: false, + isActive: true, + canWrite: false, + canManage: false, + }; + const renderItem = (item) => ( +
  • {item.data.name}
  • + ); + + beforeEach(() => { + services = createServices(mockConfig({}), actions, axiosInst); + store = configureStore(createBrowserHistory(), services, config); + store.dispatch(authActions.USER_DETAILS_SUCCESS(fakeUser)); + store.dispatch(initUserProject(TEST_PICKER_ID)); + }); + + it("renders tree picker with initial home project state", () => { + let treePicker = mount( + + {}} + toggleItemOpen={() => {}} + toggleItemActive={() => {}} + toggleItemSelection={() => {}} + /> + ); + + expect(treePicker.find(`li[data-id="${fakeUser.uuid}"]`).text()).toBe('Home Projects'); + }); + + it("displays item loaded into treePicker store", () => { + const fakeProject = { + uuid: "zzzzz-j7d0g-111111111111111", + name: "FakeProject", + kind: ResourceKind.PROJECT, + }; + + store.dispatch(receiveTreePickerData({ + id: fakeUser.uuid, + pickerId: TEST_PICKER_ID, + data: [fakeProject], + extractNodeData: extractGroupContentsNodeData(false) + })); + + let treePicker = mount( + + {}} + toggleItemOpen={() => {}} + toggleItemActive={() => {}} + toggleItemSelection={() => {}} + /> + ); + + expect(treePicker.find(`[data-id="${fakeUser.uuid}"]`).text()).toBe('Home Projects'); + expect(treePicker.find(`[data-id="${fakeProject.uuid}"]`).text()).toBe('FakeProject'); + }); + + it("preserves treenode name when exists in resources", () => { + const treeProjectResource = { + uuid: "zzzzz-j7d0g-111111111111111", + name: "FakeProject", + kind: ResourceKind.PROJECT, + }; + const treeProjectResource2 = { + uuid: "zzzzz-j7d0g-222222222222222", + name: "", + kind: ResourceKind.PROJECT, + }; + + const storeProjectResource = { + ...treeProjectResource, + name: "StoreProjectName", + description: "Test description", + }; + const storeProjectResource2 = { + ...treeProjectResource2, + name: "StoreProjectName2", + description: "Test description", + }; + + store.dispatch(updateResources([storeProjectResource, storeProjectResource2])); + store.dispatch(receiveTreePickerData({ + id: fakeUser.uuid, + pickerId: TEST_PICKER_ID, + data: [treeProjectResource, treeProjectResource2], + extractNodeData: extractGroupContentsNodeData(false) + })); + + let treePicker = mount( + + {}} + toggleItemOpen={() => {}} + toggleItemActive={() => {}} + toggleItemSelection={() => {}} + /> + ); + + expect(treePicker.find(`[data-id="${fakeUser.uuid}"]`).text()).toBe('Home Projects'); + expect(treePicker.find(`[data-id="${treeProjectResource.uuid}"]`).text()).toBe('FakeProject'); + expect(treePicker.find(`[data-id="${treeProjectResource2.uuid}"]`).text()).toBe(''); + }); + +}); -- 2.30.2