// 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 = `
`;
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 = ''; }); 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);