Files
floci-ui/packages/frontend/src/components/StorageObjectBrowser.test.tsx
T
2026-10-23 10:12:41 -04:00

134 lines
5.9 KiB
TypeScript

import {QueryClient, QueryClientProvider} from '@tanstack/react-query'
import {render, screen, waitFor} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import {expect, test, vi} from 'vitest'
import {StorageObjectBrowser} from './StorageObjectBrowser'
import type {CloudResource} from '@/types/resource'
const apiMocks = vi.hoisted(() => ({
copyStorageObject: vi.fn(),
createCloudResource: vi.fn(),
deleteStorageObject: vi.fn(),
listCloudResources: vi.fn(),
listStorageObjects: vi.fn(),
storageObjectDownloadUrl: vi.fn(),
uploadStorageObject: vi.fn(),
}))
vi.mock('@/api/cloudProxyClient', () => apiMocks)
const bucket: CloudResource = {
id: 'incoming-orders', name: 'incoming-orders', cloud: 'aws', service: 'storage', type: 'bucket',
region: null, createdAt: null, metadata: {},
}
test('deletes a folder and all nested objects', async () => {
apiMocks.listStorageObjects.mockImplementation((_cloud: string, _bucket: string, prefix: string) => {
if (prefix === 'orders/') {
return Promise.resolve({prefix, objects: [{
key: 'orders/order.json', name: 'order.json', type: 'object', size: 10, lastModified: null, metadata: {},
}]})
}
return Promise.resolve({prefix, objects: [{
key: 'orders/', name: 'orders', type: 'folder', size: null, lastModified: null, metadata: {},
}]})
})
apiMocks.deleteStorageObject.mockResolvedValue(undefined)
const user = userEvent.setup()
const queryClient = new QueryClient({defaultOptions: {queries: {retry: false}}})
render(
<QueryClientProvider client={queryClient}>
<StorageObjectBrowser cloud="aws" resource={bucket} runtimeReachable capabilities={['delete']} onSelectObject={() => {}}/>
</QueryClientProvider>,
)
await user.click(await screen.findByRole('button', {name: 'Delete orders folder'}))
await user.click(screen.getByRole('button', {name: 'Delete folder'}))
await waitFor(() => {
expect(apiMocks.deleteStorageObject).toHaveBeenCalledWith('aws', 'incoming-orders', 'orders/order.json')
expect(apiMocks.deleteStorageObject).toHaveBeenCalledWith('aws', 'incoming-orders', 'orders/')
})
})
test('requires the bucket name before emptying all folder contents', async () => {
apiMocks.listStorageObjects.mockImplementation((_cloud: string, _bucket: string, prefix: string) => {
if (prefix === 'orders/') {
return Promise.resolve({prefix, objects: [{
key: 'orders/order.json', name: 'order.json', type: 'object', size: 10, lastModified: null, metadata: {},
}]})
}
return Promise.resolve({prefix, objects: [{
key: 'orders/', name: 'orders', type: 'folder', size: null, lastModified: null, metadata: {},
}]})
})
apiMocks.deleteStorageObject.mockResolvedValue(undefined)
const user = userEvent.setup()
const queryClient = new QueryClient({defaultOptions: {queries: {retry: false}}})
render(
<QueryClientProvider client={queryClient}>
<StorageObjectBrowser cloud="aws" resource={bucket} runtimeReachable capabilities={['delete']} onSelectObject={() => {}}/>
</QueryClientProvider>,
)
await user.click(await screen.findByRole('button', {name: 'Empty bucket'}))
expect(screen.getAllByRole('button', {name: /^Empty bucket$/})[1]).toBeDisabled()
await user.type(screen.getByPlaceholderText('incoming-orders'), 'incoming-orders')
await user.click(screen.getAllByRole('button', {name: /^Empty bucket$/})[1])
await waitFor(() => {
expect(apiMocks.deleteStorageObject).toHaveBeenCalledWith('aws', 'incoming-orders', 'orders/order.json')
expect(apiMocks.deleteStorageObject).toHaveBeenCalledWith('aws', 'incoming-orders', 'orders/')
})
})
test('shows an object extension instead of a generic object type', async () => {
apiMocks.listStorageObjects.mockResolvedValue({prefix: '', objects: [{
key: 'orders/order.json', name: 'order.json', type: 'object', size: 10, lastModified: null, metadata: {},
}]})
const queryClient = new QueryClient({defaultOptions: {queries: {retry: false}}})
render(
<QueryClientProvider client={queryClient}>
<StorageObjectBrowser cloud="aws" resource={bucket} runtimeReachable capabilities={['delete']} onSelectObject={() => {}}/>
</QueryClientProvider>,
)
expect(await screen.findByText('JSON file')).toBeInTheDocument()
})
test('offers a copy action for the AWS bucket name', async () => {
apiMocks.listStorageObjects.mockResolvedValue({prefix: '', objects: []})
const queryClient = new QueryClient({defaultOptions: {queries: {retry: false}}})
render(
<QueryClientProvider client={queryClient}>
<StorageObjectBrowser cloud="aws" resource={bucket} runtimeReachable capabilities={[]} onSelectObject={() => {}}/>
</QueryClientProvider>,
)
expect(await screen.findByRole('button', {name: 'Copy Bucket name'})).toBeInTheDocument()
})
test('opens the object action with copy selected', async () => {
apiMocks.listStorageObjects.mockResolvedValue({prefix: '', objects: [{
key: 'orders/order.json', name: 'order.json', type: 'object', size: 10, lastModified: null, metadata: {},
}]})
apiMocks.listCloudResources.mockResolvedValue([bucket])
const user = userEvent.setup()
const queryClient = new QueryClient({defaultOptions: {queries: {retry: false}}})
render(
<QueryClientProvider client={queryClient}>
<StorageObjectBrowser cloud="aws" resource={bucket} runtimeReachable capabilities={['copy']} onSelectObject={() => {}}/>
</QueryClientProvider>,
)
await user.click(await screen.findByRole('button', {name: 'Copy or move order.json'}))
const copyTab = screen.getAllByRole('button', {name: 'Copy'}).find((button) => button.classList.contains('drawer-tab'))
expect(copyTab).toHaveClass('active')
})