Skip to content

Commit

Permalink
Refactor & extend test ID logic to support more components (#294)
Browse files Browse the repository at this point in the history
Co-authored-by: Felix Beceic <fbeceic@croz.net>
  • Loading branch information
fbeceic and Felix Beceic authored Jan 28, 2025
1 parent 8c3fbe6 commit 902f07a
Show file tree
Hide file tree
Showing 45 changed files with 1,226 additions and 218 deletions.
15 changes: 14 additions & 1 deletion libs/alert/src/Alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,19 @@ export type AlertProps = {
* Icon shown on the left side of the Alert.
*/
icon?: React.ReactNode;

/**
* A unique identifier for testing purposes.
* This identifier can be used in testing frameworks like Jest or Cypress to locate specific elements for testing.
* It helps ensure that UI components are behaving as expected across different scenarios.
* @type {string}
* @example
* // Usage:
* <MyComponent data-testid="my-component" />
* // In tests:
* getByTestId('my-component');
*/
"data-testid"?: string;
} & AlertTokensProps;

type AlertTokensProps = {
Expand Down Expand Up @@ -97,7 +110,7 @@ export default function Alert({
const textClassName = cx({ [tokens.text.margin]: title }, tokens.text.fontSize, tokens.text.color[variant]);

return (
<section className={alertClassName} {...props}>
<section className={alertClassName} data-testid={props["data-testid"]} {...props}>
{icon}
<div>
{title && <p className={titleClassName}>{title}</p>}
Expand Down
96 changes: 89 additions & 7 deletions libs/alert/src/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@ type ModalContentProps = {
title: React.ReactNode;

children?: React.ReactNode;
/**
* A unique identifier for testing purposes.
* This identifier can be used in testing frameworks like Jest or Cypress to locate specific elements for testing.
* It helps ensure that UI components are behaving as expected across different scenarios.
* @type {string}
* @example
* // Usage:
* <MyComponent data-testid="my-component" />
* // In tests:
* getByTestId('my-component');
*/
"data-testid"?: string;
} & TokenProps<"Modal">;

type ModalDismissProps = {
Expand All @@ -73,10 +85,36 @@ type ModalDismissProps = {
* Icon uses for dismiss button
*/
dismissIcon?: React.ReactElement;

/**
* A unique identifier for testing purposes.
* This identifier can be used in testing frameworks like Jest or Cypress to locate specific elements for testing.
* It helps ensure that UI components are behaving as expected across different scenarios.
* @type {string}
* @example
* // Usage:
* <MyComponent data-testid="my-component" />
* // In tests:
* getByTestId('my-component');
*/
"data-testid"?: string;
} & TokenProps<"Modal">;

type ModalFooterProps = {
children?: React.ReactNode;

/**
* A unique identifier for testing purposes.
* This identifier can be used in testing frameworks like Jest or Cypress to locate specific elements for testing.
* It helps ensure that UI components are behaving as expected across different scenarios.
* @type {string}
* @example
* // Usage:
* <MyComponent data-testid="my-component" />
* // In tests:
* getByTestId('my-component');
*/
"data-testid"?: string;
} & TokenProps<"Modal">;

type ModalIconProps = {
Expand All @@ -89,6 +127,19 @@ type ModalIconProps = {
* Icon used.
*/
icon: React.ReactElement;

/**
* A unique identifier for testing purposes.
* This identifier can be used in testing frameworks like Jest or Cypress to locate specific elements for testing.
* It helps ensure that UI components are behaving as expected across different scenarios.
* @type {string}
* @example
* // Usage:
* <MyComponent data-testid="my-component" />
* // In tests:
* getByTestId('my-component');
*/
"data-testid"?: string;
} & TokenProps<"Modal">;

export type UseModal<T = unknown> = {
Expand Down Expand Up @@ -118,6 +169,19 @@ export type UseModal<T = unknown> = {
* 'const modal = useModal<string>()' and open the modal with 'modal.onOpen('someString')'.
*/
state: T | null;

/**
* A unique identifier for testing purposes.
* This identifier can be used in testing frameworks like Jest or Cypress to locate specific elements for testing.
* It helps ensure that UI components are behaving as expected across different scenarios.
* @type {string}
* @example
* // Usage:
* <MyComponent data-testid="my-component" />
* // In tests:
* getByTestId('my-component');
*/
"data-testid"?: string;
};

type ModalContext = {
Expand Down Expand Up @@ -198,10 +262,14 @@ function Modal<T = unknown>({
<div className={tokens.Container.Overlay.outer}>
<div className={overlayInnerClassName}>&nbsp;</div>
</div>
<DialogContent className={contentContainerClassName} aria-label="Dialog Content">
<DialogContent
className={contentContainerClassName}
aria-label="Dialog Content"
data-testid={props["data-testid"]}
>
{canDismiss && (
<div className={tokens.Container.Content.dismiss}>
<ModalDismiss />
<ModalDismiss data-testid={`${props["data-testid"]}-dismiss`} />
</div>
)}
<div className={tokens.Container.Content.outer}>
Expand Down Expand Up @@ -230,7 +298,13 @@ function ModalDismiss({ ariaLabel = "Close", dismissIcon, ...props }: ModalDismi
const finalDismissIcon = useIcon("dismiss", dismissIcon);

return (
<button onClick={onClose} type="button" className={dismissButtonClassName} aria-label={ariaLabel}>
<button
onClick={onClose}
type="button"
className={dismissButtonClassName}
aria-label={ariaLabel}
data-testid={props["data-testid"]}
>
{finalDismissIcon}
</button>
);
Expand All @@ -247,26 +321,34 @@ function ModalContent({ title, children, ...props }: ModalContentProps) {
);

return (
<>
<div data-testid={props["data-testid"]}>
<h3 className={contentTitleClassName} id="modal-headline">
{title}
</h3>
<div className={tokens.Content.master}>{children}</div>
</>
</div>
);
}

function ModalFooter({ children, ...props }: ModalFooterProps) {
const tokens = useTokens("Modal", props.tokens);

return <div className={tokens.Footer.base}>{React.Children.map(children, (child, index) => child)}</div>;
return (
<div className={tokens.Footer.base} data-testid={props["data-testid"]}>
{React.Children.map(children, (child, index) => child)}
</div>
);
}

function ModalIcon({ className, icon, ...props }: ModalIconProps) {
const tokens = useTokens("Modal", props.tokens);
const containerClassName = cx(tokens.Icon.base, tokens.Icon.backgroundColor, className);

return <div className={containerClassName}>{icon}</div>;
return (
<div className={containerClassName} data-testid={props["data-testid"]}>
{icon}
</div>
);
}

Modal.Content = ModalContent;
Expand Down
15 changes: 14 additions & 1 deletion libs/alert/src/Notification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,19 @@ export type NotificationProps = {
* Custom container (div) className.
*/
className?: string;

/**
* A unique identifier for testing purposes.
* This identifier can be used in testing frameworks like Jest or Cypress to locate specific elements for testing.
* It helps ensure that UI components are behaving as expected across different scenarios.
* @type {string}
* @example
* // Usage:
* <MyComponent data-testid="my-component" />
* // In tests:
* getByTestId('my-component');
*/
"data-testid"?: string;
} & NotificationTokensProps;

type NotificationTokensProps = {
Expand Down Expand Up @@ -187,7 +200,7 @@ export default function Notification({
const dismissClassName = cx(tokens.dismiss.master, tokens.dismiss.margin);

return (
<section className={containerClassName}>
<section className={containerClassName} data-testid={props["data-testid"]}>
<div className={innerContainerClassName}>
{(icon || type) && <div className={tokens.icon.master}>{type ? finalMainIcon : icon}</div>}
<div className={tokens.Container.content}>
Expand Down
16 changes: 7 additions & 9 deletions libs/core/src/Badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,17 @@ export type BadgeProps = {
small?: boolean;

/**
* A unique identifier for testing purposes, equivalent to the `data-testid` attribute.
* A unique identifier for testing purposes.
* This identifier can be used in testing frameworks like Jest or Cypress to locate specific elements for testing.
* It helps ensure that UI components are behaving as expected across different scenarios.
* @type {string}
* @example
* // Usage:
* <MyComponent testId="my-component" />
* <MyComponent data-testid="my-component" />
* // In tests:
* getByTestId('my-component');
*/
testId?: string;
"data-testid"?: string;

/**
* Determines whether the style of the badge is 'filled' (text-color-800, bg-color-100)
Expand Down Expand Up @@ -123,7 +123,7 @@ export default function Badge({
);

return (
<span className={containerClassName} data-testid={props.testId} onClick={onClick}>
<span className={containerClassName} data-testid={props["data-testid"]} onClick={onClick}>
{dot && <BadgeDot color={color} variant={variant} />}
{children}
{onRemoveButtonClick && (
Expand All @@ -132,7 +132,7 @@ export default function Badge({
small={small}
variant={variant}
onClick={onRemoveButtonClick}
testId={props.testId}
data-testid={props["data-testid"] && `${props["data-testid"]}-remove`}
/>
)}
</span>
Expand All @@ -151,18 +151,16 @@ function BadgeDot({ color = "white", variant = "filled", ...props }: BadgeDotPro
);
}

function BadgeRemoveButton({ color = "white", small, onClick, testId, variant, ...props }: BadgeRemoveButtonProps) {
function BadgeRemoveButton({ color = "white", small, onClick, variant, testId, ...props }: BadgeRemoveButtonProps) {
const tokens = useTokens("Badge", props.tokens);

const className = cx(tokens.variant[variant].color[color].removeIcon, {
"flex-shrink-0 ml-1.5 inline-flex focus:outline-none ": true,
"-mr-0.5": small,
});

const buttonId = testId && `remove-button-${testId}`;

return (
<button type="button" data-testid={buttonId} className={className} onClick={onClick}>
<button type="button" data-testid={testId} className={className} onClick={onClick}>
<svg className="h-2 w-2" stroke="currentColor" fill="none" viewBox="0 0 8 8">
<path strokeLinecap="round" strokeWidth="1.5" d="M1 1l6 6m0-6L1 7" />
</svg>
Expand Down
22 changes: 20 additions & 2 deletions libs/core/src/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { ComponentTokens, cx, TokenProps, useIcon, useTokens } from "@tiller-ds/

type BreadcrumbProps = {
children: React.ReactNode;
"data-testid"?: string;
} & TokenProps<"Breadcrumbs">;

export type BreadcrumbsProps = {
Expand All @@ -38,6 +39,19 @@ export type BreadcrumbsProps = {
* Custom additional class name for the main container component.
*/
className?: string;

/**
* A unique identifier for testing purposes.
* This identifier can be used in testing frameworks like Jest or Cypress to locate specific elements for testing.
* It helps ensure that UI components are behaving as expected across different scenarios.
* @type {string}
* @example
* // Usage:
* <MyComponent data-testid="my-component" />
* // In tests:
* getByTestId('my-component');
*/
"data-testid"?: string;
} & BreadcrumbsTokensProps;

type BreadcrumbsTokensProps = {
Expand Down Expand Up @@ -66,7 +80,7 @@ function Breadcrumbs({ children, icon, className, ...props }: BreadcrumbsProps)
const breadcrumbIcon = useIcon("breadcrumbs", icon, { className: tokens.iconColor });

return (
<nav className="flex">
<nav className="flex" data-testid={props["data-testid"]}>
<ol className={containerClassName}>
{React.Children.map(
children,
Expand Down Expand Up @@ -98,7 +112,11 @@ function Breadcrumb({ children, ...props }: BreadcrumbProps) {
tokens.breadcrumb.transitionTimingFunction,
);

return <span className={breadcrumbClassname}>{children}</span>;
return (
<span className={breadcrumbClassname} data-testid={props["data-testid"]}>
{children}
</span>
);
}

Breadcrumbs.Breadcrumb = Breadcrumb;
Expand Down
9 changes: 5 additions & 4 deletions libs/core/src/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export type ButtonProps = {

/**
* The unique identifier of the button.
* Assigned as 'data-testid' attribute if 'data-testid' prop is not defined.
*/
id?: string;

Expand Down Expand Up @@ -70,17 +71,17 @@ export type ButtonProps = {
size?: ButtonSize;

/**
* A unique identifier for testing purposes, equivalent to the `data-testid` attribute.
* A unique identifier for testing purposes.
* This identifier can be used in testing frameworks like Jest or Cypress to locate specific elements for testing.
* It helps ensure that UI components are behaving as expected across different scenarios.
* @type {string}
* @example
* // Usage:
* <MyComponent testId="my-component" />
* <MyComponent data-testid="my-component" />
* // In tests:
* getByTestId('my-component');
*/
testId?: string;
"data-testid"?: string;

/**
* Icon on the right side of the button text.
Expand Down Expand Up @@ -140,7 +141,7 @@ export default function Button({
ref={buttonRef}
className={buttonClassName}
id={id}
data-testid={props.testId || id}
data-testid={props["data-testid"] ?? id}
disabled={disabled}
{...props}
>
Expand Down
Loading

0 comments on commit 902f07a

Please # to comment.