64 lines
4.4 KiB
JavaScript
64 lines
4.4 KiB
JavaScript
// User Notes plugin in Chromium with the real plugin API over a hand-built x.com profile: no note box
|
|
// until a note exists, "Add private note" in the profile's ··· menu opens one, an emptied note goes
|
|
// away, a saved note shows after reload. Not a live X test.
|
|
//
|
|
// node scripts/user-notes-check.mjs
|
|
|
|
import { build } from 'esbuild';
|
|
import { readFile } from 'node:fs/promises';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { join } from 'node:path';
|
|
import { chromium } from 'playwright';
|
|
|
|
const root = fileURLToPath(new URL('../', import.meta.url));
|
|
const api = (await build({ stdin: { contents: "import { createPluginApi } from './src/inject/pluginApi.ts'; window.BetterTwttr = { api: createPluginApi(window) };", resolveDir: root, loader: 'ts' }, bundle: true, format: 'iife', write: false, target: 'chrome120' })).outputFiles[0].text;
|
|
const plugin = await readFile(join(root, 'src-tauri/bundled-plugins/user-notes.plugin.js'), 'utf8');
|
|
const PAGE = `<!doctype html><html><body><main role="main"><div data-testid="primaryColumn">
|
|
<div><div data-testid="UserName"><span>Fishies</span><span>@playfishies</span></div><div data-testid="UserDescription">bio</div></div>
|
|
<button data-testid="userActions" id="more">···</button></div></main><div id="layers"></div>
|
|
<script>
|
|
document.getElementById('more').addEventListener('click', () => {
|
|
document.getElementById('layers').innerHTML = '<div data-testid="mask" id="mask" style="position:fixed;inset:0"></div><div role="menu" style="position:fixed;top:40px;left:40px;z-index:2;background:#fff"><div role="menuitem" data-testid="block"><svg><path d="M0 0"/></svg><span>Block @playfishies</span></div></div>';
|
|
document.getElementById('mask').addEventListener('click', () => { document.getElementById('layers').innerHTML = ''; });
|
|
});
|
|
</script></body></html>`;
|
|
|
|
const failures = [];
|
|
const check = (label, ok, detail = '') => { console.log(`${ok ? 'ok ' : 'FAIL'} ${label}${detail ? ` (${detail})` : ''}`); if (!ok) failures.push(label); };
|
|
const browser = await chromium.launch();
|
|
const page = await browser.newPage();
|
|
await page.route('https://x.com/**', route => route.fulfill({ contentType: 'text/html', body: PAGE }));
|
|
const start = async () => {
|
|
await page.goto('https://x.com/playfishies');
|
|
await page.addScriptTag({ content: api });
|
|
await page.addScriptTag({ content: `(() => { const module = { exports: {} }; ${plugin}\n; window.notes = new module.exports(); window.notes.start(); })();` });
|
|
await page.waitForTimeout(200);
|
|
};
|
|
await start();
|
|
check('no note box on a profile without a note', await page.locator('.bt-note').count() === 0);
|
|
await page.click('#more');
|
|
await page.waitForTimeout(200);
|
|
check('the ··· menu offers "Add private note"', (await page.locator('.bt-note-item').textContent())?.includes('Add private note'));
|
|
await page.click('.bt-note-item');
|
|
await page.waitForTimeout(200);
|
|
check('choosing it closes the menu and opens a focused note box', await page.locator('#layers [role="menu"]').count() === 0 && await page.evaluate(() => document.activeElement?.closest('.bt-note') !== null));
|
|
await page.keyboard.type('met at a jam');
|
|
await page.evaluate(() => document.activeElement?.blur());
|
|
check('a written note stays after blur', await page.locator('.bt-note').count() === 1);
|
|
await start();
|
|
check('the saved note shows after reload', (await page.locator('.bt-note textarea').inputValue()) === 'met at a jam');
|
|
await page.click('#more');
|
|
await page.waitForTimeout(200);
|
|
check('the menu then says "Edit private note"', (await page.locator('.bt-note-item').textContent())?.includes('Edit private note'));
|
|
await page.click('#mask');
|
|
await page.fill('.bt-note textarea', '');
|
|
await page.locator('.bt-note textarea').dispatchEvent('input');
|
|
await page.evaluate(() => document.activeElement?.blur());
|
|
check('an emptied note goes away', await page.locator('.bt-note').count() === 0);
|
|
await start();
|
|
check('and stays gone after reload', await page.locator('.bt-note').count() === 0);
|
|
await page.click('#more');
|
|
check('menus opened elsewhere get no note item', await (async () => { await page.evaluate(() => { document.getElementById('layers').innerHTML = ''; window.notes.menuFor = null; document.getElementById('layers').innerHTML = '<div role="menu"><div role="menuitem">x</div></div>'; }); await page.waitForTimeout(200); return await page.locator('.bt-note-item').count() === 0; })());
|
|
await browser.close();
|
|
console.log(failures.length ? `\n${failures.length} failed` : '\nall passed');
|
|
process.exit(failures.length ? 1 : 0);
|