Skip to content

Commit 4279e9f

Browse files
authored
test(storage-browser) Shore up action handler unit tests (#6207)
1 parent 3bedfeb commit 4279e9f

File tree

8 files changed

+432
-248
lines changed

8 files changed

+432
-248
lines changed

packages/react-storage/src/components/StorageBrowser/actions/handlers/__tests__/copy.spec.ts

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import * as StorageModule from '../../../storage-internal';
2-
1+
import { copy, CopyInput } from '../../../storage-internal';
32
import { copyHandler, CopyHandlerInput } from '../copy';
43

5-
const copySpy = jest.spyOn(StorageModule, 'copy');
4+
jest.mock('../../../storage-internal');
65

76
const baseInput: CopyHandlerInput = {
87
destinationPrefix: 'destination/',
@@ -25,8 +24,14 @@ const baseInput: CopyHandlerInput = {
2524
};
2625

2726
describe('copyHandler', () => {
27+
const mockCopy = jest.mocked(copy);
28+
29+
beforeEach(() => {
30+
mockCopy.mockResolvedValue({ path: '' });
31+
});
32+
2833
afterEach(() => {
29-
copySpy.mockClear();
34+
mockCopy.mockReset();
3035
});
3136

3237
it('calls `copy` wth the expected values', () => {
@@ -37,7 +42,7 @@ describe('copyHandler', () => {
3742
region: `${baseInput.config.region}`,
3843
};
3944

40-
const expected: StorageModule.CopyInput = {
45+
const expected: CopyInput = {
4146
destination: {
4247
expectedBucketOwner: baseInput.config.accountId,
4348
bucket,
@@ -56,7 +61,7 @@ describe('copyHandler', () => {
5661
},
5762
};
5863

59-
expect(copySpy).toHaveBeenCalledWith(expected);
64+
expect(mockCopy).toHaveBeenCalledWith(expected);
6065
});
6166

6267
it('provides eTag and notModifiedSince to copy for durableness', () => {
@@ -67,7 +72,7 @@ describe('copyHandler', () => {
6772
region: `${baseInput.config.region}`,
6873
};
6974

70-
const copyInput = copySpy.mock.lastCall?.[0];
75+
const copyInput = mockCopy.mock.lastCall?.[0];
7176
expect(copyInput).toHaveProperty('source', {
7277
expectedBucketOwner: `${baseInput.config.accountId}`,
7378
bucket,
@@ -100,6 +105,23 @@ describe('copyHandler', () => {
100105
}),
101106
});
102107

103-
expect(copySpy).toHaveBeenCalledWith(expected);
108+
expect(mockCopy).toHaveBeenCalledWith(expected);
109+
});
110+
111+
it('returns a complete status', async () => {
112+
const { result } = copyHandler(baseInput);
113+
114+
expect(await result).toEqual({ status: 'COMPLETE' });
115+
});
116+
117+
it('returns failed status', async () => {
118+
const errorMessage = 'error-message';
119+
mockCopy.mockRejectedValue(new Error(errorMessage));
120+
const { result } = copyHandler(baseInput);
121+
122+
expect(await result).toEqual({
123+
status: 'FAILED',
124+
message: errorMessage,
125+
});
104126
});
105127
});

packages/react-storage/src/components/StorageBrowser/actions/handlers/__tests__/createFolder.spec.ts

Lines changed: 36 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { createFolderHandler, CreateFolderHandlerInput } from '../createFolder';
22

3-
import * as InternalStorageModule from '../../../storage-internal';
3+
import { uploadData, UploadDataInput } from '../../../storage-internal';
44

5-
const uploadDataSpy = jest.spyOn(InternalStorageModule, 'uploadData');
5+
jest.mock('../../../storage-internal');
66

77
const credentials = jest.fn();
88

@@ -22,22 +22,28 @@ const baseInput: CreateFolderHandlerInput = {
2222
destinationPrefix: 'prefix/',
2323
};
2424

25-
const error = new Error('Failed!');
26-
2725
describe('createFolderHandler', () => {
26+
const mockUploadDataReturnValue = {
27+
cancel: jest.fn(),
28+
pause: jest.fn(),
29+
resume: jest.fn(),
30+
result: Promise.resolve({ path: '' }),
31+
state: 'SUCCESS' as const,
32+
};
33+
const mockUploadData = jest.mocked(uploadData);
34+
2835
beforeEach(() => {
2936
jest.clearAllMocks();
37+
mockUploadData.mockReturnValue(mockUploadDataReturnValue);
3038
});
3139

32-
it('behaves as expected in the happy path', async () => {
33-
uploadDataSpy.mockReturnValueOnce({
34-
cancel: jest.fn(),
35-
pause: jest.fn(),
36-
resume: jest.fn(),
37-
result: Promise.resolve({ path: '' }),
38-
state: 'SUCCESS',
39-
});
40+
afterEach(() => {
41+
mockUploadData.mockReset();
42+
});
4043

44+
beforeEach(() => {});
45+
46+
it('behaves as expected in the happy path', async () => {
4147
const { result } = createFolderHandler(baseInput);
4248

4349
expect(await result).toStrictEqual({ status: 'COMPLETE' });
@@ -46,7 +52,7 @@ describe('createFolderHandler', () => {
4652
it('calls `uploadData` with the expected values', () => {
4753
createFolderHandler({ ...baseInput, options: { preventOverwrite: true } });
4854

49-
const expected: InternalStorageModule.UploadDataInput = {
55+
const expected: UploadDataInput = {
5056
data: '',
5157
options: {
5258
expectedBucketOwner: config.accountId,
@@ -62,21 +68,14 @@ describe('createFolderHandler', () => {
6268
path: `${baseInput.destinationPrefix}${baseInput.data.key}`,
6369
};
6470

65-
expect(uploadDataSpy).toHaveBeenCalledWith(expected);
71+
expect(mockUploadData).toHaveBeenCalledWith(expected);
6672
});
6773

6874
it('calls provided onProgress callback as expected in the happy path', async () => {
69-
uploadDataSpy.mockImplementation(({ options }) => {
70-
// @ts-expect-error - `options` is potentially `undefined` in the `uploadData` input interface
71-
options.onProgress({ totalBytes: 23, transferredBytes: 23 });
72-
73-
return {
74-
cancel: jest.fn(),
75-
pause: jest.fn(),
76-
resume: jest.fn(),
77-
result: Promise.resolve({ path: '' }),
78-
state: 'SUCCESS',
79-
};
75+
mockUploadData.mockImplementation(({ options }) => {
76+
options?.onProgress?.({ totalBytes: 23, transferredBytes: 23 });
77+
78+
return mockUploadDataReturnValue;
8079
});
8180

8281
const { result } = createFolderHandler({
@@ -91,17 +90,10 @@ describe('createFolderHandler', () => {
9190
});
9291

9392
it('calls provided onProgress callback as expected when `totalBytes` is `undefined`', async () => {
94-
uploadDataSpy.mockImplementation(({ options }) => {
95-
// @ts-expect-error - `options` is potentially `undefined` in the `uploadData` input interface
96-
options.onProgress({ transferredBytes: 23 });
97-
98-
return {
99-
cancel: jest.fn(),
100-
pause: jest.fn(),
101-
resume: jest.fn(),
102-
result: Promise.resolve({ path: '' }),
103-
state: 'SUCCESS',
104-
};
93+
mockUploadData.mockImplementation(({ options }) => {
94+
options?.onProgress?.({ transferredBytes: 23 });
95+
96+
return mockUploadDataReturnValue;
10597
});
10698

10799
const { result } = createFolderHandler({
@@ -116,18 +108,18 @@ describe('createFolderHandler', () => {
116108
});
117109

118110
it('handles a failure as expected', async () => {
119-
uploadDataSpy.mockReturnValueOnce({
120-
cancel: jest.fn(),
121-
pause: jest.fn(),
122-
resume: jest.fn(),
123-
result: Promise.reject(error),
111+
const errorMessage = 'error-message';
112+
113+
mockUploadData.mockReturnValue({
114+
...mockUploadDataReturnValue,
115+
result: Promise.reject(new Error(errorMessage)),
124116
state: 'ERROR',
125117
});
126118

127119
const { result } = createFolderHandler(baseInput);
128120

129121
expect(await result).toStrictEqual({
130-
message: error.message,
122+
message: errorMessage,
131123
status: 'FAILED',
132124
});
133125
});
@@ -137,10 +129,8 @@ describe('createFolderHandler', () => {
137129
const overwritePreventedError = new Error(message);
138130
overwritePreventedError.name = 'PreconditionFailed';
139131

140-
uploadDataSpy.mockReturnValueOnce({
141-
cancel: jest.fn(),
142-
pause: jest.fn(),
143-
resume: jest.fn(),
132+
mockUploadData.mockReturnValue({
133+
...mockUploadDataReturnValue,
144134
result: Promise.reject(overwritePreventedError),
145135
state: 'ERROR',
146136
});

packages/react-storage/src/components/StorageBrowser/actions/handlers/__tests__/delete.spec.ts

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import * as StorageModule from '../../../storage-internal';
1+
import { remove, RemoveInput } from '../../../storage-internal';
22

33
import { deleteHandler, DeleteHandlerInput } from '../delete';
44

5-
const removeSpy = jest.spyOn(StorageModule, 'remove');
5+
jest.mock('../../../storage-internal');
66

77
const baseInput: DeleteHandlerInput = {
88
config: {
@@ -23,10 +23,20 @@ const baseInput: DeleteHandlerInput = {
2323
};
2424

2525
describe('deleteHandler', () => {
26+
const mockRemove = jest.mocked(remove);
27+
28+
beforeEach(() => {
29+
mockRemove.mockResolvedValue({ path: '' });
30+
});
31+
32+
afterEach(() => {
33+
mockRemove.mockReset();
34+
});
35+
2636
it('calls `remove` and returns the expected `key`', () => {
2737
deleteHandler(baseInput);
2838

29-
const expected: StorageModule.RemoveInput = {
39+
const expected: RemoveInput = {
3040
path: baseInput.data.key,
3141
options: {
3242
expectedBucketOwner: baseInput.config.accountId,
@@ -39,6 +49,23 @@ describe('deleteHandler', () => {
3949
},
4050
};
4151

42-
expect(removeSpy).toHaveBeenCalledWith(expected);
52+
expect(mockRemove).toHaveBeenCalledWith(expected);
53+
});
54+
55+
it('returns a complete status', async () => {
56+
const { result } = deleteHandler(baseInput);
57+
58+
expect(await result).toEqual({ status: 'COMPLETE' });
59+
});
60+
61+
it('returns failed status', async () => {
62+
const errorMessage = 'error-message';
63+
mockRemove.mockRejectedValue(new Error(errorMessage));
64+
const { result } = deleteHandler(baseInput);
65+
66+
expect(await result).toEqual({
67+
status: 'FAILED',
68+
message: errorMessage,
69+
});
4370
});
4471
});

packages/react-storage/src/components/StorageBrowser/actions/handlers/__tests__/download.spec.ts

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import * as StorageModule from '../../../storage-internal';
1+
import { getUrl, GetUrlInput } from '../../../storage-internal';
22

33
import { downloadHandler, DownloadHandlerInput } from '../download';
44

5-
const downloadSpy = jest.spyOn(StorageModule, 'getUrl');
5+
jest.mock('../../../storage-internal');
66

77
const baseInput: DownloadHandlerInput = {
88
config: {
@@ -23,10 +23,23 @@ const baseInput: DownloadHandlerInput = {
2323
};
2424

2525
describe('downloadHandler', () => {
26+
const url = new URL('mock://fake.url');
27+
const mockGetUrl = jest.mocked(getUrl);
28+
29+
beforeEach(() => {
30+
const expiresAt = new Date();
31+
expiresAt.setDate(expiresAt.getDate() + 1);
32+
mockGetUrl.mockResolvedValue({ expiresAt, url });
33+
});
34+
35+
afterEach(() => {
36+
mockGetUrl.mockReset();
37+
});
38+
2639
it('calls `getUrl` with the expected values', () => {
2740
downloadHandler(baseInput);
2841

29-
const expected: StorageModule.GetUrlInput = {
42+
const expected: GetUrlInput = {
3043
path: baseInput.data.key,
3144
options: {
3245
bucket: {
@@ -41,6 +54,23 @@ describe('downloadHandler', () => {
4154
},
4255
};
4356

44-
expect(downloadSpy).toHaveBeenCalledWith(expected);
57+
expect(mockGetUrl).toHaveBeenCalledWith(expected);
58+
});
59+
60+
it('returns a complete status', async () => {
61+
const { result } = downloadHandler(baseInput);
62+
63+
expect(await result).toEqual({ status: 'COMPLETE' });
64+
});
65+
66+
it('returns failed status', async () => {
67+
const errorMessage = 'error-message';
68+
mockGetUrl.mockRejectedValue(new Error(errorMessage));
69+
const { result } = downloadHandler(baseInput);
70+
71+
expect(await result).toEqual({
72+
status: 'FAILED',
73+
message: errorMessage,
74+
});
4575
});
4676
});

0 commit comments

Comments
 (0)