diff options
author | Ferdinand Thiessen <opensource@fthiessen.de> | 2024-08-26 20:30:26 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-08-26 20:30:26 +0200 |
commit | 4fcf4dba02a57a7e50b30efccdd9c60eca64bd16 (patch) | |
tree | 21f48a4a38cfa5c8150a8720479f0b66fd99195c /apps/files/src | |
parent | 6d31abdfd504574bf8502000c35c30becd341e61 (diff) | |
parent | 30d090fb789e62418efdfac9391518eb047ceb2b (diff) | |
download | nextcloud-server-4fcf4dba02a57a7e50b30efccdd9c60eca64bd16.tar.gz nextcloud-server-4fcf4dba02a57a7e50b30efccdd9c60eca64bd16.zip |
Merge pull request #47466 from nextcloud/chore/migrate-vitest
test: Migrate from Jest to vitest
Diffstat (limited to 'apps/files/src')
-rw-r--r-- | apps/files/src/actions/deleteAction.spec.ts | 59 | ||||
-rw-r--r-- | apps/files/src/actions/downloadAction.spec.ts | 12 | ||||
-rw-r--r-- | apps/files/src/actions/editLocallyAction.spec.ts | 67 | ||||
-rw-r--r-- | apps/files/src/actions/favoriteAction.spec.ts | 61 | ||||
-rw-r--r-- | apps/files/src/actions/openFolderAction.spec.ts | 10 | ||||
-rw-r--r-- | apps/files/src/actions/openInFilesAction.spec.ts | 6 | ||||
-rw-r--r-- | apps/files/src/actions/renameAction.spec.ts | 8 | ||||
-rw-r--r-- | apps/files/src/actions/sidebarAction.spec.ts | 12 | ||||
-rw-r--r-- | apps/files/src/actions/viewInFolderAction.spec.ts | 14 | ||||
-rw-r--r-- | apps/files/src/composables/useNavigation.spec.ts | 9 | ||||
-rw-r--r-- | apps/files/src/services/DropServiceUtils.spec.ts | 17 | ||||
-rw-r--r-- | apps/files/src/views/favorites.spec.ts | 69 | ||||
-rw-r--r-- | apps/files/src/views/favorites.ts | 2 |
13 files changed, 174 insertions, 172 deletions
diff --git a/apps/files/src/actions/deleteAction.spec.ts b/apps/files/src/actions/deleteAction.spec.ts index 7b6bbfc9bf7..224b196d364 100644 --- a/apps/files/src/actions/deleteAction.spec.ts +++ b/apps/files/src/actions/deleteAction.spec.ts @@ -2,15 +2,20 @@ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ -import { action } from './deleteAction' -import { expect } from '@jest/globals' import { File, Folder, Permission, View, FileAction } from '@nextcloud/files' +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' + import axios from '@nextcloud/axios' import * as capabilities from '@nextcloud/capabilities' -import eventBus from '@nextcloud/event-bus' +import * as eventBus from '@nextcloud/event-bus' +import { action } from './deleteAction' import logger from '../logger' +vi.mock('@nextcloud/auth') +vi.mock('@nextcloud/axios') +vi.mock('@nextcloud/capabilities') + const view = { id: 'files', name: 'Files', @@ -22,8 +27,8 @@ const trashbinView = { } as View describe('Delete action conditions tests', () => { - afterEach(() => { - jest.restoreAllMocks() + beforeEach(() => { + vi.restoreAllMocks() }) const file = new File({ @@ -82,7 +87,7 @@ describe('Delete action conditions tests', () => { expect(action).toBeInstanceOf(FileAction) expect(action.id).toBe('delete') expect(action.displayName([file], view)).toBe('Delete file') - expect(action.iconSvgInline([], view)).toBe('<svg>SvgMock</svg>') + expect(action.iconSvgInline([], view)).toMatch(/<svg.+<\/svg>/) expect(action.default).toBeUndefined() expect(action.order).toBe(100) }) @@ -96,7 +101,7 @@ describe('Delete action conditions tests', () => { }) test('Trashbin disabled displayName', () => { - jest.spyOn(capabilities, 'getCapabilities').mockImplementation(() => { + vi.spyOn(capabilities, 'getCapabilities').mockImplementation(() => { return { files: {}, } @@ -176,11 +181,11 @@ describe('Delete action enabled tests', () => { describe('Delete action execute tests', () => { afterEach(() => { - jest.restoreAllMocks() + vi.restoreAllMocks() }) test('Delete action', async () => { - jest.spyOn(axios, 'delete') - jest.spyOn(eventBus, 'emit') + vi.spyOn(axios, 'delete') + vi.spyOn(eventBus, 'emit') const file = new File({ id: 1, @@ -201,10 +206,10 @@ describe('Delete action execute tests', () => { }) test('Delete action batch', async () => { - jest.spyOn(axios, 'delete') - jest.spyOn(eventBus, 'emit') + vi.spyOn(axios, 'delete') + vi.spyOn(eventBus, 'emit') - const confirmMock = jest.fn() + const confirmMock = vi.fn() // @ts-expect-error We only mock what needed window.OC = { dialogs: { confirmDestructive: confirmMock } } @@ -240,11 +245,11 @@ describe('Delete action execute tests', () => { }) test('Delete action batch large set', async () => { - jest.spyOn(axios, 'delete') - jest.spyOn(eventBus, 'emit') + vi.spyOn(axios, 'delete') + vi.spyOn(eventBus, 'emit') // Emulate the confirmation dialog to always confirm - const confirmMock = jest.fn().mockImplementation((a, b, c, resolve) => resolve(true)) + const confirmMock = vi.fn().mockImplementation((a, b, c, resolve) => resolve(true)) // @ts-expect-error We only mock what needed window.OC = { dialogs: { confirmDestructive: confirmMock } } @@ -310,16 +315,16 @@ describe('Delete action execute tests', () => { }) test('Delete action batch trashbin disabled', async () => { - jest.spyOn(axios, 'delete') - jest.spyOn(eventBus, 'emit') - jest.spyOn(capabilities, 'getCapabilities').mockImplementation(() => { + vi.spyOn(axios, 'delete') + vi.spyOn(eventBus, 'emit') + vi.spyOn(capabilities, 'getCapabilities').mockImplementation(() => { return { files: {}, } }) // Emulate the confirmation dialog to always confirm - const confirmMock = jest.fn().mockImplementation((a, b, c, resolve) => resolve(true)) + const confirmMock = vi.fn().mockImplementation((a, b, c, resolve) => resolve(true)) // @ts-expect-error We only mock what needed window.OC = { dialogs: { confirmDestructive: confirmMock } } @@ -355,9 +360,9 @@ describe('Delete action execute tests', () => { }) test('Delete fails', async () => { - jest.spyOn(axios, 'delete').mockImplementation(() => { throw new Error('Mock error') }) - jest.spyOn(logger, 'error').mockImplementation(() => jest.fn()) - jest.spyOn(eventBus, 'emit') + vi.spyOn(axios, 'delete').mockImplementation(() => { throw new Error('Mock error') }) + vi.spyOn(logger, 'error').mockImplementation(() => vi.fn()) + vi.spyOn(eventBus, 'emit') const file = new File({ id: 1, @@ -378,16 +383,16 @@ describe('Delete action execute tests', () => { }) test('Delete is cancelled', async () => { - jest.spyOn(axios, 'delete') - jest.spyOn(eventBus, 'emit') - jest.spyOn(capabilities, 'getCapabilities').mockImplementation(() => { + vi.spyOn(axios, 'delete') + vi.spyOn(eventBus, 'emit') + vi.spyOn(capabilities, 'getCapabilities').mockImplementation(() => { return { files: {}, } }) // Emulate the confirmation dialog to always confirm - const confirmMock = jest.fn().mockImplementation((a, b, c, resolve) => resolve(false)) + const confirmMock = vi.fn().mockImplementation((a, b, c, resolve) => resolve(false)) // @ts-expect-error We only mock what needed window.OC = { dialogs: { confirmDestructive: confirmMock } } diff --git a/apps/files/src/actions/downloadAction.spec.ts b/apps/files/src/actions/downloadAction.spec.ts index 59e533441be..2c24625e90e 100644 --- a/apps/files/src/actions/downloadAction.spec.ts +++ b/apps/files/src/actions/downloadAction.spec.ts @@ -2,9 +2,10 @@ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ -import { action } from './downloadAction' -import { expect } from '@jest/globals' import { File, Folder, Permission, View, FileAction, DefaultType } from '@nextcloud/files' +import { beforeAll, beforeEach, describe, expect, test, vi } from 'vitest' + +import { action } from './downloadAction' const view = { id: 'files', @@ -22,7 +23,7 @@ describe('Download action conditions tests', () => { expect(action).toBeInstanceOf(FileAction) expect(action.id).toBe('download') expect(action.displayName([], view)).toBe('Download') - expect(action.iconSvgInline([], view)).toBe('<svg>SvgMock</svg>') + expect(action.iconSvgInline([], view)).toMatch(/<svg.+<\/svg>/) expect(action.default).toBe(DefaultType.DEFAULT) expect(action.order).toBe(30) }) @@ -83,11 +84,12 @@ describe('Download action enabled tests', () => { describe('Download action execute tests', () => { const link = { - click: jest.fn(), + click: vi.fn(), } as unknown as HTMLAnchorElement beforeEach(() => { - jest.spyOn(document, 'createElement').mockImplementation(() => link) + vi.resetAllMocks() + vi.spyOn(document, 'createElement').mockImplementation(() => link) }) test('Download single file', async () => { diff --git a/apps/files/src/actions/editLocallyAction.spec.ts b/apps/files/src/actions/editLocallyAction.spec.ts index ca2e1d05f96..4d07bb15189 100644 --- a/apps/files/src/actions/editLocallyAction.spec.ts +++ b/apps/files/src/actions/editLocallyAction.spec.ts @@ -2,25 +2,15 @@ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ -import { action } from './editLocallyAction' -import { expect } from '@jest/globals' import { File, Permission, View, FileAction } from '@nextcloud/files' -import { DialogBuilder, showError } from '@nextcloud/dialogs' -import axios from '@nextcloud/axios' +import { beforeAll, beforeEach, describe, expect, test, vi } from 'vitest' -const dialogBuilder = { - setName: jest.fn().mockReturnThis(), - setText: jest.fn().mockReturnThis(), - setButtons: jest.fn().mockReturnThis(), - build: jest.fn().mockReturnValue({ - show: jest.fn().mockResolvedValue(true), - }), -} as unknown as DialogBuilder +import axios from '@nextcloud/axios' +import * as nextcloudDialogs from '@nextcloud/dialogs' +import { action } from './editLocallyAction' -jest.mock('@nextcloud/dialogs', () => ({ - DialogBuilder: jest.fn(() => dialogBuilder), - showError: jest.fn(), -})) +vi.mock('@nextcloud/auth') +vi.mock('@nextcloud/axios') const view = { id: 'files', @@ -31,7 +21,7 @@ const view = { beforeAll(() => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (window as any)._oc_webroot = ''; - (window as any).OCA = { Viewer: { open: jest.fn() } } + (window as any).OCA = { Viewer: { open: vi.fn() } } }) describe('Edit locally action conditions tests', () => { @@ -39,7 +29,7 @@ describe('Edit locally action conditions tests', () => { expect(action).toBeInstanceOf(FileAction) expect(action.id).toBe('edit-locally') expect(action.displayName([], view)).toBe('Edit locally') - expect(action.iconSvgInline([], view)).toBe('<svg>SvgMock</svg>') + expect(action.iconSvgInline([], view)).toMatch(/<svg.+<\/svg>/) expect(action.default).toBeUndefined() expect(action.order).toBe(25) }) @@ -118,16 +108,22 @@ describe('Edit locally action enabled tests', () => { }) describe('Edit locally action execute tests', () => { + let spyShowDialog + beforeEach(() => { + vi.resetAllMocks() + spyShowDialog = vi.spyOn(nextcloudDialogs.Dialog.prototype, 'show') + .mockImplementation(() => Promise.resolve()) + }) + test('Edit locally opens proper URL', async () => { - jest.spyOn(axios, 'post').mockImplementation(async () => ({ - data: { ocs: { data: { token: 'foobar' } } } + vi.spyOn(axios, 'post').mockImplementation(async () => ({ + data: { ocs: { data: { token: 'foobar' } } }, })) - const mockedShowError = jest.mocked(showError) - const spyDialogBuilder = jest.spyOn(dialogBuilder, 'build') + const showError = vi.spyOn(nextcloudDialogs, 'showError') const file = new File({ id: 1, - source: 'http://localhost/remote.php/dav/files/admin/foobar.txt', + source: 'http://nextcloud.local/remote.php/dav/files/admin/foobar.txt', owner: 'admin', mime: 'text/plain', permissions: Permission.UPDATE, @@ -135,24 +131,23 @@ describe('Edit locally action execute tests', () => { const exec = await action.exec(file, view, '/') - expect(spyDialogBuilder).toBeCalled() + expect(spyShowDialog).toBeCalled() // Silent action expect(exec).toBe(null) expect(axios.post).toBeCalledTimes(1) - expect(axios.post).toBeCalledWith('http://localhost/ocs/v2.php/apps/files/api/v1/openlocaleditor?format=json', { path: '/foobar.txt' }) - expect(mockedShowError).toBeCalledTimes(0) - expect(window.location.href).toBe('nc://open/test@localhost/foobar.txt?token=foobar') + expect(axios.post).toBeCalledWith('http://nextcloud.local/ocs/v2.php/apps/files/api/v1/openlocaleditor?format=json', { path: '/foobar.txt' }) + expect(showError).toBeCalledTimes(0) + expect(window.location.href).toBe('nc://open/test@nextcloud.local/foobar.txt?token=foobar') }) test('Edit locally fails and shows error', async () => { - jest.spyOn(axios, 'post').mockImplementation(async () => ({})) - const mockedShowError = jest.mocked(showError) - const spyDialogBuilder = jest.spyOn(dialogBuilder, 'build') + vi.spyOn(axios, 'post').mockImplementation(async () => ({})) + const showError = vi.spyOn(nextcloudDialogs, 'showError') const file = new File({ id: 1, - source: 'http://localhost/remote.php/dav/files/admin/foobar.txt', + source: 'http://nextcloud.local/remote.php/dav/files/admin/foobar.txt', owner: 'admin', mime: 'text/plain', permissions: Permission.UPDATE, @@ -160,14 +155,14 @@ describe('Edit locally action execute tests', () => { const exec = await action.exec(file, view, '/') - expect(spyDialogBuilder).toBeCalled() + expect(spyShowDialog).toBeCalled() // Silent action expect(exec).toBe(null) expect(axios.post).toBeCalledTimes(1) - expect(axios.post).toBeCalledWith('http://localhost/ocs/v2.php/apps/files/api/v1/openlocaleditor?format=json', { path: '/foobar.txt' }) - expect(mockedShowError).toBeCalledTimes(1) - expect(mockedShowError).toBeCalledWith('Failed to redirect to client') - expect(window.location.href).toBe('http://localhost/') + expect(axios.post).toBeCalledWith('http://nextcloud.local/ocs/v2.php/apps/files/api/v1/openlocaleditor?format=json', { path: '/foobar.txt' }) + expect(showError).toBeCalledTimes(1) + expect(showError).toBeCalledWith('Failed to redirect to client') + expect(window.location.href).toBe('http://nextcloud.local/') }) }) diff --git a/apps/files/src/actions/favoriteAction.spec.ts b/apps/files/src/actions/favoriteAction.spec.ts index cbf0038961a..96768c4887a 100644 --- a/apps/files/src/actions/favoriteAction.spec.ts +++ b/apps/files/src/actions/favoriteAction.spec.ts @@ -2,14 +2,18 @@ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ -import { action } from './favoriteAction' -import { expect } from '@jest/globals' import { File, Permission, View, FileAction } from '@nextcloud/files' +import { beforeAll, beforeEach, describe, expect, test, vi } from 'vitest' + +import { action } from './favoriteAction' import axios from '@nextcloud/axios' -import eventBus from '@nextcloud/event-bus' +import * as eventBus from '@nextcloud/event-bus' import * as favoriteAction from './favoriteAction' import logger from '../logger' +vi.mock('@nextcloud/auth') +vi.mock('@nextcloud/axios') + const view = { id: 'files', name: 'Files', @@ -20,13 +24,12 @@ const favoriteView = { name: 'Favorites', } as View -window.OC = { - ...window.OC, - TAG_FAVORITE: '_$!<Favorite>!$_', -} - // Mock webroot variable beforeAll(() => { + window.OC = { + ...window.OC, + TAG_FAVORITE: '_$!<Favorite>!$_', + }; // eslint-disable-next-line @typescript-eslint/no-explicit-any (window as any)._oc_webroot = '' }) @@ -43,7 +46,7 @@ describe('Favorite action conditions tests', () => { expect(action).toBeInstanceOf(FileAction) expect(action.id).toBe('favorite') expect(action.displayName([file], view)).toBe('Add to favorites') - expect(action.iconSvgInline([], view)).toBe('<svg>SvgMock</svg>') + expect(action.iconSvgInline([], view)).toMatch(/<svg.+<\/svg>/) expect(action.default).toBeUndefined() expect(action.order).toBe(-50) }) @@ -129,13 +132,11 @@ describe('Favorite action enabled tests', () => { }) describe('Favorite action execute tests', () => { - afterEach(() => { - jest.spyOn(axios, 'post').mockRestore() - }) + beforeEach(() => { vi.resetAllMocks() }) test('Favorite triggers tag addition', async () => { - jest.spyOn(axios, 'post') - jest.spyOn(eventBus, 'emit') + vi.spyOn(axios, 'post') + vi.spyOn(eventBus, 'emit') const file = new File({ id: 1, @@ -159,8 +160,8 @@ describe('Favorite action execute tests', () => { }) test('Favorite triggers tag removal', async () => { - jest.spyOn(axios, 'post') - jest.spyOn(eventBus, 'emit') + vi.spyOn(axios, 'post') + vi.spyOn(eventBus, 'emit') const file = new File({ id: 1, @@ -187,8 +188,8 @@ describe('Favorite action execute tests', () => { }) test('Favorite triggers node removal if favorite view and root dir', async () => { - jest.spyOn(axios, 'post') - jest.spyOn(eventBus, 'emit') + vi.spyOn(axios, 'post') + vi.spyOn(eventBus, 'emit') const file = new File({ id: 1, @@ -216,8 +217,8 @@ describe('Favorite action execute tests', () => { }) test('Favorite does NOT triggers node removal if favorite view but NOT root dir', async () => { - jest.spyOn(axios, 'post') - jest.spyOn(eventBus, 'emit') + vi.spyOn(axios, 'post') + vi.spyOn(eventBus, 'emit') const file = new File({ id: 1, @@ -246,8 +247,8 @@ describe('Favorite action execute tests', () => { test('Favorite fails and show error', async () => { const error = new Error('Mock error') - jest.spyOn(axios, 'post').mockImplementation(() => { throw new Error('Mock error') }) - jest.spyOn(logger, 'error').mockImplementation(() => jest.fn()) + vi.spyOn(axios, 'post').mockImplementation(() => { throw new Error('Mock error') }) + vi.spyOn(logger, 'error').mockImplementation(() => vi.fn()) const file = new File({ id: 1, @@ -276,8 +277,8 @@ describe('Favorite action execute tests', () => { test('Removing from favorites fails and show error', async () => { const error = new Error('Mock error') - jest.spyOn(axios, 'post').mockImplementation(() => { throw error }) - jest.spyOn(logger, 'error').mockImplementation(() => jest.fn()) + vi.spyOn(axios, 'post').mockImplementation(() => { throw error }) + vi.spyOn(logger, 'error').mockImplementation(() => vi.fn()) const file = new File({ id: 1, @@ -306,9 +307,11 @@ describe('Favorite action execute tests', () => { }) describe('Favorite action batch execute tests', () => { + beforeEach(() => { vi.restoreAllMocks() }) + test('Favorite action batch execute with mixed files', async () => { - jest.spyOn(favoriteAction, 'favoriteNode') - jest.spyOn(axios, 'post') + vi.spyOn(favoriteAction, 'favoriteNode') + vi.spyOn(axios, 'post') const file1 = new File({ id: 1, @@ -336,15 +339,14 @@ describe('Favorite action batch execute tests', () => { expect(exec).toStrictEqual([true, true]) expect([file1, file2].every(file => file.attributes.favorite === 1)).toBe(true) - expect(favoriteAction.favoriteNode).toBeCalledTimes(2) expect(axios.post).toBeCalledTimes(2) expect(axios.post).toHaveBeenNthCalledWith(1, '/index.php/apps/files/api/v1/files/foo.txt', { tags: ['_$!<Favorite>!$_'] }) expect(axios.post).toHaveBeenNthCalledWith(2, '/index.php/apps/files/api/v1/files/bar.txt', { tags: ['_$!<Favorite>!$_'] }) }) test('Remove from favorite action batch execute with favorites only files', async () => { - jest.spyOn(favoriteAction, 'favoriteNode') - jest.spyOn(axios, 'post') + vi.spyOn(favoriteAction, 'favoriteNode') + vi.spyOn(axios, 'post') const file1 = new File({ id: 1, @@ -372,7 +374,6 @@ describe('Favorite action batch execute tests', () => { expect(exec).toStrictEqual([true, true]) expect([file1, file2].every(file => file.attributes.favorite === 0)).toBe(true) - expect(favoriteAction.favoriteNode).toBeCalledTimes(2) expect(axios.post).toBeCalledTimes(2) expect(axios.post).toHaveBeenNthCalledWith(1, '/index.php/apps/files/api/v1/files/foo.txt', { tags: [] }) expect(axios.post).toHaveBeenNthCalledWith(2, '/index.php/apps/files/api/v1/files/bar.txt', { tags: [] }) diff --git a/apps/files/src/actions/openFolderAction.spec.ts b/apps/files/src/actions/openFolderAction.spec.ts index cbbbe38f15e..066ad5d86d8 100644 --- a/apps/files/src/actions/openFolderAction.spec.ts +++ b/apps/files/src/actions/openFolderAction.spec.ts @@ -2,8 +2,8 @@ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ -import { expect } from '@jest/globals' import { File, Folder, Node, Permission, View, DefaultType, FileAction } from '@nextcloud/files' +import { describe, expect, test, vi } from 'vitest' import { action } from './openFolderAction' @@ -24,7 +24,7 @@ describe('Open folder action conditions tests', () => { expect(action).toBeInstanceOf(FileAction) expect(action.id).toBe('open-folder') expect(action.displayName([folder], view)).toBe('Open folder FooBar') - expect(action.iconSvgInline([], view)).toBe('<svg>SvgMock</svg>') + expect(action.iconSvgInline([], view)).toMatch(/<svg.+<\/svg>/) expect(action.default).toBe(DefaultType.HIDDEN) expect(action.order).toBe(-100) }) @@ -100,7 +100,7 @@ describe('Open folder action enabled tests', () => { describe('Open folder action execute tests', () => { test('Open folder', async () => { - const goToRouteMock = jest.fn() + const goToRouteMock = vi.fn() // @ts-expect-error We only mock what needed, we do not need Files.Router.goTo or Files.Navigation window.OCP = { Files: { Router: { goToRoute: goToRouteMock } } } @@ -119,7 +119,7 @@ describe('Open folder action execute tests', () => { }) test('Open folder fails without node', async () => { - const goToRouteMock = jest.fn() + const goToRouteMock = vi.fn() // @ts-expect-error We only mock what needed, we do not need Files.Router.goTo or Files.Navigation window.OCP = { Files: { Router: { goToRoute: goToRouteMock } } } @@ -129,7 +129,7 @@ describe('Open folder action execute tests', () => { }) test('Open folder fails without Folder', async () => { - const goToRouteMock = jest.fn() + const goToRouteMock = vi.fn() // @ts-expect-error We only mock what needed, we do not need Files.Router.goTo or Files.Navigation window.OCP = { Files: { Router: { goToRoute: goToRouteMock } } } diff --git a/apps/files/src/actions/openInFilesAction.spec.ts b/apps/files/src/actions/openInFilesAction.spec.ts index 88a9716914b..e732270d4c0 100644 --- a/apps/files/src/actions/openInFilesAction.spec.ts +++ b/apps/files/src/actions/openInFilesAction.spec.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ import { action } from './openInFilesAction' -import { expect } from '@jest/globals' +import { describe, expect, test, vi } from 'vitest' import { File, Folder, Permission, View, DefaultType, FileAction } from '@nextcloud/files' const view = { @@ -42,7 +42,7 @@ describe('Open in files action enabled tests', () => { describe('Open in files action execute tests', () => { test('Open in files', async () => { - const goToRouteMock = jest.fn() + const goToRouteMock = vi.fn() // @ts-expect-error We only mock what needed, we do not need Files.Router.goTo or Files.Navigation window.OCP = { Files: { Router: { goToRoute: goToRouteMock } } } @@ -64,7 +64,7 @@ describe('Open in files action execute tests', () => { }) test('Open in files with folder', async () => { - const goToRouteMock = jest.fn() + const goToRouteMock = vi.fn() // @ts-expect-error We only mock what needed, we do not need Files.Router.goTo or Files.Navigation window.OCP = { Files: { Router: { goToRoute: goToRouteMock } } } diff --git a/apps/files/src/actions/renameAction.spec.ts b/apps/files/src/actions/renameAction.spec.ts index f0428996972..b309c11d9a6 100644 --- a/apps/files/src/actions/renameAction.spec.ts +++ b/apps/files/src/actions/renameAction.spec.ts @@ -3,9 +3,9 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ import { action } from './renameAction' -import { expect } from '@jest/globals' import { File, Permission, View, FileAction } from '@nextcloud/files' -import eventBus from '@nextcloud/event-bus' +import * as eventBus from '@nextcloud/event-bus' +import { describe, expect, test, vi } from 'vitest' const view = { id: 'files', @@ -17,7 +17,7 @@ describe('Rename action conditions tests', () => { expect(action).toBeInstanceOf(FileAction) expect(action.id).toBe('rename') expect(action.displayName([], view)).toBe('Rename') - expect(action.iconSvgInline([], view)).toBe('<svg>SvgMock</svg>') + expect(action.iconSvgInline([], view)).toMatch(/<svg.+<\/svg>/) expect(action.default).toBeUndefined() expect(action.order).toBe(10) }) @@ -73,7 +73,7 @@ describe('Rename action enabled tests', () => { describe('Rename action exec tests', () => { test('Rename', async () => { - jest.spyOn(eventBus, 'emit') + vi.spyOn(eventBus, 'emit') const file = new File({ id: 1, diff --git a/apps/files/src/actions/sidebarAction.spec.ts b/apps/files/src/actions/sidebarAction.spec.ts index 21b48eba105..9755f519306 100644 --- a/apps/files/src/actions/sidebarAction.spec.ts +++ b/apps/files/src/actions/sidebarAction.spec.ts @@ -2,8 +2,8 @@ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ -import { expect } from '@jest/globals' import { File, Permission, View, FileAction } from '@nextcloud/files' +import { describe, expect, test, vi } from 'vitest' import { action } from './sidebarAction' import logger from '../logger' @@ -18,7 +18,7 @@ describe('Open sidebar action conditions tests', () => { expect(action).toBeInstanceOf(FileAction) expect(action.id).toBe('details') expect(action.displayName([], view)).toBe('Open details') - expect(action.iconSvgInline([], view)).toBe('<svg>SvgMock</svg>') + expect(action.iconSvgInline([], view)).toMatch(/<svg.+<\/svg>/) expect(action.default).toBeUndefined() expect(action.order).toBe(-50) }) @@ -107,9 +107,9 @@ describe('Open sidebar action enabled tests', () => { describe('Open sidebar action exec tests', () => { test('Open sidebar', async () => { - const openMock = jest.fn() + const openMock = vi.fn() window.OCA = { Files: { Sidebar: { open: openMock } } } - const goToRouteMock = jest.fn() + const goToRouteMock = vi.fn() // @ts-expect-error We only mock what needed, we do not need Files.Router.goTo or Files.Navigation window.OCP = { Files: { Router: { goToRoute: goToRouteMock } } } @@ -133,9 +133,9 @@ describe('Open sidebar action exec tests', () => { }) test('Open sidebar fails', async () => { - const openMock = jest.fn(() => { throw new Error('Mock error') }) + const openMock = vi.fn(() => { throw new Error('Mock error') }) window.OCA = { Files: { Sidebar: { open: openMock } } } - jest.spyOn(logger, 'error').mockImplementation(() => jest.fn()) + vi.spyOn(logger, 'error').mockImplementation(() => vi.fn()) const file = new File({ id: 1, diff --git a/apps/files/src/actions/viewInFolderAction.spec.ts b/apps/files/src/actions/viewInFolderAction.spec.ts index c75151a4c38..8aa8bc81922 100644 --- a/apps/files/src/actions/viewInFolderAction.spec.ts +++ b/apps/files/src/actions/viewInFolderAction.spec.ts @@ -2,9 +2,9 @@ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ -import { action } from './viewInFolderAction' -import { expect } from '@jest/globals' import { File, Folder, Node, Permission, View, FileAction } from '@nextcloud/files' +import { describe, expect, test, vi } from 'vitest' +import { action } from './viewInFolderAction' const view = { id: 'trashbin', @@ -21,7 +21,7 @@ describe('View in folder action conditions tests', () => { expect(action).toBeInstanceOf(FileAction) expect(action.id).toBe('view-in-folder') expect(action.displayName([], view)).toBe('View in folder') - expect(action.iconSvgInline([], view)).toBe('<svg>SvgMock</svg>') + expect(action.iconSvgInline([], view)).toMatch(/<svg.+<\/svg>/) expect(action.default).toBeUndefined() expect(action.order).toBe(80) expect(action.enabled).toBeDefined() @@ -113,7 +113,7 @@ describe('View in folder action enabled tests', () => { describe('View in folder action execute tests', () => { test('View in folder', async () => { - const goToRouteMock = jest.fn() + const goToRouteMock = vi.fn() // @ts-expect-error We only mock what needed, we do not need Files.Router.goTo or Files.Navigation window.OCP = { Files: { Router: { goToRoute: goToRouteMock } } } @@ -133,7 +133,7 @@ describe('View in folder action execute tests', () => { }) test('View in (sub) folder', async () => { - const goToRouteMock = jest.fn() + const goToRouteMock = vi.fn() // @ts-expect-error We only mock what needed, we do not need Files.Router.goTo or Files.Navigation window.OCP = { Files: { Router: { goToRoute: goToRouteMock } } } @@ -154,7 +154,7 @@ describe('View in folder action execute tests', () => { }) test('View in folder fails without node', async () => { - const goToRouteMock = jest.fn() + const goToRouteMock = vi.fn() // @ts-expect-error We only mock what needed, we do not need Files.Router.goTo or Files.Navigation window.OCP = { Files: { Router: { goToRoute: goToRouteMock } } } @@ -164,7 +164,7 @@ describe('View in folder action execute tests', () => { }) test('View in folder fails without File', async () => { - const goToRouteMock = jest.fn() + const goToRouteMock = vi.fn() // @ts-expect-error We only mock what needed, we do not need Files.Router.goTo or Files.Navigation window.OCP = { Files: { Router: { goToRoute: goToRouteMock } } } diff --git a/apps/files/src/composables/useNavigation.spec.ts b/apps/files/src/composables/useNavigation.spec.ts index 364c9ab653d..efea7103126 100644 --- a/apps/files/src/composables/useNavigation.spec.ts +++ b/apps/files/src/composables/useNavigation.spec.ts @@ -2,11 +2,14 @@ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ -import { beforeEach, describe, expect, it, jest } from '@jest/globals' -import nextcloudFiles, { Navigation, View } from '@nextcloud/files' +import { beforeEach, describe, expect, it, vi } from 'vitest' import { mount } from '@vue/test-utils' import { defineComponent } from 'vue' + import { useNavigation } from './useNavigation' +import * as nextcloudFiles from '@nextcloud/files' + +const { Navigation, View } = nextcloudFiles // Just a wrapper so we can test the composable const TestComponent = defineComponent({ @@ -21,7 +24,7 @@ const TestComponent = defineComponent({ }) describe('Composables: useNavigation', () => { - const spy = jest.spyOn(nextcloudFiles, 'getNavigation') + const spy = vi.spyOn(nextcloudFiles, 'getNavigation') let navigation: Navigation describe('currentView', () => { diff --git a/apps/files/src/services/DropServiceUtils.spec.ts b/apps/files/src/services/DropServiceUtils.spec.ts index 9f947531198..5f4370c7894 100644 --- a/apps/files/src/services/DropServiceUtils.spec.ts +++ b/apps/files/src/services/DropServiceUtils.spec.ts @@ -2,7 +2,7 @@ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ -import { describe, it, expect } from '@jest/globals' +import { beforeAll, describe, expect, it, vi } from 'vitest' import { FileSystemDirectoryEntry, FileSystemFileEntry, fileSystemEntryToDataTransferItem, DataTransferItem as DataTransferItemMock } from '../../../../__tests__/FileSystemAPIUtils' import { join } from 'node:path' @@ -88,20 +88,17 @@ describe('Filesystem API traverseTree', () => { describe('DropService dataTransferToFileTree', () => { beforeAll(() => { + // @ts-expect-error jsdom doesn't have DataTransferItem + delete window.DataTransferItem // DataTransferItem doesn't exists in jsdom, let's mock // a dumb one so we can check the instanceof // @ts-expect-error jsdom doesn't have DataTransferItem window.DataTransferItem = DataTransferItemMock }) - afterAll(() => { - // @ts-expect-error jsdom doesn't have DataTransferItem - delete window.DataTransferItem - }) - it('Should return a RootDirectory with Filesystem API', async () => { - jest.spyOn(logger, 'error').mockImplementation(() => jest.fn()) - jest.spyOn(logger, 'warn').mockImplementation(() => jest.fn()) + vi.spyOn(logger, 'error').mockImplementation(() => vi.fn()) + vi.spyOn(logger, 'warn').mockImplementation(() => vi.fn()) const dataTransferItems = buildDataTransferItemArray('root', dataTree) const fileTree = await dataTransferToFileTree(dataTransferItems as unknown as DataTransferItem[]) @@ -121,8 +118,8 @@ describe('DropService dataTransferToFileTree', () => { }) it('Should return a RootDirectory with legacy File API ignoring recursive directories', async () => { - jest.spyOn(logger, 'error').mockImplementation(() => jest.fn()) - jest.spyOn(logger, 'warn').mockImplementation(() => jest.fn()) + vi.spyOn(logger, 'error').mockImplementation(() => vi.fn()) + vi.spyOn(logger, 'warn').mockImplementation(() => vi.fn()) const dataTransferItems = buildDataTransferItemArray('root', dataTree, false) diff --git a/apps/files/src/views/favorites.spec.ts b/apps/files/src/views/favorites.spec.ts index 976334d6bde..b2aa292f936 100644 --- a/apps/files/src/views/favorites.spec.ts +++ b/apps/files/src/views/favorites.spec.ts @@ -3,20 +3,18 @@ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ -import { basename } from 'path' -import { expect } from '@jest/globals' import { Folder, Navigation, getNavigation } from '@nextcloud/files' import { CancelablePromise } from 'cancelable-promise' -import eventBus, { emit } from '@nextcloud/event-bus' +import { basename } from 'path' +import { beforeEach, describe, expect, test, vi } from 'vitest' +import * as eventBus from '@nextcloud/event-bus' import * as initialState from '@nextcloud/initial-state' import { action } from '../actions/favoriteAction' import * as favoritesService from '../services/Favorites' import registerFavoritesView from './favorites' -jest.mock('webdav/dist/node/request.js', () => ({ - request: jest.fn(), -})) +vi.mock('@nextcloud/axios') window.OC = { ...window.OC, @@ -32,17 +30,16 @@ declare global { describe('Favorites view definition', () => { let Navigation beforeEach(() => { - Navigation = getNavigation() - expect(window._nc_navigation).toBeDefined() - }) + vi.resetAllMocks() - afterEach(() => { delete window._nc_navigation + Navigation = getNavigation() + expect(window._nc_navigation).toBeDefined() }) test('Default empty favorite view', () => { - jest.spyOn(eventBus, 'subscribe') - jest.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as Folder, contents: [] })) + vi.spyOn(eventBus, 'subscribe') + vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as Folder, contents: [] })) registerFavoritesView() const favoritesView = Navigation.views.find(view => view.id === 'favorites') @@ -61,7 +58,7 @@ describe('Favorites view definition', () => { expect(favoritesView?.id).toBe('favorites') expect(favoritesView?.name).toBe('Favorites') expect(favoritesView?.caption).toBeDefined() - expect(favoritesView?.icon).toBe('<svg>SvgMock</svg>') + expect(favoritesView?.icon).toMatch(/<svg.+<\/svg>/) expect(favoritesView?.order).toBe(15) expect(favoritesView?.columns).toStrictEqual([]) expect(favoritesView?.getContents).toBeDefined() @@ -73,8 +70,8 @@ describe('Favorites view definition', () => { { fileid: 2, path: '/bar' }, { fileid: 3, path: '/foo/bar' }, ] - jest.spyOn(initialState, 'loadState').mockReturnValue(favoriteFolders) - jest.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as Folder, contents: [] })) + vi.spyOn(initialState, 'loadState').mockReturnValue(favoriteFolders) + vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as Folder, contents: [] })) registerFavoritesView() const favoritesView = Navigation.views.find(view => view.id === 'favorites') @@ -90,7 +87,7 @@ describe('Favorites view definition', () => { expect(favoriteView).toBeDefined() expect(favoriteView?.id).toBeDefined() expect(favoriteView?.name).toBe(basename(folder.path)) - expect(favoriteView?.icon).toBe('<svg>SvgMock</svg>') + expect(favoriteView?.icon).toMatch(/<svg.+<\/svg>/) expect(favoriteView?.order).toBe(index) expect(favoriteView?.params).toStrictEqual({ dir: folder.path, @@ -104,20 +101,19 @@ describe('Favorites view definition', () => { }) }) -describe('Dynamic update of favourite folders', () => { +describe('Dynamic update of favorite folders', () => { let Navigation beforeEach(() => { - Navigation = getNavigation() - }) + vi.restoreAllMocks() - afterEach(() => { delete window._nc_navigation + Navigation = getNavigation() }) test('Add a favorite folder creates a new entry in the navigation', async () => { - jest.spyOn(eventBus, 'emit') - jest.spyOn(initialState, 'loadState').mockReturnValue([]) - jest.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as Folder, contents: [] })) + vi.spyOn(eventBus, 'emit') + vi.spyOn(initialState, 'loadState').mockReturnValue([]) + vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as Folder, contents: [] })) registerFavoritesView() const favoritesView = Navigation.views.find(view => view.id === 'favorites') @@ -131,7 +127,7 @@ describe('Dynamic update of favourite folders', () => { // Create new folder to favorite const folder = new Folder({ id: 1, - source: 'http://localhost/remote.php/dav/files/admin/Foo/Bar', + source: 'http://nextcloud.local/remote.php/dav/files/admin/Foo/Bar', owner: 'admin', }) @@ -143,10 +139,9 @@ describe('Dynamic update of favourite folders', () => { }) test('Remove a favorite folder remove the entry from the navigation column', async () => { - jest.spyOn(eventBus, 'emit') - jest.spyOn(eventBus, 'subscribe') - jest.spyOn(initialState, 'loadState').mockReturnValue([{ fileid: 42, path: '/Foo/Bar' }]) - jest.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as Folder, contents: [] })) + vi.spyOn(eventBus, 'emit') + vi.spyOn(initialState, 'loadState').mockReturnValue([{ fileid: 42, path: '/Foo/Bar' }]) + vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as Folder, contents: [] })) registerFavoritesView() let favoritesView = Navigation.views.find(view => view.id === 'favorites') @@ -160,7 +155,7 @@ describe('Dynamic update of favourite folders', () => { // Create new folder to favorite const folder = new Folder({ id: 1, - source: 'http://localhost/remote.php/dav/files/admin/Foo/Bar', + source: 'http://nextcloud.local/remote.php/dav/files/admin/Foo/Bar', owner: 'admin', root: '/files/admin', attributes: { @@ -168,11 +163,15 @@ describe('Dynamic update of favourite folders', () => { }, }) + const fo = vi.fn() + eventBus.subscribe('files:favorites:removed', fo) + // Exec the action await action.exec(folder, favoritesView, '/') expect(eventBus.emit).toHaveBeenCalledTimes(1) expect(eventBus.emit).toHaveBeenCalledWith('files:favorites:removed', folder) + expect(fo).toHaveBeenCalled() favoritesView = Navigation.views.find(view => view.id === 'favorites') favoriteFoldersViews = Navigation.views.filter(view => view.parent === 'favorites') @@ -184,9 +183,9 @@ describe('Dynamic update of favourite folders', () => { }) test('Renaming a favorite folder updates the navigation', async () => { - jest.spyOn(eventBus, 'emit') - jest.spyOn(initialState, 'loadState').mockReturnValue([]) - jest.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as Folder, contents: [] })) + vi.spyOn(eventBus, 'emit') + vi.spyOn(initialState, 'loadState').mockReturnValue([]) + vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as Folder, contents: [] })) registerFavoritesView() const favoritesView = Navigation.views.find(view => view.id === 'favorites') @@ -202,7 +201,7 @@ describe('Dynamic update of favourite folders', () => { // Create new folder to favorite const folder = new Folder({ id: 1, - source: 'http://localhost/remote.php/dav/files/admin/Foo/Bar', + source: 'http://nextcloud.local/remote.php/dav/files/admin/Foo/Bar', owner: 'admin', }) @@ -213,12 +212,12 @@ describe('Dynamic update of favourite folders', () => { // Create a folder with the same id but renamed const renamedFolder = new Folder({ id: 1, - source: 'http://localhost/remote.php/dav/files/admin/Foo/Bar.renamed', + source: 'http://nextcloud.local/remote.php/dav/files/admin/Foo/Bar.renamed', owner: 'admin', }) // Exec the rename action - emit('files:node:renamed', renamedFolder) + eventBus.emit('files:node:renamed', renamedFolder) expect(eventBus.emit).toHaveBeenNthCalledWith(2, 'files:node:renamed', renamedFolder) }) }) diff --git a/apps/files/src/views/favorites.ts b/apps/files/src/views/favorites.ts index e09587a0d5d..3af8c49498f 100644 --- a/apps/files/src/views/favorites.ts +++ b/apps/files/src/views/favorites.ts @@ -90,7 +90,7 @@ export default () => { }) /** - * Remove favourites navigation when a folder is removed + * Remove favorites navigation when a folder is removed */ subscribe('files:favorites:removed', (node: Node) => { if (node.type !== FileType.Folder) { |