lion/packages/ui/components/overlays/test/utils-tests/adopt-styles.test.js
2023-11-24 12:02:06 +01:00

238 lines
8.3 KiB
JavaScript

import { expect } from '@open-wc/testing';
import { browserDetection } from '@lion/ui/core.js';
import { css } from 'lit';
import sinon from 'sinon';
import {
adoptStyle,
adoptStyles,
serializeConstructableStylesheet,
_adoptStyleUtils,
} from '../../src/utils/adopt-styles.js';
import { createShadowHost } from '../../test-helpers/createShadowHost.js';
function mockNoSupportAdoptedStylesheets() {
_adoptStyleUtils.supportsAdoptingStyleSheets = false;
}
function restoreMockNoSupportAdoptedStylesheets() {
_adoptStyleUtils.supportsAdoptingStyleSheets = true;
}
describe('adoptStyle()', () => {
it('adds a stylesheet from a CSSResult to the shadowRoot', async () => {
const { shadowHost, cleanupShadowHost } = createShadowHost();
const myCssResult = css``;
const root = /** @type {ShadowRoot} */ (shadowHost.shadowRoot);
adoptStyle(root, myCssResult);
expect(root.adoptedStyleSheets).to.include(myCssResult.styleSheet);
cleanupShadowHost();
});
it('adds a stylesheet from a CSSStyleSheet to the shadowRoot', async () => {
const { shadowHost, cleanupShadowHost } = createShadowHost();
const myCSSStyleSheet = new CSSStyleSheet();
const root = /** @type {ShadowRoot} */ (shadowHost.shadowRoot);
adoptStyle(root, myCSSStyleSheet);
expect(root.adoptedStyleSheets).to.include(myCSSStyleSheet);
cleanupShadowHost();
});
it('does not add same stylesheet twice', async () => {
const { shadowHost, cleanupShadowHost } = createShadowHost();
const myCssResult = css``;
const root = /** @type {ShadowRoot} */ (shadowHost.shadowRoot);
adoptStyle(root, myCssResult);
const amountOfStylesheetsAfterOneInit = root.adoptedStyleSheets.length;
adoptStyle(root, myCssResult);
expect(root.adoptedStyleSheets.length).to.equal(amountOfStylesheetsAfterOneInit);
cleanupShadowHost();
});
it('works as well when document is the root', async () => {
const myCssResult = css``;
const root = document;
adoptStyle(root, myCssResult);
expect(root.adoptedStyleSheets).to.include(myCssResult.styleSheet);
});
describe('Teardown', () => {
it('removes stylesheets from the shadowRoot', async () => {
const { shadowHost, cleanupShadowHost } = createShadowHost();
const myCssResult = css``;
const root = /** @type {ShadowRoot} */ (shadowHost.shadowRoot);
adoptStyle(root, myCssResult);
expect(root.adoptedStyleSheets).to.include(myCssResult.styleSheet);
adoptStyle(root, myCssResult, { teardown: true });
expect(root.adoptedStyleSheets).to.not.include(myCssResult.styleSheet);
const myCSSStyleSheet = new CSSStyleSheet();
adoptStyle(root, myCSSStyleSheet);
expect(root.adoptedStyleSheets).to.include(myCSSStyleSheet);
adoptStyle(root, myCSSStyleSheet, { teardown: true });
expect(root.adoptedStyleSheets).to.not.include(myCSSStyleSheet);
cleanupShadowHost();
});
});
describe('Fallback when adoptedStyleSheets are not supported', () => {
beforeEach(() => {
mockNoSupportAdoptedStylesheets();
});
afterEach(() => {
restoreMockNoSupportAdoptedStylesheets();
});
it('adds a "traditional" stylesheet to the shadowRoot', async () => {
const { shadowHost, cleanupShadowHost } = createShadowHost();
const myCssResult = css`
.check {
color: blue;
}
`;
const root = /** @type {ShadowRoot} */ (shadowHost.shadowRoot);
adoptStyle(root, myCssResult);
const sheets = Array.from(root.querySelectorAll('style'));
const lastAddedSheet = sheets[sheets.length - 1];
expect(lastAddedSheet.textContent).to.equal(myCssResult.cssText);
cleanupShadowHost();
});
it('adds a "traditional" stylesheet to the body', async () => {
mockNoSupportAdoptedStylesheets();
const myCssResult = css`
.check {
color: blue;
}
`;
const root = document;
adoptStyle(root, myCssResult);
const sheets = Array.from(document.body.querySelectorAll('style'));
const lastAddedSheet = sheets[sheets.length - 1];
expect(lastAddedSheet.textContent).to.equal(myCssResult.cssText);
restoreMockNoSupportAdoptedStylesheets();
});
describe('Teardown', () => {
it('removes a "traditional" stylesheet from the shadowRoot', async () => {
const { shadowHost, cleanupShadowHost } = createShadowHost();
const myCssResult = css`
.check {
color: blue;
}
`;
const root = /** @type {ShadowRoot} */ (shadowHost.shadowRoot);
adoptStyle(root, myCssResult);
const sheets1 = Array.from(root.querySelectorAll('style'));
const lastAddedSheet1 = sheets1[sheets1.length - 1];
expect(lastAddedSheet1.textContent).to.equal(myCssResult.cssText);
adoptStyle(root, myCssResult, { teardown: true });
const sheets2 = Array.from(root.querySelectorAll('style'));
const lastAddedSheet2 = sheets2[sheets2.length - 1];
expect(lastAddedSheet2?.textContent).to.not.equal(myCssResult.cssText);
const myCSSStyleSheet = new CSSStyleSheet();
myCSSStyleSheet.insertRule('.check { color: blue; }');
adoptStyle(root, myCSSStyleSheet);
const sheets3 = Array.from(root.querySelectorAll('style'));
const lastAddedSheet3 = sheets3[sheets3.length - 1];
expect(lastAddedSheet3.textContent).to.equal(
serializeConstructableStylesheet(myCSSStyleSheet),
);
adoptStyle(root, myCSSStyleSheet, { teardown: true });
const sheets4 = Array.from(root.querySelectorAll('style'));
const lastAddedSheet4 = sheets4[sheets4.length - 1];
expect(lastAddedSheet4?.textContent).to.not.equal(myCSSStyleSheet);
cleanupShadowHost();
});
});
});
});
describe('Fallback when IOS user opens overlay', () => {
it('adds a "traditional" stylesheet to the body', async () => {
const browserDetectionStub = sinon.stub(browserDetection, 'isIOS').value(true);
const myCssResult = css`
.check {
color: blue;
}
`;
const root = document;
adoptStyle(root, myCssResult);
const sheets = Array.from(document.body.querySelectorAll('style'));
const lastAddedSheet = sheets[sheets.length - 1];
expect(lastAddedSheet.textContent).to.equal(myCssResult.cssText);
browserDetectionStub.restore();
});
describe('Teardown', () => {
it('removes a "traditional" stylesheet from the shadowRoot', async () => {
const browserDetectionStub = sinon.stub(browserDetection, 'isIOS').value(true);
const { shadowHost, cleanupShadowHost } = createShadowHost();
const myCssResult = css`
.check {
color: blue;
}
`;
const root = /** @type {ShadowRoot} */ (shadowHost.shadowRoot);
adoptStyle(root, myCssResult);
const sheets1 = Array.from(root.querySelectorAll('style'));
const lastAddedSheet1 = sheets1[sheets1.length - 1];
expect(lastAddedSheet1.textContent).to.equal(myCssResult.cssText);
adoptStyle(root, myCssResult, { teardown: true });
const sheets2 = Array.from(root.querySelectorAll('style'));
const lastAddedSheet2 = sheets2[sheets2.length - 1];
expect(lastAddedSheet2?.textContent).to.not.equal(myCssResult.cssText);
const myCSSStyleSheet = new CSSStyleSheet();
myCSSStyleSheet.insertRule('.check { color: blue; }');
adoptStyle(root, myCSSStyleSheet);
const sheets3 = Array.from(root.querySelectorAll('style'));
const lastAddedSheet3 = sheets3[sheets3.length - 1];
expect(lastAddedSheet3.textContent).to.equal(
serializeConstructableStylesheet(myCSSStyleSheet),
);
adoptStyle(root, myCSSStyleSheet, { teardown: true });
const sheets4 = Array.from(root.querySelectorAll('style'));
const lastAddedSheet4 = sheets4[sheets4.length - 1];
expect(lastAddedSheet4?.textContent).to.not.equal(myCSSStyleSheet);
cleanupShadowHost();
browserDetectionStub.restore();
});
});
});
describe('adoptStyles()', () => {
it('calls "adoptStyle" for all entries in CSSResult|CSSStylesheet[]', async () => {
const spy = sinon.spy(_adoptStyleUtils, 'adoptStyle');
const myCssResult = css``;
const myCSSStyleSheet = new CSSStyleSheet();
adoptStyles(document, [myCssResult, myCSSStyleSheet]);
expect(spy).to.have.been.calledTwice;
});
});