mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
Compare commits
5 Commits
ionic-modu
...
sp/playwri
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ecd03a2dba | ||
|
|
bf18d51256 | ||
|
|
fefaa8b57c | ||
|
|
dc696695ce | ||
|
|
242dee551e |
@@ -4,68 +4,68 @@
|
||||
*/
|
||||
|
||||
: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-primary: #4d8dff;
|
||||
--ion-color-primary-rgb: 77, 141, 255;
|
||||
--ion-color-primary-contrast: #000000;
|
||||
--ion-color-primary-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-primary-shade: #447ce0;
|
||||
--ion-color-primary-tint: #5f98ff;
|
||||
|
||||
--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-secondary: #62bdff;
|
||||
--ion-color-secondary-rgb: 98, 189, 255;
|
||||
--ion-color-secondary-contrast: #000000;
|
||||
--ion-color-secondary-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-secondary-shade: #56a6e0;
|
||||
--ion-color-secondary-tint: #72c4ff;
|
||||
|
||||
--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-tertiary: #8482fb;
|
||||
--ion-color-tertiary-rgb: 132, 130, 251;
|
||||
--ion-color-tertiary-contrast: #000000;
|
||||
--ion-color-tertiary-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-tertiary-shade: #7472dd;
|
||||
--ion-color-tertiary-tint: #908ffb;
|
||||
|
||||
--ion-color-success: #2fdf75;
|
||||
--ion-color-success-rgb: 47, 223, 117;
|
||||
--ion-color-success: #2dd55b;
|
||||
--ion-color-success-rgb: 45, 213, 91;
|
||||
--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-success-shade: #28bb50;
|
||||
--ion-color-success-tint: #42d96b;
|
||||
|
||||
--ion-color-warning: #ffd534;
|
||||
--ion-color-warning-rgb: 255, 213, 52;
|
||||
--ion-color-warning: #ffce31;
|
||||
--ion-color-warning-rgb: 255, 206, 49;
|
||||
--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-warning-shade: #e0b52b;
|
||||
--ion-color-warning-tint: #ffd346;
|
||||
|
||||
--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-danger: #f56570;
|
||||
--ion-color-danger-rgb: 245, 101, 112;
|
||||
--ion-color-danger-contrast: #000000;
|
||||
--ion-color-danger-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-danger-shade: #d85963;
|
||||
--ion-color-danger-tint: #f6747e;
|
||||
|
||||
--ion-color-dark: #f4f5f8;
|
||||
--ion-color-dark-rgb: 244, 245, 248;
|
||||
--ion-color-dark: #f3f3f3;
|
||||
--ion-color-dark-rgb: 243, 243, 243;
|
||||
--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-dark-shade: #d6d6d6;
|
||||
--ion-color-dark-tint: #f4f4f4;
|
||||
|
||||
--ion-color-medium: #989aa2;
|
||||
--ion-color-medium-rgb: 152, 154, 162;
|
||||
--ion-color-medium: #959595;
|
||||
--ion-color-medium-rgb: 149, 149, 149;
|
||||
--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-medium-shade: #838383;
|
||||
--ion-color-medium-tint: #a0a0a0;
|
||||
|
||||
--ion-color-light: #222428;
|
||||
--ion-color-light-rgb: 34, 36, 40;
|
||||
--ion-color-light: #2f2f2f;
|
||||
--ion-color-light-rgb: 47, 47, 47;
|
||||
--ion-color-light-contrast: #ffffff;
|
||||
--ion-color-light-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-light-shade: #1e2023;
|
||||
--ion-color-light-tint: #383a3e;
|
||||
--ion-color-light-shade: #292929;
|
||||
--ion-color-light-tint: #444444;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
89
core/src/test/theme/dark/index.html
Normal file
89
core/src/test/theme/dark/index.html
Normal file
@@ -0,0 +1,89 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Theme - Dark</title>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||
/>
|
||||
<link href="../../../../css/ionic.bundle.css" rel="stylesheet" />
|
||||
<link href="../../../../scripts/testing/styles.css" rel="stylesheet" />
|
||||
<link href="../../../../scripts/testing/themes/dark.css" rel="stylesheet" />
|
||||
<script src="../../../../scripts/testing/scripts.js"></script>
|
||||
<script nomodule src="../../../../dist/ionic/ionic.js"></script>
|
||||
<script type="module" src="../../../../dist/ionic/ionic.esm.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ion-app>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Theme - Dark</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-padding ion-text-center" id="content" no-bounce>
|
||||
<p>
|
||||
<ion-button id="default">Default</ion-button>
|
||||
<ion-button class="ion-focused">Default.focused</ion-button>
|
||||
<ion-button class="ion-activated">Default.activated</ion-button>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<ion-button color="primary">Primary</ion-button>
|
||||
<ion-button class="ion-focused" color="primary">Primary.focused</ion-button>
|
||||
<ion-button class="ion-activated" color="primary">Primary.activated</ion-button>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<ion-button color="secondary">Secondary</ion-button>
|
||||
<ion-button class="ion-focused" color="secondary">Secondary.focused</ion-button>
|
||||
<ion-button class="ion-activated" color="secondary">Secondary.activated</ion-button>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<ion-button color="tertiary">Tertiary</ion-button>
|
||||
<ion-button class="ion-focused" color="tertiary">Tertiary.focused</ion-button>
|
||||
<ion-button class="ion-activated" color="tertiary">Tertiary.activated</ion-button>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<ion-button color="success">Success</ion-button>
|
||||
<ion-button class="ion-focused" color="success">Success.focused</ion-button>
|
||||
<ion-button class="ion-activated" color="success">Success.activated</ion-button>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<ion-button color="warning">Warning</ion-button>
|
||||
<ion-button class="ion-focused" color="warning">Warning.focused</ion-button>
|
||||
<ion-button class="ion-activated" color="warning">Warning.activated</ion-button>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<ion-button color="danger">Danger</ion-button>
|
||||
<ion-button class="ion-focused" color="danger">Danger.focused</ion-button>
|
||||
<ion-button class="ion-activated" color="danger">Danger.activated</ion-button>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<ion-button color="light">Light</ion-button>
|
||||
<ion-button class="ion-focused" color="light">Light.focused</ion-button>
|
||||
<ion-button class="ion-activated" color="light">Light.activated</ion-button>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<ion-button color="medium">Medium</ion-button>
|
||||
<ion-button class="ion-focused" color="medium">Medium.focused</ion-button>
|
||||
<ion-button class="ion-activated" color="medium">Medium.activated</ion-button>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<ion-button color="dark">Dark</ion-button>
|
||||
<ion-button class="ion-focused" color="dark">Dark.focused</ion-button>
|
||||
<ion-button class="ion-activated" color="dark">Dark.activated</ion-button>
|
||||
</p>
|
||||
</ion-content>
|
||||
</ion-app>
|
||||
</body>
|
||||
</html>
|
||||
214
core/src/test/theme/theme.e2e.ts
Normal file
214
core/src/test/theme/theme.e2e.ts
Normal file
@@ -0,0 +1,214 @@
|
||||
import AxeBuilder from '@axe-core/playwright';
|
||||
import { expect } from '@playwright/test';
|
||||
import { configs, test } from '@utils/test/playwright';
|
||||
|
||||
const styleTestHelpers = `
|
||||
<style>
|
||||
.ion-background {
|
||||
background: var(--ion-color-base);
|
||||
}
|
||||
.ion-background-opacity-08 {
|
||||
background: rgba(var(--ion-color-base-rgb), 0.08);
|
||||
}
|
||||
.ion-background-opacity-12 {
|
||||
background: rgba(var(--ion-color-base-rgb), 0.12);
|
||||
}
|
||||
.ion-background-opacity-16 {
|
||||
background: rgba(var(--ion-color-base-rgb), 0.16);
|
||||
}
|
||||
.ion-color {
|
||||
color: var(--ion-color-base);
|
||||
}
|
||||
.ion-color-contrast {
|
||||
color: var(--ion-color-contrast);
|
||||
}
|
||||
.ion-color-shade {
|
||||
color: var(--ion-color-shade);
|
||||
}
|
||||
.ion-color-tint {
|
||||
color: var(--ion-color-tint);
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
|
||||
/**
|
||||
* All colors besides `light` should be tested against a dark background on dark theme.
|
||||
*/
|
||||
configs({ modes: ['md', 'ios'], directions: ['ltr'], themes: ['dark'] }).forEach(({ config, title }) => {
|
||||
const colors = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'medium', 'dark'];
|
||||
|
||||
test.describe(title('theme'), () => {
|
||||
test.beforeEach(({ skip }) => {
|
||||
skip.browser('firefox', 'Color contrast ratio is consistent across browsers');
|
||||
skip.browser('webkit', 'Color contrast ratio is consistent across browsers');
|
||||
});
|
||||
|
||||
for (const color of colors) {
|
||||
test(`color "${color}" should pass AA guidelines`, async ({ page }) => {
|
||||
await page.setContent(
|
||||
`${styleTestHelpers}
|
||||
<main>
|
||||
<p class="ion-color ion-color-${color}">Hello World</p>
|
||||
</main>`,
|
||||
config
|
||||
);
|
||||
|
||||
const results = await new AxeBuilder({ page }).analyze();
|
||||
expect(results.violations).toEqual([]);
|
||||
});
|
||||
|
||||
test(`contrast color on "${color}" background should pass AA guidelines`, async ({ page }) => {
|
||||
await page.setContent(
|
||||
`${styleTestHelpers}
|
||||
<main>
|
||||
<p class="ion-color-contrast ion-background ion-color-${color}">Hello World</p>
|
||||
</main>`,
|
||||
config
|
||||
);
|
||||
|
||||
const results = await new AxeBuilder({ page }).analyze();
|
||||
expect(results.violations).toEqual([]);
|
||||
});
|
||||
|
||||
test(`color "${color}" on 0.08 opacity background should pass AA guidelines`, async ({ page }) => {
|
||||
await page.setContent(
|
||||
`${styleTestHelpers}
|
||||
<main>
|
||||
<p class="ion-color ion-color-${color} ion-background-opacity-08">Hello World</p>
|
||||
</main>`,
|
||||
config
|
||||
);
|
||||
|
||||
const results = await new AxeBuilder({ page }).analyze();
|
||||
expect(results.violations).toEqual([]);
|
||||
});
|
||||
|
||||
test(`color "${color}" on 0.12 opacity background should pass AA guidelines`, async ({ page }) => {
|
||||
await page.setContent(
|
||||
`${styleTestHelpers}
|
||||
<main>
|
||||
<p class="ion-color ion-color-${color} ion-background-opacity-12">Hello World</p>
|
||||
</main>`,
|
||||
config
|
||||
);
|
||||
|
||||
const results = await new AxeBuilder({ page }).analyze();
|
||||
expect(results.violations).toEqual([]);
|
||||
});
|
||||
|
||||
test(`color "${color}" on 0.16 opacity background should pass AA guidelines`, async ({ page }) => {
|
||||
await page.setContent(
|
||||
`${styleTestHelpers}
|
||||
<main>
|
||||
<p class="ion-color ion-color-${color} ion-background-opacity-16">Hello World</p>
|
||||
</main>`,
|
||||
config
|
||||
);
|
||||
|
||||
const results = await new AxeBuilder({ page }).analyze();
|
||||
expect(results.violations).toEqual([]);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* `light` color should be tested against a white background on dark theme. The mode doesn't matter here
|
||||
* since we are testing against a consistent background color.
|
||||
*/
|
||||
configs({ modes: ['md'], directions: ['ltr'], themes: ['dark'] }).forEach(({ config, title }) => {
|
||||
test.describe(title('theme'), () => {
|
||||
test(`color light should pass AA guidelines on a white background`, async ({ page, skip }) => {
|
||||
skip.browser('firefox', 'Color contrast ratio is consistent across browsers');
|
||||
skip.browser('webkit', 'Color contrast ratio is consistent across browsers');
|
||||
|
||||
await page.setContent(
|
||||
`${styleTestHelpers}
|
||||
<style>
|
||||
.md body {
|
||||
--ion-background-color: #ffffff;
|
||||
}
|
||||
</style>
|
||||
<main>
|
||||
<p class="ion-color ion-color-light">Hello World</p>
|
||||
</main>`,
|
||||
config
|
||||
);
|
||||
|
||||
const results = await new AxeBuilder({ page }).analyze();
|
||||
expect(results.violations).toEqual([]);
|
||||
});
|
||||
|
||||
test(`contrast color on "light" background should pass AA guidelines`, async ({ page }) => {
|
||||
await page.setContent(
|
||||
`${styleTestHelpers}
|
||||
<style>
|
||||
.md body {
|
||||
--ion-background-color: #ffffff;
|
||||
}
|
||||
</style>
|
||||
<main>
|
||||
<p class="ion-color-contrast ion-background ion-color-light">Hello World</p>
|
||||
</main>`,
|
||||
config
|
||||
);
|
||||
|
||||
const results = await new AxeBuilder({ page }).analyze();
|
||||
expect(results.violations).toEqual([]);
|
||||
});
|
||||
|
||||
test(`color "light" on 0.08 opacity background should pass AA guidelines`, async ({ page }) => {
|
||||
await page.setContent(
|
||||
`${styleTestHelpers}
|
||||
<style>
|
||||
.md body {
|
||||
--ion-background-color: #ffffff;
|
||||
}
|
||||
</style>
|
||||
<main>
|
||||
<p class="ion-color ion-color-light ion-background-opacity-08">Hello World</p>
|
||||
</main>`,
|
||||
config
|
||||
);
|
||||
|
||||
const results = await new AxeBuilder({ page }).analyze();
|
||||
expect(results.violations).toEqual([]);
|
||||
});
|
||||
|
||||
test(`color "light" on 0.12 opacity background should pass AA guidelines`, async ({ page }) => {
|
||||
await page.setContent(
|
||||
`${styleTestHelpers}
|
||||
<style>
|
||||
.md body {
|
||||
--ion-background-color: #ffffff;
|
||||
}
|
||||
</style>
|
||||
<main>
|
||||
<p class="ion-color ion-color-light ion-background-opacity-12">Hello World</p>
|
||||
</main>`,
|
||||
config
|
||||
);
|
||||
|
||||
const results = await new AxeBuilder({ page }).analyze();
|
||||
expect(results.violations).toEqual([]);
|
||||
});
|
||||
|
||||
test(`color "light" on 0.16 opacity background should pass AA guidelines`, async ({ page }) => {
|
||||
await page.setContent(
|
||||
`${styleTestHelpers}
|
||||
<style>
|
||||
.md body {
|
||||
--ion-background-color: #ffffff;
|
||||
}
|
||||
</style>
|
||||
<main>
|
||||
<p class="ion-color ion-color-light ion-background-opacity-16">Hello World</p>
|
||||
</main>`,
|
||||
config
|
||||
);
|
||||
|
||||
const results = await new AxeBuilder({ page }).analyze();
|
||||
expect(results.violations).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -111,4 +111,5 @@ const DEFAULT_THEMES: Theme[] = ['light'];
|
||||
const DEFAULT_TEST_CONFIG_OPTION = {
|
||||
modes: DEFAULT_MODES,
|
||||
directions: DEFAULT_DIRECTIONS,
|
||||
themes: DEFAULT_THEMES,
|
||||
};
|
||||
|
||||
@@ -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';
|
||||
|
||||
/**
|
||||
* This is an extended version of Playwright's
|
||||
@@ -28,13 +28,22 @@ configs().forEach(({ config, title }) => {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (theme !== 'light' && options?.inline === undefined) {
|
||||
throw new Error(
|
||||
'The "themes" config option is only supported when using "page.setContent". Remove the theme from the config and manually set the theme in the test template.'
|
||||
);
|
||||
}
|
||||
|
||||
const rtlString = direction === 'rtl' ? 'true' : undefined;
|
||||
|
||||
@@ -82,6 +82,6 @@ export const setContent = async (page: Page, html: string, testInfo: TestInfo, o
|
||||
}
|
||||
});
|
||||
|
||||
await page.goto(`${baseUrl}#`, options);
|
||||
await page.goto(`${baseUrl}#`, { ...options, inline: true } as E2EPageOptions);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4,7 +4,13 @@ import type { TestConfig } from './generator';
|
||||
import type { EventSpy } from './page/event-spy';
|
||||
import type { LocatorOptions, E2ELocator } from './page/utils/locator';
|
||||
|
||||
export interface E2EPageOptions extends PageOptions, TestConfig {}
|
||||
export interface E2EPageOptions extends PageOptions, TestConfig {
|
||||
/**
|
||||
* Indicates if the page content is set inline with `.setContent`. This setting can
|
||||
* only be true or not set.
|
||||
*/
|
||||
inline?: true;
|
||||
}
|
||||
|
||||
interface PageOptions {
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user