[editor-core] fix TextOperation.isNoop() for tracked-changes (#35389)

* [editor-core] add regression test for composing no-op tracked change

* [editor-core] fix TextOperation.isNoop() for tracked-changes

GitOrigin-RevId: 345ee20275db9bf32ad32037013dde2bda507027
This commit is contained in:
Jakob Ackermann
2026-09-17 11:23:53 +00:00
committed by Copybot
parent b384c06b99
commit bccef96581
2 changed files with 26 additions and 1 deletions
@@ -222,7 +222,9 @@ class TextOperation extends EditOperation {
isNoop() {
return (
this.ops.length === 0 ||
(this.ops.length === 1 && this.ops[0] instanceof RetainOp)
(this.ops.length === 1 &&
this.ops[0] instanceof RetainOp &&
!this.ops[0].tracking)
)
}
@@ -109,6 +109,29 @@ describe('TextOperation', function () {
expect(o.isNoop()).to.be.false
})
it('does not treat a tracked-change retain as a no-op when composing for undo', function () {
// A single retain with a tracking directive changes the file's tracked
// changes when applied, so isNoop() reports false and
// canBeComposedWithForUndo() does not group it with other operations.
const trackedDelete = new TextOperation().retain(5, {
tracking: new TrackingProps(
'delete',
'user-1',
new Date('2026-07-10T00:00:00.000Z')
),
})
const file = new StringFileData('lorem')
file.edit(trackedDelete)
expect(file.getTrackedChanges().asSorted()).to.have.length(1)
expect(trackedDelete.isNoop()).to.be.false
const unrelatedInsert = new TextOperation().retain(5).insert('x')
expect(trackedDelete.canBeComposedWithForUndo(unrelatedInsert)).to.be.false
expect(unrelatedInsert.canBeComposedWithForUndo(trackedDelete)).to.be.false
})
it('converts to string', function () {
const o = new TextOperation()
o.retain(2)