diff --git a/CHANGELOG.md b/CHANGELOG.md index 73cccfd8..1bf8258e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,9 +18,11 @@ The format is based on [Keep a Changelog], and this project adheres to [Semantic ### Fixed +- issue with re-adding element after removing it in `trusted-create-element` scriptlet [#434] - `trusted-click-element` scriptlet does not click on an element that is already in the DOM [#437] [Unreleased]: https://github.com/AdguardTeam/Scriptlets/compare/v1.11.6...HEAD +[#434]: https://github.com/AdguardTeam/Scriptlets/issues/434 [#435]: https://github.com/AdguardTeam/Scriptlets/issues/435 [#436]: https://github.com/AdguardTeam/Scriptlets/issues/436 [#426]: https://github.com/AdguardTeam/Scriptlets/issues/426 diff --git a/src/scriptlets/trusted-create-element.ts b/src/scriptlets/trusted-create-element.ts index ca7f9829..e7d77384 100644 --- a/src/scriptlets/trusted-create-element.ts +++ b/src/scriptlets/trusted-create-element.ts @@ -128,6 +128,8 @@ export function trustedCreateElement( let timerId: ReturnType; + let elementRemoved = false; + /** * Finds parent element by `parentElSelector` and appends the `el` element to it. * @@ -168,6 +170,7 @@ export function trustedCreateElement( if (!nativeIsNaN(removeElDelayMs)) { timerId = setTimeout(() => { el.remove(); + elementRemoved = true; clearTimeout(timerId); }, removeElDelayMs); } @@ -177,7 +180,7 @@ export function trustedCreateElement( if (!findParentAndAppendEl(parentSelector, element, cleanupDelayMs)) { observeDocumentWithTimeout((mutations, observer) => { - if (findParentAndAppendEl(parentSelector, element, cleanupDelayMs)) { + if (elementRemoved || findParentAndAppendEl(parentSelector, element, cleanupDelayMs)) { observer.disconnect(); } }); diff --git a/tests/scriptlets/trusted-create-element.test.js b/tests/scriptlets/trusted-create-element.test.js index 67a06618..6314691b 100644 --- a/tests/scriptlets/trusted-create-element.test.js +++ b/tests/scriptlets/trusted-create-element.test.js @@ -191,6 +191,35 @@ test('element cleanup by timeout', (assert) => { }, cleanupDelayMs + 10); }); +test('element cleanup by timeout, check if element was not added again', (assert) => { + // If element is re-added in a loop, then it will stuck on this test + + const childTagName = 'SPAN'; + const cleanupDelayMs = 100; + + runScriptlet(name, [ROOT_SELECTOR, childTagName, '', '', cleanupDelayMs]); + + const done = assert.async(); + + let child; + let children; + const rootElement = createRoot(ROOT_ID); + + setTimeout(() => { + children = rootElement.children; + // eslint-disable-next-line prefer-destructuring + child = children[0]; + assert.strictEqual(window.hit, 'FIRED', 'hit fired'); + assert.strictEqual(children.length, 1, 'Only specified child was appended'); + assert.strictEqual(child.tagName, childTagName, 'Tag name is set correctly'); + }, cleanupDelayMs / 2); + + setTimeout(() => { + assert.strictEqual(children.length, 0, 'Child element was removed after timeout'); + done(); + }, cleanupDelayMs + 10); +}); + test('running scriptlet before root element is created', (assert) => { const childTagName = 'div';