feat: import F95 covers using personal encrypted sessions
This commit is contained in:
1 parent
3f51f06fec
commit
219005d16a
16 files changed
+763
-26
No files matched your search
@@ -0,0 +1,98 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { createServer } from "node:http";
|
||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
import { test } from "node:test";
|
||||
import { build } from "esbuild";
|
||||
|
||||
test("F95 personal cookies: decline, expired session, retry, delete and no parent form submission", {
|
||||
skip: !process.env.PGAMES_PLAYWRIGHT_PATH,
|
||||
}, async () => {
|
||||
const { chromium } = await import(pathToFileURL(process.env.PGAMES_PLAYWRIGHT_PATH + "/index.mjs").href);
|
||||
const compiled = await build({ stdin: { contents: `
|
||||
import {createElement as h, useState} from 'react';
|
||||
import {createRoot} from 'react-dom/client';
|
||||
import {F95Fetch} from './ui/F95Fetch';
|
||||
window.submits = 0; window.loaded = [];
|
||||
function App() { const [title, setTitle] = useState('Manual title');
|
||||
return h('form', {onSubmit: e => {e.preventDefault(); window.submits++;}},
|
||||
h(F95Fetch, {onLoaded: m => {window.loaded.push(m); setTitle(m.title);}}), h('output', null, title)); }
|
||||
createRoot(document.querySelector('main')).render(h(App));`,
|
||||
resolveDir: fileURLToPath(new URL("../src/", import.meta.url)), loader: "tsx" },
|
||||
bundle: true, write: false, format: "iife", platform: "browser", logLevel: "silent" });
|
||||
let imports = 0, deleted = 0;
|
||||
const saved = [];
|
||||
const server = createServer(async (req, res) => {
|
||||
if (req.url === "/bundle.js") {
|
||||
res.setHeader("Content-Type", "application/javascript"); res.end(compiled.outputFiles[0].text); return;
|
||||
}
|
||||
if (req.url === "/api/metadata/f95/session") {
|
||||
if (req.method === "PUT") {
|
||||
let data = "";
|
||||
for await (const chunk of req) data += chunk;
|
||||
saved.push(JSON.parse(data));
|
||||
} else if (req.method === "DELETE") deleted++;
|
||||
res.writeHead(204); res.end(); return;
|
||||
}
|
||||
if (req.url === "/api/metadata/f95") {
|
||||
imports++;
|
||||
const authenticated = imports === 4;
|
||||
res.setHeader("Content-Type", "application/json");
|
||||
res.end(JSON.stringify({url: "https://f95zone.to/threads/example.123/", title: "Imported title",
|
||||
description: "Story", tags: [], cover_hash: authenticated ? "cover.webp" : null,
|
||||
cover_warning: authenticated ? null : "Нужна авторизация", auth_required: !authenticated,
|
||||
metadata_available: imports !== 5})); return;
|
||||
}
|
||||
res.setHeader("Content-Type", "text/html");
|
||||
res.end('<!doctype html><main></main><script src="/bundle.js"></script>');
|
||||
});
|
||||
await new Promise(resolve => server.listen(0, "127.0.0.1", resolve));
|
||||
let browser;
|
||||
try {
|
||||
browser = await chromium.launch({headless: true, executablePath: process.env.PGAMES_CHROMIUM_EXECUTABLE});
|
||||
const page = await browser.newPage();
|
||||
await page.goto(`http://127.0.0.1:${server.address().port}`);
|
||||
await page.getByPlaceholder("https://f95zone.to/threads/…").fill("https://f95zone.to/threads/example.123/");
|
||||
await page.getByRole("button", {name: "Подтянуть", exact: true}).click();
|
||||
const dialog = page.getByRole("dialog");
|
||||
await dialog.waitFor();
|
||||
assert.equal(await page.locator("output").textContent(), "Imported title");
|
||||
await dialog.getByRole("button", {name: "Продолжить без авторизации"}).press("Enter");
|
||||
await dialog.waitFor({state: "detached"});
|
||||
assert.equal(imports, 1);
|
||||
assert.equal(saved.length, 0);
|
||||
assert.equal(await page.locator("output").textContent(), "Imported title");
|
||||
|
||||
await page.getByRole("button", {name: "Подтянуть", exact: true}).click();
|
||||
await dialog.waitFor();
|
||||
await dialog.getByLabel("Cookie", {exact: true}).fill("xf_user=expired");
|
||||
await dialog.getByRole("button", {name: "Сохранить и повторить"}).click();
|
||||
await page.waitForFunction(() => window.loaded.length === 3);
|
||||
assert.equal(await dialog.count(), 1, "expired cookies keep the replacement dialog open");
|
||||
assert.equal(await dialog.getByLabel("Cookie", {exact: true}).inputValue(), "");
|
||||
await dialog.getByLabel("Cookie", {exact: true}).fill("xf_user=fresh; xf_session=example");
|
||||
await dialog.getByLabel("User-Agent (необязательно)").fill("Test browser");
|
||||
await dialog.getByLabel("Cookie", {exact: true}).press("Enter");
|
||||
await dialog.waitFor({state: "detached"});
|
||||
assert.deepEqual(saved, [{cookie: "xf_user=expired", user_agent: ""},
|
||||
{cookie: "xf_user=fresh; xf_session=example", user_agent: "Test browser"}]);
|
||||
assert.equal(await page.evaluate(() => window.loaded.at(-1).cover_hash), "cover.webp");
|
||||
assert.equal(await page.evaluate(() => window.submits), 0);
|
||||
assert.equal(await page.evaluate(() => localStorage.length), 0);
|
||||
|
||||
await page.getByRole("button", {name: "Забыть cookie F95zone"}).click();
|
||||
await page.getByText("Ваши сохранённые cookie F95zone удалены.").waitFor();
|
||||
assert.equal(deleted, 1);
|
||||
await page.reload();
|
||||
await page.getByPlaceholder("https://f95zone.to/threads/…").fill("https://f95zone.to/threads/example.123/");
|
||||
await page.getByRole("button", {name: "Подтянуть", exact: true}).click();
|
||||
await dialog.waitFor();
|
||||
assert.equal(await page.locator("output").textContent(), "Manual title", "login-only response cannot erase manual fields");
|
||||
await dialog.getByLabel("Cookie", {exact: true}).press("Escape");
|
||||
await dialog.waitFor({state: "detached"});
|
||||
assert.equal(imports, 5);
|
||||
assert.equal(saved.length, 2);
|
||||
} finally {
|
||||
await browser?.close();
|
||||
await new Promise(resolve => server.close(resolve));
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user