test(16.2-06): pin the untouched-value skip in cabana and PluginField

- TestFieldTypeUntouched: served values skip Decode, writes and notices;
  one changed locale writes and reports only that locale; canonical JSON
  comparison; a create never skips
- PluginField: an element that echoes its value on connect is never
  written a second time
This commit is contained in:
2026-10-10 15:42:31 +02:00
parent c07da3912b
commit 08a20021e3
2 changed files with 374 additions and 0 deletions

View File

@@ -245,6 +245,81 @@ describe('stored value reload', () => {
})
})
/** A stub element that re-emits its current value when it connects, as an
* element that normalizes nothing but announces its value on mount does. */
class AcmeDemoEcho extends AcmeDemoNotes {
connectedCallback(): void {
this.dispatchEvent(new CustomEvent(FIELD_CHANGE_EVENT, { bubbles: true, detail: { value: this.value } }))
}
}
if (!customElements.get('acme-demo-echo')) {
customElements.define('acme-demo-echo', AcmeDemoEcho)
}
describe('untouched value (D-03)', () => {
// The form: every update:modelValue becomes the next modelValue, as
// FormView's v-model does.
function mountEcho(modelValue: unknown) {
const wrapper: VueWrapper = mount(PluginField, {
props: {
field: notesField({ element: 'acme-demo-echo' }),
modelValue,
controlId: 'f-notes',
recordId: 7,
source: SOURCE,
'onUpdate:modelValue': (value: unknown) => wrapper.setProps({ modelValue: value }),
},
global: { provide: { [FORM_LOCALE as symbol]: ref('pl') } },
// Attached, so the element's connectedCallback runs.
attachTo: document.body,
})
return wrapper
}
function echoElement(wrapper: VueWrapper): AcmeDemoEcho {
const found = wrapper.find('acme-demo-echo').element
if (!(found instanceof AcmeDemoEcho)) {
throw new Error('echo element not mounted')
}
return found
}
it('keeps the served HTML identical when the element echoes it on connect', async () => {
const served = '\n<!-- imported -->\n<p>Grzyby <b>rosną</b></p>\n<footer class="author-footer"><p>Autor</p></footer>\n'
const wrapper = mountEcho(served)
await flushPromises()
const el = echoElement(wrapper)
expect(wrapper.emitted('update:modelValue')).toEqual([[served]])
expect((wrapper.props() as { modelValue: unknown }).modelValue).toBe(served)
expect(el.value).toBe(served)
// The property was written once, before connect; the echo wrote nothing.
expect(el.writes).toEqual([served])
})
it('does not write an equal object value a second time', async () => {
const served = { blocks: [{ type: 'p', text: 'a' }], version: 1 }
const wrapper = mountEcho(served)
await flushPromises()
const el = echoElement(wrapper)
expect((wrapper.props() as { modelValue: unknown }).modelValue).toEqual(served)
// An equal copy from the server (a reload) is not written either.
await wrapper.setProps({ modelValue: JSON.parse(JSON.stringify(served)) })
await flushPromises()
expect(el.writes).toEqual([served])
})
it('writes a value that really differs exactly once', async () => {
const wrapper = mountEcho('<p>a</p>')
await flushPromises()
const el = echoElement(wrapper)
await wrapper.setProps({ modelValue: '<p>b</p>' })
await flushPromises()
await wrapper.setProps({ modelValue: '<p>b</p>' })
await flushPromises()
expect(el.writes).toEqual(['<p>a</p>', '<p>b</p>'])
})
})
describe('MLPluginField', () => {
class AcmeDemoNotesml extends AcmeDemoNotes {}
if (!customElements.get('acme-demo-notesml')) {