From ad9cbe93994888e8f8ba88ce3614dc041a698930 Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Wed, 28 Sep 2022 12:42:40 +0200 Subject: [PATCH] Add unit tests --- src/theme.ts | 12 +++-- test/theme-test.ts | 111 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 test/theme-test.ts diff --git a/src/theme.ts b/src/theme.ts index a657807704..9d2f836fb4 100644 --- a/src/theme.ts +++ b/src/theme.ts @@ -261,7 +261,7 @@ export async function setTheme(theme?: string): Promise { const styleSheet = styleElements.get(stylesheetName); styleSheet.disabled = false; - return new Promise((resolve) => { + return new Promise(((resolve, reject) => { const switchTheme = function() { // we re-enable our theme here just in case we raced with another // theme set request as per https://github.com/vector-im/element-web/issues/5601. @@ -307,21 +307,23 @@ export async function setTheme(theme?: string): Promise { // Avoid to be stuck in an endless loop if there is an issue in the stylesheet loading counter++; - if (counter === 5) { + if (counter === 10) { clearInterval(intervalId); + reject(); } - }, 100); + }, 200); styleSheet.onload = () => { clearInterval(intervalId); switchTheme(); }; - styleSheet.onerror = () => { + styleSheet.onerror = (e) => { clearInterval(intervalId); + reject(e); }; } waitForStyleSheetLoading(); - }); + })); } diff --git a/test/theme-test.ts b/test/theme-test.ts new file mode 100644 index 0000000000..47e42f5a70 --- /dev/null +++ b/test/theme-test.ts @@ -0,0 +1,111 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { setTheme } from "../src/theme"; + +describe('theme', () => { + describe('setTheme', () => { + let lightTheme; + let darkTheme; + + beforeEach(() => { + const styles = [ + { + attributes: { + 'data-mx-theme': { + value: 'light', + }, + }, + disabled: true, + href: 'urlLight', + onload: () => void 0, + }, + { + attributes: { + 'data-mx-theme': { + value: 'dark', + }, + }, + disabled: true, + href: 'urlDark', + onload: () => void 0, + }, + ]; + lightTheme = styles[0]; + darkTheme = styles[1]; + + jest.spyOn(document.body, 'style', 'get').mockReturnValue([] as any); + jest.spyOn(document, 'querySelectorAll').mockReturnValue(styles as any); + }); + + afterEach(() => { + jest.restoreAllMocks(); + jest.useRealTimers(); + }); + + it('should switch theme on onload call', async () => { + // When + await new Promise(resolve => { + setTheme('light').then(resolve); + lightTheme.onload(); + }); + + // Then + expect(lightTheme.disabled).toBe(false); + expect(darkTheme.disabled).toBe(true); + }); + + it('should reject promise on onerror call', () => { + return expect(new Promise(resolve => { + setTheme('light').catch(e => resolve(e)); + lightTheme.onerror('call onerror'); + })).resolves.toBe('call onerror'); + }); + + it('should switch theme if CSS are preloaded', async () => { + // When + jest.spyOn(document, 'styleSheets', 'get').mockReturnValue([lightTheme] as any); + + await setTheme('light'); + + // Then + expect(lightTheme.disabled).toBe(false); + expect(darkTheme.disabled).toBe(true); + }); + + it('should switch theme if CSS is loaded during pooling', async () => { + // When + jest.useFakeTimers(); + await new Promise(resolve => { + setTheme('light').then(resolve); + jest.spyOn(document, 'styleSheets', 'get').mockReturnValue([lightTheme] as any); + jest.advanceTimersByTime(200); + }); + + // Then + expect(lightTheme.disabled).toBe(false); + expect(darkTheme.disabled).toBe(true); + }); + + it('should reject promise if pooling maximum value is reached', () => { + jest.useFakeTimers(); + return new Promise(resolve => { + setTheme('light').catch(resolve); + jest.advanceTimersByTime(200 * 10); + }); + }); + }); +});