From b848cd2349a478f2d27899fbfea04c5ae7ae67ed Mon Sep 17 00:00:00 2001 From: JC Franco Date: Tue, 4 Jun 2024 13:32:09 -0700 Subject: [PATCH] test: update themed to handle pseudoelements and special underline styling case (#9450) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Related Issue:** #7180 ## Summary ✨🧪✨ ### Examples ```tsx "--calcite-menu-item-action-border-color": { shadowSelector: `calcite-action::after`, targetProp: "backgroundColor", }, ``` ```tsx const tokens: ComponentTestTokens = { "--calcite-link-underline-color-start": { shadowSelector: `a`, // should probably be .anchor or similar class targetProp: "backgroundImage", }, }; themed(html` with an icon`, tokens ); }); ``` --- .../src/components/action/action.e2e.ts | 4 +- .../src/components/action/action.scss | 3 +- .../src/tests/commonTests/themed.ts | 120 +++++++++++------- 3 files changed, 75 insertions(+), 52 deletions(-) diff --git a/packages/calcite-components/src/components/action/action.e2e.ts b/packages/calcite-components/src/components/action/action.e2e.ts index 2d13a611dc3..787fc4e6e52 100755 --- a/packages/calcite-components/src/components/action/action.e2e.ts +++ b/packages/calcite-components/src/components/action/action.e2e.ts @@ -226,8 +226,8 @@ describe("calcite-action", () => { targetProp: "--calcite-icon-color", }, "--calcite-action-indicator-color": { - shadowSelector: `.${CSS.actionIndicator}`, - targetProp: "color", + shadowSelector: `.${CSS.actionIndicator}::after`, + targetProp: "background-color", }, } as const; themed( diff --git a/packages/calcite-components/src/components/action/action.scss b/packages/calcite-components/src/components/action/action.scss index 18d0f87c3c7..eb8a82441a1 100755 --- a/packages/calcite-components/src/components/action/action.scss +++ b/packages/calcite-components/src/components/action/action.scss @@ -83,7 +83,6 @@ .action-indicator { position: relative; - color: var(--calcite-action-indicator-color, var(--calcite-color-brand)); block-size: var(--calcite-internal-action-line-height); inline-size: var(--calcite-internal-action-line-height); @@ -95,7 +94,7 @@ @apply rounded-full; inset-block-end: -0.275rem; inset-inline-end: -0.275rem; - background-color: currentColor; + background-color: var(--calcite-action-indicator-color, var(--calcite-color-brand)); } } diff --git a/packages/calcite-components/src/tests/commonTests/themed.ts b/packages/calcite-components/src/tests/commonTests/themed.ts index bb8c61e1a9f..dd72ec0c4bd 100644 --- a/packages/calcite-components/src/tests/commonTests/themed.ts +++ b/packages/calcite-components/src/tests/commonTests/themed.ts @@ -7,6 +7,14 @@ import { getTagAndPage } from "./utils"; expect.extend(toHaveNoViolations); +interface TargetInfo { + el: E2EElement; + selector: string; + shadowSelector: string; +} + +const pseudoElementPattern = /:{1,2}(before|after)/; + /** * This object that represents component tokens and their respective test options. */ @@ -17,43 +25,48 @@ export type ComponentTestTokens = Record { - // const tokens: ComponentTestTokens = { - // "--calcite-action-menu-border-color": [ - // { - // targetProp: "borderLeftColor", - // }, - // { - // shadowSelector: "calcite-action", - // targetProp: "--calcite-action-border-color", - // }, - // ], - // "--calcite-action-menu-background-color": { - // targetProp: "backgroundColor", - // shadowSelector: ".container", - // }, - // "--calcite-action-menu-trigger-background-color-active": { - // shadowSelector: "calcite-action", - // targetProp: "--calcite-action-background-color", - // state: { press: { attribute: "class", value: CSS.defaultTrigger } }, - // }, - // "--calcite-action-menu-trigger-background-color-focus": { - // shadowSelector: "calcite-action", - // targetProp: "--calcite-action-background-color", - // state: "focus", - // }, - // "--calcite-action-menu-trigger-background-color-hover": { - // shadowSelector: "calcite-action", - // targetProp: "--calcite-action-background-color", - // state: "hover", - // }, - // "--calcite-action-menu-trigger-background-color": { - // shadowSelector: "calcite-action", - // targetProp: "--calcite-action-background-color", - // }, - // }; - // themed(`calcite-action-bar`, tokens); - // }); + * describe("theme", () => { + * const tokens: ComponentTestTokens = { + * "--calcite-action-menu-border-color": [ + * { + * targetProp: "borderLeftColor", + * }, + * { + * shadowSelector: "calcite-action", + * targetProp: "--calcite-action-border-color", + * }, + * { + * // added to demonstrate pseudo-element support + * shadowSelector: "calcite-action::after", + * targetProp: "borderColor", + * }, + * ], + * "--calcite-action-menu-background-color": { + * targetProp: "backgroundColor", + * shadowSelector: ".container", + * }, + * "--calcite-action-menu-trigger-background-color-active": { + * shadowSelector: "calcite-action", + * targetProp: "--calcite-action-background-color", + * state: { press: { attribute: "class", value: CSS.defaultTrigger } }, + * }, + * "--calcite-action-menu-trigger-background-color-focus": { + * shadowSelector: "calcite-action", + * targetProp: "--calcite-action-background-color", + * state: "focus", + * }, + * "--calcite-action-menu-trigger-background-color-hover": { + * shadowSelector: "calcite-action", + * targetProp: "--calcite-action-background-color", + * state: "hover", + * }, + * "--calcite-action-menu-trigger-background-color": { + * shadowSelector: "calcite-action", + * targetProp: "--calcite-action-background-color", + * }, + * }; + * themed(`calcite-action-bar`, tokens); + * }); * * @param componentTestSetup - A component tag, html, tag + e2e page or provider for setting up a test. * @param tokens - A record of token names and their associated selectors, shadow selectors, target props, and states. @@ -100,7 +113,7 @@ export function themed(componentTestSetup: ComponentTestSetup, tokens: Component const el = await page.find(selector); const tokenStyle = `${token}: ${setTokens[token]}`; - let target = el; + const target: TargetInfo = { el, selector, shadowSelector }; let contextSelector: ContextSelectByAttr; let stateName: State; @@ -115,13 +128,14 @@ export function themed(componentTestSetup: ComponentTestSetup, tokens: Component styleTargets[selector][1].push(tokenStyle); } if (shadowSelector) { - target = shadowSelector ? await page.find(`${selector} >>> ${shadowSelector}`) : target; + const effectiveShadowSelector = shadowSelector.replace(pseudoElementPattern, ""); + target.el = await page.find(`${selector} >>> ${effectiveShadowSelector}`); } if (state && typeof state !== "string") { contextSelector = Object.values(state)[0] as ContextSelectByAttr; } - if (!target) { + if (!target.el) { throw new Error( `[${token}] target (${selector}${ shadowSelector ? " >>> " + shadowSelector : "" @@ -168,9 +182,9 @@ type State = "press" | "hover" | "focus"; */ export type TestTarget = { /** - * The element to get the computed style from. + * An object with target element and selector info. */ - target: E2EElement; + target: TargetInfo; /** * @todo doc @@ -242,15 +256,21 @@ export type TestSelectToken = { * * @param element * @param property + * @param pseudoElement */ -async function getComputedStylePropertyValue(element: E2EElement, property: string): Promise { +async function getComputedStylePropertyValue( + element: E2EElement, + property: string, + pseudoElement?: string, +): Promise { type E2EElementInternal = E2EElement & { _elmHandle: ElementHandle; }; return await (element as E2EElementInternal)._elmHandle.evaluate( - (el, targetProp): string => window.getComputedStyle(el).getPropertyValue(targetProp), + (el, targetProp, pseudoElement): string => window.getComputedStyle(el, pseudoElement).getPropertyValue(targetProp), property, + pseudoElement, ); } @@ -272,6 +292,9 @@ async function assertThemedProps(page: E2EPage, options: TestTarget): Promise { const searchInShadowDom = (node: Node): HTMLElement | SVGElement | Node | undefined => { @@ -344,20 +367,21 @@ async function assertThemedProps(page: E2EPage, options: TestTarget): Promise](); + await targetEl[state as Exclude](); } await page.waitForChanges(); if (targetProp.startsWith("--calcite-")) { - expect(await getComputedStylePropertyValue(target, targetProp)).toBe(expectedValue); + expect(await getComputedStylePropertyValue(targetEl, targetProp, pseudoElement)).toBe(expectedValue); return; } - const styles = await target.getComputedStyle(); + const styles = await targetEl.getComputedStyle(pseudoElement); const isFakeBorderToken = token.includes("border-color") && targetProp === "boxShadow"; + const isLinearGradientUnderlineToken = token.includes("link-underline-color") && targetProp === "backgroundImage"; - if (isFakeBorderToken) { + if (isFakeBorderToken || isLinearGradientUnderlineToken) { expect(styles[targetProp]).toMatch(expectedValue); return; }