Skip to content

Commit

Permalink
#1188@minor: Adds support for Document.adoptedStyleSheets and ShadowR…
Browse files Browse the repository at this point in the history
…oot.adoptedStyleSheets to Window.getComputedStyle().
  • Loading branch information
capricorn86 committed Jan 14, 2024
1 parent bf76491 commit 805fde6
Show file tree
Hide file tree
Showing 10 changed files with 186 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -137,17 +137,25 @@ export default class CSSStyleDeclarationElementStyle {
}
}

for (const styleSheet of this.element[PropertySymbol.ownerDocument].adoptedStyleSheets) {
this.parseCSSRules({
elements: documentElements,
cssRules: styleSheet.cssRules
});
}

styleAndElement = { element: null, cssTexts: [] };
} else if (
styleAndElement.element[PropertySymbol.nodeType] === NodeTypeEnum.documentFragmentNode &&
(<IShadowRoot>styleAndElement.element).host
) {
const shadowRoot = <IShadowRoot>styleAndElement.element;
const styleSheets = <INodeList<IHTMLStyleElement>>(
(<IShadowRoot>styleAndElement.element).querySelectorAll('style,link[rel="stylesheet"]')
shadowRoot.querySelectorAll('style,link[rel="stylesheet"]')
);

styleAndElement = {
element: <IElement>(<IShadowRoot>styleAndElement.element).host,
element: <IElement>shadowRoot.host,
cssTexts: []
};

Expand All @@ -161,6 +169,15 @@ export default class CSSStyleDeclarationElementStyle {
});
}
}

for (const styleSheet of shadowRoot.adoptedStyleSheets) {
this.parseCSSRules({
elements: shadowRootElements,
cssRules: styleSheet.cssRules,
hostElement: styleAndElement
});
}

