aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files/src/services/DropServiceUtils.spec.ts
diff options
context:
space:
mode:
Diffstat (limited to 'apps/files/src/services/DropServiceUtils.spec.ts')
-rw-r--r--apps/files/src/services/DropServiceUtils.spec.ts143
1 files changed, 143 insertions, 0 deletions
diff --git a/apps/files/src/services/DropServiceUtils.spec.ts b/apps/files/src/services/DropServiceUtils.spec.ts
new file mode 100644
index 00000000000..5f4370c7894
--- /dev/null
+++ b/apps/files/src/services/DropServiceUtils.spec.ts
@@ -0,0 +1,143 @@
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+import { beforeAll, describe, expect, it, vi } from 'vitest'
+
+import { FileSystemDirectoryEntry, FileSystemFileEntry, fileSystemEntryToDataTransferItem, DataTransferItem as DataTransferItemMock } from '../../../../__tests__/FileSystemAPIUtils'
+import { join } from 'node:path'
+import { Directory, traverseTree } from './DropServiceUtils'
+import { dataTransferToFileTree } from './DropService'
+import logger from '../logger'
+
+const dataTree = {
+ 'file0.txt': ['Hello, world!', 1234567890],
+ dir1: {
+ 'file1.txt': ['Hello, world!', 4567891230],
+ 'file2.txt': ['Hello, world!', 7891234560],
+ },
+ dir2: {
+ 'file3.txt': ['Hello, world!', 1234567890],
+ },
+}
+
+// This is mocking a file tree using the FileSystem API
+const buildFileSystemDirectoryEntry = (path: string, tree: any): FileSystemDirectoryEntry => {
+ const entries = Object.entries(tree).map(([name, contents]) => {
+ const fullPath = join(path, name)
+ if (Array.isArray(contents)) {
+ return new FileSystemFileEntry(fullPath, contents[0], contents[1])
+ } else {
+ return buildFileSystemDirectoryEntry(fullPath, contents)
+ }
+ })
+ return new FileSystemDirectoryEntry(path, entries)
+}
+
+const buildDataTransferItemArray = (path: string, tree: any, isFileSystemAPIAvailable = true): DataTransferItemMock[] => {
+ return Object.entries(tree).map(([name, contents]) => {
+ const fullPath = join(path, name)
+ if (Array.isArray(contents)) {
+ const entry = new FileSystemFileEntry(fullPath, contents[0], contents[1])
+ return fileSystemEntryToDataTransferItem(entry, isFileSystemAPIAvailable)
+ }
+
+ const entry = buildFileSystemDirectoryEntry(fullPath, contents)
+ return fileSystemEntryToDataTransferItem(entry, isFileSystemAPIAvailable)
+ })
+}
+
+describe('Filesystem API traverseTree', () => {
+ it('Should traverse a file tree from root', async () => {
+ // Fake a FileSystemEntry tree
+ const root = buildFileSystemDirectoryEntry('root', dataTree)
+ const tree = await traverseTree(root as unknown as FileSystemEntry) as Directory
+
+ expect(tree.name).toBe('root')
+ expect(tree).toBeInstanceOf(Directory)
+ expect(tree.contents).toHaveLength(3)
+ expect(tree.size).toBe(13 * 4) // 13 bytes from 'Hello, world!'
+ })
+
+ it('Should traverse a file tree from a subdirectory', async () => {
+ // Fake a FileSystemEntry tree
+ const dir2 = buildFileSystemDirectoryEntry('dir2', dataTree.dir2)
+ const tree = await traverseTree(dir2 as unknown as FileSystemEntry) as Directory
+
+ expect(tree.name).toBe('dir2')
+ expect(tree).toBeInstanceOf(Directory)
+ expect(tree.contents).toHaveLength(1)
+ expect(tree.contents[0].name).toBe('file3.txt')
+ expect(tree.size).toBe(13) // 13 bytes from 'Hello, world!'
+ })
+
+ it('Should properly compute the last modified', async () => {
+ // Fake a FileSystemEntry tree
+ const root = buildFileSystemDirectoryEntry('root', dataTree)
+ const rootTree = await traverseTree(root as unknown as FileSystemEntry) as Directory
+
+ expect(rootTree.lastModified).toBe(7891234560)
+
+ // Fake a FileSystemEntry tree
+ const dir2 = buildFileSystemDirectoryEntry('root', dataTree.dir2)
+ const dir2Tree = await traverseTree(dir2 as unknown as FileSystemEntry) as Directory
+ expect(dir2Tree.lastModified).toBe(1234567890)
+ })
+})
+
+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
+ })
+
+ it('Should return a RootDirectory with Filesystem API', async () => {
+ 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[])
+
+ expect(fileTree.name).toBe('root')
+ expect(fileTree).toBeInstanceOf(Directory)
+ expect(fileTree.contents).toHaveLength(3)
+
+ // The file tree should be recursive when using the Filesystem API
+ expect(fileTree.contents[1]).toBeInstanceOf(Directory)
+ expect((fileTree.contents[1] as Directory).contents).toHaveLength(2)
+ expect(fileTree.contents[2]).toBeInstanceOf(Directory)
+ expect((fileTree.contents[2] as Directory).contents).toHaveLength(1)
+
+ expect(logger.error).not.toBeCalled()
+ expect(logger.warn).not.toBeCalled()
+ })
+
+ it('Should return a RootDirectory with legacy File API ignoring recursive directories', async () => {
+ vi.spyOn(logger, 'error').mockImplementation(() => vi.fn())
+ vi.spyOn(logger, 'warn').mockImplementation(() => vi.fn())
+
+ const dataTransferItems = buildDataTransferItemArray('root', dataTree, false)
+
+ const fileTree = await dataTransferToFileTree(dataTransferItems as unknown as DataTransferItem[])
+
+ expect(fileTree.name).toBe('root')
+ expect(fileTree).toBeInstanceOf(Directory)
+ expect(fileTree.contents).toHaveLength(1)
+
+ // The file tree should be recursive when using the Filesystem API
+ expect(fileTree.contents[0]).not.toBeInstanceOf(Directory)
+ expect((fileTree.contents[0].name)).toBe('file0.txt')
+
+ expect(logger.error).not.toBeCalled()
+ expect(logger.warn).toHaveBeenNthCalledWith(1, 'Could not get FilesystemEntry of item, falling back to file')
+ expect(logger.warn).toHaveBeenNthCalledWith(2, 'Could not get FilesystemEntry of item, falling back to file')
+ expect(logger.warn).toHaveBeenNthCalledWith(3, 'Browser does not support Filesystem API. Directories will not be uploaded')
+ expect(logger.warn).toHaveBeenNthCalledWith(4, 'Could not get FilesystemEntry of item, falling back to file')
+ expect(logger.warn).toHaveBeenCalledTimes(4)
+ })
+})