diff --git a/packages/react/cypress-image-diff-screenshots/baseline/IcTheme.cy.tsx-ic-theme-inherit-dark.png b/packages/react/cypress-image-diff-screenshots/baseline/IcTheme.cy.tsx-ic-theme-inherit-dark.png new file mode 100755 index 0000000000..321346fee4 Binary files /dev/null and b/packages/react/cypress-image-diff-screenshots/baseline/IcTheme.cy.tsx-ic-theme-inherit-dark.png differ diff --git a/packages/react/cypress-image-diff-screenshots/baseline/IcTheme.cy.tsx-ic-theme-inherit-light.png b/packages/react/cypress-image-diff-screenshots/baseline/IcTheme.cy.tsx-ic-theme-inherit-light.png new file mode 100755 index 0000000000..6ba5984f34 Binary files /dev/null and b/packages/react/cypress-image-diff-screenshots/baseline/IcTheme.cy.tsx-ic-theme-inherit-light.png differ diff --git a/packages/react/cypress-image-diff-screenshots/baseline/IcTheme.cy.tsx-ic-theme-light-with-components-within-ic-theme.png b/packages/react/cypress-image-diff-screenshots/baseline/IcTheme.cy.tsx-ic-theme-light-with-components-within-ic-theme.png new file mode 100755 index 0000000000..846d35d0a5 Binary files /dev/null and b/packages/react/cypress-image-diff-screenshots/baseline/IcTheme.cy.tsx-ic-theme-light-with-components-within-ic-theme.png differ diff --git a/packages/react/cypress-image-diff-screenshots/baseline/IcTheme.cy.tsx-ic-theme-light-with-dark-mode-component-overrides.png b/packages/react/cypress-image-diff-screenshots/baseline/IcTheme.cy.tsx-ic-theme-light-with-dark-mode-component-overrides.png new file mode 100755 index 0000000000..18018781e0 Binary files /dev/null and b/packages/react/cypress-image-diff-screenshots/baseline/IcTheme.cy.tsx-ic-theme-light-with-dark-mode-component-overrides.png differ diff --git a/packages/react/cypress-image-diff-screenshots/baseline/IcTheme.cy.tsx-ic-theme-system-light.png b/packages/react/cypress-image-diff-screenshots/baseline/IcTheme.cy.tsx-ic-theme-system-light.png new file mode 100755 index 0000000000..18018781e0 Binary files /dev/null and b/packages/react/cypress-image-diff-screenshots/baseline/IcTheme.cy.tsx-ic-theme-system-light.png differ diff --git a/packages/react/cypress-image-diff-screenshots/baseline/IcTheme.cy.tsx-sunrise-brand.png b/packages/react/cypress-image-diff-screenshots/baseline/IcTheme.cy.tsx-sunrise-brand.png new file mode 100755 index 0000000000..76481137ac Binary files /dev/null and b/packages/react/cypress-image-diff-screenshots/baseline/IcTheme.cy.tsx-sunrise-brand.png differ diff --git a/packages/react/src/component-tests/IcTheme/IcTheme.cy.tsx b/packages/react/src/component-tests/IcTheme/IcTheme.cy.tsx new file mode 100644 index 0000000000..ecf5441b10 --- /dev/null +++ b/packages/react/src/component-tests/IcTheme/IcTheme.cy.tsx @@ -0,0 +1,203 @@ +/* eslint-disable react/jsx-no-bind */ +/// + +import { mount } from "cypress/react"; +import React from "react"; +import { + ComponentsWithInheritThemeProp, + SwitchBrand, + ThemeWithComponentThemeProps, + ThemeWithComponentWithinSeparateIcTheme, +} from "./IcThemeTestData"; +import { + HAVE_ATTR, + HAVE_BEEN_CALLED_ONCE, + HAVE_BEEN_CALLED_WITH, +} from "../utils/constants"; +import { setThresholdBasedOnEnv } from "../../../cypress/utils/helpers"; + +const THEME_SELECTOR = "ic-theme"; +const DEFAULT_TEST_THRESHOLD = 0.048; + +describe("IcTheme end-to-end and visual regression tests", () => { + beforeEach(() => { + cy.injectAxe(); + cy.viewport(1440, 900); + }); + + afterEach(() => { + cy.task("generateReport"); + }); + + it("should render in light mode when IcTheme theme is set to light with components with theme prop set to dark rendered in dark mode", () => { + mount( + + ); + + cy.checkHydrated(THEME_SELECTOR); + + cy.checkA11yWithWait(); + cy.compareSnapshot({ + name: "ic-theme-light-with-dark-mode-component-overrides", + testThreshold: setThresholdBasedOnEnv(DEFAULT_TEST_THRESHOLD + 0.031), + }); + }); + + it("should render in light mode when IcTheme theme is set to light with components within another IcTheme component with theme set to dark rendered in dark mode", () => { + mount( + + ); + + cy.checkHydrated(THEME_SELECTOR); + + cy.checkA11yWithWait(); + cy.compareSnapshot({ + name: "ic-theme-light-with-components-within-ic-theme", + testThreshold: setThresholdBasedOnEnv(DEFAULT_TEST_THRESHOLD + 0.03), + }); + }); + + it.skip("should render according to dark mode system settings when IcTheme theme is set to system", () => { + cy.wrap( + Cypress.automation("remote:debugger:protocol", { + command: "Emulation.setEmulatedMedia", + params: { + features: [ + { + name: "prefers-color-scheme", + value: "dark", + }, + ], + }, + }) + ); + + mount( + + ); + + cy.checkHydrated(THEME_SELECTOR); + + cy.checkA11yWithWait(); + cy.compareSnapshot({ + name: "ic-theme-system-dark", + testThreshold: setThresholdBasedOnEnv(DEFAULT_TEST_THRESHOLD + 0.03), + }); + }); + + it("should render according to light mode system settings when IcTheme theme is set to system", () => { + cy.wrap( + Cypress.automation("remote:debugger:protocol", { + command: "Emulation.setEmulatedMedia", + params: { + features: [ + { + name: "prefers-color-scheme", + value: "light", + }, + ], + }, + }) + ); + + mount( + + ); + + cy.checkHydrated(THEME_SELECTOR); + + cy.checkA11yWithWait(); + cy.compareSnapshot({ + name: "ic-theme-system-light", + testThreshold: setThresholdBasedOnEnv(DEFAULT_TEST_THRESHOLD + 0.031), + }); + }); + + it("should render components with IcTheme colour when theme prop is set to inherit - dark theme", () => { + mount( + + ); + + cy.checkHydrated(THEME_SELECTOR); + + cy.checkA11yWithWait(); + cy.compareSnapshot({ + name: "ic-theme-inherit-dark", + testThreshold: setThresholdBasedOnEnv(DEFAULT_TEST_THRESHOLD), + }); + }); + + it("should render components with IcTheme colour when theme prop is set to inherit - light theme", () => { + mount( + + ); + + cy.checkHydrated(THEME_SELECTOR); + + cy.checkA11yWithWait(); + cy.compareSnapshot({ + name: "ic-theme-inherit-light", + testThreshold: setThresholdBasedOnEnv(DEFAULT_TEST_THRESHOLD + 0.004), + }); + }); + + it("should switch brand colour", () => { + mount(); + + cy.checkHydrated(THEME_SELECTOR); + cy.spy(window.console, "log").as("spyWinConsoleLog"); + cy.get(THEME_SELECTOR).invoke( + "on", + "brandChange", + cy.stub().as("brandChange") + ); + + cy.get(THEME_SELECTOR).should( + HAVE_ATTR, + "brand-color", + "rgb(255, 201, 60)" + ); + + cy.compareSnapshot({ + name: "sunrise-brand", + testThreshold: setThresholdBasedOnEnv(DEFAULT_TEST_THRESHOLD + 0.022), + }); + + cy.get("ic-button").contains("Default theme").click(); + cy.get(THEME_SELECTOR).should(HAVE_ATTR, "brand-color", "rgb(27, 60, 121)"); + cy.get("@brandChange").should(HAVE_BEEN_CALLED_ONCE); + cy.get("@spyWinConsoleLog").should(HAVE_BEEN_CALLED_WITH, { + mode: "light", + color: { + r: 27, + g: 60, + b: 121, + a: 1, + }, + }); + }); +}); diff --git a/packages/react/src/component-tests/IcTheme/IcThemeTestData.tsx b/packages/react/src/component-tests/IcTheme/IcThemeTestData.tsx new file mode 100644 index 0000000000..2b3f508897 --- /dev/null +++ b/packages/react/src/component-tests/IcTheme/IcThemeTestData.tsx @@ -0,0 +1,595 @@ +import React, { ReactElement, useState } from "react"; +import { + IcTheme, + IcTopNavigation, + IcSearchBar, + IcNavigationButton, + IcNavigationItem, + IcHero, + IcTextField, + IcButton, + IcLink, + IcSectionContainer, + IcCheckbox, + IcAlert, + IcTypography, + IcCardVertical, + IcFooter, + IcFooterLink, + IcSwitch, +} from "../../components"; +import { SlottedSVG } from "../../react-component-lib/slottedSVG"; + +export const ThemeWithComponentThemeProps = (args: { + color: "rgba(27, 60, 121, 1)"; + theme: "light" | "dark" | "system"; + backgroundColor: "white" | "black"; +}): ReactElement => { + return ( + <> +
+ + + + + + + + alert("test")} + > + + + + + + + + + + + + +
+ + + Filter + +
+ + See all + + + Help + +
+ + + + + + Button + + +