shadowRootElements = [];
} else {
styleAndElement = {
Expand Down
1 change: 1 addition & 0 deletions packages/happy-dom/src/nodes/document/IDocument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export default interface IDocument extends IParentNode {
readonly links: IHTMLCollection<IHTMLElement>;
readonly referrer: string;
readonly currentScript: IHTMLScriptElement;
adoptedStyleSheets: CSSStyleSheet[];
cookie: string;
title: string;

Expand Down
2 changes: 1 addition & 1 deletion packages/happy-dom/src/nodes/element/Element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -788,7 +788,7 @@ export default class Element extends Node implements IElement {
* @param init.mode Shadow root mode.
* @returns Shadow root.
*/
public attachShadow(init: { mode: 'open' | 'closed' }): IShadowRoot {
public attachShadow(init: { mode: string }): IShadowRoot {
if (this[PropertySymbol.shadowRoot]) {
throw new DOMException('Shadow root has already been attached.');
}
Expand Down
2 changes: 2 additions & 0 deletions packages/happy-dom/src/nodes/shadow-root/IShadowRoot.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import IDocumentFragment from '../document-fragment/IDocumentFragment.js';
import IElement from '../element/IElement.js';
import Event from '../../event/Event.js';
import { CSSStyleSheet } from '../../index.js';

/**
* ShadowRoot.
Expand All @@ -9,6 +10,7 @@ export default interface IShadowRoot extends IDocumentFragment {
mode: string;
innerHTML: string;
host: IElement;
adoptedStyleSheets: CSSStyleSheet[];
readonly activeElement: IElement | null;

// Events
Expand Down
4 changes: 2 additions & 2 deletions packages/happy-dom/src/nodes/shadow-root/ShadowRoot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ export default class ShadowRoot extends DocumentFragment implements IShadowRoot

// Internal properties
public [PropertySymbol.adoptedStyleSheets]: CSSStyleSheet[] = [];
public [PropertySymbol.mode]: 'open' | 'closed' = 'open';
public [PropertySymbol.mode] = 'open';
public [PropertySymbol.host]: IElement | null = null;

/**
* Returns mode.
*
* @returns Mode.
*/
public get mode(): 'open' | 'closed' {
public get mode(): string {
return this[PropertySymbol.mode];
}

Expand Down
83 changes: 83 additions & 0 deletions packages/happy-dom/test/AdoptedStyleSheetCustomElement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import IShadowRoot from '../src/nodes/shadow-root/IShadowRoot.js';
import HTMLElement from '../src/nodes/html-element/HTMLElement.js';
import CSSStyleSheet from '../src/css/CSSStyleSheet.js';

/**
* CustomElement test class.
*/
export default class AdoptedStyleSheetCustomElement extends HTMLElement {
public static observedAttributesCallCount = 0;
public static shadowRootMode = 'open';
public changedAttributes: Array<{
name: string;
oldValue: string | null;
newValue: string | null;
}> = [];
private internalShadowRoot: IShadowRoot;

/**
* Constructor.
*/
constructor() {
super();
this.internalShadowRoot = this.attachShadow({
mode: AdoptedStyleSheetCustomElement.shadowRootMode
});
const styleSheet = new CSSStyleSheet();
styleSheet.replaceSync(`
:host {
display: block;
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
}
span {
color: pink;
}
.propKey {
color: yellow;
}
`);
this.internalShadowRoot.adoptedStyleSheets = [styleSheet];

// Test to create a node while constructing this node.
this.ownerDocument.createElement('div');
}

/**
* Returns a list of observed attributes.
*
* @returns Observered attributes.
*/
public static get observedAttributes(): string[] {
this.observedAttributesCallCount++;
return ['key1', 'key2'];
}

/**
* @override
*/
public attributeChangedCallback(name: string, oldValue: string, newValue: string): void {
this.changedAttributes.push({ name, oldValue, newValue });
}

/**
* @override
*/
public connectedCallback(): void {
this.internalShadowRoot.innerHTML = `
<div>
<span class="propKey">
key1 is "${this.getAttribute('key1')}" and key2 is "${this.getAttribute(
'key2'
)}".
</span>
<span class="children">${this.childNodes
.map(
(child) =>
'#' + child['nodeType'] + (child['tagName'] || '') + child.textContent
)
.join(', ')}</span>
<span><slot></slot></span>
</div>
`;
}
}
36 changes: 18 additions & 18 deletions packages/happy-dom/test/fetch/Fetch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3585,7 +3585,7 @@ describe('Fetch', () => {
expect(requestCount).toBe(1);
});

it('Revalidates cache with a "If-Modified-Since" request for a GET response with "Cache-Control" set to "max-age=0.020".', async () => {
it('Revalidates cache with a "If-Modified-Since" request for a GET response with "Cache-Control" set to "max-age=0.05".', async () => {
const window = new Window({ url: 'https://localhost:8080/' });
const url = 'https://localhost:8080/some/path';
const responseText = 'some text';
Expand All @@ -3612,7 +3612,7 @@ describe('Fetch', () => {
'last-modified',
'Mon, 11 Dec 2023 02:00:00 GMT',
'cache-control',
'max-age=0.020'
'max-age=0.05'
];

callback(response);
Expand All @@ -3632,7 +3632,7 @@ describe('Fetch', () => {
'content-length',
String(responseText.length),
'cache-control',
'max-age=0.020',
'max-age=0.05',
'last-modified',
'Mon, 11 Dec 2023 01:00:00 GMT'
];
Expand Down Expand Up @@ -3677,7 +3677,7 @@ describe('Fetch', () => {
expect(headers1).toEqual({
'content-type': 'text/html',
'content-length': String(responseText.length),
'cache-control': `max-age=0.020`,
'cache-control': `max-age=0.05`,
'last-modified': 'Mon, 11 Dec 2023 01:00:00 GMT'
});

Expand All @@ -3690,7 +3690,7 @@ describe('Fetch', () => {
expect(headers2).toEqual({
'content-type': 'text/html',
'content-length': String(responseText.length),
'Cache-Control': 'max-age=0.020',
'Cache-Control': 'max-age=0.05',
'Last-Modified': 'Mon, 11 Dec 2023 02:00:00 GMT'
});

Expand Down Expand Up @@ -3737,7 +3737,7 @@ describe('Fetch', () => {
]);
});

it('Updates cache after a failed revalidation with a "If-Modified-Since" request for a GET response with "Cache-Control" set to "max-age=0.020".', async () => {
it('Updates cache after a failed revalidation with a "If-Modified-Since" request for a GET response with "Cache-Control" set to "max-age=0.05".', async () => {
const window = new Window({ url: 'https://localhost:8080/' });
const url = '/some/path';
const responseText1 = 'some text';
Expand Down Expand Up @@ -3771,7 +3771,7 @@ describe('Fetch', () => {
'content-length',
String(responseText2.length),
'cache-control',
'max-age=0.020',
'max-age=0.05',
'last-modified',
'Mon, 11 Dec 2023 02:00:00 GMT'
];
Expand All @@ -3793,7 +3793,7 @@ describe('Fetch', () => {
'content-length',
String(responseText1.length),
'cache-control',
'max-age=0.004',
'max-age=0.05',
'last-modified',
'Mon, 11 Dec 2023 01:00:00 GMT'
];
Expand All @@ -3814,7 +3814,7 @@ describe('Fetch', () => {
});
const text1 = await response1.text();

await new Promise((resolve) => setTimeout(resolve, 50));
await new Promise((resolve) => setTimeout(resolve, 100));

const response2 = await window.fetch(url);
const text2 = await response2.text();
Expand Down Expand Up @@ -3846,7 +3846,7 @@ describe('Fetch', () => {
expect(headers1).toEqual({
'content-type': 'text/html',
'content-length': String(responseText1.length),
'cache-control': `max-age=0.004`,
'cache-control': `max-age=0.05`,
'last-modified': 'Mon, 11 Dec 2023 01:00:00 GMT'
});

Expand All @@ -3859,7 +3859,7 @@ describe('Fetch', () => {
expect(headers2).toEqual({
'content-type': 'text/html',
'content-length': String(responseText2.length),
'cache-control': 'max-age=0.020',
'cache-control': 'max-age=0.05',
'last-modified': 'Mon, 11 Dec 2023 02:00:00 GMT'
});

Expand Down Expand Up @@ -3963,7 +3963,7 @@ describe('Fetch', () => {
'content-length',
String(responseText.length),
'cache-control',
'max-age=0.020',
'max-age=0.05',
'last-modified',
'Mon, 11 Dec 2023 01:00:00 GMT',
'etag',
Expand Down Expand Up @@ -4013,7 +4013,7 @@ describe('Fetch', () => {
expect(headers1).toEqual({
'content-type': 'text/html',
'content-length': String(responseText.length),
'cache-control': `max-age=0.020`,
'cache-control': `max-age=0.05`,
'last-modified': 'Mon, 11 Dec 2023 01:00:00 GMT',
etag: etag1
});
Expand All @@ -4027,7 +4027,7 @@ describe('Fetch', () => {
expect(headers2).toEqual({
'content-type': 'text/html',
'content-length': String(responseText.length),
'cache-control': `max-age=0.020`,
'cache-control': `max-age=0.05`,
'Last-Modified': 'Mon, 11 Dec 2023 02:00:00 GMT',
ETag: etag2
});
Expand Down Expand Up @@ -4111,7 +4111,7 @@ describe('Fetch', () => {
'content-length',
String(responseText2.length),
'cache-control',
'max-age=0.020',
'max-age=0.05',
'last-modified',
'Mon, 11 Dec 2023 02:00:00 GMT',
'etag',
Expand All @@ -4135,7 +4135,7 @@ describe('Fetch', () => {
'content-length',
String(responseText1.length),
'cache-control',
'max-age=0.020',
'max-age=0.05',
'last-modified',
'Mon, 11 Dec 2023 01:00:00 GMT',
'etag',
Expand Down Expand Up @@ -4182,7 +4182,7 @@ describe('Fetch', () => {
expect(headers1).toEqual({
'content-type': 'text/html',
'content-length': String(responseText1.length),
'cache-control': `max-age=0.020`,
'cache-control': `max-age=0.05`,
'last-modified': 'Mon, 11 Dec 2023 01:00:00 GMT',
etag: etag1
});
Expand All @@ -4196,7 +4196,7 @@ describe('Fetch', () => {
expect(headers2).toEqual({
'content-type': 'text/html',
'content-length': String(responseText2.length),
'cache-control': `max-age=0.020`,
'cache-control': `max-age=0.05`,
'last-modified': 'Mon, 11 Dec 2023 02:00:00 GMT',
etag: etag2
});
Expand Down
Loading

0 comments on commit 805fde6

Please sign in to comment.