diff --git a/apps/files/src/views/FilesNavigation.spec.ts b/apps/files/src/views/FilesNavigation.spec.ts index b476a4fa1a7..b6b239560a8 100644 --- a/apps/files/src/views/FilesNavigation.spec.ts +++ b/apps/files/src/views/FilesNavigation.spec.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -import type { Folder, Navigation } from '@nextcloud/files' +import type { IFolder } from '@nextcloud/files' import FolderSvg from '@mdi/svg/svg/folder.svg?raw' import { getNavigation, View } from '@nextcloud/files' @@ -21,13 +21,21 @@ beforeAll(async () => { await fireEvent.resize(window) }) +const navigation = getNavigation() +beforeEach(() => { + const views = [...navigation.views] + for (const view of views) { + navigation.remove(view.id) + } + expect(navigation.views).toHaveLength(0) +}) + describe('Navigation', () => { beforeEach(cleanup) beforeEach(async () => { - delete window._nc_navigation mockWindow() - getNavigation().register(createView('files', 'Files')) + navigation.register(createView('files', 'Files')) await router.replace({ name: 'filelist', params: { view: 'files' } }) }) @@ -130,11 +138,7 @@ describe('Navigation', () => { }) describe('Navigation API', () => { - let Navigation: Navigation - beforeEach(async () => { - delete window._nc_navigation - Navigation = getNavigation() mockWindow() await router.replace({ name: 'filelist', params: { view: 'files' } }) @@ -144,7 +148,7 @@ describe('Navigation API', () => { beforeEach(cleanup) it('Check API entries rendering', async () => { - Navigation.register(createView('files', 'Files')) + navigation.register(createView('files', 'Files')) const component = render(NavigationView, { router, @@ -171,8 +175,8 @@ describe('Navigation API', () => { }) it('Adds a new entry and render', async () => { - Navigation.register(createView('files', 'Files')) - Navigation.register(createView('sharing', 'Sharing')) + navigation.register(createView('files', 'Files')) + navigation.register(createView('sharing', 'Sharing')) const component = render(NavigationView, { router, @@ -198,9 +202,9 @@ describe('Navigation API', () => { }) it('Adds a new children, render and open menu', async () => { - Navigation.register(createView('files', 'Files')) - Navigation.register(createView('sharing', 'Sharing')) - Navigation.register(createView('sharingin', 'Shared with me', 'sharing')) + navigation.register(createView('files', 'Files')) + navigation.register(createView('sharing', 'Sharing')) + navigation.register(createView('sharingin', 'Shared with me', 'sharing')) const component = render(NavigationView, { router, @@ -272,7 +276,7 @@ function createView(id: string, name: string, parent?: string) { return new View({ id, name, - getContents: async () => ({ folder: {} as Folder, contents: [] }), + getContents: async () => ({ folder: {} as IFolder, contents: [] }), icon: FolderSvg, order: 1, parent, diff --git a/apps/files/src/views/favorites.spec.ts b/apps/files/src/views/favorites.spec.ts index a31f291a934..c36f0abce1e 100644 --- a/apps/files/src/views/favorites.spec.ts +++ b/apps/files/src/views/favorites.spec.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -import type { Navigation, Folder as NcFolder } from '@nextcloud/files' +import type { IFolder } from '@nextcloud/files' import * as eventBus from '@nextcloud/event-bus' import * as filesUtils from '@nextcloud/files' @@ -23,30 +23,26 @@ window.OC = { TAG_FAVORITE: '_$!!$_', } -declare global { - interface Window { - _nc_navigation?: Navigation +const navigation = getNavigation() +beforeEach(() => { + vi.resetAllMocks() + + const views = [...navigation.views] + for (const view of views) { + navigation.remove(view.id) } -} + expect(navigation.views).toHaveLength(0) +}) describe('Favorites view definition', () => { - let Navigation - beforeEach(() => { - vi.resetAllMocks() - - delete window._nc_navigation - Navigation = getNavigation() - expect(window._nc_navigation).toBeDefined() - }) - test('Default empty favorite view', async () => { vi.spyOn(eventBus, 'subscribe') vi.spyOn(filesDavUtils, 'getFavoriteNodes').mockReturnValue(Promise.resolve([])) - vi.spyOn(favoritesService, 'getContents').mockReturnValue(Promise.resolve({ folder: {} as NcFolder, contents: [] })) + vi.spyOn(favoritesService, 'getContents').mockReturnValue(Promise.resolve({ folder: {} as IFolder, contents: [] })) await registerFavoritesView() - const favoritesView = Navigation.views.find((view) => view.id === 'favorites') - const favoriteFoldersViews = Navigation.views.filter((view) => view.parent === 'favorites') + const favoritesView = navigation.views.find((view) => view.id === 'favorites') + const favoriteFoldersViews = navigation.views.filter((view) => view.parent === 'favorites') expect(eventBus.subscribe).toHaveBeenCalledTimes(3) expect(eventBus.subscribe).toHaveBeenNthCalledWith(1, 'files:favorites:added', expect.anything()) @@ -54,7 +50,7 @@ describe('Favorites view definition', () => { expect(eventBus.subscribe).toHaveBeenNthCalledWith(3, 'files:node:renamed', expect.anything()) // one main view and no children - expect(Navigation.views.length).toBe(1) + expect(navigation.views.length).toBe(1) expect(favoritesView).toBeDefined() expect(favoriteFoldersViews.length).toBe(0) @@ -95,14 +91,14 @@ describe('Favorites view definition', () => { }), ] vi.spyOn(filesDavUtils, 'getFavoriteNodes').mockReturnValue(Promise.resolve(favoriteFolders)) - vi.spyOn(favoritesService, 'getContents').mockReturnValue(Promise.resolve({ folder: {} as NcFolder, contents: favoriteFolders })) + vi.spyOn(favoritesService, 'getContents').mockReturnValue(Promise.resolve({ folder: {} as IFolder, contents: favoriteFolders })) await registerFavoritesView() - const favoritesView = Navigation.views.find((view) => view.id === 'favorites') - const favoriteFoldersViews = Navigation.views.filter((view) => view.parent === 'favorites') + const favoritesView = navigation.views.find((view) => view.id === 'favorites') + const favoriteFoldersViews = navigation.views.filter((view) => view.parent === 'favorites') // one main view and 3 children - expect(Navigation.views.length).toBe(5) + expect(navigation.views.length).toBe(5) expect(favoritesView).toBeDefined() expect(favoriteFoldersViews.length).toBe(4) @@ -129,25 +125,17 @@ describe('Favorites view definition', () => { }) describe('Dynamic update of favorite folders', () => { - let Navigation - - beforeEach(() => { - vi.restoreAllMocks() - delete window._nc_navigation - Navigation = getNavigation() - }) - test('Add a favorite folder creates a new entry in the navigation', async () => { vi.spyOn(eventBus, 'emit') vi.spyOn(filesDavUtils, 'getFavoriteNodes').mockReturnValue(Promise.resolve([])) - vi.spyOn(favoritesService, 'getContents').mockReturnValue(Promise.resolve({ folder: {} as NcFolder, contents: [] })) + vi.spyOn(favoritesService, 'getContents').mockReturnValue(Promise.resolve({ folder: {} as IFolder, contents: [] })) await registerFavoritesView() - const favoritesView = Navigation.views.find((view) => view.id === 'favorites') - const favoriteFoldersViews = Navigation.views.filter((view) => view.parent === 'favorites') + const favoritesView = navigation.views.find((view) => view.id === 'favorites') + const favoriteFoldersViews = navigation.views.filter((view) => view.parent === 'favorites') // one main view and no children - expect(Navigation.views.length).toBe(1) + expect(navigation.views.length).toBe(1) expect(favoritesView).toBeDefined() expect(favoriteFoldersViews.length).toBe(0) @@ -162,8 +150,8 @@ describe('Dynamic update of favorite folders', () => { // Exec the action await action.exec({ nodes: [folder], - view: favoritesView, - folder: {} as NcFolder, + view: favoritesView!, + folder: {} as IFolder, contents: [], }) @@ -181,14 +169,14 @@ describe('Dynamic update of favorite folders', () => { })] vi.spyOn(eventBus, 'emit') vi.spyOn(filesDavUtils, 'getFavoriteNodes').mockReturnValue(Promise.resolve(favoriteFolders)) - vi.spyOn(favoritesService, 'getContents').mockReturnValue(Promise.resolve({ folder: {} as NcFolder, contents: favoriteFolders })) + vi.spyOn(favoritesService, 'getContents').mockReturnValue(Promise.resolve({ folder: {} as IFolder, contents: favoriteFolders })) await registerFavoritesView() - let favoritesView = Navigation.views.find((view) => view.id === 'favorites') - let favoriteFoldersViews = Navigation.views.filter((view) => view.parent === 'favorites') + let favoritesView = navigation.views.find((view) => view.id === 'favorites') + let favoriteFoldersViews = navigation.views.filter((view) => view.parent === 'favorites') // one main view and no children - expect(Navigation.views.length).toBe(2) + expect(navigation.views.length).toBe(2) expect(favoritesView).toBeDefined() expect(favoriteFoldersViews.length).toBe(1) @@ -209,8 +197,8 @@ describe('Dynamic update of favorite folders', () => { // Exec the action await action.exec({ nodes: [folder], - view: favoritesView, - folder: {} as NcFolder, + view: favoritesView!, + folder: {} as IFolder, contents: [], }) @@ -219,11 +207,11 @@ describe('Dynamic update of favorite folders', () => { expect(eventBus.emit).toHaveBeenCalledWith('files:node:updated', folder) expect(fo).toHaveBeenCalled() - favoritesView = Navigation.views.find((view) => view.id === 'favorites') - favoriteFoldersViews = Navigation.views.filter((view) => view.parent === 'favorites') + favoritesView = navigation.views.find((view) => view.id === 'favorites') + favoriteFoldersViews = navigation.views.filter((view) => view.parent === 'favorites') // one main view and no children - expect(Navigation.views.length).toBe(1) + expect(navigation.views.length).toBe(1) expect(favoritesView).toBeDefined() expect(favoriteFoldersViews.length).toBe(0) }) @@ -231,14 +219,14 @@ describe('Dynamic update of favorite folders', () => { test('Renaming a favorite folder updates the navigation', async () => { vi.spyOn(eventBus, 'emit') vi.spyOn(filesDavUtils, 'getFavoriteNodes').mockReturnValue(Promise.resolve([])) - vi.spyOn(favoritesService, 'getContents').mockReturnValue(Promise.resolve({ folder: {} as NcFolder, contents: [] })) + vi.spyOn(favoritesService, 'getContents').mockReturnValue(Promise.resolve({ folder: {} as IFolder, contents: [] })) await registerFavoritesView() - const favoritesView = Navigation.views.find((view) => view.id === 'favorites') - const favoriteFoldersViews = Navigation.views.filter((view) => view.parent === 'favorites') + const favoritesView = navigation.views.find((view) => view.id === 'favorites') + const favoriteFoldersViews = navigation.views.filter((view) => view.parent === 'favorites') // one main view and no children - expect(Navigation.views.length).toBe(1) + expect(navigation.views.length).toBe(1) expect(favoritesView).toBeDefined() expect(favoriteFoldersViews.length).toBe(0) @@ -255,8 +243,8 @@ describe('Dynamic update of favorite folders', () => { // Exec the action await action.exec({ nodes: [folder], - view: favoritesView, - folder: {} as NcFolder, + view: favoritesView!, + folder: {} as IFolder, contents: [], }) expect(eventBus.emit).toHaveBeenCalledWith('files:favorites:added', folder) diff --git a/apps/files_sharing/src/files_views/shares.spec.ts b/apps/files_sharing/src/files_views/shares.spec.ts index a7b2a8672d5..43c9fdf5898 100644 --- a/apps/files_sharing/src/files_views/shares.spec.ts +++ b/apps/files_sharing/src/files_views/shares.spec.ts @@ -3,44 +3,40 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -import type { Navigation, View } from '@nextcloud/files' +import type { View } from '@nextcloud/files' import type { OCSResponse } from '@nextcloud/typings/ocs' import axios from '@nextcloud/axios' -import { Folder, getNavigation } from '@nextcloud/files' +import { getNavigation } from '@nextcloud/files' import * as ncInitialState from '@nextcloud/initial-state' import { beforeEach, describe, expect, test, vi } from 'vitest' import registerSharingViews from './shares.ts' import '../main.ts' -declare global { - interface Window { - _nc_navigation?: Navigation +const navigation = getNavigation() +beforeEach(() => { + vi.resetAllMocks() + + const views = [...navigation.views] + for (const view of views) { + navigation.remove(view.id) } -} + expect(navigation.views).toHaveLength(0) +}) describe('Sharing views definition', () => { - let Navigation - beforeEach(() => { - delete window._nc_navigation - Navigation = getNavigation() - expect(window._nc_navigation).toBeDefined() - }) - test('Default values', () => { - vi.spyOn(Navigation, 'register') - - expect(Navigation.views.length).toBe(0) + vi.spyOn(navigation, 'register') registerSharingViews() - const shareOverviewView = Navigation.views.find((view) => view.id === 'shareoverview') as View - const sharesChildViews = Navigation.views.filter((view) => view.parent === 'shareoverview') as View[] + const shareOverviewView = navigation.views.find((view) => view.id === 'shareoverview') as View + const sharesChildViews = navigation.views.filter((view) => view.parent === 'shareoverview') as View[] - expect(Navigation.register).toHaveBeenCalledTimes(7) + expect(navigation.register).toHaveBeenCalledTimes(7) // one main view and no children - expect(Navigation.views.length).toBe(7) + expect(navigation.views.length).toBe(7) expect(shareOverviewView).toBeDefined() expect(sharesChildViews.length).toBe(6) @@ -76,35 +72,28 @@ describe('Sharing views definition', () => { }) test('Shared with others view is not registered if user has no storage quota', () => { - vi.spyOn(Navigation, 'register') + vi.spyOn(navigation, 'register') const spy = vi.spyOn(ncInitialState, 'loadState').mockImplementationOnce(() => ({ quota: 0 })) - expect(Navigation.views.length).toBe(0) + expect(navigation.views.length).toBe(0) registerSharingViews() - expect(Navigation.register).toHaveBeenCalledTimes(6) - expect(Navigation.views.length).toBe(6) + expect(navigation.register).toHaveBeenCalledTimes(6) + expect(navigation.views.length).toBe(6) - const shareOverviewView = Navigation.views.find((view) => view.id === 'shareoverview') as View - const sharesChildViews = Navigation.views.filter((view) => view.parent === 'shareoverview') as View[] + const shareOverviewView = navigation.views.find((view) => view.id === 'shareoverview') as View + const sharesChildViews = navigation.views.filter((view) => view.parent === 'shareoverview') as View[] expect(shareOverviewView).toBeDefined() expect(sharesChildViews.length).toBe(5) expect(spy).toHaveBeenCalled() expect(spy).toHaveBeenCalledWith('files', 'storageStats', { quota: -1 }) - const sharedWithOthersView = Navigation.views.find((view) => view.id === 'sharingout') + const sharedWithOthersView = navigation.views.find((view) => view.id === 'sharingout') expect(sharedWithOthersView).toBeUndefined() }) }) describe('Sharing views contents', () => { - let Navigation - beforeEach(() => { - delete window._nc_navigation - Navigation = getNavigation() - expect(window._nc_navigation).toBeDefined() - }) - test('Sharing overview get contents', async () => { vi.spyOn(axios, 'get').mockImplementation(async (): Promise => { return { @@ -122,11 +111,11 @@ describe('Sharing views contents', () => { }) registerSharingViews() - expect(Navigation.views.length).toBe(7) - Navigation.views.forEach(async (view: View) => { - const content = await view.getContents('/') + expect(navigation.views.length).toBe(7) + for (const view of navigation.views) { + const content = await view.getContents('/', { signal: new AbortController().signal }) expect(content.contents).toStrictEqual([]) - expect(content.folder).toBeInstanceOf(Folder) - }) + expect(content.folder).toBeTypeOf('object') + } }) }) diff --git a/apps/files_trashbin/src/files_actions/restoreAction.spec.ts b/apps/files_trashbin/src/files_actions/restoreAction.spec.ts index 6058ef45ecf..8b8ce36faf1 100644 --- a/apps/files_trashbin/src/files_actions/restoreAction.spec.ts +++ b/apps/files_trashbin/src/files_actions/restoreAction.spec.ts @@ -170,13 +170,13 @@ describe('files_trashbin: file actions - restore action', () => { }) it('does not delete node from view if request failed', async () => { - const node = new Folder({ owner: 'test', source: 'https://example.com/remote.php/dav/trashbin/test/folder', root: '/trashbin/test/', permissions: PERMISSION_ALL }) - + vi.spyOn(window.console, 'error').mockImplementation(() => {}) + const emitSpy = vi.spyOn(ncEventBus, 'emit') axiosMock.request.mockImplementationOnce(() => { throw new Error() }) - const emitSpy = vi.spyOn(ncEventBus, 'emit') + const node = new Folder({ owner: 'test', source: 'https://example.com/remote.php/dav/trashbin/test/folder', root: '/trashbin/test/', permissions: PERMISSION_ALL }) expect(await restoreAction.exec({ nodes: [node], view: trashbinView, @@ -189,6 +189,7 @@ describe('files_trashbin: file actions - restore action', () => { }) it('batch: only returns success if all requests worked', async () => { + vi.spyOn(window.console, 'error').mockImplementation(() => {}) const node = new Folder({ owner: 'test', source: 'https://example.com/remote.php/dav/trashbin/test/folder', root: '/trashbin/test/', permissions: PERMISSION_ALL }) expect(await restoreAction.execBatch!({ @@ -201,6 +202,7 @@ describe('files_trashbin: file actions - restore action', () => { }) it('batch: only returns success if all requests worked - one failed', async () => { + vi.spyOn(window.console, 'error').mockImplementation(() => {}) const node = new Folder({ owner: 'test', source: 'https://example.com/remote.php/dav/trashbin/test/folder', root: '/trashbin/test/', permissions: PERMISSION_ALL }) axiosMock.request.mockImplementationOnce(() => { diff --git a/cypress/e2e/files/files-actions.cy.ts b/cypress/e2e/files/files-actions.cy.ts index 37e48a429eb..f717213c15a 100644 --- a/cypress/e2e/files/files-actions.cy.ts +++ b/cypress/e2e/files/files-actions.cy.ts @@ -4,7 +4,6 @@ */ import type { User } from '@nextcloud/e2e-test-server/cypress' -import type { IFileAction } from '@nextcloud/files' import { getActionButtonForFileId, getActionEntryForFileId, getRowForFile, getSelectionActionButton, getSelectionActionEntry, selectRowForFile } from './FilesUtils.ts' @@ -12,12 +11,6 @@ const ACTION_DELETE = 'delete' const ACTION_COPY_MOVE = 'move-copy' const ACTION_DETAILS = 'details' -declare global { - interface Window { - _nc_fileactions: IFileAction[] - } -} - // Those two arrays doesn't represent the full list of actions // the goal is to test a few, we're not trying to match the full feature set const expectedDefaultActionsIDs = [ @@ -57,77 +50,6 @@ describe('Files: Actions', { testIsolation: true }, () => { }) }) - it('Show some nested actions', () => { - const parent: IFileAction = { - id: 'nested-action', - displayName: () => 'Nested Action', - exec: cy.spy(), - iconSvgInline: () => '', - } - - const child1: IFileAction = { - id: 'nested-child-1', - displayName: () => 'Nested Child 1', - exec: cy.spy(), - iconSvgInline: () => '', - parent: 'nested-action', - } - - const child2: IFileAction = { - id: 'nested-child-2', - displayName: () => 'Nested Child 2', - exec: cy.spy(), - iconSvgInline: () => '', - parent: 'nested-action', - } - - cy.visit('/apps/files', { - // Cannot use registerFileAction here - onBeforeLoad: (win) => { - if (!win._nc_fileactions) { - win._nc_fileactions = [] - } - // Cannot use registerFileAction here - win._nc_fileactions.push(parent) - win._nc_fileactions.push(child1) - win._nc_fileactions.push(child2) - }, - }) - - // Open the menu - getActionButtonForFileId(fileId) - .scrollIntoView() - .click({ force: true }) - - // Check we have the parent action but not the children - getActionEntryForFileId(fileId, 'nested-action').should('be.visible') - getActionEntryForFileId(fileId, 'menu-back').should('not.exist') - getActionEntryForFileId(fileId, 'nested-child-1').should('not.exist') - getActionEntryForFileId(fileId, 'nested-child-2').should('not.exist') - - // Click on the parent action - getActionEntryForFileId(fileId, 'nested-action') - .should('be.visible') - .click() - - // Check we have the children and the back button but not the parent - getActionEntryForFileId(fileId, 'nested-action').should('not.exist') - getActionEntryForFileId(fileId, 'menu-back').should('be.visible') - getActionEntryForFileId(fileId, 'nested-child-1').should('be.visible') - getActionEntryForFileId(fileId, 'nested-child-2').should('be.visible') - - // Click on the back button - getActionEntryForFileId(fileId, 'menu-back') - .should('be.visible') - .click() - - // Check we have the parent action but not the children - getActionEntryForFileId(fileId, 'nested-action').should('be.visible') - getActionEntryForFileId(fileId, 'menu-back').should('not.exist') - getActionEntryForFileId(fileId, 'nested-child-1').should('not.exist') - getActionEntryForFileId(fileId, 'nested-child-2').should('not.exist') - }) - it('Show some actions for a selection', () => { cy.visit('/apps/files') getRowForFile('image.jpg').should('be.visible') @@ -145,126 +67,4 @@ describe('Files: Actions', { testIsolation: true }, () => { getSelectionActionEntry(actionId).should('be.visible') }) }) - - it('Show some nested actions for a selection', () => { - const parent: IFileAction = { - id: 'nested-action', - displayName: () => 'Nested Action', - exec: cy.spy(), - iconSvgInline: () => '', - } - - const child1: IFileAction = { - id: 'nested-child-1', - displayName: () => 'Nested Child 1', - exec: cy.spy(), - execBatch: cy.spy(), - iconSvgInline: () => '', - parent: 'nested-action', - } - - const child2: IFileAction = { - id: 'nested-child-2', - displayName: () => 'Nested Child 2', - exec: cy.spy(), - execBatch: cy.spy(), - iconSvgInline: () => '', - parent: 'nested-action', - } - - cy.visit('/apps/files', { - // Cannot use registerFileAction here - onBeforeLoad: (win) => { - if (!win._nc_fileactions) { - win._nc_fileactions = [] - } - // Cannot use registerFileAction here - win._nc_fileactions.push(parent) - win._nc_fileactions.push(child1) - win._nc_fileactions.push(child2) - }, - }) - - selectRowForFile('image.jpg') - - // Open the menu - getSelectionActionButton().click({ force: true }) - - // Check we have the parent action but not the children - getSelectionActionEntry('nested-action').should('be.visible') - getSelectionActionEntry('menu-back').should('not.exist') - getSelectionActionEntry('nested-child-1').should('not.exist') - getSelectionActionEntry('nested-child-2').should('not.exist') - - // Click on the parent action - getSelectionActionEntry('nested-action') - .find('button').last() - .should('exist').click({ force: true }) - - // Check we have the children and the back button but not the parent - getSelectionActionEntry('nested-action').should('not.exist') - getSelectionActionEntry('menu-back').should('be.visible') - getSelectionActionEntry('nested-child-1').should('be.visible') - getSelectionActionEntry('nested-child-2').should('be.visible') - - // Click on the back button - getSelectionActionEntry('menu-back') - .find('button').last() - .should('exist').click({ force: true }) - - // Check we have the parent action but not the children - getSelectionActionEntry('nested-action').should('be.visible') - getSelectionActionEntry('menu-back').should('not.exist') - getSelectionActionEntry('nested-child-1').should('not.exist') - getSelectionActionEntry('nested-child-2').should('not.exist') - }) - - it('Do not show parent if nested action has no batch support', () => { - const parent: IFileAction = { - id: 'nested-action', - displayName: () => 'Nested Action', - exec: cy.spy(), - iconSvgInline: () => '', - } - - const child1: IFileAction = { - id: 'nested-child-1', - displayName: () => 'Nested Child 1', - exec: cy.spy(), - iconSvgInline: () => '', - parent: 'nested-action', - } - - const child2: IFileAction = { - id: 'nested-child-2', - displayName: () => 'Nested Child 2', - exec: cy.spy(), - iconSvgInline: () => '', - parent: 'nested-action', - } - - cy.visit('/apps/files', { - // Cannot use registerFileAction here - onBeforeLoad: (win) => { - if (!win._nc_fileactions) { - win._nc_fileactions = [] - } - // Cannot use registerFileAction here - win._nc_fileactions.push(parent) - win._nc_fileactions.push(child1) - win._nc_fileactions.push(child2) - }, - }) - - selectRowForFile('image.jpg') - - // Open the menu - getSelectionActionButton().click({ force: true }) - - // Check we have the parent action but not the children - getSelectionActionEntry('nested-action').should('not.exist') - getSelectionActionEntry('menu-back').should('not.exist') - getSelectionActionEntry('nested-child-1').should('not.exist') - getSelectionActionEntry('nested-child-2').should('not.exist') - }) })