feat: stream challenge submissions and tidy challenge imports
This commit is contained in:
parent
8fd3c4bb64
commit
cb4cde0ed2
13 changed files with 309 additions and 93 deletions
|
|
@ -1,23 +1,33 @@
|
|||
import { submitChallengeAttempt } from '@/service/challenges'
|
||||
import { postPublic } from '@/service/base'
|
||||
import { PUBLIC_API_PREFIX } from '@/config'
|
||||
|
||||
jest.mock('@/service/base', () => ({
|
||||
getPublic: jest.fn(),
|
||||
postPublic: jest.fn(),
|
||||
}))
|
||||
|
||||
const mockedPostPublic = postPublic as jest.MockedFunction<typeof postPublic>
|
||||
const originalFetch = globalThis.fetch
|
||||
let fetchMock: jest.Mock
|
||||
let ssePostMock: jest.SpyInstance
|
||||
|
||||
jest.mock('@/service/base', () => {
|
||||
const actual = jest.requireActual('@/service/base')
|
||||
return {
|
||||
...actual,
|
||||
ssePost: jest.fn(),
|
||||
}
|
||||
})
|
||||
|
||||
jest.mock('@/app/components/share/utils', () => ({
|
||||
...jest.requireActual('@/app/components/share/utils'),
|
||||
getInitialTokenV2: () => ({ version: 2 }),
|
||||
isTokenV1: () => false,
|
||||
}))
|
||||
|
||||
describe('submitChallengeAttempt', () => {
|
||||
beforeEach(() => {
|
||||
fetchMock = jest.fn()
|
||||
globalThis.fetch = fetchMock as unknown as typeof fetch
|
||||
|
||||
mockedPostPublic.mockReset()
|
||||
mockedPostPublic.mockResolvedValue({ result: 'success' } as any)
|
||||
ssePostMock = jest.spyOn(require('@/service/base'), 'ssePost').mockImplementation((_url: string, _options: any, handlers: any) => {
|
||||
handlers.onCompleted?.()
|
||||
return Promise.resolve()
|
||||
})
|
||||
|
||||
localStorage.clear()
|
||||
})
|
||||
|
|
@ -36,7 +46,7 @@ describe('submitChallengeAttempt', () => {
|
|||
).rejects.toThrow('Challenge app is not published')
|
||||
|
||||
expect(fetchMock).not.toHaveBeenCalled()
|
||||
expect(mockedPostPublic).not.toHaveBeenCalled()
|
||||
expect(ssePostMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('requests a passport token and submits chat attempts through /chat-messages', async () => {
|
||||
|
|
@ -46,6 +56,14 @@ describe('submitChallengeAttempt', () => {
|
|||
json: jest.fn().mockResolvedValue({ access_token: passportToken }),
|
||||
})
|
||||
|
||||
ssePostMock.mockImplementation((_url, _options, handlers) => {
|
||||
handlers.getAbortController?.(new AbortController())
|
||||
handlers.onData?.('Hello', true, { messageId: 'msg-1' } as any)
|
||||
handlers.onMessageEnd?.({ metadata: { outputs: { challenge_succeeded: true }, answer: 'All good' } } as any)
|
||||
handlers.onCompleted?.()
|
||||
return Promise.resolve()
|
||||
})
|
||||
|
||||
await submitChallengeAttempt('challenge-123', 'app-abc', 'site-code-xyz', 'chat', 'solve this')
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledWith(`${PUBLIC_API_PREFIX}/passport`, {
|
||||
|
|
@ -56,14 +74,14 @@ describe('submitChallengeAttempt', () => {
|
|||
credentials: 'include',
|
||||
})
|
||||
|
||||
expect(mockedPostPublic).toHaveBeenCalledWith('/chat-messages', expect.objectContaining({
|
||||
expect(ssePostMock).toHaveBeenCalledWith('/chat-messages', expect.objectContaining({
|
||||
body: {
|
||||
query: 'solve this',
|
||||
inputs: {},
|
||||
response_mode: 'blocking',
|
||||
response_mode: 'streaming',
|
||||
conversation_id: '',
|
||||
},
|
||||
}))
|
||||
}), expect.any(Object))
|
||||
|
||||
const storedToken = JSON.parse(localStorage.getItem('token') || '{}')
|
||||
expect(storedToken.version).toBe(2)
|
||||
|
|
@ -77,6 +95,14 @@ describe('submitChallengeAttempt', () => {
|
|||
json: jest.fn().mockResolvedValue({ access_token: passportToken }),
|
||||
})
|
||||
|
||||
ssePostMock.mockImplementation((_url, _options, handlers) => {
|
||||
handlers.getAbortController?.(new AbortController())
|
||||
handlers.onTextChunk?.({ data: { text: 'partial' } } as any)
|
||||
handlers.onWorkflowFinished?.({ data: { outputs: { challenge_succeeded: false, message: 'nope' } } } as any)
|
||||
handlers.onCompleted?.()
|
||||
return Promise.resolve()
|
||||
})
|
||||
|
||||
await submitChallengeAttempt('challenge-456', 'app-def', 'site-code-xyz', 'workflow', 'my answer')
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledWith(`${PUBLIC_API_PREFIX}/passport`, {
|
||||
|
|
@ -87,14 +113,14 @@ describe('submitChallengeAttempt', () => {
|
|||
credentials: 'include',
|
||||
})
|
||||
|
||||
expect(mockedPostPublic).toHaveBeenCalledWith('/workflows/run', expect.objectContaining({
|
||||
expect(ssePostMock).toHaveBeenCalledWith('/workflows/run', expect.objectContaining({
|
||||
body: {
|
||||
inputs: {
|
||||
user_prompt: 'my answer',
|
||||
},
|
||||
response_mode: 'blocking',
|
||||
response_mode: 'streaming',
|
||||
},
|
||||
}))
|
||||
}), expect.any(Object))
|
||||
|
||||
const storedToken = JSON.parse(localStorage.getItem('token') || '{}')
|
||||
expect(storedToken['challenge-456'].DEFAULT).toBe(passportToken)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue