From 6f304d147c4ec86ade2699dd3553906f9123b902 Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Thu, 28 Oct 2021 15:11:16 +0100 Subject: [PATCH 1/2] Unit tests for getEffectiveTheme --- test/settings/watchers/ThemeWatcher-test.tsx | 152 +++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 test/settings/watchers/ThemeWatcher-test.tsx diff --git a/test/settings/watchers/ThemeWatcher-test.tsx b/test/settings/watchers/ThemeWatcher-test.tsx new file mode 100644 index 00000000000..149c43d9a02 --- /dev/null +++ b/test/settings/watchers/ThemeWatcher-test.tsx @@ -0,0 +1,152 @@ +/* +Copyright 2021 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 SettingsStore from '../../../src/settings/SettingsStore'; +import ThemeWatcher from '../../../src/settings/watchers/ThemeWatcher'; +import { SettingLevel } from '../../../src/settings/SettingLevel'; + +function makeMatchMedia(values: any) { + class FakeMediaQueryList { + matches: false; + media: null; + onchange: null; + addListener() {} + removeListener() {} + addEventListener() {} + removeEventListener() {} + dispatchEvent() { return true; } + + constructor(query: string) { + this.matches = values[query]; + } + } + + return function matchMedia(query: string) { + return new FakeMediaQueryList(query); + }; +} + +function makeGetValue(values: any) { + return function getValue( + settingName: string, + _roomId: string = null, + _excludeDefault = false, + ): T { + return values[settingName]; + }; +} + +function makeGetValueAt(values: any) { + return function getValueAt( + _level: SettingLevel, + settingName: string, + _roomId: string = null, + _explicit = false, + _excludeDefault = false, + ): any { + return values[settingName]; + }; +} + +describe('ThemeWatcher', function() { + it('should choose a light theme by default', () => { + // Given no system settings + global.matchMedia = makeMatchMedia({}); + + // Then getEffectiveTheme returns light + const themeWatcher = new ThemeWatcher(); + expect(themeWatcher.getEffectiveTheme()).toBe("light"); + }); + + it('should choose a dark theme if that is selected', () => { + // Given system settings say light and theme is set to dark + global.matchMedia = makeMatchMedia({ "(prefers-color-scheme: light)": true }); + SettingsStore.getValue = makeGetValue({ "theme": "dark" }); + + // Then getEffectiveTheme returns dark + const themeWatcher = new ThemeWatcher(); + expect(themeWatcher.getEffectiveTheme()).toBe("dark"); + }); + + it('should choose a light theme if that is selected', () => { + // Given system settings say dark and theme set to light + global.matchMedia = makeMatchMedia({ "(prefers-color-scheme: dark)": true }); + SettingsStore.getValue = makeGetValue({ "theme": "light" }); + + // Then getEffectiveTheme returns light + const themeWatcher = new ThemeWatcher(); + expect(themeWatcher.getEffectiveTheme()).toBe("light"); + }); + + it('should choose a light-high-contrast theme if that is selected', () => { + // Given system settings say dark and theme set to light-high-contrast + global.matchMedia = makeMatchMedia({ "(prefers-color-scheme: dark)": true }); + SettingsStore.getValue = makeGetValue({ "theme": "light-high-contrast" }); + + // Then getEffectiveTheme returns light-high-contrast + const themeWatcher = new ThemeWatcher(); + expect(themeWatcher.getEffectiveTheme()).toBe("light-high-contrast"); + }); + + it('should choose a light theme if system prefers it (via default)', () => { + // Given system prefers lightness, even though we did not + // click "Use system theme" or choose a theme explicitly + global.matchMedia = makeMatchMedia({ "(prefers-color-scheme: light)": true }); + SettingsStore.getValueAt = makeGetValueAt({}); + SettingsStore.getValue = makeGetValue({ "use_system_theme": true }); + + // Then getEffectiveTheme returns light + const themeWatcher = new ThemeWatcher(); + expect(themeWatcher.getEffectiveTheme()).toBe("light"); + }); + + it('should choose a dark theme if system prefers it (via default)', () => { + // Given system prefers darkness, even though we did not + // click "Use system theme" or choose a theme explicitly + global.matchMedia = makeMatchMedia({ "(prefers-color-scheme: dark)": true }); + SettingsStore.getValueAt = makeGetValueAt({}); + SettingsStore.getValue = makeGetValue({ "use_system_theme": true }); + + // Then getEffectiveTheme returns dark + const themeWatcher = new ThemeWatcher(); + expect(themeWatcher.getEffectiveTheme()).toBe("dark"); + }); + + it('should choose a light theme if system prefers it (explicit)', () => { + // Given system prefers lightness, even though we did not + // click "Use system theme" or choose a theme explicitly + global.matchMedia = makeMatchMedia({ "(prefers-color-scheme: light)": true }); + SettingsStore.getValueAt = makeGetValueAt({ "use_system_theme": true }); + SettingsStore.getValue = makeGetValue({ "use_system_theme": true }); + + // Then getEffectiveTheme returns light + const themeWatcher = new ThemeWatcher(); + expect(themeWatcher.getEffectiveTheme()).toBe("light"); + }); + + it('should choose a dark theme if system prefers it (explicit)', () => { + // Given system prefers darkness, even though we did not + // click "Use system theme" or choose a theme explicitly + global.matchMedia = makeMatchMedia({ "(prefers-color-scheme: dark)": true }); + SettingsStore.getValueAt = makeGetValueAt({ "use_system_theme": true }); + SettingsStore.getValue = makeGetValue({ "use_system_theme": true }); + + // Then getEffectiveTheme returns dark + const themeWatcher = new ThemeWatcher(); + expect(themeWatcher.getEffectiveTheme()).toBe("dark"); + }); +}); + From ba4a41b2602a084bcb925178a3bc80be964ada50 Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Thu, 28 Oct 2021 15:26:41 +0100 Subject: [PATCH 2/2] Unit tests for choosing high-contrast theme --- test/settings/watchers/ThemeWatcher-test.tsx | 68 ++++++++++++++++---- 1 file changed, 57 insertions(+), 11 deletions(-) diff --git a/test/settings/watchers/ThemeWatcher-test.tsx b/test/settings/watchers/ThemeWatcher-test.tsx index 149c43d9a02..c97ba13a33c 100644 --- a/test/settings/watchers/ThemeWatcher-test.tsx +++ b/test/settings/watchers/ThemeWatcher-test.tsx @@ -71,10 +71,26 @@ describe('ThemeWatcher', function() { expect(themeWatcher.getEffectiveTheme()).toBe("light"); }); + it('should choose default theme if system settings are inconclusive', () => { + // Given no system settings but we asked to use them + global.matchMedia = makeMatchMedia({}); + SettingsStore.getValue = makeGetValue({ + "use_system_theme": true, + "theme": "light", + }); + + // Then getEffectiveTheme returns light + const themeWatcher = new ThemeWatcher(); + expect(themeWatcher.getEffectiveTheme()).toBe("light"); + }); + it('should choose a dark theme if that is selected', () => { - // Given system settings say light and theme is set to dark - global.matchMedia = makeMatchMedia({ "(prefers-color-scheme: light)": true }); - SettingsStore.getValue = makeGetValue({ "theme": "dark" }); + // Given system says light high contrast but theme is set to dark + global.matchMedia = makeMatchMedia({ + "(prefers-contrast: more)": true, + "(prefers-color-scheme: light)": true, + }); + SettingsStore.getValueAt = makeGetValueAt({ "theme": "dark" }); // Then getEffectiveTheme returns dark const themeWatcher = new ThemeWatcher(); @@ -82,9 +98,12 @@ describe('ThemeWatcher', function() { }); it('should choose a light theme if that is selected', () => { - // Given system settings say dark and theme set to light - global.matchMedia = makeMatchMedia({ "(prefers-color-scheme: dark)": true }); - SettingsStore.getValue = makeGetValue({ "theme": "light" }); + // Given system settings say dark high contrast but theme set to light + global.matchMedia = makeMatchMedia({ + "(prefers-contrast: more)": true, + "(prefers-color-scheme: dark)": true, + }); + SettingsStore.getValueAt = makeGetValueAt({ "theme": "light" }); // Then getEffectiveTheme returns light const themeWatcher = new ThemeWatcher(); @@ -94,7 +113,7 @@ describe('ThemeWatcher', function() { it('should choose a light-high-contrast theme if that is selected', () => { // Given system settings say dark and theme set to light-high-contrast global.matchMedia = makeMatchMedia({ "(prefers-color-scheme: dark)": true }); - SettingsStore.getValue = makeGetValue({ "theme": "light-high-contrast" }); + SettingsStore.getValueAt = makeGetValueAt({ "theme": "light-high-contrast" }); // Then getEffectiveTheme returns light-high-contrast const themeWatcher = new ThemeWatcher(); @@ -126,8 +145,7 @@ describe('ThemeWatcher', function() { }); it('should choose a light theme if system prefers it (explicit)', () => { - // Given system prefers lightness, even though we did not - // click "Use system theme" or choose a theme explicitly + // Given system prefers lightness global.matchMedia = makeMatchMedia({ "(prefers-color-scheme: light)": true }); SettingsStore.getValueAt = makeGetValueAt({ "use_system_theme": true }); SettingsStore.getValue = makeGetValue({ "use_system_theme": true }); @@ -138,8 +156,7 @@ describe('ThemeWatcher', function() { }); it('should choose a dark theme if system prefers it (explicit)', () => { - // Given system prefers darkness, even though we did not - // click "Use system theme" or choose a theme explicitly + // Given system prefers darkness global.matchMedia = makeMatchMedia({ "(prefers-color-scheme: dark)": true }); SettingsStore.getValueAt = makeGetValueAt({ "use_system_theme": true }); SettingsStore.getValue = makeGetValue({ "use_system_theme": true }); @@ -148,5 +165,34 @@ describe('ThemeWatcher', function() { const themeWatcher = new ThemeWatcher(); expect(themeWatcher.getEffectiveTheme()).toBe("dark"); }); + + it('should choose a high-contrast theme if system prefers it', () => { + // Given system prefers high contrast and light + global.matchMedia = makeMatchMedia({ + "(prefers-contrast: more)": true, + "(prefers-color-scheme: light)": true, + }); + SettingsStore.getValueAt = makeGetValueAt({ "use_system_theme": true }); + SettingsStore.getValue = makeGetValue({ "use_system_theme": true }); + + // Then getEffectiveTheme returns light-high-contrast + const themeWatcher = new ThemeWatcher(); + expect(themeWatcher.getEffectiveTheme()).toBe("light-high-contrast"); + }); + + it('should not choose a high-contrast theme if not available', () => { + // Given system prefers high contrast and dark, but we don't (yet) + // have a high-contrast dark theme + global.matchMedia = makeMatchMedia({ + "(prefers-contrast: more)": true, + "(prefers-color-scheme: dark)": true, + }); + SettingsStore.getValueAt = makeGetValueAt({ "use_system_theme": true }); + SettingsStore.getValue = makeGetValue({ "use_system_theme": true }); + + // Then getEffectiveTheme returns dark + const themeWatcher = new ThemeWatcher(); + expect(themeWatcher.getEffectiveTheme()).toBe("dark"); + }); });