mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix: make OCR portable and reliable across AMD64 and ARM64 (#519)
* fix: make OCR portable and reliable * fix: harden OCR installation portability * fix: pin OCR partials across downloads * fix: make OCR execution reliably asynchronous * fix: harden OCR portability and docs routes * fix: preserve decoder and docs safeguards
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import "@testing-library/jest-dom/vitest";
|
||||
import type { FeatureBundleState } from "@snapotter/shared";
|
||||
import { cleanup, fireEvent, render, screen } from "@testing-library/react";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const useAuth = vi.hoisted(() => vi.fn());
|
||||
const processFiles = vi.hoisted(() => vi.fn());
|
||||
const processAllFiles = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("@/hooks/use-auth", () => ({ useAuth }));
|
||||
vi.mock("@/hooks/use-tool-processor", () => ({
|
||||
useToolProcessor: () => ({
|
||||
processFiles,
|
||||
processAllFiles,
|
||||
processing: false,
|
||||
error: null,
|
||||
downloadUrl: null,
|
||||
progress: null,
|
||||
}),
|
||||
}));
|
||||
|
||||
import { OcrPdfSettings } from "@/components/tools/ocr-pdf-settings";
|
||||
import { OcrSettings } from "@/components/tools/ocr-settings";
|
||||
import { useFeaturesStore } from "@/stores/features-store";
|
||||
import { useFileStore } from "@/stores/file-store";
|
||||
|
||||
function fastOnlyOcrBundle(): FeatureBundleState {
|
||||
return {
|
||||
id: "ocr",
|
||||
name: "OCR",
|
||||
description: "Accurate local OCR",
|
||||
status: "not_installed",
|
||||
installedVersion: null,
|
||||
estimatedSize: "~300 MB",
|
||||
downloadBytes: 293_502_277,
|
||||
missingDownloadBytes: 293_502_277,
|
||||
compatibility: "compatible",
|
||||
compatibilityReason: "descriptor-missing",
|
||||
selectedTarget: "linux-amd64-cpu-py312",
|
||||
healthyGeneration: null,
|
||||
availableQualities: ["fast"],
|
||||
enablesTools: ["ocr", "ocr-pdf"],
|
||||
progress: null,
|
||||
error: null,
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
useAuth.mockReturnValue({ hasPermission: () => true });
|
||||
useFeaturesStore.setState({
|
||||
bundles: [fastOnlyOcrBundle()],
|
||||
loaded: true,
|
||||
loadError: false,
|
||||
installing: {},
|
||||
errors: {},
|
||||
queued: [],
|
||||
installAllActive: false,
|
||||
startTimes: {},
|
||||
installBundle: vi.fn(),
|
||||
});
|
||||
useFileStore.setState({
|
||||
files: [new File(["input"], "input.png", { type: "image/png" })],
|
||||
processing: false,
|
||||
error: null,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
useFileStore.setState({ files: [], processing: false, error: null });
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
function expectKoreanAccuratePackContract(submit: HTMLElement) {
|
||||
expect(screen.getByRole("button", { name: "Fast" })).toBeDisabled();
|
||||
expect(screen.getByRole("button", { name: "Fast" })).toHaveAccessibleDescription(
|
||||
/does not support Korean.*Accurate OCR pack.*Balanced or Best/i,
|
||||
);
|
||||
expect(screen.getByRole("button", { name: "Best" })).toHaveAttribute("aria-pressed", "true");
|
||||
expect(screen.getByRole("button", { name: /Enable OCR/ })).toBeInTheDocument();
|
||||
expect(submit).toBeDisabled();
|
||||
}
|
||||
|
||||
describe("Korean OCR settings", () => {
|
||||
it("enforces the accurate-pack contract in the image OCR form and restores Fast", () => {
|
||||
render(<OcrSettings />);
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: /Language/i }));
|
||||
const language = screen.getByRole("combobox");
|
||||
const submit = screen.getByTestId("ocr-submit");
|
||||
|
||||
fireEvent.change(language, { target: { value: "ko" } });
|
||||
expectKoreanAccuratePackContract(submit);
|
||||
|
||||
fireEvent.change(language, { target: { value: "en" } });
|
||||
expect(screen.getByRole("button", { name: "Fast" })).toBeEnabled();
|
||||
expect(screen.getByRole("button", { name: "Fast" })).toHaveAttribute("aria-pressed", "true");
|
||||
expect(submit).toBeEnabled();
|
||||
});
|
||||
|
||||
it("enforces the accurate-pack contract in the PDF OCR form and restores Fast", () => {
|
||||
render(<OcrPdfSettings />);
|
||||
|
||||
const language = screen.getByLabelText("Language");
|
||||
const submit = screen.getByRole("button", { name: "Extract Text" });
|
||||
|
||||
fireEvent.change(language, { target: { value: "ko" } });
|
||||
expectKoreanAccuratePackContract(submit);
|
||||
|
||||
fireEvent.change(language, { target: { value: "en" } });
|
||||
expect(screen.getByRole("button", { name: "Fast" })).toBeEnabled();
|
||||
expect(screen.getByRole("button", { name: "Fast" })).toHaveAttribute("aria-pressed", "true");
|
||||
expect(submit).toBeEnabled();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user