Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: capricorn86/happy-dom
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v16.7.3
Choose a base ref
...
head repository: capricorn86/happy-dom
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: df8425798252466767eefa81e92ce3c1f6befa9b
Choose a head ref
  • 1 commit
  • 3 files changed
  • 1 contributor

Commits on Jan 31, 2025

  1. feat: [1708] Add support for insertRow and deleteRow to HTMLTableSect…

    …ionElement (#1709)
    christiango authored Jan 31, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    df84257 View commit details
Original file line number Diff line number Diff line change
@@ -1,7 +1,88 @@
import QuerySelector from '../../query-selector/QuerySelector.js';
import * as PropertySymbol from '../../PropertySymbol.js';
import HTMLElement from '../html-element/HTMLElement.js';
import HTMLTableRowElement from '../html-table-row-element/HTMLTableRowElement.js';
import DOMExceptionNameEnum from '../../exception/DOMExceptionNameEnum.js';
/**
* HTMLTableSectionElement
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableSectionElement
*/
export default class HTMLTableSectionElement extends HTMLElement {}
export default class HTMLTableSectionElement extends HTMLElement {
/**
* Returns an HTMLTableRowElement representing a new row of the table. It inserts it in the rows collection immediately before the <tr> element at the given index position. If the index is -1, the new row is appended to the collection. If the index is smaller than -1 or greater than the number of rows in the collection, a DOMException with the value IndexSizeError is raised.
*
* @param [index] Index.
* @returns Row.
*/
public insertRow(index: number = -1): HTMLTableRowElement {
if (typeof index !== 'number') {
index = -1;
}

const rows = QuerySelector.querySelectorAll(this, 'tr')[PropertySymbol.items];

if (index < -1) {
throw new this[PropertySymbol.window].DOMException(
`Failed to execute 'insertRow' on 'HTMLTableSectionElement': The index provided (${index}) is less than -1.`,
DOMExceptionNameEnum.indexSizeError
);
}

if (index > rows.length) {
throw new this[PropertySymbol.window].DOMException(
`Failed to execute 'insertRow' on 'HTMLTableSectionElement': The index provided (${index}) is greater than the number of rows (${rows.length}).`,
DOMExceptionNameEnum.indexSizeError
);
}

const row = this[PropertySymbol.ownerDocument].createElement('tr');

if (index === -1 || index === rows.length) {
this.appendChild(row);
} else {
this.insertBefore(row, rows[index]);
}

return row;
}

/**
* Removes the row corresponding to the index given in parameter. If the index value is -1 the last row is removed; if it is smaller than -1 or greater than the amount of rows in the collection, a DOMException with the value IndexSizeError is raised.
*
* @param index Index.
*/
public deleteRow(index: number): void {
if (arguments.length === 0) {
throw new this[PropertySymbol.window].TypeError(
"Failed to execute 'deleteRow' on 'HTMLTableSectionElement': 1 argument required, but only 0 present."
);
}

if (typeof index !== 'number') {
index = -1;
}

if (index < -1) {
throw new this[PropertySymbol.window].DOMException(
`Failed to execute 'deleteRow' on 'HTMLTableSectionElement': The index provided (${index}) is less than -1.`,
DOMExceptionNameEnum.indexSizeError
);
}

const rows = QuerySelector.querySelectorAll(this, 'tr')[PropertySymbol.items];

if (index >= rows.length) {
throw new this[PropertySymbol.window].DOMException(
`Failed to execute 'deleteRow' on 'HTMLTableSectionElement': The index provided (${index}) is greater than the number of rows in the table (${rows.length}).`,
DOMExceptionNameEnum.indexSizeError
);
}

if (index === -1) {
index = rows.length - 1;
}

rows[index].remove();
}
}
Original file line number Diff line number Diff line change
@@ -450,6 +450,15 @@ describe('HTMLTableElement', () => {
);
});

it('Throws an error if there are no arguments', () => {
expect(() => {
// @ts-expect-error -- We are intentionally calling this in an unsupported way (no arguments) for this test
element.deleteRow();
}).toThrow(
"Failed to execute 'deleteRow' on 'HTMLTableElement': 1 argument required, but only 0 present."
);
});

