detection 畫框、classification 改在影像右上角疊標籤(不畫框), 並在推論面板提供即時切換解析方式與上傳 label 檔。 - 新增 InferenceOverlay 依 taskType 分派;ClassificationOverlay 用 DOM 而非 canvas,讓 CJK 排版與 aria-live 交給瀏覽器處理 - 標籤防閃爍:挑戰者需連續 3 幀居冠才切換,或信心度領先 15% 直接切; 低於門檻立即清空(顯示過期標籤比空白更糟) - 身分比對優先用 classIndex,避免換 label 檔時被誤判為換類別 - 推論設定卡片:即時切 detection/classification、上傳 .txt label、 清除 label,皆不需重燒 - classification-result 原本無條件渲染,導致 detection 模式下側欄 永遠顯示「分類結果」與空圖表,改為依 taskType 切換 - 清掉 camera-overlay 每幀執行的 debug console.log - 補 ResizeObserver stub,原本任何渲染 InferencePanel 的測試都會 在 jsdom 直接拋錯 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
47 lines
1.5 KiB
TypeScript
47 lines
1.5 KiB
TypeScript
import '@testing-library/jest-dom';
|
|
import { afterEach, vi } from 'vitest';
|
|
import { cleanup } from '@testing-library/react';
|
|
|
|
afterEach(() => {
|
|
cleanup();
|
|
});
|
|
|
|
// jsdom does not implement ResizeObserver, which Radix primitives (Slider) and
|
|
// CameraFeed rely on. A no-op stub is enough: tests assert on rendered output,
|
|
// not on resize-driven behaviour.
|
|
if (!('ResizeObserver' in globalThis)) {
|
|
class ResizeObserverStub implements ResizeObserver {
|
|
observe() {}
|
|
unobserve() {}
|
|
disconnect() {}
|
|
}
|
|
globalThis.ResizeObserver = ResizeObserverStub;
|
|
}
|
|
|
|
// jsdom implements neither the Pointer Capture API nor scrollIntoView, both of
|
|
// which Radix Select calls while opening its dropdown. Without these stubs the
|
|
// trigger throws `target.hasPointerCapture is not a function` and the listbox
|
|
// never mounts, so any test that opens a <Select> is untestable.
|
|
if (!Element.prototype.hasPointerCapture) {
|
|
Element.prototype.hasPointerCapture = () => false;
|
|
Element.prototype.setPointerCapture = () => {};
|
|
Element.prototype.releasePointerCapture = () => {};
|
|
}
|
|
if (!Element.prototype.scrollIntoView) {
|
|
Element.prototype.scrollIntoView = () => {};
|
|
}
|
|
|
|
Object.defineProperty(window, 'matchMedia', {
|
|
writable: true,
|
|
value: vi.fn().mockImplementation((query: string) => ({
|
|
matches: false,
|
|
media: query,
|
|
onchange: null,
|
|
addListener: vi.fn(),
|
|
removeListener: vi.fn(),
|
|
addEventListener: vi.fn(),
|
|
removeEventListener: vi.fn(),
|
|
dispatchEvent: vi.fn(),
|
|
})),
|
|
});
|