First-run gate offers free Ollama vs paid providers; add Google Gemini
The gate (user-key installs) now headlines Ollama with a "Free" badge and adds an "or - Use a paid provider instead" option that opens the same provider rows as Settings, framed as billed by the provider directly. Saving a provider key there lists its models and switches study generation to it automatically, so the gate steps aside with no Ollama key at all. Gemini joins the registry via its OpenAI-compatible endpoint (generativelanguage.googleapis.com/v1beta/openai); the privacy policy names it (en+cs). Providers suite grows to 20 checks: the gate scenario runs against a second user-key-mode app instance (free badge, paid option, provider rows, pass-through, generation switch). All other gates green: contrast 0 findings, mobile 126/126, chat 102/102, wizard 95/95, bubbles 34/34, regression 44/44, i18n 13/13, native 33/33. Version 0.4.9, SW -> freezmo-v73.
This commit is contained in:
parent
4372423167
commit
8651674cf5
8 changed files with 132 additions and 8 deletions
|
|
@ -113,6 +113,7 @@ const providerSeed = {
|
|||
generation: { provider: "custom", textModel: "free-model-a", visionModel: "free-model-a" },
|
||||
};
|
||||
|
||||
let gateApp = null;
|
||||
try {
|
||||
/* 1. API: the listing route forwards the key and returns the models ---- */
|
||||
{
|
||||
|
|
@ -211,6 +212,7 @@ try {
|
|||
await page.locator("nav.tabbar").getByRole("button").click();
|
||||
await page.getByRole("dialog").waitFor({ timeout: 6000 });
|
||||
await page.waitForTimeout(600);
|
||||
check("settings: Google Gemini is offered", (await page.locator('input[aria-label="Google Gemini API key"]').count()) === 1);
|
||||
const row = page.locator('input[aria-label="Custom (OpenAI-compatible) API key"]');
|
||||
await row.scrollIntoViewIfNeeded();
|
||||
await row.fill(PROVIDER_KEY);
|
||||
|
|
@ -224,8 +226,57 @@ try {
|
|||
await context.close();
|
||||
}
|
||||
|
||||
/* 5. First run: the gate offers the free Ollama path and paid providers - */
|
||||
{
|
||||
const GATE_PORT = 3214;
|
||||
check("gate app port is free", !(await portInUse(GATE_PORT)));
|
||||
// No OLLAMA_AUTH: the default user-key mode, so the first-run gate shows.
|
||||
gateApp = spawnApp(GATE_PORT, {
|
||||
OLLAMA_BASE_URL: `http://127.0.0.1:${STUB_PORT}`,
|
||||
OLLAMA_VERIFY_KEY: "false",
|
||||
});
|
||||
await waitForHttp(`http://127.0.0.1:${GATE_PORT}/api/healthz`);
|
||||
|
||||
const { context, page } = await makePage(browser, { width: 390, height: 844 });
|
||||
await seed(page, {
|
||||
decks: [],
|
||||
key: "",
|
||||
extra: {
|
||||
"freezmo.providers.v1": JSON.stringify({ keys: {}, models: {}, customBaseUrl: PROVIDER_BASE, generation: null }),
|
||||
},
|
||||
});
|
||||
await page.goto(`http://127.0.0.1:${GATE_PORT}/`, { waitUntil: "networkidle" });
|
||||
await page.waitForTimeout(1400);
|
||||
|
||||
check("gate: the free Ollama path is the headline", (await page.getByText("Free").count()) >= 1);
|
||||
const paid = page.getByRole("button", { name: "Use a paid provider instead" });
|
||||
check("gate: the paid option is visible on first run", await paid.isVisible());
|
||||
await paid.click();
|
||||
await page.waitForTimeout(500);
|
||||
check("gate: the provider rows open", (await page.locator('input[aria-label="OpenAI API key"]').count()) === 1);
|
||||
|
||||
const gateKey = page.locator('input[aria-label="Custom (OpenAI-compatible) API key"]');
|
||||
await gateKey.scrollIntoViewIfNeeded();
|
||||
await gateKey.fill(PROVIDER_KEY);
|
||||
await gateKey.locator("xpath=..").getByRole("button", { name: "Save key", exact: true }).click();
|
||||
await page.waitForTimeout(2200);
|
||||
check(
|
||||
"gate: a saved provider key lets the app through",
|
||||
await page.getByRole("heading", { name: "Your icebox" }).isVisible(),
|
||||
);
|
||||
check(
|
||||
"gate: the provider became the study-generation model",
|
||||
(await page.evaluate(() => {
|
||||
const state = JSON.parse(localStorage.getItem("freezmo.providers.v1") ?? "{}");
|
||||
return state.generation?.provider === "custom" && state.generation?.textModel === "free-model-a";
|
||||
})),
|
||||
);
|
||||
await context.close();
|
||||
}
|
||||
|
||||
check("stub saw both endpoints", seen.models >= 1 && seen.completions >= 1, JSON.stringify(seen));
|
||||
} finally {
|
||||
gateApp?.stop();
|
||||
app.stop();
|
||||
stub.close();
|
||||
await browser.close();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue