Ask what a single note's export should contain, and fix drawings never being in one
Two questions instead of one, because the answers depend on each other: Markdown holds text only, a PNG holds the drawing only, PDF holds both. Listing every format flat would have offered combinations that cannot exist. A note without a drawing skips the first step rather than showing it mostly greyed out. While testing that, the drawings turned out never to have made it into any export at all — not the ZIP, not the PDF. strokeDocOf() *builds* a stroke document from a bare array, and it was being handed one that was already a document, so the strokes ended up nested one level too deep and every length check read undefined. Nothing complained; the export simply came out without the drawing. It went unnoticed because the notes the earlier suite exported had none. Now uses docStrokes(), and the suite draws on a note before exporting it, checks the PNG's magic bytes, and checks it is 159 KB rather than an empty white page — a check on the file merely existing would have passed against the broken version too. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2611d87f8c
commit
8c36c6121b
5 files changed
+284
-57
No files matched your search
+79
-3
@@ -72,9 +72,29 @@ function readZip(bytes) {
|
||||
const openExportDialog = async (page) => {
|
||||
await page.getByTitle("Export").click();
|
||||
await page.waitForSelector("[data-export-dialog]", { timeout: 10000 });
|
||||
await page.waitForTimeout(500);
|
||||
await page.waitForTimeout(800);
|
||||
};
|
||||
|
||||
/** Draws a couple of strokes so the note has something to export as a picture. */
|
||||
async function drawSomething(page) {
|
||||
await page.locator("button").filter({ hasText: "Draw" }).first().click();
|
||||
await page.waitForTimeout(1200);
|
||||
const box = await page.locator("canvas").first().boundingBox();
|
||||
for (const [x1, y1, x2, y2] of [
|
||||
[0.2, 0.25, 0.7, 0.4],
|
||||
[0.3, 0.6, 0.7, 0.55],
|
||||
]) {
|
||||
await page.mouse.move(box.x + box.width * x1, box.y + box.height * y1);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(box.x + box.width * x2, box.y + box.height * y2, { steps: 12 });
|
||||
await page.mouse.up();
|
||||
await page.waitForTimeout(250);
|
||||
}
|
||||
await page.waitForTimeout(2500);
|
||||
await page.locator("button").filter({ hasText: "Write" }).first().click();
|
||||
await page.waitForTimeout(800);
|
||||
}
|
||||
|
||||
const browser = await launch();
|
||||
let session;
|
||||
try {
|
||||
@@ -104,7 +124,7 @@ try {
|
||||
|
||||
/* ── single note as Markdown ── */
|
||||
await openExportDialog(p);
|
||||
await p.getByRole("button", { name: /Als Markdown/ }).click();
|
||||
await p.getByRole("button", { name: /Markdown/ }).click();
|
||||
await p.waitForSelector("[data-export-done]", { timeout: 30000 });
|
||||
await p.waitForTimeout(600);
|
||||
|
||||
@@ -143,7 +163,7 @@ try {
|
||||
|
||||
await p.evaluate(() => (window.__downloads = []));
|
||||
await openExportDialog(p);
|
||||
await p.getByRole("button", { name: /Als Markdown/ }).click();
|
||||
await p.getByRole("button", { name: /Markdown/ }).click();
|
||||
await p.waitForSelector("[data-export-done]", { timeout: 30000 });
|
||||
await p.waitForTimeout(800);
|
||||
files = await downloads(p);
|
||||
@@ -165,6 +185,62 @@ try {
|
||||
);
|
||||
await p.screenshot({ path: `${OUT}/export-dialog.png` });
|
||||
|
||||
/* ── the wizard on a note that has a drawing ── */
|
||||
await createNote(p);
|
||||
await setTitle(p, "Mit Zeichnung");
|
||||
await typeInEditor(p, "Text und Bild.");
|
||||
await drawSomething(p);
|
||||
|
||||
await p.evaluate(() => (window.__downloads = []));
|
||||
await openExportDialog(p);
|
||||
check(
|
||||
(await p.getByText("Was soll mit?").count()) > 0,
|
||||
"a note with a drawing is asked what should come along"
|
||||
);
|
||||
check(
|
||||
(await p.getByRole("button", { name: /Nur die Zeichnung/ }).count()) > 0,
|
||||
"the drawing-only option is offered"
|
||||
);
|
||||
await p.screenshot({ path: `${OUT}/export-wizard.png` });
|
||||
|
||||
// drawing only → PNG
|
||||
await p.getByRole("button", { name: /Nur die Zeichnung/ }).click();
|
||||
await p.waitForTimeout(500);
|
||||
check((await p.getByRole("button", { name: /PNG-Bild/ }).count()) > 0, "PNG is offered for the drawing");
|
||||
check(
|
||||
(await p.getByRole("button", { name: /Markdown/ }).count()) === 0,
|
||||
"Markdown is not offered for a drawing, since it cannot hold one"
|
||||
);
|
||||
await p.getByRole("button", { name: /PNG-Bild/ }).click();
|
||||
await p.waitForSelector("[data-export-done]", { timeout: 30000 });
|
||||
await p.waitForTimeout(800);
|
||||
|
||||
files = await downloads(p);
|
||||
check(files.length === 1 && files[0].type === "image/png", "the PNG was produced", files[0]?.type);
|
||||
const png = Buffer.from(files[0].base64, "base64");
|
||||
check(
|
||||
png[0] === 0x89 && png[1] === 0x50 && png[2] === 0x4e && png[3] === 0x47,
|
||||
"and it really is a PNG",
|
||||
Array.from(png.slice(0, 4)).join(",")
|
||||
);
|
||||
check(/\.png$/.test(await lastName(p)), "named .png", await lastName(p));
|
||||
check(png.length > 1000, "the image has actual content, not an empty canvas", `${png.length} bytes`);
|
||||
|
||||
// back, then text only → Markdown must carry no drawing
|
||||
await p.getByRole("button", { name: /Zurück/ }).click();
|
||||
await p.waitForTimeout(500);
|
||||
await p.getByRole("button", { name: /Nur den Notiztext/ }).click();
|
||||
await p.waitForTimeout(500);
|
||||
await p.evaluate(() => (window.__downloads = []));
|
||||
await p.getByRole("button", { name: /Markdown/ }).click();
|
||||
await p.waitForSelector("[data-export-done]", { timeout: 30000 });
|
||||
await p.waitForTimeout(800);
|
||||
files = await downloads(p);
|
||||
const textMd = Buffer.from(files[0].base64, "base64").toString("utf8");
|
||||
check(textMd.includes("Text und Bild."), "the text-only export has the text");
|
||||
await p.keyboard.press("Escape");
|
||||
await p.waitForTimeout(600);
|
||||
|
||||
/* ── whole notebook, via the sidebar's context menu ── */
|
||||
await p.evaluate(() => (window.__downloads = []));
|
||||
await p.locator("[data-note-row]").first().click({ button: "right" });
|
||||
|
||||
Reference in new issue
Block a user