72 lines
3.8 KiB
TypeScript
72 lines
3.8 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 {RedisDataExplorer} from './RedisDataExplorer'
|
|
import type {CloudResource} from '@/types/resource'
|
|
|
|
const apiMocks = vi.hoisted(() => ({
|
|
connectRedis: vi.fn(),
|
|
scanRedisKeys: vi.fn(),
|
|
getRedisKeyDetails: vi.fn(),
|
|
setRedisString: vi.fn(),
|
|
deleteRedisKey: vi.fn(),
|
|
}))
|
|
|
|
vi.mock('@/api/elasticacheClient', () => apiMocks)
|
|
|
|
const cache: CloudResource = {
|
|
id: 'orders', name: 'orders', cloud: 'aws', service: 'elasticache', type: 'replication-group',
|
|
region: 'us-east-1', createdAt: null, engine: 'redis', metadata: {},
|
|
}
|
|
|
|
function renderExplorer() {
|
|
const queryClient = new QueryClient({defaultOptions: {queries: {retry: false}}})
|
|
return render(<QueryClientProvider client={queryClient}><RedisDataExplorer resource={cache} runtimeReachable/></QueryClientProvider>)
|
|
}
|
|
|
|
test('connects, scans matching keys, and inspects a typed value', async () => {
|
|
apiMocks.connectRedis.mockResolvedValue({ping: 'PONG', target: {engine: 'redis', endpoint: {address: 'redis.local', port: 6379, kind: 'primary'}}})
|
|
apiMocks.scanRedisKeys.mockResolvedValue({cursor: '0', keys: ['order:1']})
|
|
apiMocks.getRedisKeyDetails.mockResolvedValue({key: 'order:1', type: 'hash', ttlSeconds: 60, value: {status: 'new'}})
|
|
const user = userEvent.setup()
|
|
renderExplorer()
|
|
|
|
await user.type(screen.getByLabelText('Redis username'), 'app')
|
|
await user.type(screen.getByLabelText('Redis password'), 'secret')
|
|
await user.click(screen.getByRole('button', {name: 'Connect and ping'}))
|
|
await screen.findByText('redis.local:6379 (primary)')
|
|
expect(apiMocks.connectRedis).toHaveBeenCalledWith({resourceId: 'orders', credentials: {username: 'app', password: 'secret'}})
|
|
|
|
await user.type(screen.getByLabelText('Key match pattern'), 'order:*')
|
|
await user.click(screen.getByRole('button', {name: 'Scan keys'}))
|
|
expect(await screen.findByText('order:1')).toBeInTheDocument()
|
|
expect(apiMocks.scanRedisKeys).toHaveBeenCalledWith({resourceId: 'orders', credentials: {username: 'app', password: 'secret'}, match: 'order:*'})
|
|
|
|
await user.click(screen.getByRole('button', {name: 'order:1'}))
|
|
await screen.findByText('hash · 60s TTL')
|
|
expect(screen.getByText(/"status": "new"/)).toBeInTheDocument()
|
|
})
|
|
|
|
test('sets a string with a TTL and deletes the selected key', async () => {
|
|
apiMocks.connectRedis.mockResolvedValue({ping: 'PONG', target: {engine: 'valkey', endpoint: {address: 'cache.local', port: 6379, kind: 'configuration'}}})
|
|
apiMocks.scanRedisKeys.mockResolvedValue({cursor: '0', keys: ['order:1']})
|
|
apiMocks.getRedisKeyDetails.mockResolvedValue({key: 'order:1', type: 'string', ttlSeconds: -1, value: 'pending'})
|
|
apiMocks.setRedisString.mockResolvedValue({ok: true})
|
|
apiMocks.deleteRedisKey.mockResolvedValue({deleted: true})
|
|
const user = userEvent.setup()
|
|
renderExplorer()
|
|
|
|
await user.click(screen.getByRole('button', {name: 'Connect and ping'}))
|
|
await user.click(screen.getByRole('button', {name: 'Scan keys'}))
|
|
await user.click(await screen.findByRole('button', {name: 'order:1'}))
|
|
await user.click(await screen.findByRole('button', {name: 'Delete key'}))
|
|
await waitFor(() => expect(apiMocks.deleteRedisKey).toHaveBeenCalledWith({resourceId: 'orders', key: 'order:1'}))
|
|
|
|
await user.type(screen.getByLabelText('New Redis key'), 'order:2')
|
|
await user.type(screen.getByLabelText('New Redis value'), 'created')
|
|
await user.type(screen.getByLabelText('TTL seconds'), '30')
|
|
await user.click(screen.getByRole('button', {name: 'Set string'}))
|
|
await waitFor(() => expect(apiMocks.setRedisString).toHaveBeenCalledWith({resourceId: 'orders', key: 'order:2', value: 'created', ttlSeconds: 30}))
|
|
})
|