// Browser check of the bundled Emoji Picker (3.x) with the BUILT X runtime (src-tauri/x-runtime.js) // on X-shaped composer pages served at https://x.com/ (Playwright route, no network; see // scripts/emoji-picker-fixture.mjs): the home composer, the reply box on a post page and the modal // composer of /compose/post. Screenshots the picker opened from X's emoji button in each of them in // X Lights out, Paper and Tokyo Night, in a 1180 px and a 420 px pane, plus search, the empty state, // the skin tones, the inline `:shortcode` list and card close-ups; then checks placement, keyboard, // insertion, theming and cleanup. Pages are served with X's real Content-Security-Policy; the // runtime and the plugin are evaluated the way the app does (native script evaluation, which the // page's CSP does not govern), and any CSP violation fails the run. // // node scripts/build-inject.mjs && node scripts/emoji-picker-verify.mjs [--label v3] [--out dir] [--shots-only] import { mkdir, readFile, writeFile } from 'node:fs/promises'; import { dirname, join, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import { chromium } from 'playwright'; import { composerPage, PATHS, xCsp } from './emoji-picker-fixture.mjs'; const here = dirname(fileURLToPath(import.meta.url)); const app = resolve(here, '..'); const arg = (name, fallback) => { const i = process.argv.indexOf(name); return i > 0 ? process.argv[i + 1] : fallback; }; const label = arg('--label', 'v3'); const shotsOnly = process.argv.includes('--shots-only'); const out = resolve(arg('--out', join(app, '../../verification/emoji-picker-v3'))); await mkdir(out, { recursive: true }); const runtime = await readFile(join(app, 'src-tauri/x-runtime.js'), 'utf8'); const pluginSource = await readFile(join(app, 'src-tauri/bundled-plugins/emoji-picker.plugin.js'), 'utf8'); const THEMES = [['lightsout', 'dark', 'x'], ['paper', 'light', 'paper'], ['tokyo-night', 'dark', 'tokyo-night']]; const HEIGHT = 860; const X_EMOJI = '[data-testid="toolBar"] [aria-label="Add emoji"]'; const HOST = 'wb-emoji-picker:not([data-closing])'; const editorOf = { home: '[data-testid="tweetTextarea_0"]', reply: '[data-testid="tweetTextarea_1"]', modal: '[role="dialog"] [data-testid="tweetTextarea_0"]' }; /** A policy stricter than X's today: inline