Skip to content

Fix typing bugs and add end-to-end tests - #14

Merged
lobbystack merged 27 commits into
mainfrom
fix/editor-normalized-saves
Sep 29, 2026
Merged

lobbystack merged 27 commits into
mainfrom
fix/editor-normalized-saves

Conversation

@lobbystack

@lobbystack lobbystack commented Sep 29, 2026 •

Copy link
Copy Markdown
Owner

Typing a space at the end of a note deleted it and showed "Merged changes from another app". This PR fixes that bug and adds end-to-end tests. The tests found 16 more bugs, which this PR also fixes.

The space bug

  • Serializer: serialize_object trimmed trailing spaces. It now keeps them and still normalizes trailing line breaks. Two trailing spaces are a Markdown line break, so this was also losing content.

  • Editors: the editors treated any difference between the saved text and the sent text as an outside merge. Saves now report a real merge:

    • merged from native and browser raw saves
    • a changed body from note reconciliation

    The note, Markdown, task and project editors only change the text on screen in that case.

  • Shared fixtures: conformance-v1.json gains object_body cases, which run in Rust and through the WebAssembly serializer.

End-to-end tests

  • Suite: 65 Playwright tests in apps/app/tests/e2e. They run the web build, which uses the same shell, editor and format code as desktop. Run them with bun run --cwd apps/app test:e2e (about 30 s).
  • CI: a new e2e job.

Bugs found and fixed, each with a failing test first:

  1. Cmd-K in a note added a link and opened the command palette.
  2. F2 after clicking a file did nothing, so Cmd-A plus a name could replace the note's text. F2 now renames the active document.
  3. Trashing the open document left a tab highlighted over "No file open".
  4. Enter in a new note's name before the editor loaded lost the next words.
  5. Launch stayed on Home. Reloading a document showed "No file open". Returning to Files showed nothing while a tab was highlighted.
  6. Pressing a shortcut twice quickly ran it once.
  7. Reloading Tasks, Projects or Calendar went to Home.
  8. "Add a task for today" created a task with no due date.
  9. Task pane: the toolbar overflowed, and statuses showed raw ids.
  10. The tab bar showed a horizontal scrollbar.
  11. Callouts showed raw > markers.
  12. Code highlighting was nearly invisible in dark mode.
  13. Checked boxes had no check mark.
  14. A save during a rename failed.
  15. Closing a tab lost the last text typed.
  16. Letters typed right after Cmd-O went into the note.

Known and left as is

  • A note loses blank lines at its start and end after a reload. This is the note format's normalization, and they stay on screen until then.
  • A note saved in CRLF is rewritten in LF on its first save. Plain Markdown files keep CRLF.
  • The New note tooltip can cover the first file in the tree.

Checks

  • bun run check, bun test (842), format:check, lint, test:e2e (65)
  • Clippy, cargo test --workspace

Saving a note trimmed trailing whitespace, and the editor then treated
the saved text as an outside edit: it replaced what was on screen,
deleting the space just typed, and showed "Merged changes from another
app". The serializer now keeps trailing spaces (two are a Markdown line
break), and the note, Markdown, task and project editors change their
text only when a save actually merged another app's edit.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-29T19:17:51.811425Z 7bdb711 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7bdb71183f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/app/src/lib/components/raw-markdown-editor.svelte
Comment thread crates/workspace-format/src/lib.rs
Comment thread apps/app/src/lib/editor/note-save.ts Outdated
The tests drive the built app in Chromium on a fresh browser workspace
each time and type with real key events. They check what the editor
shows and what the note file holds, read through a second workspace
worker the way another tab would. The first suite covers typing spaces
and line breaks, typing across autosave, undo after saves, reloads and
an outside edit.

A new CI job installs Chromium and runs the suite on Ubuntu.
Cmd-K in a note inserts a link, but the window handlers for the command
palette opened it on the same key press. The palette took focus, so the
link target typed next went into the palette instead of the note. Both
handlers now skip key presses that the focused control already handled.

The new editing tests also cover typing while a save waits for storage,
list indentation with Tab, input method composition, formatting
shortcuts, checklists and find and replace.
Raw Markdown saves returned saved even after folding in another
program's edit, so the editor never showed that edit and could save
over it. Native and browser saves now return merged when the saved text
differs from what the editor sent. Note saves count a merge only when
the body changed, so a title or property edit elsewhere no longer
rewrites text just typed. Shared conformance fixtures now cover how
note bodies round-trip, and both Rust and the WebAssembly build run
them.
The Markdown file editor waited for a "merged" save status that raw
saves never return. When another app changed the file while you typed,
the save merged both edits on disk, but the editor kept showing only
your text, and the next save wrote that text back over the other app's
edit. The editor now treats a save whose text differs from what it sent
as a merge, updates the text on screen and says so.

New tests edit plain Markdown files with frontmatter, tables, code
blocks, callouts, wikilinks, checkboxes, CRLF line endings and a byte
order mark, and check that the rest of the file keeps its bytes.
Clicking a file in the tree opens it and moves focus into its text, so
the tree's F2 no longer applied. Pressing F2 did nothing, and a user who
then pressed Cmd-A and typed a name replaced the note's content. F2 now
selects the name in the document header from anywhere outside other
text fields and dialogs. Settings lists the shortcut.

