A filed note stays filed, and the handles are asked for
Three things that all came from chapters being thought through too late. A note put into a chapter came back out of it a few seconds later. The server had it right the whole time; every sync rebuilds the local copy from the server's answer, and the function doing that never carried chapter_id — so each sync handed back a note belonging to no chapter and the notebook took it in again. The bin's query left the column out too, which would have unfiled anything restored from it. A separator drawn in a notebook vanished when a chapter was opened. "Which chapter is open" and "which list is on screen" were one value. Opened beside or below, the list still shows the notebook — but everything around it had switched to the chapter, so the notebook's own separators were filtered away and a drag among its rows was measured against the chapter's notes, found nothing, and did nothing. And where a new note lands is now visible and yours to choose: pressing in either place makes it the one being worked in, marked with a line along its top and the word "here", and the + button names it. Rearranging becomes a mode, switched on beside the sort menu — until then no row wears a grip and none can be dragged. Filing a note is back in the row's own menu, where starring and exporting already are; the button that had appeared in every row is gone with its dialog. The account panel closes with Escape. Thirteen suites green: 335 browser checks, 241 unit tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4bb86bc5ac
commit
b2a5f051fe
12 files changed
+406
-291
No files matched your search
+100
-15
@@ -31,16 +31,22 @@ try {
|
||||
await p.getByRole("button", { name: "Create", exact: true }).click();
|
||||
await p.waitForTimeout(2000);
|
||||
};
|
||||
/* One press of the button on the row, then choose. It used to be a
|
||||
right-click into a submenu — two steps before the places even appeared, and
|
||||
on a phone a long press followed by a flyout. */
|
||||
/* Filing a note is one of the things a row can have done to it, and they all
|
||||
live in the row's own menu. A button for this one on every row put a second
|
||||
icon beside every title, for something done once in a note's life. */
|
||||
const moveTo = async (noteTitle, target) => {
|
||||
const row = p.locator("[data-note-row]").filter({ hasText: noteTitle }).first();
|
||||
await row.locator("xpath=preceding-sibling::button[@data-move-note]").first().click();
|
||||
await p.waitForTimeout(700);
|
||||
await p.locator("[data-move-target]").filter({ hasText: target }).first().click();
|
||||
await row.click({ button: "right", force: true });
|
||||
await p.waitForTimeout(600);
|
||||
await p.locator("[data-submenu-toggle]").filter({ hasText: "Move to" }).first().click();
|
||||
await p.waitForTimeout(500);
|
||||
await p.locator("[data-submenu] button").filter({ hasText: target }).first().click();
|
||||
await p.waitForTimeout(2500);
|
||||
};
|
||||
const openNotebook = async () => {
|
||||
await p.locator("button").filter({ hasText: "Haus" }).first().click();
|
||||
await p.waitForTimeout(1200);
|
||||
};
|
||||
|
||||
await createNotebook(p, "Haus");
|
||||
await p.locator("button").filter({ hasText: "Haus" }).first().click();
|
||||
@@ -62,8 +68,8 @@ try {
|
||||
|
||||
/* ── filing a note ── */
|
||||
check(
|
||||
(await p.locator("[data-move-note]").count()) === 2,
|
||||
"every note has a move button, without a right-click",
|
||||
(await p.locator("[data-move-note]").count()) === 0,
|
||||
"filing is in the row's menu, not a button standing in every row",
|
||||
String(await p.locator("[data-move-note]").count())
|
||||
);
|
||||
await moveTo("Stromrechnung", "Rechnungen");
|
||||
@@ -73,6 +79,20 @@ try {
|
||||
(await titles()).join(", ")
|
||||
);
|
||||
|
||||
/* ── and stays filed ──
|
||||
* It did not. The server had it right, but the sync that follows replaced
|
||||
* every local note with one belonging to no chapter — so about five seconds
|
||||
* after being filed, the note walked back out into the notebook by itself.
|
||||
* A reload is the same journey: the mirror is rebuilt from the server. */
|
||||
await p.reload();
|
||||
await p.waitForTimeout(4000);
|
||||
await openNotebook();
|
||||
check(
|
||||
(await titles()).join(",") === "Zählerstand",
|
||||
"and is still in it after the next sync, not back in the notebook",
|
||||
(await titles()).join(", ")
|
||||
);
|
||||
|
||||
await p.locator("[data-chapter-row]").first().click();
|
||||
await p.waitForTimeout(1200);
|
||||
const inChapter = () =>
|
||||
@@ -90,10 +110,37 @@ try {
|
||||
const made = (await api(p, "GET", "/notes")).body.find((n) => n.title === "Wasserrechnung");
|
||||
check(made?.chapter_id === filed?.chapter_id, "a note made while it is open is filed there", String(made?.chapter_id));
|
||||
|
||||
/* ── which of the two am I in ──
|
||||
* Beside the list, a chapter does not replace the notebook: both are on
|
||||
* screen at once. A new note used to go into the chapter however far away the
|
||||
* user had since clicked, and nothing said which of the two was meant. */
|
||||
check(
|
||||
(await p.locator('[data-chapter-current="on"]').count()) === 1,
|
||||
"opening a chapter makes it the place being written into, and shows it"
|
||||
);
|
||||
// Into the empty space under the notebook's own notes.
|
||||
await p.locator("[data-note-list-body]").click({ position: { x: 140, y: 330 } });
|
||||
await p.waitForTimeout(700);
|
||||
check(
|
||||
(await p.locator('[data-list-current="on"]').count()) === 1 &&
|
||||
(await p.locator('[data-chapter-current="off"]').count()) === 1,
|
||||
"clicking into the notebook puts you back in the notebook, visibly"
|
||||
);
|
||||
await createNote(p);
|
||||
await setTitle(p, "Gartenzaun");
|
||||
await p.waitForTimeout(1500);
|
||||
const loose = (await api(p, "GET", "/notes")).body.find((n) => n.title === "Gartenzaun");
|
||||
check(!loose?.chapter_id, "and a note made then is the notebook's, not the chapter's", String(loose?.chapter_id));
|
||||
check(
|
||||
(await titles()).sort().join(",") === "Gartenzaun,Zählerstand",
|
||||
"so it appears in the notebook's own list",
|
||||
(await titles()).join(", ")
|
||||
);
|
||||
|
||||
await p.locator("[data-chapter-close]").click();
|
||||
await p.waitForTimeout(1200);
|
||||
check(
|
||||
(await titles()).join(",") === "Zählerstand",
|
||||
(await titles()).sort().join(",") === "Gartenzaun,Zählerstand",
|
||||
"and the notebook's own list never held the chapter's notes",
|
||||
(await titles()).join(", ")
|
||||
);
|
||||
@@ -117,10 +164,16 @@ try {
|
||||
await p.waitForTimeout(800);
|
||||
await p.locator('[data-chapter-view="inline"]').click();
|
||||
await p.waitForTimeout(1500);
|
||||
await p.mouse.click(1380, 900); // outside the panel
|
||||
await p.waitForTimeout(1200);
|
||||
await p.locator("[data-chapter-row]").first().click();
|
||||
/* Escape closes it. Only a click beside the panel did, which on one this wide
|
||||
means aiming at a sliver of page. */
|
||||
await p.keyboard.press("Escape");
|
||||
await p.waitForTimeout(1200);
|
||||
check(
|
||||
(await p.locator("[data-chapter-view]").count()) === 0,
|
||||
"the account panel closes with Escape, not only by clicking beside it"
|
||||
);
|
||||
// No second click: the chapter that was open stays open, and changing the
|
||||
// setting changes only where it is shown.
|
||||
check((await p.locator("[data-chapter-notes]").count()) === 1, "the other setting unfolds it under its row");
|
||||
check((await p.locator("[data-chapter-column]").count()) === 0, "and there is no column then");
|
||||
|
||||
@@ -134,11 +187,43 @@ try {
|
||||
await p.waitForTimeout(300);
|
||||
await p.locator('[data-sort-option="manual"]').click();
|
||||
await p.waitForTimeout(1200);
|
||||
|
||||
/* Rearranging is asked for, and until it is, no row wears a handle.
|
||||
* Six dots stood beside every title at all times for something done once in a
|
||||
* while, and a press meant to open a note could carry it off instead. */
|
||||
check(
|
||||
(await p.locator("[data-reorder-grip]").count()) >= 2,
|
||||
"a chapter has a grip like a note does",
|
||||
(await p.locator("[data-reorder-grip]").count()) === 0,
|
||||
"no row wears a handle until rearranging is switched on",
|
||||
String(await p.locator("[data-reorder-grip]").count())
|
||||
);
|
||||
await p.locator("[data-reorder-toggle]").click();
|
||||
await p.waitForTimeout(600);
|
||||
check(
|
||||
(await p.locator("[data-reorder-grip]").count()) >= 2,
|
||||
"switched on, a chapter has a grip like a note does",
|
||||
String(await p.locator("[data-reorder-grip]").count())
|
||||
);
|
||||
await p.locator("[data-reorder-toggle]").click();
|
||||
await p.waitForTimeout(600);
|
||||
check((await p.locator("[data-reorder-grip]").count()) === 0, "and they go away again when it is done");
|
||||
|
||||
/* ── a separator drawn in the notebook belongs to the notebook ──
|
||||
* Opening a chapter used to take the notebook's own separators off the screen
|
||||
* with it: the list still showed the notebook, but everything around it had
|
||||
* quietly switched to the chapter. A line vanished for no reason anyone could
|
||||
* see, and dragging in that list wrote nothing at all. */
|
||||
await p.locator("[data-add-separator]").click();
|
||||
await p.waitForTimeout(2000);
|
||||
check((await p.locator("[data-separator]").count()) === 1, "a separator can be drawn in the notebook");
|
||||
await p.locator("[data-chapter-row]").first().click();
|
||||
await p.waitForTimeout(1500);
|
||||
check(
|
||||
(await p.locator("[data-separator]").count()) === 1,
|
||||
"and it is still there once a chapter is opened",
|
||||
String(await p.locator("[data-separator]").count())
|
||||
);
|
||||
await p.locator("[data-chapter-row]").first().click();
|
||||
await p.waitForTimeout(1200);
|
||||
|
||||
/* ── its own colour ── */
|
||||
await p.locator("[data-chapter-row]").first().click({ button: "right", force: true });
|
||||
@@ -172,7 +257,7 @@ try {
|
||||
);
|
||||
const after = (await titles()).sort().join(",");
|
||||
check(
|
||||
after === "Stromrechnung,Wasserrechnung,Zählerstand",
|
||||
after === "Gartenzaun,Stromrechnung,Wasserrechnung,Zählerstand",
|
||||
"and every note it held is back in the notebook",
|
||||
after
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user