diff --git a/package.json b/package.json index 168c553946..8f620765c2 100644 --- a/package.json +++ b/package.json @@ -130,7 +130,7 @@ "@box/box-ai-content-answers": "^0.139.0", "@box/box-item-type-selector": "^0.73.1", "@box/cldr-data": "^34.2.0", - "@box/combobox-with-api": "^0.34.9", + "@box/combobox-with-api": "^1.3.11", "@box/copy-input": "^1.5.3", "@box/frontend": "^11.0.1", "@box/item-icon": "^0.27.1", @@ -302,7 +302,7 @@ "@box/box-ai-content-answers": "^0.139.0", "@box/box-item-type-selector": "^0.73.1", "@box/cldr-data": ">=34.2.0", - "@box/combobox-with-api": "^0.34.9", + "@box/combobox-with-api": "^1.3.11", "@box/copy-input": "^1.5.3", "@box/item-icon": "^0.27.1", "@box/metadata-editor": "^1.5.3", diff --git a/src/api/Metadata.js b/src/api/Metadata.js index ddc567aaa4..b9ed9a1fc7 100644 --- a/src/api/Metadata.js +++ b/src/api/Metadata.js @@ -1348,19 +1348,19 @@ class Metadata extends File { const { marker, - searchInput: query_text, + searchInput: query, onlySelectableOptions, - ancestorId: ancestor_id, + ancestorId: ancestor, level: optionsLevel, signal, } = options; const params: {} = { ...(marker ? { marker } : {}), - ...(query_text ? { query_text } : {}), + ...(query ? { query } : {}), ...(optionsLevel ? { level: optionsLevel } : {}), - ...(ancestor_id ? { ancestor_id } : {}), - ...(onlySelectableOptions !== undefined ? { only_selectable_options: !!onlySelectableOptions } : {}), + ...(ancestor ? { ancestor } : {}), + ...(onlySelectableOptions !== undefined ? { 'only-selectable-options': !!onlySelectableOptions } : {}), limit: 100, }; diff --git a/src/api/__tests__/Metadata.test.js b/src/api/__tests__/Metadata.test.js index 00c17e5c58..fc9428cac3 100644 --- a/src/api/__tests__/Metadata.test.js +++ b/src/api/__tests__/Metadata.test.js @@ -3184,12 +3184,12 @@ describe('api/Metadata', () => { url: 'options_url', id: 'file_id', params: { - ancestor_id: '123', + ancestor: '123', level: 1, limit: 100, marker: 'current_marker', - only_selectable_options: false, - query_text: 'search_term', + 'only-selectable-options': false, + query: 'search_term', }, }); }); diff --git a/src/elements/content-sidebar/stories/__mocks__/TaxonomyMocks.ts b/src/elements/content-sidebar/stories/__mocks__/TaxonomyMocks.ts index 5ee9532ae1..307b95dd77 100644 --- a/src/elements/content-sidebar/stories/__mocks__/TaxonomyMocks.ts +++ b/src/elements/content-sidebar/stories/__mocks__/TaxonomyMocks.ts @@ -2,7 +2,8 @@ import { http, HttpResponse } from 'msw'; import type { HttpHandler } from 'msw'; import { DEFAULT_HOSTNAME_API } from '../../../../constants'; -import { fileIdWithMetadata, mockFileRequest } from './MetadataSidebarRedesignedMocks'; +import { fileIdWithMetadata, mockFileRequest, mockGlobalMetadataTemplates } from './MetadataSidebarRedesignedMocks'; +import { mockUserRequest } from '../../../common/__mocks__/mockRequests'; const apiV2Path = `${DEFAULT_HOSTNAME_API}/2.0`; @@ -397,9 +398,15 @@ export const mockSinglelevelTaxonomyNodes = { }; export const taxonomyMockHandlers: HttpHandler[] = [ + http.get(mockUserRequest.url, () => { + return HttpResponse.json(mockUserRequest.response); + }), http.get(mockFileRequest.url, () => { return HttpResponse.json(mockFileRequest.response); }), + http.get(mockGlobalMetadataTemplates.url, () => { + return HttpResponse.json(mockGlobalMetadataTemplates.response); + }), http.get(mockMetadataInstancesWithTaxonomy.url, () => { return HttpResponse.json(mockMetadataInstancesWithTaxonomy.response); }), @@ -417,7 +424,7 @@ export const taxonomyMockHandlers: HttpHandler[] = [ }), http.get(mockMultilevelTaxonomyOptions.url, ({ request }) => { const url = new URL(request.url); - const ancestorId = url.searchParams.get('ancestor_id'); + const ancestorId = url.searchParams.get('ancestor'); if (!ancestorId) { return HttpResponse.json(mockMultilevelTaxonomyOptions.response.firstLevel); diff --git a/src/elements/content-sidebar/stories/tests/MetadataSidebarRedesign-visual.stories.tsx b/src/elements/content-sidebar/stories/tests/MetadataSidebarRedesign-visual.stories.tsx index 4463026d30..8dbc9d3c50 100644 --- a/src/elements/content-sidebar/stories/tests/MetadataSidebarRedesign-visual.stories.tsx +++ b/src/elements/content-sidebar/stories/tests/MetadataSidebarRedesign-visual.stories.tsx @@ -48,6 +48,17 @@ const mockLogger = { }, }; +const waitForLoadingToComplete = async (canvas: ReturnType) => { + const loadingIndicator = await canvas.findByRole('status', { name: 'Loading' }); + expect(loadingIndicator).toBeInTheDocument(); + await waitFor( + async () => { + expect(loadingIndicator).not.toBeInTheDocument(); + }, + { timeout: 10000 }, + ); +}; + export const AddTemplateDropdownMenuOn = { play: async ({ canvasElement }) => { const canvas = within(canvasElement); @@ -76,6 +87,7 @@ export const AddTemplateDropdownMenuOnEmpty = { }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); + const addTemplateButton = await canvas.findByRole('button', { name: 'Add template' }, { timeout: 2000 }); expect(addTemplateButton).toBeInTheDocument(); @@ -616,6 +628,8 @@ export const ViewMultilevelTaxonomy: StoryObj = play: async ({ canvasElement }) => { const canvas = within(canvasElement); + await waitForLoadingToComplete(canvas); + await waitFor(async () => { const multilevelOptionButton = canvas.getByRole('button', { name: 'London' }); @@ -644,6 +658,8 @@ export const ViewSinglelevelTaxonomy: StoryObj = play: async ({ canvasElement }) => { const canvas = within(canvasElement); + await waitForLoadingToComplete(canvas); + await waitFor(async () => { const singlelevelOptionButton = canvas.getByRole('button', { name: 'Blue' }); @@ -663,41 +679,45 @@ export const EditMultilevelTaxonomy: StoryObj = play: async ({ canvasElement }) => { const canvas = within(canvasElement); - const editButton = await waitFor(() => canvas.getByRole('button', { name: 'Edit My Taxonomy' })); + await waitForLoadingToComplete(canvas); + const editButton = await canvas.findByRole('button', { name: 'Edit My Taxonomy' }); await userEvent.click(editButton); - const multilevelInput = canvas.getByRole('combobox'); - const optionChip = canvas.getByRole('button', { name: 'London' }); + const navigateToSapporoTreeItem = async () => { + const multilevelInput = await canvas.findByRole('combobox'); + await userEvent.click(multilevelInput); - expect(multilevelInput).toBeInTheDocument(); - expect(optionChip).toBeInTheDocument(); + const listbox = await canvas.findByRole('listbox'); + const listboxCanvas = within(listbox); - await userEvent.click(multilevelInput); + const japanLabel = await listboxCanvas.findByText('Japan'); + const japanTreeitem = japanLabel.closest('[role="treeitem"]') as HTMLElement | null; + expect(japanTreeitem).not.toBeNull(); + const expander = within(japanTreeitem as HTMLElement).getByRole('button', { name: 'Expand branch' }); + await userEvent.click(expander); - const listbox = await waitFor(() => canvas.getByRole('listbox')); - expect(listbox).toBeInTheDocument(); + const hokkaidoLabel = await listboxCanvas.findByText('Hokkaido'); + const hokkaidoTreeitem = hokkaidoLabel.closest('[role="treeitem"]') as HTMLElement | null; + expect(hokkaidoTreeitem).not.toBeNull(); + const hokkaidoExpander = within(hokkaidoTreeitem as HTMLElement).getByRole('button', { + name: 'Expand branch', + }); + await userEvent.click(hokkaidoExpander); - const expandButtons = await waitFor(() => canvas.getAllByRole('button', { name: 'Expand branch' })); + const sapporoTreeitem = await listboxCanvas.findByRole('treeitem', { name: 'Sapporo' }); + return sapporoTreeitem; + }; - await userEvent.click(expandButtons[1]); - - const hokkaidoOption = await waitFor(() => canvas.getByText('Hokkaido')); - expect(hokkaidoOption).toBeInTheDocument(); - - const nestedExpandButtons = await waitFor(() => screen.getAllByRole('button', { name: 'Expand branch' })); - - await userEvent.click(nestedExpandButtons[2]); - - const sapporoOption = await waitFor(() => canvas.getByRole('treeitem', { name: 'Sapporo' })); - - expect(sapporoOption).toBeInTheDocument(); - expect(sapporoOption).toHaveAttribute('aria-selected', 'false'); - - await userEvent.click(sapporoOption); + const unselectedSapporoTreeitem = await navigateToSapporoTreeItem(); + expect(unselectedSapporoTreeitem).toHaveAttribute('aria-selected', 'false'); + await userEvent.click(unselectedSapporoTreeitem); const sapporoSelection = await waitFor(() => canvas.getByRole('gridcell', { name: 'Sapporo' })); expect(sapporoSelection).toBeInTheDocument(); + + const selectedSapporoTreeitem = await navigateToSapporoTreeItem(); + expect(selectedSapporoTreeitem).toHaveAttribute('aria-selected', 'true'); }, }; @@ -706,6 +726,8 @@ export const EditSinglelevelTaxonomy: StoryObj = play: async ({ canvasElement }) => { const canvas = within(canvasElement); + await waitForLoadingToComplete(canvas); + const editButton = await waitFor(() => canvas.getByRole('button', { name: 'Edit My Taxonomy' })); await userEvent.click(editButton); diff --git a/yarn.lock b/yarn.lock index ed50410277..a633b5d2a4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1480,12 +1480,12 @@ resolved "https://registry.yarnpkg.com/@box/cldr-data/-/cldr-data-34.8.0.tgz#36e6ddcea8e20653326aba2e0d13e07f34b7704f" integrity sha512-jsTnhhpFy/eMossMr3cP9+1VFqOxOzO1GX/csw0LzasPl0Dg2Jhn8ypeNTBnFwlOB2Dp6XoxdvQHkBG4eVQe/Q== -"@box/combobox-with-api@^0.34.9": - version "0.34.9" - resolved "https://registry.yarnpkg.com/@box/combobox-with-api/-/combobox-with-api-0.34.9.tgz#0620ac1ef80719a3c6d95f27f731ec92e03bb05c" - integrity sha512-jE257A/6rlN5GydNWh+T+K4w8xmoaDaPb+J6MOh8pz4AkTJuZXOSp9jhfHP7KRwrQs849moBDpWowF0xOnQ2+g== +"@box/combobox-with-api@^1.3.11": + version "1.3.13" + resolved "https://registry.yarnpkg.com/@box/combobox-with-api/-/combobox-with-api-1.3.13.tgz#bfe008b1fac3ac59a2459a98b1e7d9f8783799b0" + integrity sha512-PN+unnjkbiJf55JTKhz2lYIxCI28IX7b+ds+YUsStcrER9IrQuX7sbdA7UwJ+yW/uJBXF5zpyd4tnDIAloaSIQ== dependencies: - "@box/tree" "^0.45.4" + "@box/tree" "^1.2.6" react-accessible-treeview "2.9.0" "@box/copy-input@^1.5.3": @@ -1539,10 +1539,10 @@ prop-types "^15.7.2" react-lifecycles-compat "^3.0.4" -"@box/tree@^0.45.4": - version "0.45.4" - resolved "https://registry.yarnpkg.com/@box/tree/-/tree-0.45.4.tgz#605051e77e64ebb3c03ceefc9ee99f0a0d2ed4ae" - integrity sha512-gJLYz4bF+xci7o0e8oM2qAtc0lSRQYGrlOYMtZO5QvoLY0JjtAHtNaI9axmL7leJsy7VuCCxFoSFUoSXMHVRMA== +"@box/tree@^1.2.6": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@box/tree/-/tree-1.2.6.tgz#998611a8e23f94959a20e9aa37ee89ab6d7d556b" + integrity sha512-BWJhvfnwbKTqEKS3mXWY8jfSI5zteSNEVfA06vA7+JPpiGrRWMIvolRiSQ4aeDAPXLoHqulzAm9PHmkSEnNsVw== "@box/types@^0.2.1": version "0.2.1"