New tests cover creating notes and folders at the root and in folders,
inline and case-only renames, drag and drop, duplicate, keyboard
navigation and expanded folders after a reload.
Trashing the open document from the tree closed its tab, which made the
neighboring tab active, but then opened the page with no document. The
tab bar highlighted a tab while the page said "No file open". Trashing
now shows the tab that took the closed tab's place, the same as closing
a tab, and shows nothing only when no tab is left.
…itor loads

Enter in a document's name moves the caret to its text. The text editor
loads its code on first use, so on a slow machine Enter could arrive
before it was ready: nothing took focus and the words typed next went
nowhere. The note and Markdown editors now remember the request and
focus the text as soon as it is ready.
The tab bar and the Files page react to navigations, but both mount only
once the workspace is ready, after the navigation that opened the app.
They never saw it. Opening the app at its start page stayed on Home
instead of the last page, reloading a document's address showed "No
file open", and the Files page showed no document while a tab was
highlighted. Both now handle the current address when they mount, and
the Files page shows the highlighted tab's document when nothing else is
open.

The tests run Chromium with its own user agent, so the app and the
tests agree on Cmd or Ctrl. New tests cover renaming from the document
header, tabs, quick open, content search and wikilinks.
To avoid running a command twice when the macOS menu bar and the key
press both report it, every command was ignored for 300 ms after it
ran. Pressing Cmd-W twice quickly closed one tab, and Cmd-O right after
opening a file from quick open did nothing. Now only a report from the
other source within that time is ignored.
Pages that belong to a turned-off plugin send you to Home. While a
workspace opens, a plugin sync can settle before the workspace is open;
it lists no plugins, so reloading /tasks or reopening the app on it
counted Tasks as turned off and went to Home. The check now waits for a
sync of the open workspace itself.
The field on Home reads "Add a task for today", but it created a task
with no due date. The task never showed under Due today or in the
Today view, so it looked like the add had failed. It is now due today.

New tests cover Home, typing a task's title and body across saves and
an outside edit to an open task.
At a normal window width the formatting toolbar in the task pane ran
past its edge behind a horizontal scrollbar. It now wraps onto a second
line. Status and priority menus showed stored IDs such as "todo" and
"in-progress"; they, the project status menu and the board columns now
read To do, In progress, Medium and so on.
With many tabs open, a horizontal scrollbar showed under the tabs and
squeezed them against the top of the window. The bar now hides its
scrollbar and a mouse wheel scrolls it sideways; trackpads scroll it as
before.
A callout such as "> [!note] Title" showed the ">" marker on every line
and hid its type. With the caret outside the callout, the markers now
hide and the type reads as a label ("Note Title"); with the caret
inside, the source shows as typed.
Code blocks colored tokens with the chart colors, which this theme sets
to grays. In dark mode a keyword such as "const" was barely visible and
a variable name matched the block's background. The app now defines
syntax colors for each theme, and the editor uses them.
A checked "- [x]" box rendered as a filled square with no check mark:
the app's fill rule reset the editor's check image, and the check was
drawn in white, which the dark theme's light fill hides anyway. The
check is now a mask filled with the theme's contrast color.
The tests type a project's title and overview across saves, change its
status, and follow a task due today from the calendar and from Home's
next seven days.
Renaming a note holds autosave while the file moves. A save asked for
in that time, such as the one before closing the note, returned
"Couldn't save" and kept the note open. It now waits for the rename,
then saves.
Closing the tab of the open note removed its editor at once, so text
typed in the last moments before the close button, Cmd-W or a
middle-click was never saved. Closing the tab on screen now saves
first, and asks what to do when it can't.

New tests also cover leaving a note for another tab or for Home while
a save waits, renaming while typing, undo after a merge, and the same
note typed in two browser tabs.
The quick open field takes focus a moment after the palette appears.
Letters typed in that moment went into the note behind it, and a
palette reopened while it was still closing never focused its field,
so the whole search went into the note. The palette now releases focus
when it opens, collects those letters into its query, focuses its
field itself, and gives focus back when it closes.
A note written by another app, with aliases, tags, a URL and a table,
keeps every byte except the edited line and its updated time.
svelte-check covers apps/app/tests, so element callbacks now name their
element type. The second workspace worker is looked up when a test
first needs it, since the web server builds the app after the tests
load.
@lobbystack lobbystack changed the title Fix spaces and line breaks disappearing while typing in notes Fix typing bugs and add end-to-end tests Sep 29, 2026
On Linux, Playwright sends Shift with a lowercase letter, which no real
keyboard produces, so CodeMirror read Ctrl-Shift-Z as undo and
Ctrl-Shift-F as find. The tests now press the physical keys. The link
completion test waits out CodeMirror's 75 ms guard before Enter.
Closing a tab with the middle button no longer lets Linux paste the
last selection into the open note, and CI retries a test once so a
timing-sensitive one shows as flaky instead of failing the build.
bun audit started failing on joi 17.13.6 (an optional peer of
sveltekit-superforms that nothing installs) and undici 6.28.0 (a
leftover under node-gyp). Neither is needed; re-resolving the lockfile
removes them, and bun install --frozen-lockfile still passes.
@lobbystack
lobbystack merged commit 3a4410a into main Sep 29, 2026
8 checks passed
@lobbystack
lobbystack deleted the fix/editor-normalized-saves branch September 29, 2026 23:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant