mirror of
https://github.com/stablyai/orca.git
synced 2026-09-23 16:02:24 +00:00
fix: time out stalled feedback submissions (#3778)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const { fetchMock, handlers } = vi.hoisted(() => ({
|
||||
fetchMock: vi.fn(),
|
||||
@@ -29,11 +29,16 @@ function postedBody(): Record<string, unknown> {
|
||||
|
||||
describe('submitFeedback', () => {
|
||||
beforeEach(() => {
|
||||
vi.useRealTimers()
|
||||
handlers.clear()
|
||||
fetchMock.mockReset()
|
||||
fetchMock.mockResolvedValue(okResponse())
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers()
|
||||
})
|
||||
|
||||
it('strips GitHub identity and anonymous contact fields when submitted anonymously', async () => {
|
||||
const anonymousArgs = {
|
||||
feedback: 'private bug report',
|
||||
@@ -94,6 +99,29 @@ describe('submitFeedback', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('falls back when the primary feedback request stalls', async () => {
|
||||
vi.useFakeTimers()
|
||||
fetchMock.mockImplementation((url: string, init?: RequestInit) => {
|
||||
if (url.includes('api.onorca.dev')) {
|
||||
return new Promise((_resolve, reject) => {
|
||||
init?.signal?.addEventListener('abort', () => reject(new Error('request aborted')))
|
||||
})
|
||||
}
|
||||
return Promise.resolve(okResponse())
|
||||
})
|
||||
|
||||
const result = submitFeedback({
|
||||
feedback: 'stalled primary',
|
||||
submitAnonymously: false,
|
||||
githubLogin: 'trusted-user',
|
||||
githubEmail: 'trusted@example.com'
|
||||
})
|
||||
await vi.advanceTimersByTimeAsync(10_000)
|
||||
|
||||
await expect(Promise.race([result, Promise.resolve('pending')])).resolves.toEqual({ ok: true })
|
||||
expect(fetchMock).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
it('forces renderer IPC submissions onto the feedback lane', async () => {
|
||||
registerFeedbackHandlers()
|
||||
await handlers.get('feedback:submit')?.(null, {
|
||||
|
||||
@@ -8,6 +8,7 @@ import { app, ipcMain, net } from 'electron'
|
||||
// same pattern used by updater-changelog.ts and updater-nudge.ts.
|
||||
const FEEDBACK_API_URL = 'https://api.onorca.dev/v1/feedback'
|
||||
const FEEDBACK_API_FALLBACK_URL = 'https://www.onorca.dev/v1/feedback'
|
||||
const FEEDBACK_REQUEST_TIMEOUT_MS = 10_000
|
||||
|
||||
export type FeedbackSubmissionType = 'feedback' | 'crash'
|
||||
|
||||
@@ -61,11 +62,20 @@ function buildSubmitBody(args: InternalFeedbackSubmitArgs): FeedbackSubmitBody {
|
||||
}
|
||||
|
||||
async function postFeedback(url: string, body: FeedbackSubmitBody): Promise<Response> {
|
||||
return net.fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body)
|
||||
})
|
||||
const controller = new AbortController()
|
||||
// Why: a silent feedback endpoint should not leave IPC or crash-report
|
||||
// submission flows pending forever.
|
||||
const timeout = setTimeout(() => controller.abort(), FEEDBACK_REQUEST_TIMEOUT_MS)
|
||||
try {
|
||||
return await net.fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body),
|
||||
signal: controller.signal
|
||||
})
|
||||
} finally {
|
||||
clearTimeout(timeout)
|
||||
}
|
||||
}
|
||||
|
||||
export async function submitFeedback(
|
||||
|
||||
Reference in New Issue
Block a user