Something went wrong. Try again.
Markdown editor
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105const { app, Menu } = require("electron");const fs = require("node:fs");const os = require("node:os");const path = require("node:path");const assert = require("node:assert/strict");
const fixture = fs.mkdtempSync(path.join(os.tmpdir(), "paper-block-check-"));fs.writeFileSync( path.join(fixture, "blocks.md"), "# Heading\n\nFirst line\nsecond line\n\n> Quote\n\n- Apple\n - Nested\n3. Three\n\n```zig\nconst x = 1;\n# not heading\n```\n",);let finished = false;function finish(error) { if (finished) return; finished = true; clearTimeout(timeout); fs.rmSync(fixture, { recursive: true, force: true }); if (error) console.error(error); else console.log( "Block editor passed: semantic projection, marker-free content, list/quote continuation, code newline, undo.", ); app.exit(error ? 1 : 0);}const timeout = setTimeout(() => finish(new Error("Block editor check timed out")), 25000);app.on("browser-window-created", (_event, win) => { win.webContents.once("did-finish-load", async () => { const js = (code) => win.webContents.executeJavaScript(code); async function wait(expression) { for (let i = 0; i < 150; i++) { if (await js(expression)) return; await new Promise((resolve) => setTimeout(resolve, 40)); } throw new Error("Wait failed: " + expression); } async function enter(selector) { await js(`(() => { const node = document.querySelector(${JSON.stringify(selector)}); const walker = document.createTreeWalker(node, NodeFilter.SHOW_TEXT); let last, text; while (text = walker.nextNode()) last = text; document.querySelector('#editor').focus(); window.getSelection().setBaseAndExtent(last, last.length, last, last.length); document.querySelector('#editor').dispatchEvent(new InputEvent('beforeinput', {inputType:'insertParagraph',bubbles:true,cancelable:true})); })()`); } const undo = () => js( `document.querySelector('#editor').dispatchEvent(new InputEvent('beforeinput', {inputType:'historyUndo',bubbles:true,cancelable:true}))`, ); try { await wait(`document.querySelector('#editor').getAttribute('aria-busy') === 'false'`); const command = Menu.getApplicationMenu().getMenuItemById("files.open"); command.click(command, win, {}); await wait( `!!document.querySelector('[role="combobox"]')?.value && document.querySelector('[role="listbox"]').getAttribute('aria-busy') === 'false'`, ); await js(`(() => { const input = document.querySelector('[role="combobox"]'); Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set.call(input, ${JSON.stringify(fixture + path.sep)}); input.dispatchEvent(new Event('input', {bubbles:true})); })()`); await wait( `document.querySelector('[role="option"]')?.textContent === 'blocks.md' && document.querySelector('[role="listbox"]').getAttribute('aria-busy') === 'false'`, ); await js(`document.querySelector('[role="option"]').click()`); await wait( `!document.querySelector('[role="dialog"]') && !!document.querySelector('#editor pre')`, ); const projection = await js( `Array.from(document.querySelector('#editor').children).map(node => ({tag:node.tagName, text:node.textContent, start:node.getAttribute('start')}))`, ); assert(projection.some((b) => b.tag === "H1" && b.text === "Heading")); assert(projection.some((b) => b.tag === "P" && b.text === "First line\nsecond line")); assert(projection.some((b) => b.tag === "BLOCKQUOTE" && b.text === "Quote")); assert(projection.some((b) => b.tag === "UL" && b.text === "Apple")); assert(projection.some((b) => b.tag === "OL" && b.start === "3" && b.text === "Three")); assert(projection.some((b) => b.tag === "PRE" && b.text === "const x = 1;\n# not heading")); const count = await js(`document.querySelector('#editor').children.length`); await enter("#editor ul li"); assert.equal(await js(`document.querySelectorAll('#editor ul').length`), 3); await undo(); assert.equal(await js(`document.querySelector('#editor').children.length`), count); await enter("#editor blockquote"); assert.equal(await js(`document.querySelectorAll('#editor blockquote').length`), 2); await undo(); await enter("#editor pre code"); assert.equal( await js(`document.querySelector('#editor pre').textContent`), "const x = 1;\n# not heading\n", ); assert.equal(await js(`document.querySelector('#editor').children.length`), count); await undo(); assert.equal( await js(`document.querySelector('#editor pre').textContent`), "const x = 1;\n# not heading", ); assert.equal(await js(`document.querySelector('#error-message').hidden`), true); finish(); } catch (error) { finish(error); } });});require("../dist/electron/main.js");