Browse Source
Added file upload store tests
Added file upload store tests
Signed-off-by: Vincent Petry <vincent@nextcloud.com>pull/5522/head
No known key found for this signature in database
GPG Key ID: E055D6A4D513575C
5 changed files with 390 additions and 5 deletions
-
8.eslintrc.js
-
5jest.config.js
-
16package-lock.json
-
5package.json
-
361src/store/fileUploadStore.spec.js
@ -0,0 +1,361 @@ |
|||
import mockConsole from 'jest-mock-console' |
|||
import Vuex from 'vuex' |
|||
import { cloneDeep } from 'lodash' |
|||
import { createLocalVue } from '@vue/test-utils' |
|||
|
|||
import client from '../services/DavClient' |
|||
import { findUniquePath, getFileExtension } from '../utils/fileUpload' |
|||
import { shareFile } from '../services/filesSharingServices' |
|||
import { setAttachmentFolder } from '../services/settingsService' |
|||
import { showError } from '@nextcloud/dialogs' |
|||
|
|||
import fileUploadStore from './fileUploadStore' |
|||
|
|||
jest.mock('../services/DavClient') |
|||
jest.mock('./helper') |
|||
jest.mock('../utils/fileUpload', () => ({ |
|||
findUniquePath: jest.fn(), |
|||
getFileExtension: jest.fn(), |
|||
})) |
|||
jest.mock('../services/filesSharingServices', () => ({ |
|||
shareFile: jest.fn(), |
|||
})) |
|||
jest.mock('../services/settingsService', () => ({ |
|||
setAttachmentFolder: jest.fn(), |
|||
})) |
|||
jest.mock('@nextcloud/dialogs', () => ({ |
|||
showError: jest.fn(), |
|||
})) |
|||
|
|||
describe('fileUploadStore', () => { |
|||
let localVue = null |
|||
let storeConfig = null |
|||
let store = null |
|||
let mockedActions = null |
|||
|
|||
beforeEach(() => { |
|||
let temporaryMessageCount = 0 |
|||
|
|||
localVue = createLocalVue() |
|||
localVue.use(Vuex) |
|||
|
|||
mockedActions = { |
|||
createTemporaryMessage: jest.fn() |
|||
.mockImplementation((context, { file, index, uploadId, localUrl, token }) => { |
|||
temporaryMessageCount += 1 |
|||
return { |
|||
id: temporaryMessageCount, |
|||
referenceId: 'reference-id-' + temporaryMessageCount, |
|||
token, |
|||
messageParameters: { |
|||
file: { |
|||
uploadId, |
|||
index, |
|||
token, |
|||
localUrl, |
|||
file: file, |
|||
}, |
|||
}, |
|||
} |
|||
}), |
|||
addTemporaryMessage: jest.fn(), |
|||
markTemporaryMessageAsFailed: jest.fn(), |
|||
} |
|||
|
|||
global.URL.createObjectURL = jest.fn().mockImplementation((file) => 'local-url:' + file.name) |
|||
global.OC.MimeType = { |
|||
getIconUrl: jest.fn().mockImplementation((type) => 'icon-url:' + type), |
|||
} |
|||
|
|||
storeConfig = cloneDeep(fileUploadStore) |
|||
storeConfig.actions = Object.assign(storeConfig.actions, mockedActions) |
|||
storeConfig.getters.getUserId = jest.fn().mockReturnValue(() => 'current-user') |
|||
}) |
|||
|
|||
afterEach(() => { |
|||
jest.clearAllMocks() |
|||
}) |
|||
|
|||
describe('uploading', () => { |
|||
let restoreConsole |
|||
|
|||
beforeEach(() => { |
|||
storeConfig.getters.getAttachmentFolder = jest.fn().mockReturnValue(() => '/Talk') |
|||
store = new Vuex.Store(storeConfig) |
|||
restoreConsole = mockConsole(['error', 'debug']) |
|||
}) |
|||
|
|||
afterEach(() => { |
|||
restoreConsole() |
|||
}) |
|||
|
|||
test('initialises upload for given files', async() => { |
|||
const files = [ |
|||
{ |
|||
name: 'pngimage.png', |
|||
type: 'image/png', |
|||
size: 123, |
|||
lastModified: Date.UTC(2021, 3, 27, 15, 30, 0), |
|||
}, |
|||
{ |
|||
name: 'jpgimage.jpg', |
|||
type: 'image/jpeg', |
|||
size: 456, |
|||
lastModified: Date.UTC(2021, 3, 26, 15, 30, 0), |
|||
}, |
|||
{ |
|||
name: 'textfile.txt', |
|||
type: 'text/plain', |
|||
size: 111, |
|||
lastModified: Date.UTC(2021, 3, 25, 15, 30, 0), |
|||
}, |
|||
] |
|||
await store.dispatch('initialiseUpload', { |
|||
uploadId: 'upload-id1', |
|||
token: 'XXTOKENXX', |
|||
files, |
|||
}) |
|||
|
|||
const uploads = store.getters.getInitialisedUploads('upload-id1') |
|||
expect(Object.keys(uploads).length).toBe(3) |
|||
|
|||
for (let i = 0; i < files.length; i++) { |
|||
expect(mockedActions.createTemporaryMessage.mock.calls[i][1].text).toBe('{file}') |
|||
expect(mockedActions.createTemporaryMessage.mock.calls[i][1].uploadId).toBe('upload-id1') |
|||
expect(mockedActions.createTemporaryMessage.mock.calls[i][1].index).toBeDefined() |
|||
expect(mockedActions.createTemporaryMessage.mock.calls[i][1].file).toBe(files[i]) |
|||
expect(mockedActions.createTemporaryMessage.mock.calls[i][1].token).toBe('XXTOKENXX') |
|||
} |
|||
|
|||
expect(mockedActions.createTemporaryMessage.mock.calls[0][1].localUrl).toBe('local-url:pngimage.png') |
|||
expect(mockedActions.createTemporaryMessage.mock.calls[1][1].localUrl).toBe('local-url:jpgimage.jpg') |
|||
expect(mockedActions.createTemporaryMessage.mock.calls[2][1].localUrl).toBe('icon-url:text/plain') |
|||
}) |
|||
|
|||
test('performs upload by uploading then sharing', async() => { |
|||
const files = [ |
|||
{ |
|||
name: 'pngimage.png', |
|||
type: 'image/png', |
|||
size: 123, |
|||
lastModified: Date.UTC(2021, 3, 27, 15, 30, 0), |
|||
}, |
|||
{ |
|||
name: 'textfile.txt', |
|||
type: 'text/plain', |
|||
size: 111, |
|||
lastModified: Date.UTC(2021, 3, 25, 15, 30, 0), |
|||
}, |
|||
] |
|||
|
|||
await store.dispatch('initialiseUpload', { |
|||
uploadId: 'upload-id1', |
|||
token: 'XXTOKENXX', |
|||
files, |
|||
}) |
|||
|
|||
expect(store.getters.currentUploadId).toBe('upload-id1') |
|||
|
|||
findUniquePath |
|||
.mockResolvedValueOnce('/Talk/' + files[0].name + 'uniq') |
|||
.mockResolvedValueOnce('/Talk/' + files[1].name + 'uniq') |
|||
client.putFileContents.mockResolvedValue() |
|||
shareFile.mockResolvedValue() |
|||
|
|||
await store.dispatch('uploadFiles', 'upload-id1') |
|||
|
|||
expect(client.putFileContents).toHaveBeenCalledTimes(2) |
|||
expect(shareFile).toHaveBeenCalledTimes(2) |
|||
|
|||
for (let i = 0; i < files.length; i++) { |
|||
expect(findUniquePath).toHaveBeenCalledWith(client, '/files/current-user', '/Talk/' + files[i].name) |
|||
expect(client.putFileContents.mock.calls[i][0]).toBe('/files/current-user/Talk/' + files[i].name + 'uniq') |
|||
expect(client.putFileContents.mock.calls[i][1]).toBe(files[i]) |
|||
|
|||
expect(shareFile.mock.calls[i][0]).toBe('//Talk/' + files[i].name + 'uniq') |
|||
expect(shareFile.mock.calls[i][1]).toBe('XXTOKENXX') |
|||
expect(shareFile.mock.calls[i][2]).toBe('reference-id-' + (i + 1)) |
|||
} |
|||
|
|||
expect(mockedActions.addTemporaryMessage).toHaveBeenCalledTimes(2) |
|||
expect(store.getters.currentUploadId).not.toBeDefined() |
|||
}) |
|||
|
|||
test('marks temporary message as failed in case of upload error', async() => { |
|||
const files = [ |
|||
{ |
|||
name: 'pngimage.png', |
|||
type: 'image/png', |
|||
size: 123, |
|||
lastModified: Date.UTC(2021, 3, 27, 15, 30, 0), |
|||
}, |
|||
] |
|||
|
|||
await store.dispatch('initialiseUpload', { |
|||
uploadId: 'upload-id1', |
|||
token: 'XXTOKENXX', |
|||
files, |
|||
}) |
|||
|
|||
findUniquePath |
|||
.mockResolvedValueOnce('/Talk/' + files[0].name + 'uniq') |
|||
client.putFileContents.mockRejectedValueOnce({ |
|||
response: { |
|||
status: 403, |
|||
}, |
|||
}) |
|||
|
|||
await store.dispatch('uploadFiles', 'upload-id1') |
|||
|
|||
expect(client.putFileContents).toHaveBeenCalledTimes(1) |
|||
expect(shareFile).not.toHaveBeenCalled() |
|||
|
|||
expect(mockedActions.addTemporaryMessage).toHaveBeenCalledTimes(1) |
|||
expect(mockedActions.markTemporaryMessageAsFailed).toHaveBeenCalledTimes(1) |
|||
expect(mockedActions.markTemporaryMessageAsFailed.mock.calls[0][1].message.referenceId).toBe('reference-id-1') |
|||
expect(mockedActions.markTemporaryMessageAsFailed.mock.calls[0][1].reason).toBe('failed-upload') |
|||
expect(showError).toHaveBeenCalled() |
|||
expect(console.error).toHaveBeenCalled() |
|||
}) |
|||
|
|||
test('marks temporary message as failed in case of sharing error', async() => { |
|||
const files = [ |
|||
{ |
|||
name: 'pngimage.png', |
|||
type: 'image/png', |
|||
size: 123, |
|||
lastModified: Date.UTC(2021, 3, 27, 15, 30, 0), |
|||
}, |
|||
] |
|||
|
|||
await store.dispatch('initialiseUpload', { |
|||
uploadId: 'upload-id1', |
|||
token: 'XXTOKENXX', |
|||
files, |
|||
}) |
|||
|
|||
findUniquePath |
|||
.mockResolvedValueOnce('/Talk/' + files[0].name + 'uniq') |
|||
client.putFileContents.mockResolvedValue() |
|||
shareFile.mockRejectedValueOnce({ |
|||
response: { |
|||
status: 403, |
|||
}, |
|||
}) |
|||
|
|||
await store.dispatch('uploadFiles', 'upload-id1') |
|||
|
|||
expect(client.putFileContents).toHaveBeenCalledTimes(1) |
|||
expect(shareFile).toHaveBeenCalledTimes(1) |
|||
|
|||
expect(mockedActions.addTemporaryMessage).toHaveBeenCalledTimes(1) |
|||
expect(mockedActions.markTemporaryMessageAsFailed).toHaveBeenCalledTimes(1) |
|||
expect(mockedActions.markTemporaryMessageAsFailed.mock.calls[0][1].message.referenceId).toBe('reference-id-1') |
|||
expect(mockedActions.markTemporaryMessageAsFailed.mock.calls[0][1].reason).toBe('failed-share') |
|||
expect(showError).toHaveBeenCalled() |
|||
expect(console.error).toHaveBeenCalled() |
|||
}) |
|||
|
|||
test('removes file from selection', async() => { |
|||
const files = [ |
|||
{ |
|||
name: 'pngimage.png', |
|||
type: 'image/png', |
|||
size: 123, |
|||
lastModified: Date.UTC(2021, 3, 27, 15, 30, 0), |
|||
}, |
|||
{ |
|||
name: 'textfile.txt', |
|||
type: 'text/plain', |
|||
size: 111, |
|||
lastModified: Date.UTC(2021, 3, 25, 15, 30, 0), |
|||
}, |
|||
] |
|||
|
|||
await store.dispatch('initialiseUpload', { |
|||
uploadId: 'upload-id1', |
|||
token: 'XXTOKENXX', |
|||
files, |
|||
}) |
|||
|
|||
// temporary message mock uses incremental id
|
|||
await store.dispatch('removeFileFromSelection', 2) |
|||
|
|||
const uploads = store.getters.getInitialisedUploads('upload-id1') |
|||
expect(Object.keys(uploads).length).toBe(1) |
|||
|
|||
expect(Object.values(uploads)[0].file).toBe(files[0]) |
|||
}) |
|||
|
|||
test('discard an entire upload', async() => { |
|||
const files = [ |
|||
{ |
|||
name: 'pngimage.png', |
|||
type: 'image/png', |
|||
size: 123, |
|||
lastModified: Date.UTC(2021, 3, 27, 15, 30, 0), |
|||
}, |
|||
{ |
|||
name: 'textfile.txt', |
|||
type: 'text/plain', |
|||
size: 111, |
|||
lastModified: Date.UTC(2021, 3, 25, 15, 30, 0), |
|||
}, |
|||
] |
|||
|
|||
await store.dispatch('initialiseUpload', { |
|||
uploadId: 'upload-id1', |
|||
token: 'XXTOKENXX', |
|||
files, |
|||
}) |
|||
|
|||
await store.dispatch('discardUpload', 'upload-id1') |
|||
|
|||
const uploads = store.getters.getInitialisedUploads('upload-id1') |
|||
expect(uploads).toStrictEqual({}) |
|||
|
|||
expect(store.getters.currentUploadId).not.toBeDefined() |
|||
}) |
|||
|
|||
test('autorenames files using timestamps when requested', async() => { |
|||
const files = [ |
|||
{ |
|||
name: 'pngimage.png', |
|||
type: 'image/png', |
|||
size: 123, |
|||
lastModified: Date.UTC(2021, 3, 27, 15, 30, 0), |
|||
}, |
|||
{ |
|||
name: 'textfile.txt', |
|||
type: 'text/plain', |
|||
size: 111, |
|||
lastModified: Date.UTC(2021, 3, 25, 15, 30, 0), |
|||
}, |
|||
] |
|||
|
|||
getFileExtension |
|||
.mockReturnValueOnce('.png') |
|||
.mockReturnValueOnce('.txt') |
|||
|
|||
await store.dispatch('initialiseUpload', { |
|||
uploadId: 'upload-id1', |
|||
token: 'XXTOKENXX', |
|||
files, |
|||
rename: true, |
|||
}) |
|||
|
|||
expect(files[0].newName).toBe('20210427_153000.png') |
|||
expect(files[1].newName).toBe('20210425_153000.txt') |
|||
}) |
|||
}) |
|||
|
|||
test('set attachment folder', async() => { |
|||
store = new Vuex.Store(storeConfig) |
|||
|
|||
setAttachmentFolder.mockResolvedValue() |
|||
await store.dispatch('setAttachmentFolder', '/Talk-another') |
|||
|
|||
expect(setAttachmentFolder).toHaveBeenCalledWith('/Talk-another') |
|||
expect(store.getters.getAttachmentFolder()).toBe('/Talk-another') |
|||
}) |
|||
}) |
Write
Preview
Loading…
Cancel
Save
Reference in new issue