import json import subprocess from pathlib import Path MERGER = Path(__file__).parents[1] / "frontend" / "checklist-conflict.js" def run_node(script: str): result = subprocess.run(["node", "-e", script], check=True, capture_output=True, text=True) return json.loads(result.stdout) def test_merge_applies_local_task_delta_to_latest_body_without_reverting_remote_edits(): script = f""" const mergeChecklistConflict = require({json.dumps(str(MERGER))}); const result = mergeChecklistConflict({{ baseBody:'Intro\\n- [ ] Build\\n- [ ] Test', localBody:'Intro\\n- [x] Build\\n- [ ] Test', remoteBody:'Updated intro\\n- [ ] Test\\n- [ ] Build\\n- [x] Document', }}); process.stdout.write(JSON.stringify(result)); """ output = run_node(script) assert output == { "body": "Updated intro\n- [ ] Test\n- [x] Build\n- [x] Document", "changes": [{"label": "Build", "checked": True}], "conflicts": [], } def test_merge_reports_missing_or_ambiguous_changed_tasks_without_writing_a_body(): script = f""" const mergeChecklistConflict = require({json.dumps(str(MERGER))}); const missing = mergeChecklistConflict({{ baseBody:'- [ ] Ship', localBody:'- [x] Ship', remoteBody:'- [ ] Release', }}); const duplicate = mergeChecklistConflict({{ baseBody:'- [ ] Ship', localBody:'- [x] Ship', remoteBody:'- [ ] Ship\\n- [ ] Ship', }}); process.stdout.write(JSON.stringify({{missing,duplicate}})); """ output = run_node(script) assert output["missing"]["body"] is None assert output["missing"]["conflicts"] == [{"label": "Ship", "reason": "missing"}] assert output["duplicate"]["body"] is None assert output["duplicate"]["conflicts"] == [{"label": "Ship", "reason": "ambiguous"}] def test_merge_appends_a_locally_added_step_to_remote_edits_without_reverting_them(): script = f""" const mergeChecklistConflict = require({json.dumps(str(MERGER))}); const result = mergeChecklistConflict({{ baseBody:'Intro\\n- [ ] Build', localBody:'Intro\\n- [ ] Build\\n- [ ] Verify rollback', remoteBody:'Updated intro\\n- [x] Build\\n- [ ] Notify support', }}); process.stdout.write(JSON.stringify(result)); """ output = run_node(script) assert output == { "body": "Updated intro\n- [x] Build\n- [ ] Notify support\n- [ ] Verify rollback", "changes": [{"label": "Verify rollback", "checked": False, "added": True}], "conflicts": [], } def test_merge_rejects_an_ambiguous_locally_added_duplicate(): script = f""" const mergeChecklistConflict = require({json.dumps(str(MERGER))}); const result = mergeChecklistConflict({{ baseBody:'- [ ] Build', localBody:'- [ ] Build\\n- [ ] Verify rollback\\n- [ ] verify rollback ', remoteBody:'- [x] Build', }}); process.stdout.write(JSON.stringify(result)); """ output = run_node(script) assert output["body"] is None assert output["conflicts"] == [{"label": "Verify rollback", "reason": "ambiguous"}] def test_merge_replays_rename_and_reorder_intent_onto_unrelated_remote_edits(): script = f""" const mergeChecklistConflict = require({json.dumps(str(MERGER))}); const result = mergeChecklistConflict({{ baseBody:'Intro\\n- [ ] Build\\n- [ ] Test', localBody:'Intro\\n- [ ] Test\\n- [ ] Compile', remoteBody:'Updated intro\\n- [x] Build\\n- [ ] Test\\nRemote note', operations:[ {{action:'rename',index:0,label:'Compile'}}, {{action:'move-later',index:0}}, ], }}); process.stdout.write(JSON.stringify(result)); """ output = run_node(script) assert output == { "body": "Updated intro\n- [ ] Test\n- [x] Compile\nRemote note", "changes": [ {"label": "Build", "renamed": "Compile"}, {"label": "Compile", "moved": "later"}, ], "conflicts": [], }