+ This is some text and + this is an inline link IcLink + within the text +

+
+
+ +
+ + + + + + The component theme prop should override the IcTheme theme prop + +
+
+ + + Get Started + + + Accessibility + + + Styles + + + Components + + + Patterns + + + Design toolkit + +
+ Slotted Button +
+
+
+
+ + ); +}; + +export const ThemeWithComponentWithinSeparateIcTheme = (args: { + color: "rgba(27, 60, 121, 1)"; + theme: "light" | "dark" | "system"; + backgroundColor: "white" | "black"; +}): ReactElement => { + return ( + <> +
+ + + + + + + + alert("test")} + > + + + + + + + + + + + + +
+ + + Filter + +
+ + See all + + + Help + +
+ + + + + + Button + + +

+ This is some text and + this is an inline link IcLink + within the text +

+
+
+ +
+ + This content is in an IcTheme component with dark mode set + + + + + +
+
+ + + Get Started + + + Accessibility + + + Styles + + + Components + + + Patterns + + + Design toolkit + +
+ Slotted Button +
+
+
+
+ + ); +}; + +export const ComponentsWithInheritThemeProp = (args: { + color: "rgba(27, 60, 121, 1)"; + theme: "light" | "dark" | "system"; + backgroundColor: "white" | "black"; +}): ReactElement => { + return ( + <> +
+ + + + + + + + alert("test")} + > + + + + + + + + + + + + + + +
+ + + + + + Components will inherit their theme colour based on IcTheme when + theme="inherit" + +
+
+
+
+ + ); +}; + +export const SwitchBrand = () => { + const [color, setColour] = useState("rgb(255, 201, 60)"); + const defaultButtonClickHandler = () => { + setColour("rgb(27, 60, 121)"); + }; + const differentButtonClickHandler = () => { + setColour("rgb(255, 201, 60)"); + }; + const handleBrandChange = (e: CustomEvent) => { + console.log(e.detail); + }; + return ( + <> + + + Default theme + + + Sunset theme + +
+ + + + + + + + + + + + + + + + + + + +
+ + + Filter + +
+ + See all + + + Help + +
+ + + Get Started + + + Accessibility + + + Styles + + + Components + + + Patterns + + + Design toolkit + +
+ Slotted Button + + + + + + +
+
+
+ + ); +}; diff --git a/packages/react/src/stories/ic-theme.stories.mdx b/packages/react/src/stories/ic-theme.stories.mdx index dbdf539117..4a0274010e 100644 --- a/packages/react/src/stories/ic-theme.stories.mdx +++ b/packages/react/src/stories/ic-theme.stories.mdx @@ -105,11 +105,11 @@ export const Controlled = () => { full-width >
- + > Filter @@ -117,13 +117,13 @@ export const Controlled = () => { See all - Help - + {

This is some text and - this is an inline link ic-link + this is an inline link ic-link within the text

{ style={{ display: "flex", alignItems: "center", - gap: "var(--ic-space-sm);", + gap: "var(--ic-space-sm)", }} > Slotted Button @@ -269,11 +269,11 @@ export const defaultArgs = { full-width >
- + > Filter @@ -281,13 +281,13 @@ export const defaultArgs = { See all - Help - +

This is some text and - this is an inline link ic-link + this is an inline link ic-link within the text

@@ -361,7 +361,7 @@ export const defaultArgs = { style={{ display: "flex", alignItems: "center", - gap: "var(--ic-space-sm);", + gap: "var(--ic-space-sm)", }} > Slotted Button