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() } 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})) })