it('Throws an error if the index is less than -1', () => {
expect(() => {
element.deleteRow(-2);
Original file line number Diff line number Diff line change
@@ -19,4 +19,109 @@ describe('HTMLTableSectionElement', () => {
expect(element instanceof HTMLTableSectionElement).toBe(true);
});
});

describe('insertRow()', () => {
it('Inserts a new row at the end', () => {
const row = element.insertRow();
expect(element.children[0]).toBe(row);
expect(element.innerHTML).toBe('<tr></tr>');
const row2 = element.insertRow();
expect(element.children[1]).toBe(row2);
expect(element.innerHTML).toBe('<tr></tr><tr></tr>');
});

it('Inserts a new row at the given index', () => {
element.innerHTML = '<tr><td>test</td></tr><tr><td>test</td></tr>';
const row = element.insertRow(1);
expect(element.children[1]).toBe(row);
expect(element.innerHTML).toBe('<tr><td>test</td></tr><tr></tr><tr><td>test</td></tr>');
});

it('Inserts a new row at the end if the index is -1', () => {
element.innerHTML = '<tr><td>test</td></tr><tr><td>test</td></tr>';
const row = element.insertRow(-1);
expect(element.children[2]).toBe(row);
expect(element.innerHTML).toBe('<tr><td>test</td></tr><tr><td>test</td></tr><tr></tr>');
});

it('Inserts a new row at the end if the index is not a number', () => {
element.innerHTML = '<tr><td>test</td></tr><tr><td>test</td></tr>';
const row = element.insertRow(<number>(<unknown>'test'));
expect(element.children[2]).toBe(row);
expect(element.innerHTML).toBe('<tr><td>test</td></tr><tr><td>test</td></tr><tr></tr>');
});

it('Inserts a new row at the end if the index is equal to the length of rows', () => {
element.innerHTML = '<tr><td>test</td></tr><tr><td>test</td></tr>';
const row = element.insertRow(2);
expect(element.children[2]).toBe(row);
expect(element.innerHTML).toBe('<tr><td>test</td></tr><tr><td>test</td></tr><tr></tr>');
});

it('Throws an error if the index is less than -1', () => {
expect(() => {
element.insertRow(-2);
}).toThrow(
"Failed to execute 'insertRow' on 'HTMLTableSectionElement': The index provided (-2) is less than -1."
);
});

it('Throws an error if the index is greater than the number of rows', () => {
element.innerHTML = '<tr><td>test</td></tr><tr><td>test</td></tr>';
expect(() => {
element.insertRow(3);
}).toThrow(
"Failed to execute 'insertRow' on 'HTMLTableSectionElement': The index provided (3) is greater than the number of rows (2)."
);
});
});

describe('deleteRow()', () => {
it('Removes the row at the given index', () => {
element.innerHTML = '<tr><td>Row 1</td></tr><tr><td>Row 2</td></tr><tr><td>Row 3</td></tr>';
element.deleteRow(1);
expect(element.children.length).toBe(2);
expect(element.innerHTML).toBe('<tr><td>Row 1</td></tr><tr><td>Row 3</td></tr>');
});

it('Removes the last row if the index is -1', () => {
element.innerHTML = '<tr><td>Row 1</td></tr><tr><td>Row 2</td></tr><tr><td>Row 3</td></tr>';
element.deleteRow(-1);
expect(element.children.length).toBe(2);
expect(element.innerHTML).toBe('<tr><td>Row 1</td></tr><tr><td>Row 2</td></tr>');
});

it('Removes the last row if the index is not a number', () => {
element.innerHTML = '<tr><td>Row 1</td></tr><tr><td>Row 2</td></tr><tr><td>Row 3</td></tr>';
element.deleteRow(<number>(<unknown>'test'));
expect(element.children.length).toBe(2);
expect(element.innerHTML).toBe('<tr><td>Row 1</td></tr><tr><td>Row 2</td></tr>');
});

it('Throws an error if there are no arguments', () => {
expect(() => {
// @ts-expect-error -- We are intentionally calling this in an unsupported way (no arguments) for this test
element.deleteRow();
}).toThrow(
"Failed to execute 'deleteRow' on 'HTMLTableSectionElement': 1 argument required, but only 0 present."
);
});

it('Throws an error if the index is less than -1', () => {
expect(() => {
element.deleteRow(-2);
}).toThrow(
"Failed to execute 'deleteRow' on 'HTMLTableSectionElement': The index provided (-2) is less than -1."
);
});

it('Throws an error if the index is greater than the number of rows', () => {
element.innerHTML = '<tr><td>test</td></tr><tr><td>test</td></tr>';
expect(() => {
element.deleteRow(2);
}).toThrow(
"Failed to execute 'deleteRow' on 'HTMLTableSectionElement': The index provided (2) is greater than the number of rows in the table (2)."
);
});
});
});