Release Healer Man 0.1.46

This commit is contained in:
phenom committed 2026-09-16 14:30:58 -04:00
1 parent f82daf1c13
commit 9ff574ac0b
73 files changed
+33486 -174

No files matched your search

+148
View File
@@ -0,0 +1,148 @@
const assert = require("node:assert/strict");
const fs = require("node:fs");
const path = require("node:path");
const { chromium } = require("C:/Users/phenom/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/playwright");
const base = process.env.MOUSE_CAMERA_TEST_URL || "http://127.0.0.1:5176";
const directory = path.resolve("playtest-artifacts/mouse-camera");
fs.mkdirSync(directory, { recursive: true });
(async () => {
const browser = await chromium.launch({ channel: "msedge", headless: true });
const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
page.setDefaultTimeout(120_000);
const errors = [];
page.on("pageerror", (error) => errors.push(error.message));
const gameState = () => page.evaluate(async () => {
const storeEntry = performance.getEntriesByType("resource")
.findLast((entry) => new URL(entry.name).pathname === "/src/game/store.ts");
if (!storeEntry) throw new Error("game store module was not loaded");
const { useGameStore } = await import(storeEntry.name);
const state = useGameStore.getState();
return {
cameraLookActive: state.cameraLookActive,
cameraYaw: state.cameraYaw,
pointerLocked: document.pointerLockElement !== null,
selection: window.getSelection()?.toString() ?? "",
};
});
try {
await page.goto(base, { waitUntil: "domcontentloaded" });
await page.getByRole("button", { name: /Play offline/ }).click();
await page.getByRole("button", { name: /Create character/ }).click();
await page.getByRole("button", { name: /Customize & name/ }).click();
await page.getByLabel("Character name").fill("Mouselooker");
await page.getByRole("button", { name: /Create character/ }).click();
await page.getByRole("button", { name: /Continue|Enter world/ }).first().click();
await page.locator(".main-menu-screen").waitFor();
await page.getByRole("button", { name: /^Dungeons/ }).click();
await page.getByRole("button", { name: /Choose role/ }).click();
await page.locator(".dungeon-role-option").first().click();
await page.locator(".game-shell").waitFor();
await page.waitForFunction(async () => {
const storeEntry = performance.getEntriesByType("resource")
.findLast((entry) => new URL(entry.name).pathname === "/src/game/store.ts");
if (!storeEntry) return false;
const { useGameStore } = await import(storeEntry.name);
return ["ready", "proxy", "error"].includes(useGameStore.getState().assetStatus);
});
await page.locator(".loading-screen").waitFor({ state: "hidden" });
await page.waitForTimeout(1_000);
const selectionBefore = await page.evaluate(() => {
const fixture = document.createElement("p");
fixture.textContent = "Existing browser selection";
fixture.style.userSelect = "text";
fixture.style.position = "fixed";
fixture.style.left = "-10000px";
document.body.append(fixture);
const range = document.createRange();
range.selectNodeContents(fixture);
const selection = window.getSelection();
if (!selection) throw new Error("browser selection API is unavailable");
selection.removeAllRanges();
selection.addRange(range);
return selection.toString();
});
assert.equal(selectionBefore, "Existing browser selection");
const scene = page.locator(".scene-shell");
const bounds = await scene.boundingBox();
assert(bounds, "3D scene is visible");
const cdp = await page.context().newCDPSession(page);
const start = { x: bounds.x + bounds.width * 0.55, y: bounds.y + bounds.height * 0.55 };
const before = await gameState();
assert.equal(before.cameraLookActive, false);
await page.mouse.move(start.x, start.y);
await page.mouse.down({ button: "right" });
await page.waitForFunction(async () => {
const storeEntry = performance.getEntriesByType("resource")
.findLast((entry) => new URL(entry.name).pathname === "/src/game/store.ts");
if (!storeEntry) return false;
const { useGameStore } = await import(storeEntry.name);
return useGameStore.getState().cameraLookActive;
});
const captured = await gameState();
assert.equal(captured.pointerLocked, false);
assert.equal(captured.selection, "");
await cdp.send("Input.dispatchMouseEvent", {
type: "mouseMoved",
x: start.x + 160,
y: start.y - 55,
button: "right",
buttons: 2,
pointerType: "mouse",
});
await page.waitForTimeout(350);
const moved = await gameState();
assert.notEqual(moved.cameraYaw, before.cameraYaw);
await page.screenshot({ path: path.join(directory, "right-drag-camera.png") });
await page.mouse.up({ button: "right" });
await page.waitForFunction(async () => {
const storeEntry = performance.getEntriesByType("resource")
.findLast((entry) => new URL(entry.name).pathname === "/src/game/store.ts");
if (!storeEntry) return false;
const { useGameStore } = await import(storeEntry.name);
return !useGameStore.getState().cameraLookActive;
});
const released = await gameState();
await page.mouse.move(start.x - 120, start.y + 70, { steps: 8 });
await page.waitForTimeout(350);
const afterReleaseMove = await gameState();
assert.equal(afterReleaseMove.cameraYaw, released.cameraYaw);
assert.equal(afterReleaseMove.pointerLocked, false);
assert.equal(
await page.locator(".game-shell").evaluate((element) => getComputedStyle(element).userSelect),
"none",
);
assert.deepEqual(errors, []);
const result = {
passed: true,
yawBefore: before.cameraYaw,
yawDuringDrag: moved.cameraYaw,
yawAfterRelease: afterReleaseMove.cameraYaw,
pointerLocked: afterReleaseMove.pointerLocked,
selectionCleared: captured.selection === "",
errors,
};
fs.writeFileSync(path.join(directory, "results.json"), `${JSON.stringify(result, null, 2)}\n`);
console.log(JSON.stringify(result, null, 2));
console.log("Mouse camera playtest passed");
} catch (error) {
await page.mouse.up({ button: "right" }).catch(() => {});
await page.screenshot({ path: path.join(directory, "failure.png") });
console.log((await page.locator("body").innerText()).slice(-2_000));
console.log("Browser errors:", errors);
throw error;
} finally {
await browser.close();
}
})().catch((error) => {
console.error(error);
process.exitCode = 1;
});