From afb8029a5075abe77ab38c56eb7b4d3e63fb9e64 Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Mon, 8 Jun 2026 11:30:15 -0700 Subject: [PATCH] Fix live accept cleanup for mapped lists (#229) --- .../skills/impeccable/scripts/live-browser.js | 54 +++++++++++-------- .../skills/impeccable/scripts/live-browser.js | 54 +++++++++++-------- .../skills/impeccable/scripts/live-browser.js | 54 +++++++++++-------- .../skills/impeccable/scripts/live-browser.js | 54 +++++++++++-------- .../skills/impeccable/scripts/live-browser.js | 54 +++++++++++-------- .../skills/impeccable/scripts/live-browser.js | 54 +++++++++++-------- .../skills/impeccable/scripts/live-browser.js | 54 +++++++++++-------- .pi/skills/impeccable/scripts/live-browser.js | 54 +++++++++++-------- .../skills/impeccable/scripts/live-browser.js | 54 +++++++++++-------- .../skills/impeccable/scripts/live-browser.js | 54 +++++++++++-------- .../skills/impeccable/scripts/live-browser.js | 54 +++++++++++-------- .../skills/impeccable/scripts/live-browser.js | 54 +++++++++++-------- .../skills/impeccable/scripts/live-browser.js | 54 +++++++++++-------- skill/scripts/live-browser.js | 54 +++++++++++-------- tests/live-browser-source.test.mjs | 18 +++++-- ...ive-e2e-accept-cleanup-regression.test.mjs | 6 +-- 16 files changed, 465 insertions(+), 315 deletions(-) diff --git a/.agents/skills/impeccable/scripts/live-browser.js b/.agents/skills/impeccable/scripts/live-browser.js index 302b9ec23..0a533945f 100644 --- a/.agents/skills/impeccable/scripts/live-browser.js +++ b/.agents/skills/impeccable/scripts/live-browser.js @@ -6855,7 +6855,14 @@ void main() { function scheduleAcceptCleanup(accepted) { setTimeout(function() { - if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + if (!accepted?.isSvelteComponent && !acceptedDomAlreadyClean(accepted)) { + setTimeout(function() { + if (pendingAcceptedSession?.id !== accepted?.id) return; + if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + cleanupAcceptedSession(); + }, 1800); + return; + } cleanupAcceptedSession(); }, 1200); } @@ -6884,39 +6891,42 @@ void main() { function acceptedDomAlreadyClean(pending) { if (!pending?.acceptedSelector) return false; const matches = [...document.querySelectorAll(pending.acceptedSelector)]; - return matches.some((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant]')); + return matches.length > 0 + && matches.every((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant],[data-impeccable-carbonize]')); } function ensureAcceptedDomClean(pending) { + if (acceptedDomAlreadyClean(pending)) return; const sessionId = pending?.id; const variantId = pending?.variant; - const wrapper = findAcceptedRuntimeWrapper(sessionId); - const accepted = wrapper?.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); - if (!wrapper) { + const wrappers = findAcceptedRuntimeWrappers(sessionId); + if (wrappers.length === 0) { restoreAcceptedDomFromSnapshot(pending); return; } - if (acceptedDomAlreadyClean(pending)) { + for (const wrapper of wrappers) { + if (!wrapper?.isConnected) continue; + const accepted = wrapper.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); + if (!accepted) { + wrapper.remove(); + continue; + } + const parent = wrapper.parentElement; + if (!parent) continue; + while (accepted.firstChild) { + parent.insertBefore(accepted.firstChild, wrapper); + } wrapper.remove(); - return; } - if (!accepted) { - wrapper.remove(); - restoreAcceptedDomFromSnapshot(pending); - return; - } - const parent = wrapper.parentElement; - if (!parent) return; - while (accepted.firstChild) { - parent.insertBefore(accepted.firstChild, wrapper); - } - wrapper.remove(); + if (!acceptedDomAlreadyClean(pending)) restoreAcceptedDomFromSnapshot(pending); } - function findAcceptedRuntimeWrapper(sessionId) { - if (!sessionId) return null; - return document.querySelector('[data-impeccable-variants="' + sessionId + '"]') - || document.querySelector('[data-impeccable-carbonize="' + sessionId + '"]'); + function findAcceptedRuntimeWrappers(sessionId) { + if (!sessionId) return []; + return [...new Set([ + ...document.querySelectorAll('[data-impeccable-variants="' + sessionId + '"]'), + ...document.querySelectorAll('[data-impeccable-carbonize="' + sessionId + '"]'), + ])]; } function restoreAcceptedDomFromSnapshot(pending) { diff --git a/.claude/skills/impeccable/scripts/live-browser.js b/.claude/skills/impeccable/scripts/live-browser.js index 302b9ec23..0a533945f 100644 --- a/.claude/skills/impeccable/scripts/live-browser.js +++ b/.claude/skills/impeccable/scripts/live-browser.js @@ -6855,7 +6855,14 @@ void main() { function scheduleAcceptCleanup(accepted) { setTimeout(function() { - if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + if (!accepted?.isSvelteComponent && !acceptedDomAlreadyClean(accepted)) { + setTimeout(function() { + if (pendingAcceptedSession?.id !== accepted?.id) return; + if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + cleanupAcceptedSession(); + }, 1800); + return; + } cleanupAcceptedSession(); }, 1200); } @@ -6884,39 +6891,42 @@ void main() { function acceptedDomAlreadyClean(pending) { if (!pending?.acceptedSelector) return false; const matches = [...document.querySelectorAll(pending.acceptedSelector)]; - return matches.some((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant]')); + return matches.length > 0 + && matches.every((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant],[data-impeccable-carbonize]')); } function ensureAcceptedDomClean(pending) { + if (acceptedDomAlreadyClean(pending)) return; const sessionId = pending?.id; const variantId = pending?.variant; - const wrapper = findAcceptedRuntimeWrapper(sessionId); - const accepted = wrapper?.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); - if (!wrapper) { + const wrappers = findAcceptedRuntimeWrappers(sessionId); + if (wrappers.length === 0) { restoreAcceptedDomFromSnapshot(pending); return; } - if (acceptedDomAlreadyClean(pending)) { + for (const wrapper of wrappers) { + if (!wrapper?.isConnected) continue; + const accepted = wrapper.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); + if (!accepted) { + wrapper.remove(); + continue; + } + const parent = wrapper.parentElement; + if (!parent) continue; + while (accepted.firstChild) { + parent.insertBefore(accepted.firstChild, wrapper); + } wrapper.remove(); - return; } - if (!accepted) { - wrapper.remove(); - restoreAcceptedDomFromSnapshot(pending); - return; - } - const parent = wrapper.parentElement; - if (!parent) return; - while (accepted.firstChild) { - parent.insertBefore(accepted.firstChild, wrapper); - } - wrapper.remove(); + if (!acceptedDomAlreadyClean(pending)) restoreAcceptedDomFromSnapshot(pending); } - function findAcceptedRuntimeWrapper(sessionId) { - if (!sessionId) return null; - return document.querySelector('[data-impeccable-variants="' + sessionId + '"]') - || document.querySelector('[data-impeccable-carbonize="' + sessionId + '"]'); + function findAcceptedRuntimeWrappers(sessionId) { + if (!sessionId) return []; + return [...new Set([ + ...document.querySelectorAll('[data-impeccable-variants="' + sessionId + '"]'), + ...document.querySelectorAll('[data-impeccable-carbonize="' + sessionId + '"]'), + ])]; } function restoreAcceptedDomFromSnapshot(pending) { diff --git a/.cursor/skills/impeccable/scripts/live-browser.js b/.cursor/skills/impeccable/scripts/live-browser.js index 302b9ec23..0a533945f 100644 --- a/.cursor/skills/impeccable/scripts/live-browser.js +++ b/.cursor/skills/impeccable/scripts/live-browser.js @@ -6855,7 +6855,14 @@ void main() { function scheduleAcceptCleanup(accepted) { setTimeout(function() { - if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + if (!accepted?.isSvelteComponent && !acceptedDomAlreadyClean(accepted)) { + setTimeout(function() { + if (pendingAcceptedSession?.id !== accepted?.id) return; + if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + cleanupAcceptedSession(); + }, 1800); + return; + } cleanupAcceptedSession(); }, 1200); } @@ -6884,39 +6891,42 @@ void main() { function acceptedDomAlreadyClean(pending) { if (!pending?.acceptedSelector) return false; const matches = [...document.querySelectorAll(pending.acceptedSelector)]; - return matches.some((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant]')); + return matches.length > 0 + && matches.every((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant],[data-impeccable-carbonize]')); } function ensureAcceptedDomClean(pending) { + if (acceptedDomAlreadyClean(pending)) return; const sessionId = pending?.id; const variantId = pending?.variant; - const wrapper = findAcceptedRuntimeWrapper(sessionId); - const accepted = wrapper?.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); - if (!wrapper) { + const wrappers = findAcceptedRuntimeWrappers(sessionId); + if (wrappers.length === 0) { restoreAcceptedDomFromSnapshot(pending); return; } - if (acceptedDomAlreadyClean(pending)) { + for (const wrapper of wrappers) { + if (!wrapper?.isConnected) continue; + const accepted = wrapper.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); + if (!accepted) { + wrapper.remove(); + continue; + } + const parent = wrapper.parentElement; + if (!parent) continue; + while (accepted.firstChild) { + parent.insertBefore(accepted.firstChild, wrapper); + } wrapper.remove(); - return; } - if (!accepted) { - wrapper.remove(); - restoreAcceptedDomFromSnapshot(pending); - return; - } - const parent = wrapper.parentElement; - if (!parent) return; - while (accepted.firstChild) { - parent.insertBefore(accepted.firstChild, wrapper); - } - wrapper.remove(); + if (!acceptedDomAlreadyClean(pending)) restoreAcceptedDomFromSnapshot(pending); } - function findAcceptedRuntimeWrapper(sessionId) { - if (!sessionId) return null; - return document.querySelector('[data-impeccable-variants="' + sessionId + '"]') - || document.querySelector('[data-impeccable-carbonize="' + sessionId + '"]'); + function findAcceptedRuntimeWrappers(sessionId) { + if (!sessionId) return []; + return [...new Set([ + ...document.querySelectorAll('[data-impeccable-variants="' + sessionId + '"]'), + ...document.querySelectorAll('[data-impeccable-carbonize="' + sessionId + '"]'), + ])]; } function restoreAcceptedDomFromSnapshot(pending) { diff --git a/.gemini/skills/impeccable/scripts/live-browser.js b/.gemini/skills/impeccable/scripts/live-browser.js index 302b9ec23..0a533945f 100644 --- a/.gemini/skills/impeccable/scripts/live-browser.js +++ b/.gemini/skills/impeccable/scripts/live-browser.js @@ -6855,7 +6855,14 @@ void main() { function scheduleAcceptCleanup(accepted) { setTimeout(function() { - if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + if (!accepted?.isSvelteComponent && !acceptedDomAlreadyClean(accepted)) { + setTimeout(function() { + if (pendingAcceptedSession?.id !== accepted?.id) return; + if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + cleanupAcceptedSession(); + }, 1800); + return; + } cleanupAcceptedSession(); }, 1200); } @@ -6884,39 +6891,42 @@ void main() { function acceptedDomAlreadyClean(pending) { if (!pending?.acceptedSelector) return false; const matches = [...document.querySelectorAll(pending.acceptedSelector)]; - return matches.some((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant]')); + return matches.length > 0 + && matches.every((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant],[data-impeccable-carbonize]')); } function ensureAcceptedDomClean(pending) { + if (acceptedDomAlreadyClean(pending)) return; const sessionId = pending?.id; const variantId = pending?.variant; - const wrapper = findAcceptedRuntimeWrapper(sessionId); - const accepted = wrapper?.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); - if (!wrapper) { + const wrappers = findAcceptedRuntimeWrappers(sessionId); + if (wrappers.length === 0) { restoreAcceptedDomFromSnapshot(pending); return; } - if (acceptedDomAlreadyClean(pending)) { + for (const wrapper of wrappers) { + if (!wrapper?.isConnected) continue; + const accepted = wrapper.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); + if (!accepted) { + wrapper.remove(); + continue; + } + const parent = wrapper.parentElement; + if (!parent) continue; + while (accepted.firstChild) { + parent.insertBefore(accepted.firstChild, wrapper); + } wrapper.remove(); - return; } - if (!accepted) { - wrapper.remove(); - restoreAcceptedDomFromSnapshot(pending); - return; - } - const parent = wrapper.parentElement; - if (!parent) return; - while (accepted.firstChild) { - parent.insertBefore(accepted.firstChild, wrapper); - } - wrapper.remove(); + if (!acceptedDomAlreadyClean(pending)) restoreAcceptedDomFromSnapshot(pending); } - function findAcceptedRuntimeWrapper(sessionId) { - if (!sessionId) return null; - return document.querySelector('[data-impeccable-variants="' + sessionId + '"]') - || document.querySelector('[data-impeccable-carbonize="' + sessionId + '"]'); + function findAcceptedRuntimeWrappers(sessionId) { + if (!sessionId) return []; + return [...new Set([ + ...document.querySelectorAll('[data-impeccable-variants="' + sessionId + '"]'), + ...document.querySelectorAll('[data-impeccable-carbonize="' + sessionId + '"]'), + ])]; } function restoreAcceptedDomFromSnapshot(pending) { diff --git a/.github/skills/impeccable/scripts/live-browser.js b/.github/skills/impeccable/scripts/live-browser.js index 302b9ec23..0a533945f 100644 --- a/.github/skills/impeccable/scripts/live-browser.js +++ b/.github/skills/impeccable/scripts/live-browser.js @@ -6855,7 +6855,14 @@ void main() { function scheduleAcceptCleanup(accepted) { setTimeout(function() { - if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + if (!accepted?.isSvelteComponent && !acceptedDomAlreadyClean(accepted)) { + setTimeout(function() { + if (pendingAcceptedSession?.id !== accepted?.id) return; + if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + cleanupAcceptedSession(); + }, 1800); + return; + } cleanupAcceptedSession(); }, 1200); } @@ -6884,39 +6891,42 @@ void main() { function acceptedDomAlreadyClean(pending) { if (!pending?.acceptedSelector) return false; const matches = [...document.querySelectorAll(pending.acceptedSelector)]; - return matches.some((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant]')); + return matches.length > 0 + && matches.every((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant],[data-impeccable-carbonize]')); } function ensureAcceptedDomClean(pending) { + if (acceptedDomAlreadyClean(pending)) return; const sessionId = pending?.id; const variantId = pending?.variant; - const wrapper = findAcceptedRuntimeWrapper(sessionId); - const accepted = wrapper?.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); - if (!wrapper) { + const wrappers = findAcceptedRuntimeWrappers(sessionId); + if (wrappers.length === 0) { restoreAcceptedDomFromSnapshot(pending); return; } - if (acceptedDomAlreadyClean(pending)) { + for (const wrapper of wrappers) { + if (!wrapper?.isConnected) continue; + const accepted = wrapper.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); + if (!accepted) { + wrapper.remove(); + continue; + } + const parent = wrapper.parentElement; + if (!parent) continue; + while (accepted.firstChild) { + parent.insertBefore(accepted.firstChild, wrapper); + } wrapper.remove(); - return; } - if (!accepted) { - wrapper.remove(); - restoreAcceptedDomFromSnapshot(pending); - return; - } - const parent = wrapper.parentElement; - if (!parent) return; - while (accepted.firstChild) { - parent.insertBefore(accepted.firstChild, wrapper); - } - wrapper.remove(); + if (!acceptedDomAlreadyClean(pending)) restoreAcceptedDomFromSnapshot(pending); } - function findAcceptedRuntimeWrapper(sessionId) { - if (!sessionId) return null; - return document.querySelector('[data-impeccable-variants="' + sessionId + '"]') - || document.querySelector('[data-impeccable-carbonize="' + sessionId + '"]'); + function findAcceptedRuntimeWrappers(sessionId) { + if (!sessionId) return []; + return [...new Set([ + ...document.querySelectorAll('[data-impeccable-variants="' + sessionId + '"]'), + ...document.querySelectorAll('[data-impeccable-carbonize="' + sessionId + '"]'), + ])]; } function restoreAcceptedDomFromSnapshot(pending) { diff --git a/.kiro/skills/impeccable/scripts/live-browser.js b/.kiro/skills/impeccable/scripts/live-browser.js index 302b9ec23..0a533945f 100644 --- a/.kiro/skills/impeccable/scripts/live-browser.js +++ b/.kiro/skills/impeccable/scripts/live-browser.js @@ -6855,7 +6855,14 @@ void main() { function scheduleAcceptCleanup(accepted) { setTimeout(function() { - if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + if (!accepted?.isSvelteComponent && !acceptedDomAlreadyClean(accepted)) { + setTimeout(function() { + if (pendingAcceptedSession?.id !== accepted?.id) return; + if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + cleanupAcceptedSession(); + }, 1800); + return; + } cleanupAcceptedSession(); }, 1200); } @@ -6884,39 +6891,42 @@ void main() { function acceptedDomAlreadyClean(pending) { if (!pending?.acceptedSelector) return false; const matches = [...document.querySelectorAll(pending.acceptedSelector)]; - return matches.some((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant]')); + return matches.length > 0 + && matches.every((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant],[data-impeccable-carbonize]')); } function ensureAcceptedDomClean(pending) { + if (acceptedDomAlreadyClean(pending)) return; const sessionId = pending?.id; const variantId = pending?.variant; - const wrapper = findAcceptedRuntimeWrapper(sessionId); - const accepted = wrapper?.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); - if (!wrapper) { + const wrappers = findAcceptedRuntimeWrappers(sessionId); + if (wrappers.length === 0) { restoreAcceptedDomFromSnapshot(pending); return; } - if (acceptedDomAlreadyClean(pending)) { + for (const wrapper of wrappers) { + if (!wrapper?.isConnected) continue; + const accepted = wrapper.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); + if (!accepted) { + wrapper.remove(); + continue; + } + const parent = wrapper.parentElement; + if (!parent) continue; + while (accepted.firstChild) { + parent.insertBefore(accepted.firstChild, wrapper); + } wrapper.remove(); - return; } - if (!accepted) { - wrapper.remove(); - restoreAcceptedDomFromSnapshot(pending); - return; - } - const parent = wrapper.parentElement; - if (!parent) return; - while (accepted.firstChild) { - parent.insertBefore(accepted.firstChild, wrapper); - } - wrapper.remove(); + if (!acceptedDomAlreadyClean(pending)) restoreAcceptedDomFromSnapshot(pending); } - function findAcceptedRuntimeWrapper(sessionId) { - if (!sessionId) return null; - return document.querySelector('[data-impeccable-variants="' + sessionId + '"]') - || document.querySelector('[data-impeccable-carbonize="' + sessionId + '"]'); + function findAcceptedRuntimeWrappers(sessionId) { + if (!sessionId) return []; + return [...new Set([ + ...document.querySelectorAll('[data-impeccable-variants="' + sessionId + '"]'), + ...document.querySelectorAll('[data-impeccable-carbonize="' + sessionId + '"]'), + ])]; } function restoreAcceptedDomFromSnapshot(pending) { diff --git a/.opencode/skills/impeccable/scripts/live-browser.js b/.opencode/skills/impeccable/scripts/live-browser.js index 302b9ec23..0a533945f 100644 --- a/.opencode/skills/impeccable/scripts/live-browser.js +++ b/.opencode/skills/impeccable/scripts/live-browser.js @@ -6855,7 +6855,14 @@ void main() { function scheduleAcceptCleanup(accepted) { setTimeout(function() { - if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + if (!accepted?.isSvelteComponent && !acceptedDomAlreadyClean(accepted)) { + setTimeout(function() { + if (pendingAcceptedSession?.id !== accepted?.id) return; + if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + cleanupAcceptedSession(); + }, 1800); + return; + } cleanupAcceptedSession(); }, 1200); } @@ -6884,39 +6891,42 @@ void main() { function acceptedDomAlreadyClean(pending) { if (!pending?.acceptedSelector) return false; const matches = [...document.querySelectorAll(pending.acceptedSelector)]; - return matches.some((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant]')); + return matches.length > 0 + && matches.every((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant],[data-impeccable-carbonize]')); } function ensureAcceptedDomClean(pending) { + if (acceptedDomAlreadyClean(pending)) return; const sessionId = pending?.id; const variantId = pending?.variant; - const wrapper = findAcceptedRuntimeWrapper(sessionId); - const accepted = wrapper?.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); - if (!wrapper) { + const wrappers = findAcceptedRuntimeWrappers(sessionId); + if (wrappers.length === 0) { restoreAcceptedDomFromSnapshot(pending); return; } - if (acceptedDomAlreadyClean(pending)) { + for (const wrapper of wrappers) { + if (!wrapper?.isConnected) continue; + const accepted = wrapper.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); + if (!accepted) { + wrapper.remove(); + continue; + } + const parent = wrapper.parentElement; + if (!parent) continue; + while (accepted.firstChild) { + parent.insertBefore(accepted.firstChild, wrapper); + } wrapper.remove(); - return; } - if (!accepted) { - wrapper.remove(); - restoreAcceptedDomFromSnapshot(pending); - return; - } - const parent = wrapper.parentElement; - if (!parent) return; - while (accepted.firstChild) { - parent.insertBefore(accepted.firstChild, wrapper); - } - wrapper.remove(); + if (!acceptedDomAlreadyClean(pending)) restoreAcceptedDomFromSnapshot(pending); } - function findAcceptedRuntimeWrapper(sessionId) { - if (!sessionId) return null; - return document.querySelector('[data-impeccable-variants="' + sessionId + '"]') - || document.querySelector('[data-impeccable-carbonize="' + sessionId + '"]'); + function findAcceptedRuntimeWrappers(sessionId) { + if (!sessionId) return []; + return [...new Set([ + ...document.querySelectorAll('[data-impeccable-variants="' + sessionId + '"]'), + ...document.querySelectorAll('[data-impeccable-carbonize="' + sessionId + '"]'), + ])]; } function restoreAcceptedDomFromSnapshot(pending) { diff --git a/.pi/skills/impeccable/scripts/live-browser.js b/.pi/skills/impeccable/scripts/live-browser.js index 302b9ec23..0a533945f 100644 --- a/.pi/skills/impeccable/scripts/live-browser.js +++ b/.pi/skills/impeccable/scripts/live-browser.js @@ -6855,7 +6855,14 @@ void main() { function scheduleAcceptCleanup(accepted) { setTimeout(function() { - if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + if (!accepted?.isSvelteComponent && !acceptedDomAlreadyClean(accepted)) { + setTimeout(function() { + if (pendingAcceptedSession?.id !== accepted?.id) return; + if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + cleanupAcceptedSession(); + }, 1800); + return; + } cleanupAcceptedSession(); }, 1200); } @@ -6884,39 +6891,42 @@ void main() { function acceptedDomAlreadyClean(pending) { if (!pending?.acceptedSelector) return false; const matches = [...document.querySelectorAll(pending.acceptedSelector)]; - return matches.some((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant]')); + return matches.length > 0 + && matches.every((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant],[data-impeccable-carbonize]')); } function ensureAcceptedDomClean(pending) { + if (acceptedDomAlreadyClean(pending)) return; const sessionId = pending?.id; const variantId = pending?.variant; - const wrapper = findAcceptedRuntimeWrapper(sessionId); - const accepted = wrapper?.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); - if (!wrapper) { + const wrappers = findAcceptedRuntimeWrappers(sessionId); + if (wrappers.length === 0) { restoreAcceptedDomFromSnapshot(pending); return; } - if (acceptedDomAlreadyClean(pending)) { + for (const wrapper of wrappers) { + if (!wrapper?.isConnected) continue; + const accepted = wrapper.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); + if (!accepted) { + wrapper.remove(); + continue; + } + const parent = wrapper.parentElement; + if (!parent) continue; + while (accepted.firstChild) { + parent.insertBefore(accepted.firstChild, wrapper); + } wrapper.remove(); - return; } - if (!accepted) { - wrapper.remove(); - restoreAcceptedDomFromSnapshot(pending); - return; - } - const parent = wrapper.parentElement; - if (!parent) return; - while (accepted.firstChild) { - parent.insertBefore(accepted.firstChild, wrapper); - } - wrapper.remove(); + if (!acceptedDomAlreadyClean(pending)) restoreAcceptedDomFromSnapshot(pending); } - function findAcceptedRuntimeWrapper(sessionId) { - if (!sessionId) return null; - return document.querySelector('[data-impeccable-variants="' + sessionId + '"]') - || document.querySelector('[data-impeccable-carbonize="' + sessionId + '"]'); + function findAcceptedRuntimeWrappers(sessionId) { + if (!sessionId) return []; + return [...new Set([ + ...document.querySelectorAll('[data-impeccable-variants="' + sessionId + '"]'), + ...document.querySelectorAll('[data-impeccable-carbonize="' + sessionId + '"]'), + ])]; } function restoreAcceptedDomFromSnapshot(pending) { diff --git a/.qoder/skills/impeccable/scripts/live-browser.js b/.qoder/skills/impeccable/scripts/live-browser.js index 302b9ec23..0a533945f 100644 --- a/.qoder/skills/impeccable/scripts/live-browser.js +++ b/.qoder/skills/impeccable/scripts/live-browser.js @@ -6855,7 +6855,14 @@ void main() { function scheduleAcceptCleanup(accepted) { setTimeout(function() { - if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + if (!accepted?.isSvelteComponent && !acceptedDomAlreadyClean(accepted)) { + setTimeout(function() { + if (pendingAcceptedSession?.id !== accepted?.id) return; + if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + cleanupAcceptedSession(); + }, 1800); + return; + } cleanupAcceptedSession(); }, 1200); } @@ -6884,39 +6891,42 @@ void main() { function acceptedDomAlreadyClean(pending) { if (!pending?.acceptedSelector) return false; const matches = [...document.querySelectorAll(pending.acceptedSelector)]; - return matches.some((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant]')); + return matches.length > 0 + && matches.every((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant],[data-impeccable-carbonize]')); } function ensureAcceptedDomClean(pending) { + if (acceptedDomAlreadyClean(pending)) return; const sessionId = pending?.id; const variantId = pending?.variant; - const wrapper = findAcceptedRuntimeWrapper(sessionId); - const accepted = wrapper?.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); - if (!wrapper) { + const wrappers = findAcceptedRuntimeWrappers(sessionId); + if (wrappers.length === 0) { restoreAcceptedDomFromSnapshot(pending); return; } - if (acceptedDomAlreadyClean(pending)) { + for (const wrapper of wrappers) { + if (!wrapper?.isConnected) continue; + const accepted = wrapper.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); + if (!accepted) { + wrapper.remove(); + continue; + } + const parent = wrapper.parentElement; + if (!parent) continue; + while (accepted.firstChild) { + parent.insertBefore(accepted.firstChild, wrapper); + } wrapper.remove(); - return; } - if (!accepted) { - wrapper.remove(); - restoreAcceptedDomFromSnapshot(pending); - return; - } - const parent = wrapper.parentElement; - if (!parent) return; - while (accepted.firstChild) { - parent.insertBefore(accepted.firstChild, wrapper); - } - wrapper.remove(); + if (!acceptedDomAlreadyClean(pending)) restoreAcceptedDomFromSnapshot(pending); } - function findAcceptedRuntimeWrapper(sessionId) { - if (!sessionId) return null; - return document.querySelector('[data-impeccable-variants="' + sessionId + '"]') - || document.querySelector('[data-impeccable-carbonize="' + sessionId + '"]'); + function findAcceptedRuntimeWrappers(sessionId) { + if (!sessionId) return []; + return [...new Set([ + ...document.querySelectorAll('[data-impeccable-variants="' + sessionId + '"]'), + ...document.querySelectorAll('[data-impeccable-carbonize="' + sessionId + '"]'), + ])]; } function restoreAcceptedDomFromSnapshot(pending) { diff --git a/.rovodev/skills/impeccable/scripts/live-browser.js b/.rovodev/skills/impeccable/scripts/live-browser.js index 302b9ec23..0a533945f 100644 --- a/.rovodev/skills/impeccable/scripts/live-browser.js +++ b/.rovodev/skills/impeccable/scripts/live-browser.js @@ -6855,7 +6855,14 @@ void main() { function scheduleAcceptCleanup(accepted) { setTimeout(function() { - if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + if (!accepted?.isSvelteComponent && !acceptedDomAlreadyClean(accepted)) { + setTimeout(function() { + if (pendingAcceptedSession?.id !== accepted?.id) return; + if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + cleanupAcceptedSession(); + }, 1800); + return; + } cleanupAcceptedSession(); }, 1200); } @@ -6884,39 +6891,42 @@ void main() { function acceptedDomAlreadyClean(pending) { if (!pending?.acceptedSelector) return false; const matches = [...document.querySelectorAll(pending.acceptedSelector)]; - return matches.some((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant]')); + return matches.length > 0 + && matches.every((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant],[data-impeccable-carbonize]')); } function ensureAcceptedDomClean(pending) { + if (acceptedDomAlreadyClean(pending)) return; const sessionId = pending?.id; const variantId = pending?.variant; - const wrapper = findAcceptedRuntimeWrapper(sessionId); - const accepted = wrapper?.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); - if (!wrapper) { + const wrappers = findAcceptedRuntimeWrappers(sessionId); + if (wrappers.length === 0) { restoreAcceptedDomFromSnapshot(pending); return; } - if (acceptedDomAlreadyClean(pending)) { + for (const wrapper of wrappers) { + if (!wrapper?.isConnected) continue; + const accepted = wrapper.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); + if (!accepted) { + wrapper.remove(); + continue; + } + const parent = wrapper.parentElement; + if (!parent) continue; + while (accepted.firstChild) { + parent.insertBefore(accepted.firstChild, wrapper); + } wrapper.remove(); - return; } - if (!accepted) { - wrapper.remove(); - restoreAcceptedDomFromSnapshot(pending); - return; - } - const parent = wrapper.parentElement; - if (!parent) return; - while (accepted.firstChild) { - parent.insertBefore(accepted.firstChild, wrapper); - } - wrapper.remove(); + if (!acceptedDomAlreadyClean(pending)) restoreAcceptedDomFromSnapshot(pending); } - function findAcceptedRuntimeWrapper(sessionId) { - if (!sessionId) return null; - return document.querySelector('[data-impeccable-variants="' + sessionId + '"]') - || document.querySelector('[data-impeccable-carbonize="' + sessionId + '"]'); + function findAcceptedRuntimeWrappers(sessionId) { + if (!sessionId) return []; + return [...new Set([ + ...document.querySelectorAll('[data-impeccable-variants="' + sessionId + '"]'), + ...document.querySelectorAll('[data-impeccable-carbonize="' + sessionId + '"]'), + ])]; } function restoreAcceptedDomFromSnapshot(pending) { diff --git a/.trae-cn/skills/impeccable/scripts/live-browser.js b/.trae-cn/skills/impeccable/scripts/live-browser.js index 302b9ec23..0a533945f 100644 --- a/.trae-cn/skills/impeccable/scripts/live-browser.js +++ b/.trae-cn/skills/impeccable/scripts/live-browser.js @@ -6855,7 +6855,14 @@ void main() { function scheduleAcceptCleanup(accepted) { setTimeout(function() { - if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + if (!accepted?.isSvelteComponent && !acceptedDomAlreadyClean(accepted)) { + setTimeout(function() { + if (pendingAcceptedSession?.id !== accepted?.id) return; + if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + cleanupAcceptedSession(); + }, 1800); + return; + } cleanupAcceptedSession(); }, 1200); } @@ -6884,39 +6891,42 @@ void main() { function acceptedDomAlreadyClean(pending) { if (!pending?.acceptedSelector) return false; const matches = [...document.querySelectorAll(pending.acceptedSelector)]; - return matches.some((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant]')); + return matches.length > 0 + && matches.every((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant],[data-impeccable-carbonize]')); } function ensureAcceptedDomClean(pending) { + if (acceptedDomAlreadyClean(pending)) return; const sessionId = pending?.id; const variantId = pending?.variant; - const wrapper = findAcceptedRuntimeWrapper(sessionId); - const accepted = wrapper?.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); - if (!wrapper) { + const wrappers = findAcceptedRuntimeWrappers(sessionId); + if (wrappers.length === 0) { restoreAcceptedDomFromSnapshot(pending); return; } - if (acceptedDomAlreadyClean(pending)) { + for (const wrapper of wrappers) { + if (!wrapper?.isConnected) continue; + const accepted = wrapper.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); + if (!accepted) { + wrapper.remove(); + continue; + } + const parent = wrapper.parentElement; + if (!parent) continue; + while (accepted.firstChild) { + parent.insertBefore(accepted.firstChild, wrapper); + } wrapper.remove(); - return; } - if (!accepted) { - wrapper.remove(); - restoreAcceptedDomFromSnapshot(pending); - return; - } - const parent = wrapper.parentElement; - if (!parent) return; - while (accepted.firstChild) { - parent.insertBefore(accepted.firstChild, wrapper); - } - wrapper.remove(); + if (!acceptedDomAlreadyClean(pending)) restoreAcceptedDomFromSnapshot(pending); } - function findAcceptedRuntimeWrapper(sessionId) { - if (!sessionId) return null; - return document.querySelector('[data-impeccable-variants="' + sessionId + '"]') - || document.querySelector('[data-impeccable-carbonize="' + sessionId + '"]'); + function findAcceptedRuntimeWrappers(sessionId) { + if (!sessionId) return []; + return [...new Set([ + ...document.querySelectorAll('[data-impeccable-variants="' + sessionId + '"]'), + ...document.querySelectorAll('[data-impeccable-carbonize="' + sessionId + '"]'), + ])]; } function restoreAcceptedDomFromSnapshot(pending) { diff --git a/.trae/skills/impeccable/scripts/live-browser.js b/.trae/skills/impeccable/scripts/live-browser.js index 302b9ec23..0a533945f 100644 --- a/.trae/skills/impeccable/scripts/live-browser.js +++ b/.trae/skills/impeccable/scripts/live-browser.js @@ -6855,7 +6855,14 @@ void main() { function scheduleAcceptCleanup(accepted) { setTimeout(function() { - if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + if (!accepted?.isSvelteComponent && !acceptedDomAlreadyClean(accepted)) { + setTimeout(function() { + if (pendingAcceptedSession?.id !== accepted?.id) return; + if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + cleanupAcceptedSession(); + }, 1800); + return; + } cleanupAcceptedSession(); }, 1200); } @@ -6884,39 +6891,42 @@ void main() { function acceptedDomAlreadyClean(pending) { if (!pending?.acceptedSelector) return false; const matches = [...document.querySelectorAll(pending.acceptedSelector)]; - return matches.some((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant]')); + return matches.length > 0 + && matches.every((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant],[data-impeccable-carbonize]')); } function ensureAcceptedDomClean(pending) { + if (acceptedDomAlreadyClean(pending)) return; const sessionId = pending?.id; const variantId = pending?.variant; - const wrapper = findAcceptedRuntimeWrapper(sessionId); - const accepted = wrapper?.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); - if (!wrapper) { + const wrappers = findAcceptedRuntimeWrappers(sessionId); + if (wrappers.length === 0) { restoreAcceptedDomFromSnapshot(pending); return; } - if (acceptedDomAlreadyClean(pending)) { + for (const wrapper of wrappers) { + if (!wrapper?.isConnected) continue; + const accepted = wrapper.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); + if (!accepted) { + wrapper.remove(); + continue; + } + const parent = wrapper.parentElement; + if (!parent) continue; + while (accepted.firstChild) { + parent.insertBefore(accepted.firstChild, wrapper); + } wrapper.remove(); - return; } - if (!accepted) { - wrapper.remove(); - restoreAcceptedDomFromSnapshot(pending); - return; - } - const parent = wrapper.parentElement; - if (!parent) return; - while (accepted.firstChild) { - parent.insertBefore(accepted.firstChild, wrapper); - } - wrapper.remove(); + if (!acceptedDomAlreadyClean(pending)) restoreAcceptedDomFromSnapshot(pending); } - function findAcceptedRuntimeWrapper(sessionId) { - if (!sessionId) return null; - return document.querySelector('[data-impeccable-variants="' + sessionId + '"]') - || document.querySelector('[data-impeccable-carbonize="' + sessionId + '"]'); + function findAcceptedRuntimeWrappers(sessionId) { + if (!sessionId) return []; + return [...new Set([ + ...document.querySelectorAll('[data-impeccable-variants="' + sessionId + '"]'), + ...document.querySelectorAll('[data-impeccable-carbonize="' + sessionId + '"]'), + ])]; } function restoreAcceptedDomFromSnapshot(pending) { diff --git a/plugin/skills/impeccable/scripts/live-browser.js b/plugin/skills/impeccable/scripts/live-browser.js index 302b9ec23..0a533945f 100644 --- a/plugin/skills/impeccable/scripts/live-browser.js +++ b/plugin/skills/impeccable/scripts/live-browser.js @@ -6855,7 +6855,14 @@ void main() { function scheduleAcceptCleanup(accepted) { setTimeout(function() { - if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + if (!accepted?.isSvelteComponent && !acceptedDomAlreadyClean(accepted)) { + setTimeout(function() { + if (pendingAcceptedSession?.id !== accepted?.id) return; + if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + cleanupAcceptedSession(); + }, 1800); + return; + } cleanupAcceptedSession(); }, 1200); } @@ -6884,39 +6891,42 @@ void main() { function acceptedDomAlreadyClean(pending) { if (!pending?.acceptedSelector) return false; const matches = [...document.querySelectorAll(pending.acceptedSelector)]; - return matches.some((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant]')); + return matches.length > 0 + && matches.every((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant],[data-impeccable-carbonize]')); } function ensureAcceptedDomClean(pending) { + if (acceptedDomAlreadyClean(pending)) return; const sessionId = pending?.id; const variantId = pending?.variant; - const wrapper = findAcceptedRuntimeWrapper(sessionId); - const accepted = wrapper?.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); - if (!wrapper) { + const wrappers = findAcceptedRuntimeWrappers(sessionId); + if (wrappers.length === 0) { restoreAcceptedDomFromSnapshot(pending); return; } - if (acceptedDomAlreadyClean(pending)) { + for (const wrapper of wrappers) { + if (!wrapper?.isConnected) continue; + const accepted = wrapper.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); + if (!accepted) { + wrapper.remove(); + continue; + } + const parent = wrapper.parentElement; + if (!parent) continue; + while (accepted.firstChild) { + parent.insertBefore(accepted.firstChild, wrapper); + } wrapper.remove(); - return; } - if (!accepted) { - wrapper.remove(); - restoreAcceptedDomFromSnapshot(pending); - return; - } - const parent = wrapper.parentElement; - if (!parent) return; - while (accepted.firstChild) { - parent.insertBefore(accepted.firstChild, wrapper); - } - wrapper.remove(); + if (!acceptedDomAlreadyClean(pending)) restoreAcceptedDomFromSnapshot(pending); } - function findAcceptedRuntimeWrapper(sessionId) { - if (!sessionId) return null; - return document.querySelector('[data-impeccable-variants="' + sessionId + '"]') - || document.querySelector('[data-impeccable-carbonize="' + sessionId + '"]'); + function findAcceptedRuntimeWrappers(sessionId) { + if (!sessionId) return []; + return [...new Set([ + ...document.querySelectorAll('[data-impeccable-variants="' + sessionId + '"]'), + ...document.querySelectorAll('[data-impeccable-carbonize="' + sessionId + '"]'), + ])]; } function restoreAcceptedDomFromSnapshot(pending) { diff --git a/skill/scripts/live-browser.js b/skill/scripts/live-browser.js index 302b9ec23..0a533945f 100644 --- a/skill/scripts/live-browser.js +++ b/skill/scripts/live-browser.js @@ -6855,7 +6855,14 @@ void main() { function scheduleAcceptCleanup(accepted) { setTimeout(function() { - if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + if (!accepted?.isSvelteComponent && !acceptedDomAlreadyClean(accepted)) { + setTimeout(function() { + if (pendingAcceptedSession?.id !== accepted?.id) return; + if (!accepted?.isSvelteComponent) ensureAcceptedDomClean(accepted); + cleanupAcceptedSession(); + }, 1800); + return; + } cleanupAcceptedSession(); }, 1200); } @@ -6884,39 +6891,42 @@ void main() { function acceptedDomAlreadyClean(pending) { if (!pending?.acceptedSelector) return false; const matches = [...document.querySelectorAll(pending.acceptedSelector)]; - return matches.some((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant]')); + return matches.length > 0 + && matches.every((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant],[data-impeccable-carbonize]')); } function ensureAcceptedDomClean(pending) { + if (acceptedDomAlreadyClean(pending)) return; const sessionId = pending?.id; const variantId = pending?.variant; - const wrapper = findAcceptedRuntimeWrapper(sessionId); - const accepted = wrapper?.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); - if (!wrapper) { + const wrappers = findAcceptedRuntimeWrappers(sessionId); + if (wrappers.length === 0) { restoreAcceptedDomFromSnapshot(pending); return; } - if (acceptedDomAlreadyClean(pending)) { + for (const wrapper of wrappers) { + if (!wrapper?.isConnected) continue; + const accepted = wrapper.querySelector?.('[data-impeccable-variant="' + variantId + '"]'); + if (!accepted) { + wrapper.remove(); + continue; + } + const parent = wrapper.parentElement; + if (!parent) continue; + while (accepted.firstChild) { + parent.insertBefore(accepted.firstChild, wrapper); + } wrapper.remove(); - return; } - if (!accepted) { - wrapper.remove(); - restoreAcceptedDomFromSnapshot(pending); - return; - } - const parent = wrapper.parentElement; - if (!parent) return; - while (accepted.firstChild) { - parent.insertBefore(accepted.firstChild, wrapper); - } - wrapper.remove(); + if (!acceptedDomAlreadyClean(pending)) restoreAcceptedDomFromSnapshot(pending); } - function findAcceptedRuntimeWrapper(sessionId) { - if (!sessionId) return null; - return document.querySelector('[data-impeccable-variants="' + sessionId + '"]') - || document.querySelector('[data-impeccable-carbonize="' + sessionId + '"]'); + function findAcceptedRuntimeWrappers(sessionId) { + if (!sessionId) return []; + return [...new Set([ + ...document.querySelectorAll('[data-impeccable-variants="' + sessionId + '"]'), + ...document.querySelectorAll('[data-impeccable-carbonize="' + sessionId + '"]'), + ])]; } function restoreAcceptedDomFromSnapshot(pending) { diff --git a/tests/live-browser-source.test.mjs b/tests/live-browser-source.test.mjs index 4fa41dcd3..b9e8ec085 100644 --- a/tests/live-browser-source.test.mjs +++ b/tests/live-browser-source.test.mjs @@ -321,17 +321,27 @@ describe('live-browser source contracts', () => { ); assert.match( SOURCE, - /function ensureAcceptedDomClean\(pending\)[\s\S]*?findAcceptedRuntimeWrapper\(sessionId\)[\s\S]*?acceptedDomAlreadyClean\(pending\)[\s\S]*?wrapper\.remove\(\);[\s\S]*?parent\.insertBefore\(accepted\.firstChild, wrapper\);[\s\S]*?wrapper\.remove\(\);/, + /function scheduleAcceptCleanup\(accepted\)[\s\S]*?acceptedDomAlreadyClean\(accepted\)[\s\S]*?setTimeout\(function\(\) \{[\s\S]*?ensureAcceptedDomClean\(accepted\);[\s\S]*?cleanupAcceptedSession\(\);[\s\S]*?\}, 1800\);/, + 'post-cleanup fallback should give HMR a second chance before mutating React-owned DOM', + ); + assert.match( + SOURCE, + /function ensureAcceptedDomClean\(pending\)[\s\S]*?acceptedDomAlreadyClean\(pending\)[\s\S]*?findAcceptedRuntimeWrappers\(sessionId\)[\s\S]*?for \(const wrapper of wrappers\)[\s\S]*?parent\.insertBefore\(accepted\.firstChild, wrapper\);[\s\S]*?wrapper\.remove\(\);[\s\S]*?acceptedDomAlreadyClean\(pending\)/, 'post-cleanup fallback should unwrap the accepted variant instead of preserving live runtime wrappers', ); assert.match( SOURCE, - /function findAcceptedRuntimeWrapper\(sessionId\)[\s\S]*?data-impeccable-variants[\s\S]*?data-impeccable-carbonize/, - 'post-cleanup fallback should also remove stale carbonize wrappers left by React HMR after accept', + /function acceptedDomAlreadyClean\(pending\)[\s\S]*?matches\.length > 0[\s\S]*?matches\.every[\s\S]*?data-impeccable-carbonize/, + 'accepted DOM should not be considered clean while any matching root is still inside a carbonize wrapper', ); assert.match( SOURCE, - /if \(!accepted\) \{[\s\S]{0,120}?wrapper\.remove\(\);[\s\S]{0,120}?restoreAcceptedDomFromSnapshot\(pending\);[\s\S]{0,80}?return;/, + /function findAcceptedRuntimeWrappers\(sessionId\)[\s\S]*?querySelectorAll\('\[data-impeccable-variants=[\s\S]*?querySelectorAll\('\[data-impeccable-carbonize=/, + 'post-cleanup fallback should remove every stale variants/carbonize wrapper left by React HMR after accept', + ); + assert.match( + SOURCE, + /if \(!accepted\) \{[\s\S]{0,80}?wrapper\.remove\(\);[\s\S]{0,80}?continue;/, 'post-cleanup fallback should not leave a variants wrapper behind when the accepted variant node is missing', ); assert.match( diff --git a/tests/live-e2e-accept-cleanup-regression.test.mjs b/tests/live-e2e-accept-cleanup-regression.test.mjs index 9b6b3f520..01b5e48a1 100644 --- a/tests/live-e2e-accept-cleanup-regression.test.mjs +++ b/tests/live-e2e-accept-cleanup-regression.test.mjs @@ -184,7 +184,7 @@ async function waitForAcceptedDomClean(page, selector, { timeoutMs, sourceFile, (sel) => { const matches = [...document.querySelectorAll(sel)]; return matches.length > 0 - && matches.every((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant]')); + && matches.every((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant],[data-impeccable-carbonize]')); }, selector, { timeout: timeoutMs }, @@ -204,8 +204,8 @@ async function waitForAcceptedDomClean(page, selector, { timeoutMs, sourceFile, async function collectAcceptedDomDiagnostic(page, selector) { return page.evaluate((sel) => { const matches = [...document.querySelectorAll(sel)]; - const clean = matches.filter((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant]')); - const stale = matches.filter((el) => el.closest('[data-impeccable-variants],[data-impeccable-variant]')); + const clean = matches.filter((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant],[data-impeccable-carbonize]')); + const stale = matches.filter((el) => el.closest('[data-impeccable-variants],[data-impeccable-variant],[data-impeccable-carbonize]')); const local = {}; for (const key of [ 'impeccable-live-session',