als-document
Version:
A powerful HTML parser & DOM manipulation library for both backend and frontend.
411 lines (327 loc) • 15.8 kB
JavaScript
const { describe, it, beforeEach } = require('node:test')
const assert = require('node:assert')
const { Node, Root, TextNode, Document } = require('../index')
describe('Constructor and Basic Properties', () => {
it('Creates an element', () => {
const node = new Node('div');
assert(node instanceof Node, "Element was not created correctly");
});
it('Checks the setting of element properties: tagName, attributes, parent, etc.', () => {
const rootNode = new Node('ROOT');
const divNode = new Node('div', { class: 'container' }, rootNode);
assert(divNode.tagName === 'DIV', "Tag name is correct");
assert(divNode.attributes.class === 'container', "Attributes are correct");
assert(divNode.parent === rootNode, "Parent node is correct");
});
it('Adds a new element to the parent\'s childNodes', () => {
const rootNode = new Node('ROOT');
const childNode = new Node('child', {}, rootNode);
assert(rootNode.childNodes.includes(childNode), "New element was added to parent's childNodes");
});
});
describe('DOM Search and Navigation', () => {
it('Gets the previous and next element', () => {
const rootNode = new Node('ROOT');
const div1 = new Node('div', {}, rootNode);
const div2 = new Node('div', {}, rootNode);
assert(div2.previousElementSibling === div1, "Previous sibling is correct");
assert(div2.nextElementSibling === null, "Next sibling is correct");
});
it('Gets the list of ancestors', () => {
const rootNode = new Node('ROOT');
const firstLevel = new Node('first', {}, rootNode);
const secondLevel = new Node('second', {}, firstLevel);
const thirdLevel = new Node('third', {}, secondLevel);
const ancestors = thirdLevel.ancestors;
assert(ancestors.length === 2, "The number of ancestors is correct");
assert(ancestors[0] === firstLevel, "First ancestor is correct");
assert(ancestors[1] === secondLevel, "Second ancestor is correct");
});
it('Searches for elements using different methods', () => {
const rootNode = new Node('ROOT');
const div1 = new Node('div', { class: 'test', id: 'first' }, rootNode);
const div2 = new Node('div', { class: 'test' }, rootNode);
const p = new Node('p', {}, rootNode);
const divs = rootNode.getElementsByTagName('div');
assert(divs.length === 2, "getElementsByTagName did find correct number of divs");
const testClassNodes = rootNode.getElementsByClassName('test');
assert(testClassNodes.length === 2, "getElementsByClassName did find correct number of .test elements");
const firstDiv = rootNode.getElementById('first');
assert(firstDiv === div1, "getElementById did find the correct element");
const firstQuery = rootNode.querySelector('.test');
assert(firstQuery === div1, "querySelector did return the first matching element");
const allQuery = rootNode.querySelectorAll('.test');
assert(allQuery.length === 2 && allQuery[0] === div1 && allQuery[1] === div2, "querySelectorAll did not find all matching elements");
});
});
describe('Attribute Operations', () => {
it('Gets, sets, and removes attributes', () => {
const attrNode = new Node('div');
attrNode.setAttribute('data-test', 'testValue');
assert(attrNode.getAttribute('data-test') === 'testValue', "getAttribute/setAttribute is correct");
attrNode.removeAttribute('data-test');
assert(!attrNode.getAttribute('data-test'), "removeAttribute is correct");
});
it('Handles classList', () => {
const nodeWithClasses = new Node('div', { class: 'class1 class2' });
// Assertion to check if classList contains the right classes
assert(nodeWithClasses.classList.contains('class1'), "The classList contain 'class1'");
assert(nodeWithClasses.classList.contains('class2'), "The classList contain 'class2'");
// Modifying classList and checking
nodeWithClasses.classList.add('class3');
assert(nodeWithClasses.classList.contains('class3'), "The classList contain 'class3' after addition");
nodeWithClasses.classList.remove('class1');
assert(!nodeWithClasses.classList.contains('class1'), "The classList doesn't contains 'class1' after removal");
});
it('Handles style', () => {
const nodeWithStyle = new Node('div', { style: 'color: red; font-size: 16px;' });
// Assertions to check if style is correctly set
assert(nodeWithStyle.style.color === 'red', "The style property color is correctly set or retrieved");
assert(nodeWithStyle.style.fontSize === '16px', "The style property fontSize is correctly set or retrieved");
});
});
describe('Content Manipulation', () => {
it('Adds and removes child elements', () => {
const rootNode = new Node('ROOT');
const childNode = new Node('child');
rootNode.appendChild(childNode);
assert(rootNode.childNodes.includes(childNode), "Child node was added");
childNode.remove();
assert(!rootNode.childNodes.includes(childNode), "Child node was removed");
});
it('Inserts content adjacent to an element', () => {
const rootNode = new Node('div');
const childNode = new Node('p', {}, rootNode);
childNode.insertAdjacentElement('beforebegin', new Node('span'));
assert(rootNode.childNodes[0].tagName === 'SPAN');
childNode.insertAdjacentElement('afterend', new Node('a'));
assert(rootNode.childNodes[2].tagName === 'A');
childNode.insertAdjacentHTML('beforebegin', '<strong></strong>');
assert(rootNode.childNodes[1].tagName === 'STRONG');
childNode.insertAdjacentText('afterend', 'Some text');
assert(typeof rootNode.childNodes[3].nodeValue === 'string');
assert(rootNode.childNodes[3].nodeValue === 'Some text');
});
// it('Gets and sets innerHTML and outerHTML', () => {
// const rootNode = new Node('div');
// new Node('p', {id: 'test'}, rootNode);
// assert(rootNode.innerHTML === '<p id="test"></p>');
// const newNode = new Node('span');
// newNode.innerHTML = '<a href="#">Link</a>';
// assert(newNode.childNodes[0].tagName === 'a');
// newNode.childNodes[0].outerHTML = '<div><strong>New content</strong></div>';
// assert(newNode.childNodes[0].childNodes[0].tagName === 'strong');
// });
// it('Works with text content', () => {
// const rootNode = new Node('div');
// new Node('p', {}, rootNode).textContent = 'Hello World';
// assert(rootNode.textContent === 'Hello World');
// rootNode.textContent = 'Changed Text';
// assert(rootNode.textContent === 'Changed Text');
// assert(rootNode.childNodes.leng === 1);
// assert(rootNode.childNodes[0] === 'Changed Text');
// });
});
describe('Other Methods and Properties', () => {
it('Gets the list of child elements', () => {
const rootNode = new Node('div');
// Добавление дочерних элементов
new Node('p', {}, rootNode);
new Node('span', {}, rootNode);
new Node('a', {}, rootNode);
rootNode.appendChild('Some text'); // Добавляем текстовый узел
// Проверяем, что у корневого элемента теперь 4 дочерних узла (3 элемента + 1 текстовый узел)
assert(rootNode.childNodes.length === 4);
// Проверяем свойство children
assert(rootNode.children.length === 3);
assert(rootNode.children[0].tagName.toLowerCase() === 'p');
assert(rootNode.children[1].tagName.toLowerCase() === 'span');
assert(rootNode.children[2].tagName.toLowerCase() === 'a');
});
it('Gets the parent element', () => {
const rootNode = new Node('ROOT');
const childNode = new Node('child', {}, rootNode);
assert(childNode.parentNode === rootNode, "Parent node is correct");
});
});
describe('Method and properties 2', () => {
let node
beforeEach(() => {node = new Node('div')})
it('set id', () => {
assert(node.getAttribute('id') === null)
assert(node.id === null)
node.id = 'test'
assert(node.getAttribute('id') === 'test')
assert(node.id === 'test')
})
it('get className', () => {
assert(node.classList.constructor.name === 'NodeClassList')
})
it('get outerHTML', () => {
assert(node.outerHTML === '<div></div>')
})
it('set innerHTML', () => {
assert(node.innerHTML === '')
node.innerHTML = 'some test'
assert(node.innerHTML === 'some test')
})
it('set outerHTML error no parent', () => {
assert.throws(() => {node.outerHTML = '<div>some test</div>'}) // element has no parent node
})
it('set outerHTML', () => {
const parent = new Node('div')
parent.insert(1,node)
assert(parent.children[0].outerHTML === '<div></div>')
const html = '<div>some test</div>'
node.outerHTML = html
assert(parent.children[0].outerHTML === html)
})
describe('set textContent', () => {
it('sets and gets textContent correctly', () => {
const node = new Node('div');
node.textContent = 'Hello World';
assert.strictEqual(node.textContent, 'Hello World', 'textContent should be "Hello World"');
});
});
describe('get innerHTML', () => {
it('gets correct innerHTML', () => {
const parent = new Node('div');
const child = new Node('span');
parent.appendChild(child);
assert.strictEqual(parent.innerHTML, '<span></span>', 'innerHTML should include child node markup');
});
});
describe('insertAdjacentHTML', () => {
it('inserts HTML correctly before begin', () => {
const node = new Node('div');
node.insertAdjacentHTML('afterbegin', '<span>test</span>');
assert(node.innerHTML === '<span>test</span>', 'Should insert <span>test</span> before the node');
});
});
describe('insertAdjacentText', () => {
it('inserts text correctly after end', () => {
const node = new Node('div');
const parent = new Node('div');
parent.appendChild(node);
node.insertAdjacentText('afterend', 'Hello');
assert.strictEqual(parent.childNodes[1].nodeValue, 'Hello', 'Should insert "Hello" after the node');
});
});
describe('appendChild', () => {
it('appends a child node correctly', () => {
const parentNode = new Node('div');
const childNode = new Node('span');
parentNode.appendChild(childNode);
assert(parentNode.childNodes.includes(childNode), 'Child node should be in parent\'s childNodes array');
});
});
describe('get textContent', () => {
it('returns correct text content', () => {
const node = new Node('div');
const child1 = new TextNode('Hello');
const child2 = new TextNode('World');
node.appendChild(child1);
node.appendChild(child2);
assert.strictEqual(node.textContent, 'HelloWorld', 'textContent should be "HelloWorld"');
});
});
describe('insertAdjacentElement', () => {
it('inserts an element adjacent to another', () => {
const root = new Root();
const refNode = new Node('div');
const newNode = new Node('span');
root.appendChild(refNode);
refNode.insertAdjacentElement('afterend', newNode);
assert.strictEqual(root.childNodes[1], newNode, 'New node should be inserted after the reference node');
});
});
})
describe('query', () => {
describe('$$', () => {
it('returns all elements matching the selector', () => {
const root = new Root();
const child1 = new Node('div', { class: 'test' });
const child2 = new Node('div', { class: 'test' });
root.appendChild(child1);
root.appendChild(child2);
assert.strictEqual(root.$$('.test').length, 2, 'Should find two elements with class "test"');
});
});
describe('$', () => {
it('returns the first element matching the selector', () => {
const root = new Root();
const child1 = new Node('div', { class: 'test' });
const child2 = new Node('div', { class: 'test' });
root.appendChild(child1);
root.appendChild(child2);
assert.strictEqual(root.$('.test'), child1, 'Should return the first element with class "test"');
});
});
describe('querySelectorAll', () => {
it('finds all elements matching a complex query', () => {
const root = new Root();
const child1 = new Node('div', { id: 'unique' });
const child2 = new Node('div', { class: 'test' });
root.appendChild(child1);
root.appendChild(child2);
assert.strictEqual(root.querySelectorAll('div').length, 2, 'Should find two div elements');
});
});
describe('querySelector', () => {
it('finds the first element matching a complex query', () => {
const root = new Root();
const child1 = new Node('div', { id: 'unique' });
const child2 = new Node('div', { class: 'test' });
root.appendChild(child1);
root.appendChild(child2);
assert.strictEqual(root.querySelector('#unique'), child1, 'Should find the first div with id "unique"');
});
});
describe('getElementsByClassName', () => {
it('finds elements by class name', () => {
const root = new Root();
const child1 = new Node('div', { class: 'test' });
const child2 = new Node('div', { class: 'test' });
root.appendChild(child1);
root.appendChild(child2);
assert.strictEqual(root.getElementsByClassName('test').length, 2, 'Should find two elements with class "test"');
});
});
describe('getElementsByTagName', () => {
it('finds elements by tag name', () => {
const root = new Root();
const child1 = new Node('div');
const child2 = new Node('span');
root.appendChild(child1);
root.appendChild(child2);
assert.strictEqual(root.getElementsByTagName('div').length, 1, 'Should find one div element');
});
});
describe('getElementById', () => {
it('finds an element by ID', () => {
const root = new Root();
const child = new Node('div', { id: 'unique' });
root.appendChild(child);
assert.strictEqual(root.getElementById('unique'), child, 'Should find the element with id "unique"');
});
});
})
describe('Document element', () => {
it('get body', () => {
const document = new Document();
assert(document.body !== undefined);
assert(document.body instanceof Node);
});
it('get head', () => {
const document = new Document();
assert(document.head !== undefined);
assert(document.head instanceof Node);
});
it('get and set title', () => {
const root = new Document();
root.title = 'Original Title';
assert.strictEqual(root.title, 'Original Title', 'Should get the title');
root.title = 'New Title';
assert.strictEqual(root.title, 'New Title', 'Should set the new title');
});
})