Skip to content

Commit

Permalink
feat: [#1159] Adds support for the :disabled pseudo-class in CSS and …
Browse files Browse the repository at this point in the history
…query selectors
  • Loading branch information
capricorn86 committed Nov 6, 2024
1 parent cecb787 commit d3ce812
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 4 deletions.
5 changes: 5 additions & 0 deletions packages/happy-dom/src/query-selector/SelectorItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,11 @@ export default class SelectorItem {
return element[PropertySymbol.tagName] === 'INPUT' && (<HTMLInputElement>element).checked
? { priorityWeight: 10 }
: null;
case 'disabled':
return 'disabled' in element &&
element[PropertySymbol.attributes][PropertySymbol.namedItems].has('disabled')
? { priorityWeight: 10 }
: null;
case 'empty':
return !(<Element>element)[PropertySymbol.elementArray].length
? { priorityWeight: 10 }
Expand Down
4 changes: 2 additions & 2 deletions packages/happy-dom/src/window/BrowserWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ import {
} from 'node:perf_hooks';
import EventPhaseEnum from '../event/EventPhaseEnum.js';
import HTMLOptionsCollection from '../nodes/html-select-element/HTMLOptionsCollection.js';
import WindowClassExtender from './WindowClassExtender.js';
import WindowContextClassExtender from './WindowContextClassExtender.js';
import WindowBrowserContext from './WindowBrowserContext.js';
import CanvasCaptureMediaStreamTrack from '../nodes/html-canvas-element/CanvasCaptureMediaStreamTrack.js';
import SVGSVGElement from '../nodes/svg-svg-element/SVGSVGElement.js';
Expand Down Expand Up @@ -825,7 +825,7 @@ export default class BrowserWindow extends EventTarget implements INodeJSGlobal

this[PropertySymbol.setupVMContext]();

WindowClassExtender.extendClass(this);
WindowContextClassExtender.extendClasses(this);

// Document
this.document = new this.HTMLDocument();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@ import NamedNodeMapImplementation from '../nodes/element/NamedNodeMap.js';
*
* By using WindowBrowserContext, the classes can get access to their Browser context, for accessing settings or navigating the browser.
*/
export default class WindowClassExtender {
export default class WindowContextClassExtender {
/**
* Extends classes with a "window" property.
*
* @param window Window.
*/
public static extendClass(window: BrowserWindow): void {
public static extendClasses(window: BrowserWindow): void {
/* eslint-disable jsdoc/require-jsdoc */

// Document
Expand Down
39 changes: 39 additions & 0 deletions packages/happy-dom/test/query-selector/QuerySelector.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,45 @@ describe('QuerySelector', () => {
expect((<HTMLInputElement>elements[0]).value).toBe('two');
});

it('Returns all elements matching ":disabled".', () => {
const container = document.createElement('div');
container.innerHTML = `
<form>
<input type="radio" id="id1" name="op" value="one" disabled/>
<input type="radio" id="id2" name="op" value="two"/>
<button disabled>Disabled</button>
<fieldset disabled></fieldset>
<select disabled>
<option>Option 1</option>
<option disabled>Option 2</option>
</select>
<textarea disabled></textarea>
</form>
`;
const elements = container.querySelectorAll(':disabled');

expect(elements.length).toBe(6);
expect(elements[0] === container.children[0].children[0]).toBe(true);
expect(elements[1] === container.children[0].children[2]).toBe(true);
expect(elements[2] === container.children[0].children[3]).toBe(true);
expect(elements[3] === container.children[0].children[4]).toBe(true);
expect(elements[4] === container.children[0].children[4].children[1]).toBe(true);
expect(elements[5] === container.children[0].children[5]).toBe(true);

// Here we also tests that cache works

(<HTMLInputElement>container.children[0].children[0]).disabled = false;

const elements2 = container.querySelectorAll(':disabled');

expect(elements2.length).toBe(5);
expect(elements2[0] === container.children[0].children[2]).toBe(true);
expect(elements2[1] === container.children[0].children[3]).toBe(true);
expect(elements2[2] === container.children[0].children[4]).toBe(true);
expect(elements2[3] === container.children[0].children[4].children[1]).toBe(true);
expect(elements2[4] === container.children[0].children[5]).toBe(true);
});

it('Returns all elements matching "span:not([type=hidden])".', () => {
const container = document.createElement('div');
container.innerHTML = QuerySelectorHTML;
Expand Down

0 comments on commit d3ce812

Please sign in to comment.