test: cover case-only file renames in Obsidian

This commit is contained in:
vorotamoroz
2026-07-16 09:26:45 +00:00
parent 203ccfb74a
commit 37a6db05b9
3 changed files with 39 additions and 1 deletions
+2
View File
@@ -859,6 +859,8 @@ If this enabled, all chunks will be stored with the revision made from its conte
Setting key: handleFilenameCaseSensitive
If this enabled, All files are handled as case-Sensitive (Previous behaviour).
When this setting is disabled, changing only the letter case of a file name within the same directory is synchronised as a rename. Changing the letter case of a directory name is not supported by this handling.
### 4. Compatibility (Internal API Usage)
#### Scan changes on customisation sync
+1 -1
View File
@@ -91,7 +91,7 @@ LIVESYNC_CLI_COMMAND="docker run --rm --network host --user $(id -u):$(id -g) --
`test:e2e:obsidian:startup-scan` configures a temporary CouchDB database, stops Obsidian, writes a note directly into the vault, restarts Obsidian, and verifies from CouchDB that the boot-time scan picked up the offline file.
`test:e2e:obsidian:two-vault-sync` runs a two-vault note synchronisation workflow. It verifies note creation, update, rename, deletion, per-device target filters where one vault ignores a note that the other vault synchronises, and a separate encrypted round-trip with Path Obfuscation enabled. The optional Markdown conflict automatic merge check can be enabled with `E2E_OBSIDIAN_INCLUDE_MARKDOWN_CONFLICT=true`, but it is not part of the default local suite.
`test:e2e:obsidian:two-vault-sync` runs a two-vault note synchronisation workflow. It verifies note creation, update, ordinary rename, a case-only file name change within the same directory, deletion, per-device target filters where one vault ignores a note that the other vault synchronises, and a separate encrypted round-trip with Path Obfuscation enabled. Directory case changes deliberately remain outside this scenario because they require directory-aware rename handling. The optional Markdown conflict automatic merge check can be enabled with `E2E_OBSIDIAN_INCLUDE_MARKDOWN_CONFLICT=true`, but it is not part of the default local suite.
`test:e2e:obsidian:hidden-file-snippet-sync` runs a two-vault hidden file round-trip. It verifies creation and deletion of a real `.obsidian/snippets/*.css` file, automatic JSON conflict merging for a hidden file with the merged result propagated by a second synchronisation, manual JSON Resolve dialogue application through Obsidian's UI, and per-device target patterns where one vault ignores a hidden file that the other vault synchronises.
@@ -31,6 +31,8 @@ const updatePath = "E2E/two-vault/update.md";
const deletePath = "E2E/two-vault/delete.md";
const renameFromPath = "E2E/two-vault/rename-source.md";
const renameToPath = "E2E/two-vault/renamed/rename-target.md";
const caseRenameFromPath = "E2E/two-vault/Case-Rename.md";
const caseRenameToPath = "E2E/two-vault/case-rename.md";
const conflictPath = "E2E/two-vault/conflict.md";
const targetMismatchPath = "E2E/two-vault/target-mismatch.md";
const encryptedPath = "E2E/two-vault/encrypted.md";
@@ -362,6 +364,39 @@ async function runRename(context: RunnerContext, vaultA: TemporaryVault, vaultB:
console.log("Two-vault note rename round-tripped.");
}
async function runCaseOnlyRename(
context: RunnerContext,
vaultA: TemporaryVault,
vaultB: TemporaryVault
): Promise<void> {
const fileContent = "# Case-only rename\n\nThe document ID should remain live.\n";
let session = await startConfiguredSession(context, vaultA);
await writeNoteViaObsidian(context.cliBinary, session.cliEnv, caseRenameFromPath, fileContent);
await uploadNote(context, session, caseRenameFromPath);
await session.app.stop();
session = await startConfiguredSession(context, vaultB);
await syncAndApply(context, session);
await waitForPathContent(vaultB.path, caseRenameFromPath, (content) => content === fileContent);
await session.app.stop();
session = await startConfiguredSession(context, vaultA);
await renameNoteViaObsidian(context.cliBinary, session.cliEnv, caseRenameFromPath, caseRenameToPath);
await waitForLocalDatabaseEntry(context.cliBinary, session.cliEnv, caseRenameToPath);
await pushLocalChanges(context.cliBinary, session.cliEnv);
await session.app.stop();
session = await startConfiguredSession(context, vaultB);
await syncAndApply(context, session);
const renamedOnB = await waitForPathContent(vaultB.path, caseRenameToPath, (content) => content === fileContent);
await waitForPathDeleted(vaultB.path, caseRenameFromPath);
await session.app.stop();
assertEqual(renamedOnB, fileContent, "Case-only note rename did not round-trip to the second vault.");
console.log("Two-vault case-only note rename round-tripped without a tombstone.");
}
async function runEncryptedRoundTrip(
context: RunnerContext,
vaultA: TemporaryVault,
@@ -498,6 +533,7 @@ async function main(): Promise<void> {
await runCreateUpdateDelete(context, vaultA, vaultB);
await runRename(context, vaultA, vaultB);
await runCaseOnlyRename(context, vaultA, vaultB);
if (process.env.E2E_OBSIDIAN_INCLUDE_MARKDOWN_CONFLICT === "true") {
await runMarkdownAutoMerge(context, vaultA, vaultB);
}