mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-19 02:20:17 -05:00
119 lines
6.4 KiB
JavaScript
119 lines
6.4 KiB
JavaScript
// Real app UI with isolated, deterministic IPC responses. Run against a dev or
|
|
// preview URL. Native HTTP/CORS correctness is tested separately in Rust and in
|
|
// the real-webview procedure in docs/desktop-session-regression.md.
|
|
import assert from "node:assert/strict";
|
|
import { chromium, expect } from "@playwright/test";
|
|
import { installBrowserFixture } from "../performance/browser-fixture.mjs";
|
|
|
|
const url = new URL(process.argv[2] || "http://127.0.0.1:5193");
|
|
if (!["127.0.0.1", "localhost", "[::1]"].includes(url.hostname)) {
|
|
throw new Error("Use the local development or preview URL printed by the launcher.");
|
|
}
|
|
const browser = await chromium.launch({ channel: "chrome", headless: true });
|
|
try {
|
|
const context = await browser.newContext({ viewport: { width: 1440, height: 1000 } });
|
|
await context.addInitScript(installBrowserFixture);
|
|
await context.addInitScript(installSessionFixture);
|
|
await context.route("**/*", (route) => {
|
|
const target = route.request().url();
|
|
return target.startsWith(url.origin) || target.startsWith("blob:")
|
|
? route.continue() : route.abort();
|
|
});
|
|
const page = await context.newPage();
|
|
const errors = [];
|
|
page.on("pageerror", (error) => errors.push(error.message));
|
|
const home = async () => {
|
|
await page.goto(url.href);
|
|
await expect(page.getByRole("heading", { name: "What will you craft today?" })).toBeVisible({ timeout: 60000 });
|
|
await expect(page.getByRole("button", { name: "42 Credits" })).toBeVisible();
|
|
};
|
|
const account = async () => {
|
|
await page.getByRole("button", { name: "Settings", exact: true }).click();
|
|
await page.getByRole("button", { name: "Accounts", exact: true }).click();
|
|
await expect(page.getByText("Session Smoke Account", { exact: true })).toBeVisible();
|
|
await expect(page.getByRole("button", { name: "Log Out", exact: true })).toBeVisible();
|
|
};
|
|
|
|
await home();
|
|
await account();
|
|
await page.keyboard.press("Escape");
|
|
await page.getByRole("button", { name: "My Library" }).click();
|
|
await expect(page.getByRole("img", { name: "Session smoke image", exact: true })).toBeVisible();
|
|
await expect.poll(() => page.getByRole("img", { name: "Session smoke image", exact: true })
|
|
.evaluate((image) => image.complete && image.naturalWidth > 0)).toBe(true);
|
|
await expect(page.getByText("Log in to browse and use your library.")).toHaveCount(0);
|
|
await page.keyboard.press("Escape");
|
|
await page.getByRole("button", { name: "Create Image Generate AI images" }).click();
|
|
await expect(page.getByRole("img", { name: "Session smoke image", exact: true })).toBeVisible();
|
|
await account();
|
|
await page.keyboard.press("Escape");
|
|
for (const [card, heading] of [
|
|
["Create Video Create video from images", "Create Video"],
|
|
["Create Audio Generate music and sound effects", "Create Audio"],
|
|
]) {
|
|
await home();
|
|
await page.getByRole("button", { name: card }).click();
|
|
await expect(page.getByRole("heading", { name: heading, exact: true }).first()).toBeVisible();
|
|
}
|
|
await account();
|
|
await page.getByRole("button", { name: "Log Out", exact: true }).click();
|
|
await expect(page.getByRole("heading", { name: "Create your account" })).toBeVisible();
|
|
await page.getByRole("button", { name: "Log in", exact: true }).click();
|
|
await page.getByPlaceholder("you@example.com or username").fill("session_smoke");
|
|
await page.getByPlaceholder("Min. 8 characters").fill("fixture-password-only");
|
|
await page.getByRole("button", { name: "Log in", exact: true }).click();
|
|
await expect(page.getByRole("heading", { name: "Welcome back" })).toHaveCount(0, { timeout: 10000 });
|
|
await account();
|
|
assert.deepEqual(errors, [], "Application runtime errors");
|
|
console.log("PASS: credits, Accounts, Library media, deferred image/video/audio pages, logout gate, and sign-in agree.");
|
|
} finally {
|
|
await browser.close();
|
|
}
|
|
|
|
function installSessionFixture() {
|
|
const invoke = window.__TAURI_INTERNALS__.invoke;
|
|
let loggedIn = true;
|
|
let nextResource = 0;
|
|
const responses = new Map();
|
|
const user = {
|
|
username: "session_smoke", display_name: "Session Smoke Account",
|
|
user_token: "u_session_smoke", can_access_studio: true, maybe_feature_flags: [],
|
|
};
|
|
const image = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAusB9Wl6mTQAAAAASUVORK5CYII=";
|
|
const media = {
|
|
token: "m_session_smoke", media_class: "image", media_type: "png",
|
|
maybe_title: "Session smoke image", created_at: new Date().toISOString(),
|
|
origin_category: "inference", origin: { origin_category: "inference" },
|
|
media_links: { cdn_url: image, maybe_thumbnail_template: image, thumbnail_template: image },
|
|
stats: { positive_rating_count: 0, bookmark_count: 0 },
|
|
};
|
|
window.__TAURI_INTERNALS__.invoke = async (command, args) => {
|
|
if (command === "storyteller_get_login_session_command") return loggedIn ? user : null;
|
|
if (command === "storyteller_password_login_command") { loggedIn = true; return user; }
|
|
if (command === "storyteller_purge_credentials_command") { loggedIn = false; return; }
|
|
if (command === "get_app_info_command") return { payload: { storyteller_host: "https://api.storyteller.ai" } };
|
|
if (command === "storyteller_get_credits_command") return { payload: { free_credits: 0, monthly_credits: 42, banked_credits: 0, sum_total_credits: 42 } };
|
|
if (command === "plugin:http|fetch") {
|
|
const request = new URL(args.clientConfig.url);
|
|
let body = { success: true, results: [], folders: [], tags: [], active_subscriptions: [] };
|
|
if (request.pathname === "/v1/session") body = { success: true, logged_in: loggedIn, user: loggedIn ? user : undefined };
|
|
if (request.pathname === "/v1/logout") loggedIn = false;
|
|
if (request.pathname === "/v1/media_files/list/user/session_smoke") body = { success: true, results: [media], pagination: { has_next: false } };
|
|
responses.set(++nextResource, { url: request.href, body });
|
|
return nextResource;
|
|
}
|
|
if (command === "plugin:http|fetch_send") {
|
|
const response = responses.get(args.rid);
|
|
return { rid: args.rid, status: 200, statusText: "OK", url: response.url, headers: [["content-type", "application/json"]] };
|
|
}
|
|
if (command === "plugin:http|fetch_read_body") {
|
|
const response = responses.get(args.rid);
|
|
args.streamChannel.onmessage([...new TextEncoder().encode(JSON.stringify(response.body)), 0]);
|
|
args.streamChannel.onmessage([1]);
|
|
responses.delete(args.rid);
|
|
return;
|
|
}
|
|
return invoke(command, args);
|
|
};
|
|
}
|