diff --git a/core/scripts/testing/themes/dark.css b/core/scripts/testing/themes/dark.css
new file mode 100644
index 0000000000..e263803d56
--- /dev/null
+++ b/core/scripts/testing/themes/dark.css
@@ -0,0 +1,151 @@
+/*
+ * Dark Colors
+ * -------------------------------------------
+ */
+
+:root {
+ --ion-color-primary: #428cff;
+ --ion-color-primary-rgb: 66, 140, 255;
+ --ion-color-primary-contrast: #ffffff;
+ --ion-color-primary-contrast-rgb: 255, 255, 255;
+ --ion-color-primary-shade: #3a7be0;
+ --ion-color-primary-tint: #5598ff;
+
+ --ion-color-secondary: #50c8ff;
+ --ion-color-secondary-rgb: 80, 200, 255;
+ --ion-color-secondary-contrast: #ffffff;
+ --ion-color-secondary-contrast-rgb: 255, 255, 255;
+ --ion-color-secondary-shade: #46b0e0;
+ --ion-color-secondary-tint: #62ceff;
+
+ --ion-color-tertiary: #6a64ff;
+ --ion-color-tertiary-rgb: 106, 100, 255;
+ --ion-color-tertiary-contrast: #ffffff;
+ --ion-color-tertiary-contrast-rgb: 255, 255, 255;
+ --ion-color-tertiary-shade: #5d58e0;
+ --ion-color-tertiary-tint: #7974ff;
+
+ --ion-color-success: #2fdf75;
+ --ion-color-success-rgb: 47, 223, 117;
+ --ion-color-success-contrast: #000000;
+ --ion-color-success-contrast-rgb: 0, 0, 0;
+ --ion-color-success-shade: #29c467;
+ --ion-color-success-tint: #44e283;
+
+ --ion-color-warning: #ffd534;
+ --ion-color-warning-rgb: 255, 213, 52;
+ --ion-color-warning-contrast: #000000;
+ --ion-color-warning-contrast-rgb: 0, 0, 0;
+ --ion-color-warning-shade: #e0bb2e;
+ --ion-color-warning-tint: #ffd948;
+
+ --ion-color-danger: #ff4961;
+ --ion-color-danger-rgb: 255, 73, 97;
+ --ion-color-danger-contrast: #ffffff;
+ --ion-color-danger-contrast-rgb: 255, 255, 255;
+ --ion-color-danger-shade: #e04055;
+ --ion-color-danger-tint: #ff5b71;
+
+ --ion-color-dark: #f4f5f8;
+ --ion-color-dark-rgb: 244, 245, 248;
+ --ion-color-dark-contrast: #000000;
+ --ion-color-dark-contrast-rgb: 0, 0, 0;
+ --ion-color-dark-shade: #d7d8da;
+ --ion-color-dark-tint: #f5f6f9;
+
+ --ion-color-medium: #989aa2;
+ --ion-color-medium-rgb: 152, 154, 162;
+ --ion-color-medium-contrast: #000000;
+ --ion-color-medium-contrast-rgb: 0, 0, 0;
+ --ion-color-medium-shade: #86888f;
+ --ion-color-medium-tint: #a2a4ab;
+
+ --ion-color-light: #222428;
+ --ion-color-light-rgb: 34, 36, 40;
+ --ion-color-light-contrast: #ffffff;
+ --ion-color-light-contrast-rgb: 255, 255, 255;
+ --ion-color-light-shade: #1e2023;
+ --ion-color-light-tint: #383a3e;
+}
+
+/*
+ * iOS Dark Theme
+ * -------------------------------------------
+ */
+
+.ios body {
+ --ion-background-color: #000000;
+ --ion-background-color-rgb: 0, 0, 0;
+
+ --ion-text-color: #ffffff;
+ --ion-text-color-rgb: 255, 255, 255;
+
+ --ion-color-step-50: #0d0d0d;
+ --ion-color-step-100: #1a1a1a;
+ --ion-color-step-150: #262626;
+ --ion-color-step-200: #333333;
+ --ion-color-step-250: #404040;
+ --ion-color-step-300: #4d4d4d;
+ --ion-color-step-350: #595959;
+ --ion-color-step-400: #666666;
+ --ion-color-step-450: #737373;
+ --ion-color-step-500: #808080;
+ --ion-color-step-550: #8c8c8c;
+ --ion-color-step-600: #999999;
+ --ion-color-step-650: #a6a6a6;
+ --ion-color-step-700: #b3b3b3;
+ --ion-color-step-750: #bfbfbf;
+ --ion-color-step-800: #cccccc;
+ --ion-color-step-850: #d9d9d9;
+ --ion-color-step-900: #e6e6e6;
+ --ion-color-step-950: #f2f2f2;
+
+ --ion-toolbar-background: #0d0d0d;
+
+ --ion-item-background: #000000;
+
+ --ion-card-background: #1c1c1d;
+}
+
+/*
+ * Material Design Dark Theme
+ * -------------------------------------------
+ */
+
+.md body {
+ --ion-background-color: #121212;
+ --ion-background-color-rgb: 18, 18, 18;
+
+ --ion-text-color: #ffffff;
+ --ion-text-color-rgb: 255, 255, 255;
+
+ --ion-border-color: #222222;
+
+ --ion-color-step-50: #1e1e1e;
+ --ion-color-step-100: #2a2a2a;
+ --ion-color-step-150: #363636;
+ --ion-color-step-200: #414141;
+ --ion-color-step-250: #4d4d4d;
+ --ion-color-step-300: #595959;
+ --ion-color-step-350: #656565;
+ --ion-color-step-400: #717171;
+ --ion-color-step-450: #7d7d7d;
+ --ion-color-step-500: #898989;
+ --ion-color-step-550: #949494;
+ --ion-color-step-600: #a0a0a0;
+ --ion-color-step-650: #acacac;
+ --ion-color-step-700: #b8b8b8;
+ --ion-color-step-750: #c4c4c4;
+ --ion-color-step-800: #d0d0d0;
+ --ion-color-step-850: #dbdbdb;
+ --ion-color-step-900: #e7e7e7;
+ --ion-color-step-950: #f3f3f3;
+
+ --ion-item-background: #1e1e1e;
+
+ --ion-toolbar-background: #1f1f1f;
+
+ --ion-tab-bar-background: #1f1f1f;
+
+ --ion-card-background: #1e1e1e;
+}
diff --git a/core/src/utils/test/playwright/generator.ts b/core/src/utils/test/playwright/generator.ts
index e2cdd940f9..41b2abc183 100644
--- a/core/src/utils/test/playwright/generator.ts
+++ b/core/src/utils/test/playwright/generator.ts
@@ -1,5 +1,12 @@
export type Mode = 'ios' | 'md';
export type Direction = 'ltr' | 'rtl';
+/**
+ * The theme to use for the playwright test.
+ *
+ * - `light`: The fallback theme values. Theme stylesheet will not be included.
+ * - `dark`: The dark theme values.
+ */
+export type Theme = 'light' | 'dark';
export type TitleFn = (title: string) => string;
export type ScreenshotFn = (fileName: string) => string;
@@ -7,6 +14,7 @@ export type ScreenshotFn = (fileName: string) => string;
export interface TestConfig {
mode: Mode;
direction: Direction;
+ theme: Theme;
}
interface TestUtilities {
@@ -18,6 +26,7 @@ interface TestUtilities {
interface TestConfigOption {
modes?: Mode[];
directions?: Direction[];
+ themes?: Theme[];
}
/**
@@ -27,9 +36,19 @@ interface TestConfigOption {
* each test title is unique.
*/
const generateTitle = (title: string, config: TestConfig): string => {
- const { mode, direction } = config;
+ const { mode, direction, theme } = config;
- return `${title} - ${mode}/${direction}`;
+ if (theme === 'light') {
+ /**
+ * Ionic has many existing tests that existed prior to
+ * the introduction of theme testing. To maintain backwards
+ * compatibility, we will not include the theme in the test
+ * title if the theme is set to light.
+ */
+ return `${title} - ${mode}/${direction}`;
+ }
+
+ return `${title} - ${mode}/${direction}/${theme}`;
};
/**
@@ -37,9 +56,19 @@ const generateTitle = (title: string, config: TestConfig): string => {
* and a test config.
*/
const generateScreenshotName = (fileName: string, config: TestConfig): string => {
- const { mode, direction } = config;
+ const { mode, direction, theme } = config;
- return `${fileName}-${mode}-${direction}.png`;
+ if (theme === 'light') {
+ /**
+ * Ionic has many existing tests that existed prior to
+ * the introduction of theme testing. To maintain backwards
+ * compatibility, we will not include the theme in the screenshot
+ * name if the theme is set to light.
+ */
+ return `${fileName}-${mode}-${direction}.png`;
+ }
+
+ return `${fileName}-${mode}-${direction}-${theme}.png`;
};
/**
@@ -54,12 +83,15 @@ export const configs = (testConfig: TestConfigOption = DEFAULT_TEST_CONFIG_OPTIO
* If certain options are not provided,
* fall back to the defaults.
*/
- const processedMode: Mode[] = modes ?? DEFAULT_MODES;
- const processedDirection: Direction[] = directions ?? DEFAULT_DIRECTIONS;
+ const processedMode = modes ?? DEFAULT_MODES;
+ const processedDirection = directions ?? DEFAULT_DIRECTIONS;
+ const processedTheme = testConfig.themes ?? DEFAULT_THEMES;
- processedMode.forEach((mode: Mode) => {
- processedDirection.forEach((direction: Direction) => {
- configs.push({ mode, direction });
+ processedMode.forEach((mode) => {
+ processedDirection.forEach((direction) => {
+ processedTheme.forEach((theme) => {
+ configs.push({ mode, direction, theme });
+ });
});
});
@@ -74,6 +106,7 @@ export const configs = (testConfig: TestConfigOption = DEFAULT_TEST_CONFIG_OPTIO
const DEFAULT_MODES: Mode[] = ['ios', 'md'];
const DEFAULT_DIRECTIONS: Direction[] = ['ltr', 'rtl'];
+const DEFAULT_THEMES: Theme[] = ['light'];
const DEFAULT_TEST_CONFIG_OPTION = {
modes: DEFAULT_MODES,
diff --git a/core/src/utils/test/playwright/page/utils/set-content.ts b/core/src/utils/test/playwright/page/utils/set-content.ts
index 16fd1cc3b3..1f0e6b2a4a 100644
--- a/core/src/utils/test/playwright/page/utils/set-content.ts
+++ b/core/src/utils/test/playwright/page/utils/set-content.ts
@@ -1,5 +1,5 @@
import type { Page, TestInfo } from '@playwright/test';
-import type { E2EPageOptions, Mode, Direction } from '@utils/test/playwright';
+import type { E2EPageOptions, Mode, Direction, Theme } from '@utils/test/playwright';
/**
* Overwrites the default Playwright page.setContent method.
@@ -19,13 +19,16 @@ export const setContent = async (page: Page, html: string, testInfo: TestInfo, o
let mode: Mode;
let direction: Direction;
+ let theme: Theme;
if (options == undefined) {
mode = testInfo.project.metadata.mode;
direction = testInfo.project.metadata.rtl ? 'rtl' : 'ltr';
+ theme = testInfo.project.metadata.theme;
} else {
mode = options.mode;
direction = options.direction;
+ theme = options.theme;
}
const baseUrl = process.env.PLAYWRIGHT_TEST_BASE_URL;
@@ -39,6 +42,7 @@ export const setContent = async (page: Page, html: string, testInfo: TestInfo, o
+ ${theme !== 'light' ? `` : ''}