Skip to content

Commit

Permalink
Some fixes (#211)
Browse files Browse the repository at this point in the history
* replaceChildren appends all new children

* Remove unsupported method

* Implement element.replaceWith function

* Add test for event listeners on cloneNode

* PR fixes

* Update changelog and version number
  • Loading branch information
hilleso authored Jan 15, 2025
1 parent a5a7318 commit ccdad00
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 12 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
Changelog
=========

## 16.0.3

- Add replaceWith() method to element
- Removed the clone() method from DocumentFragment because it's not part of the specification.
- Bugfix: replaceChildren() adds all supplied elements instead of only the first one.

## 16.0.2

- Fix: Ensure that `fetch._pendingRequests` doesn't resolve prematurely
Expand Down
2 changes: 1 addition & 1 deletion docs/API.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!-- version -->
# 16.0.1 API Reference
# 16.0.3 API Reference
<!-- versionstop -->

<!-- toc -->
Expand Down
4 changes: 0 additions & 4 deletions lib/DocumentFragment.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ const Node = require("./Node.js");
const { DOCUMENT_FRAGMENT_NODE } = require("./nodeTypes.js");

const dollarSymbol = Symbol.for("$");
const bodySymbol = Symbol.for("$body");
const loadedSymbol = Symbol.for("loaded");

module.exports = class DocumentFragment extends Node {
Expand Down Expand Up @@ -45,9 +44,6 @@ module.exports = class DocumentFragment extends Node {
if (!$lastChild.length) return null;
return this.ownerDocument._getElement($lastChild);
}
clone(deep) {
return new DocumentFragment(this.ownerDocument, deep && { $elm: this[bodySymbol] });
}
querySelector(selector) {
return this.ownerDocument._getElement(this.$elm.find(selector).eq(0)) || null;
}
Expand Down
21 changes: 16 additions & 5 deletions lib/Element.js
Original file line number Diff line number Diff line change
Expand Up @@ -365,15 +365,26 @@ module.exports = class Element extends Node {
this.$elm.remove();
parentElement?._emitter.emit("_insert");
}
replaceChildren(newChildren) {
replaceChildren() {
this.$elm.contents().remove();

if (newChildren !== undefined) {
this.appendChild(newChildren);
} else {
for (const child of arguments) {
this.appendChild(child);
}
if (arguments.length === 0) {
this._emitter.emit("_insert");
}
}
replaceWith() {
const params = [];
for (const newElement of arguments) {
if (newElement && newElement.$elm) {
params.push(newElement.$elm);
} else {
params.push(String(newElement));
}
}
this.$elm.replaceWith(params);
}
removeAttribute(name) {
if (!this.hasAttribute(name)) return;
this.$elm.removeAttr(name);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@expressen/tallahassee",
"version": "16.0.2",
"version": "16.0.3",
"description": "Lightweight client testing framework",
"main": "index.js",
"license": "BSD-3-Clause",
Expand Down
81 changes: 80 additions & 1 deletion test/elements-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,6 @@ describe("elements", () => {

it("replaces all children with new child", () => {
const parent = document.getElementById("grandparent");

expect(parent.children.length).to.equal(2);

const newChild = document.createElement("p");
Expand All @@ -595,6 +594,77 @@ describe("elements", () => {
parent.replaceChildren(newChild);
expect(parent.childNodes.length).to.equal(1);
expect(parent.textContent.trim()).to.equal("I will replace you");
expect(parent.innerHTML).to.equal("<p>I will replace you</p>");
});

it("replaces all children with new children", () => {
const parent = document.getElementById("grandparent");
expect(parent.children.length).to.equal(2);

const newChild = document.createElement("p");
newChild.textContent = "First";
const newChild2 = document.createElement("p");
newChild2.textContent = "Second";
const newChild3 = document.createElement("p");
newChild3.textContent = "Third";

parent.replaceChildren(newChild, newChild2, newChild3);
expect(parent.childNodes.length).to.equal(3);
expect(parent.innerHTML).to.equal("<p>First</p><p>Second</p><p>Third</p>");
});
});

describe("replaceWith()", () => {
let document;
let parent;
let span;

beforeEach(() => {
document = new Document({
text: `
<html>
<body>
<div id="parent">
<span class="child">åäö</span>
</div>
</body>
</html>`,
});
parent = document.getElementById("parent");
span = parent.getElementsByTagName("span")[0];
});

it("replaces element in the children list of its parent with the supplied element", () => {
const p = document.createElement("p");
p.textContent = "New text";
span.replaceWith(p);
expect(parent.innerHTML.trim()).to.equal("<p>New text</p>");
});

it("replaces element in the children list of its parent with the supplied elements", () => {
const p = document.createElement("p");
p.textContent = "New text";
const p2 = document.createElement("p");
p2.textContent = "A new row";
span.replaceWith(p, p2);
expect(parent.innerHTML.trim()).to.equal("<p>New text</p><p>A new row</p>");
});

it("removes the element from the parent if no new element is supplied", () => {
span.replaceWith();
expect(parent.innerHTML.trim()).to.equal("");
});

[ "a new value", undefined, null ].forEach((value) => {
it(`replaces the element in the parent with the string ${value} if ${value} is passed to the function`, () => {
span.replaceWith(value);
expect(parent.innerHTML.trim()).to.equal(String(value));
});
});

it("replaces element in the children list of its parent with the supplied strings", () => {
span.replaceWith("1 ", "2");
expect(parent.innerHTML.trim()).to.equal("1 2");
});
});

Expand Down Expand Up @@ -1418,6 +1488,15 @@ describe("elements", () => {

expect(elmCloneChild === elmChild).to.be.false;
});

it("returns a clone without event listerners", () => {
const elm = document.getElementsByClassName("block")[0];
let clicked = false;
elm.addEventListener("click", () => (clicked = true));
const elmClone = elm.cloneNode(true);
elmClone.click();
expect(clicked).to.be.false;
});
});

describe("video element", () => {
Expand Down

0 comments on commit ccdad00

Please sign in to comment.