|
| 1 | +// Licensed to Cloudera, Inc. under one |
| 2 | +// or more contributor license agreements. See the NOTICE file |
| 3 | +// distributed with this work for additional information |
| 4 | +// regarding copyright ownership. Cloudera, Inc. licenses this file |
| 5 | +// to you under the Apache License, Version 2.0 (the |
| 6 | +// "License"); you may not use this file except in compliance |
| 7 | +// with the License. You may obtain a copy of the License at |
| 8 | +// |
| 9 | +// http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | +// |
| 11 | +// Unless required by applicable law or agreed to in writing, software |
| 12 | +// distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | +// See the License for the specific language governing permissions and |
| 15 | +// limitations under the License. |
| 16 | + |
1 | 17 | import React from 'react'; |
2 | | -import { render, screen, fireEvent, waitFor, act } from '@testing-library/react'; |
| 18 | +import { render, screen, fireEvent, waitFor, cleanup } from '@testing-library/react'; |
| 19 | +import userEvent from '@testing-library/user-event'; |
3 | 20 | import '@testing-library/jest-dom'; |
4 | 21 | import CreateAndUploadAction from './CreateAndUploadAction'; |
5 | 22 | import { CREATE_DIRECTORY_API_URL, CREATE_FILE_API_URL } from '../../../api'; |
| 23 | +import * as storageUtils from '../../../../../utils/storageBrowserUtils'; |
6 | 24 |
|
7 | 25 | const mockSave = jest.fn(); |
8 | 26 | jest.mock('../../../../../utils/hooks/useSaveData/useSaveData', () => ({ |
9 | 27 | __esModule: true, |
10 | 28 | default: jest.fn(() => ({ |
11 | | - save: mockSave |
| 29 | + save: mockSave, |
| 30 | + loading: false, |
| 31 | + error: undefined |
12 | 32 | })) |
13 | 33 | })); |
14 | 34 |
|
15 | | -jest.mock('../../../../../utils/huePubSub', () => ({ |
16 | | - __esModule: true, |
17 | | - publish: jest.fn() |
18 | | -})); |
19 | | - |
20 | 35 | describe('CreateAndUploadAction', () => { |
21 | | - const currentPath = '/some/path'; |
| 36 | + const defaultPath = '/some/path'; |
22 | 37 | const onActionSuccess = jest.fn(); |
23 | 38 | const onActionError = jest.fn(); |
24 | 39 | const mockFilesUpload = jest.fn(); |
25 | 40 |
|
26 | | - beforeEach(() => { |
27 | | - jest.clearAllMocks(); |
28 | | - |
| 41 | + const setup = (path = defaultPath) => |
29 | 42 | render( |
30 | 43 | <CreateAndUploadAction |
31 | | - currentPath={currentPath} |
| 44 | + currentPath={path} |
32 | 45 | onActionSuccess={onActionSuccess} |
33 | 46 | onFilesUpload={mockFilesUpload} |
34 | 47 | onActionError={onActionError} |
35 | 48 | /> |
36 | 49 | ); |
| 50 | + |
| 51 | + const openDropdown = async user => { |
| 52 | + await user.click(screen.getByRole('button', { name: 'New' })); |
| 53 | + }; |
| 54 | + |
| 55 | + beforeEach(() => { |
| 56 | + jest.clearAllMocks(); |
| 57 | + jest.spyOn(storageUtils, 'isS3').mockReturnValue(false); |
| 58 | + jest.spyOn(storageUtils, 'isGS').mockReturnValue(false); |
| 59 | + jest.spyOn(storageUtils, 'isABFS').mockReturnValue(false); |
| 60 | + jest.spyOn(storageUtils, 'isOFS').mockReturnValue(false); |
| 61 | + }); |
| 62 | + |
| 63 | + const clickMenuOption = async (label: string, user) => { |
| 64 | + await openDropdown(user); |
| 65 | + await user.click(screen.getByRole('menuitem', { name: label })); |
| 66 | + }; |
| 67 | + |
| 68 | + afterEach(() => { |
| 69 | + cleanup(); |
37 | 70 | }); |
38 | 71 |
|
39 | | - it('should render the dropdown with actions', async () => { |
| 72 | + it('renders the New button', () => { |
| 73 | + setup(); |
40 | 74 | const newButton = screen.getByRole('button', { name: 'New' }); |
41 | 75 | expect(newButton).toBeInTheDocument(); |
| 76 | + }); |
42 | 77 |
|
43 | | - await act(async () => fireEvent.click(newButton)); |
44 | | - |
| 78 | + it('should render the dropdown with CREATE and UPLOAD group actions', async () => { |
| 79 | + const user = userEvent.setup(); |
| 80 | + setup(); |
| 81 | + await openDropdown(user); |
45 | 82 | // Check that the "Create" and "Upload" groups are in the dropdown |
46 | 83 | expect(screen.getByText('CREATE')).toBeInTheDocument(); |
47 | 84 | expect(screen.getByText('UPLOAD')).toBeInTheDocument(); |
48 | 85 | }); |
49 | 86 |
|
50 | | - it('should open the folder creation modal when "New Folder" is clicked', async () => { |
51 | | - const newButton = screen.getByRole('button', { name: 'New' }); |
52 | | - await act(async () => fireEvent.click(newButton)); |
53 | | - |
54 | | - const newFolderButton = screen.getByRole('menuitem', { name: 'New Folder' }); |
55 | | - await act(async () => fireEvent.click(newFolderButton)); |
| 87 | + describe('create actions', () => { |
| 88 | + it.each([ |
| 89 | + { label: 'New Folder', modalTitle: 'Create Folder', api: CREATE_DIRECTORY_API_URL }, |
| 90 | + { label: 'New File', modalTitle: 'Create File', api: CREATE_FILE_API_URL } |
| 91 | + ])('opens ${label} modal and calls correct API', async ({ label, modalTitle, api }) => { |
| 92 | + const user = userEvent.setup(); |
| 93 | + setup(); |
| 94 | + await clickMenuOption(label, user); |
56 | 95 |
|
57 | | - expect(screen.getByRole('dialog', { name: 'Create Folder' })).toBeInTheDocument(); |
58 | | - }); |
| 96 | + expect(screen.getByText(modalTitle)).toBeInTheDocument(); |
59 | 97 |
|
60 | | - it('should open the file creation modal when "New File" is clicked', async () => { |
61 | | - const newButton = screen.getByRole('button', { name: 'New' }); |
62 | | - await act(async () => fireEvent.click(newButton)); |
| 98 | + const input = screen.getByRole('textbox'); |
| 99 | + fireEvent.change(input, { target: { value: `Test ${label}` } }); |
63 | 100 |
|
64 | | - const newFileButton = screen.getByRole('menuitem', { name: 'New File' }); |
65 | | - await act(async () => fireEvent.click(newFileButton)); |
| 101 | + fireEvent.click(screen.getByRole('button', { name: 'Create' })); |
66 | 102 |
|
67 | | - expect(screen.getByRole('dialog', { name: 'Create File' })).toBeInTheDocument(); |
| 103 | + await waitFor(() => { |
| 104 | + expect(mockSave).toHaveBeenCalledWith( |
| 105 | + { path: defaultPath, name: `Test ${label}` }, |
| 106 | + { url: api } |
| 107 | + ); |
| 108 | + }); |
| 109 | + }); |
68 | 110 | }); |
69 | 111 |
|
70 | | - it('should render hidden file input for upload functionality', async () => { |
71 | | - const fileInput = document.querySelector('input[type="file"]'); |
72 | | - expect(fileInput).toBeInTheDocument(); |
73 | | - expect(fileInput).toHaveAttribute('hidden'); |
74 | | - expect(fileInput).toHaveAttribute('multiple'); |
75 | | - }); |
| 112 | + describe('upload actions', () => { |
| 113 | + it('should render hidden file input for upload functionality', async () => { |
| 114 | + setup(); |
| 115 | + const fileInput = document.querySelector('input[type="file"]'); |
| 116 | + expect(fileInput).toBeInTheDocument(); |
| 117 | + expect(fileInput).toHaveAttribute('hidden'); |
| 118 | + expect(fileInput).toHaveAttribute('multiple'); |
| 119 | + }); |
76 | 120 |
|
77 | | - it('should handle file selection and call onFilesUpload', async () => { |
78 | | - const fileInput = document.querySelector('input[type="file"]'); |
79 | | - expect(fileInput).toBeInTheDocument(); |
| 121 | + it('should handle file selection and call onFilesUpload', async () => { |
| 122 | + setup(); |
| 123 | + const fileInput = document.querySelector('input[type="file"]'); |
| 124 | + expect(fileInput).toBeInTheDocument(); |
80 | 125 |
|
81 | | - const file1 = new File(['test content 1'], 'test1.txt', { type: 'text/plain' }); |
82 | | - const file2 = new File(['test content 2'], 'test2.txt', { type: 'text/plain' }); |
| 126 | + const file1 = new File(['test content 1'], 'test1.txt', { type: 'text/plain' }); |
| 127 | + const file2 = new File(['test content 2'], 'test2.txt', { type: 'text/plain' }); |
83 | 128 |
|
84 | | - fireEvent.change(fileInput!, { |
85 | | - target: { files: [file1, file2] } |
86 | | - }); |
| 129 | + fireEvent.change(fileInput!, { |
| 130 | + target: { files: [file1, file2] } |
| 131 | + }); |
87 | 132 |
|
88 | | - expect(mockFilesUpload).toHaveBeenCalledWith([file1, file2]); |
| 133 | + expect(mockFilesUpload).toHaveBeenCalledWith([file1, file2]); |
| 134 | + }); |
89 | 135 | }); |
90 | 136 |
|
91 | | - it('should call the correct API for creating a folder', async () => { |
92 | | - const newButton = screen.getByRole('button', { name: 'New' }); |
93 | | - await act(async () => fireEvent.click(newButton)); |
| 137 | + describe('storage-specific actions', () => { |
| 138 | + it('shows New Bucket when S3 root', async () => { |
| 139 | + const user = userEvent.setup(); |
| 140 | + jest.spyOn(storageUtils, 'isS3').mockReturnValue(true); |
| 141 | + jest.spyOn(storageUtils, 'isS3Root').mockReturnValue(true); |
94 | 142 |
|
95 | | - const newFolderButton = screen.getByRole('menuitem', { name: 'New Folder' }); |
96 | | - await act(async () => fireEvent.click(newFolderButton)); |
| 143 | + setup('/'); |
| 144 | + await openDropdown(user); |
| 145 | + expect(screen.getByRole('menuitem', { name: 'New Bucket' })).toBeInTheDocument(); |
| 146 | + }); |
| 147 | + |
| 148 | + it('shows New Bucket when OFS root', async () => { |
| 149 | + const user = userEvent.setup(); |
| 150 | + jest.spyOn(storageUtils, 'isOFS').mockReturnValue(true); |
| 151 | + jest.spyOn(storageUtils, 'isOFSRoot').mockReturnValue(true); |
97 | 152 |
|
98 | | - const input = screen.getByRole('textbox'); |
99 | | - fireEvent.change(input, { target: { value: 'Test Folder' } }); |
| 153 | + setup('/'); |
| 154 | + await openDropdown(user); |
| 155 | + expect(screen.getByRole('menuitem', { name: 'New Bucket' })).toBeInTheDocument(); |
| 156 | + }); |
100 | 157 |
|
101 | | - const createButton = screen.getByRole('button', { name: 'Create' }); |
102 | | - fireEvent.click(createButton); |
| 158 | + it('does not show New Bucket when not in S3 root', async () => { |
| 159 | + const user = userEvent.setup(); |
| 160 | + jest.spyOn(storageUtils, 'isS3').mockReturnValue(true); |
| 161 | + jest.spyOn(storageUtils, 'isS3Root').mockReturnValue(false); |
103 | 162 |
|
104 | | - await waitFor(() => { |
105 | | - expect(mockSave).toHaveBeenCalledWith( |
106 | | - { path: currentPath, name: 'Test Folder' }, |
107 | | - { url: CREATE_DIRECTORY_API_URL } |
108 | | - ); |
| 163 | + setup('s3://user'); |
| 164 | + await openDropdown(user); |
| 165 | + expect(screen.queryByRole('menuitem', { name: 'New Bucket' })).not.toBeInTheDocument(); |
109 | 166 | }); |
110 | | - }); |
111 | 167 |
|
112 | | - it('should call the correct API for creating a file', async () => { |
113 | | - const newButton = screen.getByRole('button', { name: 'New' }); |
114 | | - await act(async () => fireEvent.click(newButton)); |
| 168 | + it('shows New File System when ABFS root', async () => { |
| 169 | + const user = userEvent.setup(); |
| 170 | + jest.spyOn(storageUtils, 'isABFS').mockReturnValue(true); |
| 171 | + jest.spyOn(storageUtils, 'isABFSRoot').mockReturnValue(true); |
| 172 | + |
| 173 | + setup('/'); |
| 174 | + await openDropdown(user); |
| 175 | + expect(screen.getByRole('menuitem', { name: 'New File System' })).toBeInTheDocument(); |
| 176 | + }); |
115 | 177 |
|
116 | | - const newFileButton = screen.getByRole('menuitem', { name: 'New File' }); |
117 | | - await act(async () => fireEvent.click(newFileButton)); |
| 178 | + it('shows New Volume when OFS service ID', async () => { |
| 179 | + const user = userEvent.setup(); |
| 180 | + jest.spyOn(storageUtils, 'isOFS').mockReturnValue(true); |
| 181 | + jest.spyOn(storageUtils, 'isOFSServiceID').mockReturnValue(true); |
118 | 182 |
|
119 | | - // Simulate file name submission |
120 | | - const input = screen.getByRole('textbox'); |
121 | | - fireEvent.change(input, { target: { value: 'Test File' } }); |
| 183 | + setup('/ofs-service'); |
| 184 | + await openDropdown(user); |
| 185 | + expect(screen.getByRole('menuitem', { name: 'New Volume' })).toBeInTheDocument(); |
| 186 | + }); |
122 | 187 |
|
123 | | - const createButton = screen.getByRole('button', { name: 'Create' }); |
124 | | - fireEvent.click(createButton); |
| 188 | + it('does not show New Volume when OFS service ID', async () => { |
| 189 | + const user = userEvent.setup(); |
| 190 | + jest.spyOn(storageUtils, 'isOFS').mockReturnValue(true); |
| 191 | + jest.spyOn(storageUtils, 'isOFSServiceID').mockReturnValue(false); |
125 | 192 |
|
126 | | - await waitFor(() => { |
127 | | - expect(mockSave).toHaveBeenCalledWith( |
128 | | - { path: currentPath, name: 'Test File' }, |
129 | | - { url: CREATE_FILE_API_URL } |
130 | | - ); |
| 193 | + setup('/ofs-service'); |
| 194 | + await openDropdown(user); |
| 195 | + expect(screen.queryByRole('menuitem', { name: 'New Volume' })).not.toBeInTheDocument(); |
131 | 196 | }); |
132 | 197 | }); |
133 | 198 | }); |
0 commit comments