223 lines
6.5 KiB
TypeScript
223 lines
6.5 KiB
TypeScript
import React, { Dispatch } from "react";
|
|
import { render, screen, fireEvent, act } from "@testing-library/react-native";
|
|
import SettingsComponent from "@/components/Settings";
|
|
import { language_matrix } from "@/app/i18n/api";
|
|
import { Settings } from "@/app/lib/settings";
|
|
import { getDb, migrateDb } from "@/app/lib/db";
|
|
import { Knex } from "knex";
|
|
import { WhisperFile } from "@/app/lib/whisper";
|
|
import { SQLiteDatabase } from "expo-sqlite";
|
|
|
|
const RENDER_TIME = 1000;
|
|
|
|
jest.mock("@/app/lib/whisper", () => {
|
|
const originalModule = jest.requireActual("@/app/lib/whisper");
|
|
|
|
return {
|
|
...originalModule,
|
|
WhisperFile: jest.fn().mockImplementation((tag, targetFileName, label, size) => ({
|
|
tag,
|
|
targetFileName,
|
|
label,
|
|
size,
|
|
doesTargetExist: jest.fn(),
|
|
getDownloadStatus: jest.fn(), // Mock other methods as needed
|
|
isDownloadComplete: jest.fn(() => false), // Initially assume download is not complete
|
|
createDownloadResumable: jest.fn().mockResolvedValue({
|
|
startAsync: jest.fn().mockResolvedValue({}),
|
|
}),
|
|
})),
|
|
};
|
|
});
|
|
|
|
jest.mock("expo-file-system", () => {
|
|
const originalModule = jest.requireActual("expo-file-system");
|
|
|
|
return {
|
|
...originalModule,
|
|
File: jest.fn().mockImplementation(() => ({
|
|
bytes: jest.fn(),
|
|
exists: jest.fn(),
|
|
})),
|
|
};
|
|
});
|
|
|
|
jest.mock("@/app/i18n/api", () => {
|
|
const LanguageServer = jest.fn();
|
|
const Translator = jest.fn();
|
|
|
|
// Mock the fetchLanguages method to return a predefined language matrix
|
|
LanguageServer.prototype.fetchLanguages = jest.fn(() => ({
|
|
en: {
|
|
code: "en",
|
|
name: "English",
|
|
targets: ["fr", "es"],
|
|
},
|
|
fr: {
|
|
code: "fr",
|
|
name: "French",
|
|
targets: ["en", "es"],
|
|
},
|
|
es: {
|
|
code: "es",
|
|
name: "Spanish",
|
|
targets: ["en", "fr"],
|
|
},
|
|
} as language_matrix));
|
|
|
|
// Mock the translate method
|
|
Translator.prototype.translate = jest.fn((text: string, target: string) => {
|
|
return "Hola, como estas?";
|
|
});
|
|
|
|
return {
|
|
LanguageServer,
|
|
Translator,
|
|
};
|
|
});
|
|
|
|
|
|
describe("SettingsComponent", () => {
|
|
let db: SQLiteDatabase;
|
|
let settings: Settings;
|
|
|
|
beforeEach(async () => {
|
|
db = await getDb("development");
|
|
await migrateDb("development");
|
|
settings = new Settings(db);
|
|
jest.spyOn(Settings, 'getDefault').mockResolvedValue(settings);
|
|
await settings.setHostLanguage("en");
|
|
await settings.setLibretranslateBaseUrl("https://example.com");
|
|
});
|
|
|
|
afterEach(async () => {
|
|
jest.restoreAllMocks();
|
|
await migrateDb("development", "down");
|
|
});
|
|
|
|
beforeAll(async () => {
|
|
jest.useFakeTimers();
|
|
});
|
|
|
|
afterAll(() => {
|
|
jest.useRealTimers();
|
|
});
|
|
|
|
test("renders correctly with initial settings", async () => {
|
|
render(<SettingsComponent />);
|
|
screen.debug();
|
|
|
|
// Wait for the component to fetch and display the initial settings
|
|
await screen.findByText(/Host Language:/i);
|
|
await screen.findByText(/LibreTranslate Base URL:/i);
|
|
|
|
// expect(screen.getByDisplayValue("English")).toBeTruthy();
|
|
expect(
|
|
screen.getByAccessibilityHint("libretranslate base url")
|
|
).toBeTruthy();
|
|
});
|
|
|
|
test("updates host language setting when input changes", async () => {
|
|
render(<SettingsComponent />);
|
|
|
|
// Wait for the component to fetch and display the initial settings
|
|
await screen.findByText(/Host Language:/i);
|
|
await screen.findByText(/LibreTranslate Base URL:/i);
|
|
|
|
// Change the host language input value
|
|
const picker = screen.getByAccessibilityHint("host language");
|
|
fireEvent(picker, "onvalueChange", "es");
|
|
expect(picker.props.selectedIndex).toStrictEqual(0);
|
|
});
|
|
|
|
test("updates LibreTranslate base URL setting when input changes", async () => {
|
|
render(<SettingsComponent />);
|
|
|
|
jest.advanceTimersByTime(RENDER_TIME);
|
|
screen.debug();
|
|
|
|
// Wait for the component to fetch and display the initial settings
|
|
await screen.findByText(/Host Language:/i);
|
|
await screen.findByText(/LibreTranslate Base URL:/i);
|
|
|
|
// Change the LibreTranslate base URL input value
|
|
fireEvent.changeText(
|
|
screen.getByAccessibilityHint("libretranslate base url"),
|
|
"http://new-example.com"
|
|
);
|
|
jest.advanceTimersByTime(RENDER_TIME);
|
|
|
|
expect(
|
|
screen.getByAccessibilityHint("libretranslate base url")
|
|
).toBeTruthy();
|
|
});
|
|
|
|
|
|
describe("Download Whisper Model", () => {
|
|
it("should trigger download when model is not present", async () => {
|
|
const whisperFile = new WhisperFile("small");
|
|
(whisperFile.doesTargetExist as jest.Mock).mockResolvedValue(false);
|
|
|
|
render(<SettingsComponent />);
|
|
await screen.findByText(/\s*Download Small\s*/i);
|
|
// Assuming there's a button or trigger to start download
|
|
act(() => {
|
|
fireEvent.press(screen.getByText(/\s*Download Small\s*/i));
|
|
})
|
|
|
|
expect(whisperFile.createDownloadResumable).toHaveBeenCalled();
|
|
});
|
|
|
|
it("should show progress when download is in progress", async () => {
|
|
const whisperFile = new WhisperFile("small");
|
|
(whisperFile.doesTargetExist as jest.Mock).mockResolvedValue(false);
|
|
(whisperFile.getDownloadStatus as jest.Mock).mockResolvedValue({
|
|
doesTargetExist: false,
|
|
isDownloadComplete: false,
|
|
hasDownloadStarted: true,
|
|
progress: {
|
|
current: 1024,
|
|
total: 2048,
|
|
remaining: 1024,
|
|
percentRemaining: 50,
|
|
},
|
|
});
|
|
|
|
render(<SettingsComponent />);
|
|
await screen.findByText(/Host Language:/i);
|
|
fireEvent.press(screen.getByText(/Download Model/i));
|
|
|
|
expect(await screen.findByText("50%")).toBeTruthy();
|
|
});
|
|
|
|
it("should indicate download is complete", async () => {
|
|
const whisperFile = new WhisperFile("small");
|
|
(whisperFile.doesTargetExist as jest.Mock).mockResolvedValue(false);
|
|
(whisperFile.getDownloadStatus as jest.Mock)
|
|
.mockResolvedValueOnce({
|
|
doesTargetExist: false,
|
|
isDownloadComplete: false,
|
|
hasDownloadStarted: true,
|
|
progress: {
|
|
current: 1024,
|
|
total: 2048,
|
|
remaining: 1024,
|
|
percentRemaining: 50,
|
|
},
|
|
})
|
|
.mockResolvedValueOnce({
|
|
doesTargetExist: true,
|
|
isDownloadComplete: true,
|
|
hasDownloadStarted: false,
|
|
progress: undefined,
|
|
});
|
|
|
|
render(<SettingsComponent />);
|
|
await screen.findByText(/Host Language:/i);
|
|
fireEvent.press(screen.getByText(/Download Model/i));
|
|
|
|
expect(await screen.findByText("Download Complete")).toBeTruthy();
|
|
});
|
|
});
|
|
});
|