179 lines
7.6 KiB
TypeScript
179 lines
7.6 KiB
TypeScript
import '../support/polyfills';
|
|
import {DEFAULT_THEME} from '../../../src/defaults';
|
|
import {createOrUpdateDynamicTheme, removeDynamicTheme} from '../../../src/inject/dynamic-theme';
|
|
import {isFirefox, isSafari} from '../../../src/utils/platform';
|
|
import {multiline, timeout} from '../support/test-utils';
|
|
|
|
const theme = {
|
|
...DEFAULT_THEME,
|
|
darkSchemeBackgroundColor: 'black',
|
|
darkSchemeTextColor: 'white',
|
|
};
|
|
let container: HTMLElement;
|
|
|
|
beforeEach(() => {
|
|
container = document.body;
|
|
container.innerHTML = '';
|
|
});
|
|
|
|
afterEach(() => {
|
|
removeDynamicTheme();
|
|
container.innerHTML = '';
|
|
});
|
|
|
|
describe('SHADOW DOM', () => {
|
|
it('should add static overrides', async () => {
|
|
container.innerHTML = multiline(
|
|
'<div class="shadow-dom-wrapper"></div>',
|
|
);
|
|
document.querySelector('.shadow-dom-wrapper')!.attachShadow({mode: 'open'});
|
|
createOrUpdateDynamicTheme(theme, null, false);
|
|
const shadowRoot = document.querySelector('.shadow-dom-wrapper')!.shadowRoot!;
|
|
expect(shadowRoot.firstElementChild!.classList.contains('darkreader--inline')).toBe(true);
|
|
expect(shadowRoot.firstElementChild!.nextElementSibling!.classList.contains('darkreader--override')).toBe(true);
|
|
expect(shadowRoot.firstElementChild!.nextElementSibling!.nextElementSibling!.classList.contains('darkreader--invert')).toBe(true);
|
|
});
|
|
|
|
it('should override styles', async () => {
|
|
container.innerHTML = multiline(
|
|
'<div class="shadow-dom-wrapper"></div>',
|
|
);
|
|
const shadow = document.querySelector('.shadow-dom-wrapper')!.attachShadow({mode: 'open'});
|
|
const style = document.createElement('style');
|
|
style.classList.add('test-case-style');
|
|
shadow.appendChild(style);
|
|
style.sheet!.insertRule('h1 { color: gray }');
|
|
style.sheet!.insertRule('strong { color: red }');
|
|
createOrUpdateDynamicTheme(theme, null, false);
|
|
|
|
const shadowRoot = document.querySelector('.shadow-dom-wrapper')!.shadowRoot!;
|
|
const testCase = shadowRoot.querySelector('.test-case-style')!;
|
|
expect(testCase.nextElementSibling!.classList.contains('darkreader--sync')).toBe(true);
|
|
expect((testCase.nextElementSibling as HTMLStyleElement).sheet!.cssRules.length).toBe(2);
|
|
});
|
|
|
|
it('should react to DOM changes', async () => {
|
|
container.innerHTML = multiline(
|
|
'<div class="shadow-dom-wrapper"></div>',
|
|
);
|
|
const shadow = document.querySelector('.shadow-dom-wrapper')!.attachShadow({mode: 'open'});
|
|
|
|
createOrUpdateDynamicTheme(theme, null, false);
|
|
const style = document.createElement('style');
|
|
style.classList.add('test-case-style');
|
|
shadow.appendChild(style);
|
|
style.sheet!.insertRule('h1 { color: gray }');
|
|
style.sheet!.insertRule('strong { color: red }');
|
|
|
|
await timeout(0);
|
|
const shadowRoot = document.querySelector('.shadow-dom-wrapper')!.shadowRoot!;
|
|
const testCase = shadowRoot.querySelector('.test-case-style')!;
|
|
expect(shadowRoot.firstElementChild!.classList.contains('darkreader--inline')).toBe(true);
|
|
expect(shadowRoot.firstElementChild!.nextElementSibling!.classList.contains('darkreader--override')).toBe(true);
|
|
expect(testCase.nextElementSibling!.classList.contains('darkreader--sync')).toBe(true);
|
|
expect((testCase.nextElementSibling as HTMLStyleElement).sheet!.cssRules.length).toBe(2);
|
|
});
|
|
|
|
it('should override inline styles', async () => {
|
|
container.innerHTML = multiline(
|
|
'<div class="shadow-dom-wrapper"></div>',
|
|
);
|
|
const shadow = document.querySelector('.shadow-dom-wrapper')!.attachShadow({mode: 'open'});
|
|
|
|
createOrUpdateDynamicTheme(theme, null, false);
|
|
const standardElement = document.createElement('p');
|
|
standardElement.style.color = 'red';
|
|
shadow.appendChild(standardElement);
|
|
|
|
await timeout(0);
|
|
const shadowRoot = document.querySelector('.shadow-dom-wrapper')!.shadowRoot!;
|
|
expect(getComputedStyle(shadowRoot.querySelector('p')!).color).toBe('rgb(255, 26, 26)');
|
|
});
|
|
|
|
it('should handle defined custom elements', async () => {
|
|
container.innerHTML = multiline(
|
|
'<custom-element>',
|
|
'</custom-element>',
|
|
);
|
|
class CustomElement extends HTMLElement {
|
|
constructor() {
|
|
super();
|
|
const shadowRoot = this.attachShadow({mode: 'open'});
|
|
const style = document.createElement('style');
|
|
style.textContent = 'p { color: pink }';
|
|
const paragraph = document.createElement('p');
|
|
paragraph.textContent = 'Some text content that should be pink.';
|
|
|
|
shadowRoot.append(style);
|
|
shadowRoot.append(paragraph);
|
|
}
|
|
}
|
|
customElements.define('custom-element', CustomElement);
|
|
|
|
createOrUpdateDynamicTheme(theme, null, false);
|
|
const shadowRoot = document.querySelector('custom-element')!.shadowRoot!;
|
|
expect(getComputedStyle(shadowRoot.querySelector('p')!).color).toBe('rgb(255, 198, 208)');
|
|
});
|
|
|
|
it('should react to defined custom elements', async () => {
|
|
container.innerHTML = multiline(
|
|
'<delayed-custom-element>',
|
|
'</delayed-custom-element>',
|
|
);
|
|
class DelayedCustomElement extends HTMLElement {
|
|
constructor() {
|
|
super();
|
|
const shadowRoot = this.attachShadow({mode: 'open'});
|
|
const style = document.createElement('style');
|
|
style.textContent = 'p { color: pink }';
|
|
const paragraph = document.createElement('p');
|
|
paragraph.textContent = 'Some text content that should be pink.';
|
|
|
|
shadowRoot.append(style);
|
|
shadowRoot.append(paragraph);
|
|
}
|
|
}
|
|
|
|
createOrUpdateDynamicTheme(theme, null, false);
|
|
customElements.define('delayed-custom-element', DelayedCustomElement);
|
|
await timeout(0);
|
|
const shadowRoot = document.querySelector('delayed-custom-element')!.shadowRoot!;
|
|
expect(getComputedStyle(shadowRoot.querySelector('p')!).color).toBe('rgb(255, 198, 208)');
|
|
});
|
|
|
|
it('should override styles', async () => {
|
|
// Firefox by default doesn't enable the CSSStyleSheet constructor.
|
|
if (isFirefox || isSafari) {
|
|
return;
|
|
}
|
|
|
|
container.innerHTML = multiline(
|
|
'<div class="shadow-dom-wrapper"></div>',
|
|
);
|
|
|
|
const newRule = new CSSStyleSheet();
|
|
newRule.insertRule(':host { --red: red }');
|
|
|
|
const shadow = document.querySelector('.shadow-dom-wrapper')!.attachShadow({mode: 'open'});
|
|
shadow.adoptedStyleSheets = [newRule];
|
|
|
|
const style = document.createElement('style');
|
|
style.classList.add('test-case-style');
|
|
shadow.appendChild(style);
|
|
style.sheet!.insertRule('h1 { color: var(--red) }');
|
|
|
|
const h1 = document.createElement('h1');
|
|
shadow.appendChild(h1);
|
|
|
|
createOrUpdateDynamicTheme(theme, null, false);
|
|
|
|
const shadowRoot = document.querySelector('.shadow-dom-wrapper')!.shadowRoot!;
|
|
const testCase = shadowRoot.querySelector('.test-case-style')!;
|
|
const darkendH1 = shadowRoot.querySelector('h1')!;
|
|
expect(testCase.nextElementSibling!.classList.contains('darkreader--sync')).toBe(true);
|
|
expect((testCase.nextElementSibling as HTMLStyleElement).sheet!.cssRules.length).toBe(1);
|
|
expect(shadowRoot.adoptedStyleSheets.length).toBe(2);
|
|
expect(getComputedStyle(darkendH1).color).toBe('rgb(255, 26, 26)');
|
|
});
|
|
});
|