Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,24 @@ import { renderHook, act } from '@testing-library/react-hooks'
import { useCreateIndex } from './useCreateIndex'
import {
CreateSearchIndexParameters,
SampleDataContent,
SampleDataType,
SearchIndexType,
} from '../types'

const mockLoad = jest.fn()
const mockDispatch = jest.fn()
const mockExecute = jest.fn()
const mockAddCommands = jest.fn()

jest.mock('uiSrc/services/hooks', () => ({
useLoadData: () => ({
load: mockLoad,
}),
useDispatchWbQuery: () => mockDispatch,
useExecuteQuery: () => mockExecute,
}))

jest.mock('uiSrc/services/workbenchStorage', () => ({
addCommands: (...args: any[]) => mockAddCommands(...args),
}))

jest.mock('uiSrc/utils/index/generateFtCreateCommand', () => ({
Expand All @@ -26,18 +32,18 @@ describe('useCreateIndex', () => {
})

const defaultParams: CreateSearchIndexParameters = {
dataContent: '',
usePresetVectorIndex: true,
presetVectorIndexName: '',
tags: [],
instanceId: 'test-instance-id',
searchIndexType: SearchIndexType.REDIS_QUERY_ENGINE,
dataContent: SampleDataContent.E_COMMERCE_DISCOVERY,
sampleDataType: SampleDataType.PRESET_DATA,
searchIndexType: SearchIndexType.REDIS_QUERY_ENGINE,
usePresetVectorIndex: true,
indexName: 'bikes',
indexFields: [],
}

it('should complete flow successfully', async () => {
mockLoad.mockResolvedValue(undefined)
mockDispatch.mockImplementation((_data, { afterAll }) => afterAll?.())
mockExecute.mockResolvedValue([{ id: '1', databaseId: 'test-instance-id' }])

const { result } = renderHook(() => useCreateIndex())

Expand All @@ -46,7 +52,8 @@ describe('useCreateIndex', () => {
})

expect(mockLoad).toHaveBeenCalledWith('test-instance-id', 'bikes')
expect(mockDispatch).toHaveBeenCalled()
expect(mockExecute).toHaveBeenCalled()
expect(mockAddCommands).toHaveBeenCalled()
expect(result.current.success).toBe(true)
expect(result.current.error).toBeNull()
expect(result.current.loading).toBe(false)
Expand Down Expand Up @@ -80,22 +87,20 @@ describe('useCreateIndex', () => {
expect(result.current.loading).toBe(false)
})

it('should handle dispatch failure', async () => {
it('should handle execution failure', async () => {
mockLoad.mockResolvedValue(undefined)
mockDispatch.mockImplementation((_data, { onFail }) =>
onFail?.(new Error('Dispatch failed')),
)
mockExecute.mockRejectedValue(new Error('Execution failed'))

const { result } = renderHook(() => useCreateIndex())

await act(async () => {
await result.current.run(defaultParams)
})

expect(mockDispatch).toHaveBeenCalled()
expect(mockExecute).toHaveBeenCalled()
expect(result.current.success).toBe(false)
expect(result.current.error).toBeInstanceOf(Error)
expect(result.current.error?.message).toBe('Dispatch failed')
expect(result.current.error?.message).toBe('Execution failed')
expect(result.current.loading).toBe(false)
})
})
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { useCallback, useState } from 'react'
import { useLoadData, useDispatchWbQuery } from 'uiSrc/services/hooks'
import { reverse } from 'lodash'
import { useLoadData, useExecuteQuery } from 'uiSrc/services/hooks'
import { addCommands } from 'uiSrc/services/workbenchStorage'
import { generateFtCreateCommand } from 'uiSrc/utils/index/generateFtCreateCommand'
import { CreateSearchIndexParameters, PresetDataType } from '../types'

Expand All @@ -20,7 +22,7 @@ export const useCreateIndex = (): UseCreateIndexResult => {
const [error, setError] = useState<Error | null>(null)

const { load } = useLoadData()
const dispatchCreateIndex = useDispatchWbQuery()
const executeQuery = useExecuteQuery()

const run = useCallback(
async ({ instanceId }: CreateSearchIndexParameters) => {
Expand All @@ -40,22 +42,22 @@ export const useCreateIndex = (): UseCreateIndexResult => {
await load(instanceId, collectionName)

// Step 2: Create the search index
await new Promise<void>((resolve, reject) => {
dispatchCreateIndex(generateFtCreateCommand(), {
afterAll: () => {
setSuccess(true)
resolve()
},
onFail: reject,
})
})
const cmd = generateFtCreateCommand()
const data = await executeQuery(instanceId, cmd)

// Step 3: Persist results locally so Vector Search history (CommandsView) shows it
if (Array.isArray(data) && data.length) {
await addCommands(reverse(data))
}

setSuccess(true)
} catch (e) {
setError(e instanceof Error ? e : new Error(String(e)))
} finally {
setLoading(false)
}
},
[load, dispatchCreateIndex],
[load, executeQuery],
)

return {
Expand Down
2 changes: 1 addition & 1 deletion redisinsight/ui/src/services/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ export * from './hooks'
export * from './useWebworkers'
export * from './useCabability'
export * from './useStateWithContext'
export * from './useDispatchWbQuery'
export * from './useExecuteQuery'
export * from './useLoadData'
83 changes: 0 additions & 83 deletions redisinsight/ui/src/services/hooks/useDispatchWbQuery.spec.ts

This file was deleted.

33 changes: 0 additions & 33 deletions redisinsight/ui/src/services/hooks/useDispatchWbQuery.ts

This file was deleted.

118 changes: 118 additions & 0 deletions redisinsight/ui/src/services/hooks/useExecuteQuery.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { renderHook, act } from '@testing-library/react-hooks'
import { rest } from 'msw'
import { ApiEndpoints } from 'uiSrc/constants'
import { mswServer } from 'uiSrc/mocks/server'
import { getMswURL } from 'uiSrc/utils/test-utils'
import { getUrl } from 'uiSrc/utils'
import { RunQueryMode, ResultsMode } from 'uiSrc/slices/interfaces'

import { useExecuteQuery } from './useExecuteQuery'

describe('useExecuteQuery', () => {
const instanceId = 'test-instance-id'
const command = 'FT.CREATE idx:bikes_vss ...'

beforeEach(() => {
mswServer.resetHandlers()
jest.clearAllMocks()
})

it('should return empty array and not call API when data is null', async () => {
const { result: hookResult } = renderHook(() => useExecuteQuery())

let result: any
await act(async () => {
result = await hookResult.current(instanceId, null)
})

expect(result).toEqual([])
})

it('should return empty array and not call API when data is undefined', async () => {
const { result: hookResult } = renderHook(() => useExecuteQuery())

let result: any
await act(async () => {
result = await hookResult.current(instanceId, undefined)
})

expect(result).toEqual([])
})

it('should call API with correct parameters and return result', async () => {
const mockResponse = [{ id: '1', databaseId: instanceId }]

mswServer.use(
rest.post(
getMswURL(
getUrl(instanceId, ApiEndpoints.WORKBENCH_COMMAND_EXECUTIONS),
),
async (req, res, ctx) => {
const body = await req.json()
expect(body).toEqual({
commands: [command],
mode: RunQueryMode.ASCII,
resultsMode: ResultsMode.Default,
type: 'SEARCH',
})
return res(ctx.status(200), ctx.json(mockResponse))
},
),
)

const { result } = renderHook(() => useExecuteQuery())

let returned
await act(async () => {
returned = await result.current(instanceId, command)
})

expect(returned).toEqual(mockResponse)
})

it('should invoke afterAll callback on success', async () => {
const mockResponse = [{ id: '1', databaseId: instanceId }]

mswServer.use(
rest.post(
getMswURL(
getUrl(instanceId, ApiEndpoints.WORKBENCH_COMMAND_EXECUTIONS),
),
async (_req, res, ctx) => res(ctx.status(200), ctx.json(mockResponse)),
),
)

const afterAll = jest.fn()

const { result } = renderHook(() => useExecuteQuery())

await act(async () => {
await result.current(instanceId, command, { afterAll })
})

expect(afterAll).toHaveBeenCalled()
})

it('should invoke onFail and throw on error', async () => {
mswServer.use(
rest.post(
getMswURL(
getUrl(instanceId, ApiEndpoints.WORKBENCH_COMMAND_EXECUTIONS),
),
async (_req, res, ctx) => res(ctx.status(500)),
),
)

const onFail = jest.fn()

const { result } = renderHook(() => useExecuteQuery())

await act(async () => {
await expect(
result.current(instanceId, command, { onFail }),
).rejects.toThrow()
})

expect(onFail).toHaveBeenCalled()
})
})
Loading
Loading