From 3a863a7f44c7f5d65d9a35820f5c3abc4efc1c84 Mon Sep 17 00:00:00 2001 From: koji Date: Thu, 28 Mar 2024 13:23:22 -0400 Subject: [PATCH] update test for Chip Desktop --- components/src/atoms/Chip/Chip.stories.tsx | 2 +- .../src/atoms/Chip/__tests__/Chip.test.tsx | 266 +++++++++++++++++- components/src/atoms/Chip/index.tsx | 114 ++++---- 3 files changed, 308 insertions(+), 74 deletions(-) diff --git a/components/src/atoms/Chip/Chip.stories.tsx b/components/src/atoms/Chip/Chip.stories.tsx index 48df47a6990..2868d7246f7 100644 --- a/components/src/atoms/Chip/Chip.stories.tsx +++ b/components/src/atoms/Chip/Chip.stories.tsx @@ -7,7 +7,7 @@ import { Chip } from '.' import type { Meta, StoryObj } from '@storybook/react' const meta: Meta = { - title: 'ODD/Atoms/Chip', + title: 'Library/Atoms/Chip', argTypes: { type: { options: ['basic', 'error', 'info', 'neutral', 'success', 'warning'], diff --git a/components/src/atoms/Chip/__tests__/Chip.test.tsx b/components/src/atoms/Chip/__tests__/Chip.test.tsx index abd935e9857..6c976d1effa 100644 --- a/components/src/atoms/Chip/__tests__/Chip.test.tsx +++ b/components/src/atoms/Chip/__tests__/Chip.test.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { describe, it, expect } from 'vitest' +import { describe, it, expect, beforeEach, vi } from 'vitest' import { screen } from '@testing-library/react' import { BORDERS, COLORS } from '../../../helix-design-system' import { SPACING } from '../../../ui-style-constants' @@ -10,9 +10,260 @@ const render = (props: React.ComponentProps) => { return renderWithProviders() } -describe('Chip', () => { +Object.defineProperty(window, 'matchMedia', { + writable: true, + value: vi.fn().mockImplementation(query => ({ + matches: false, + media: '(height: 600px) and (width: 1024px)', + onchange: null, + addListener: vi.fn(), // Deprecated + removeListener: vi.fn(), // Deprecated + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + })), +}) + +describe('Chip Touchscreen', () => { let props: React.ComponentProps + it('should render text, no icon with basic colors', () => { + props = { + text: 'mockBasic', + type: 'basic', + } + render(props) + const chip = screen.getByTestId('Chip_basic') + const chipText = screen.getByText('mockBasic') + expect(chip).toHaveStyle( + `background-color: ${COLORS.black90}${COLORS.opacity20HexCode}` + ) + expect(chipText).toHaveStyle(`color: ${COLORS.grey60}`) + // ToDo (kk:03/28/2024) seems that jsdom doesn't support switching via media query + // I will keep investigating this + // expect(chipText).toHaveStyle( + // `padding: ${SPACING.spacing8} ${SPACING.spacing16}` + // ) + expect(screen.queryByLabelText('icon_mockBasic')).not.toBeInTheDocument() + }) + + it('should render text, icon, bgcolor with success colors', () => { + props = { + text: 'mockSuccess', + type: 'success', + } + render(props) + const chip = screen.getByTestId('Chip_success') + const chipText = screen.getByText('mockSuccess') + expect(chip).toHaveStyle(`background-color: ${COLORS.green35}`) + expect(chip).toHaveStyle(`border-radius: ${BORDERS.borderRadius40}`) + expect(chipText).toHaveStyle(`color: ${COLORS.green60}`) + const icon = screen.getByLabelText('icon_mockSuccess') + expect(icon).toHaveStyle(`color: ${COLORS.green60}`) + // ToDo (kk:03/28/2024) seems that jsdom doesn't support switching via media query + // I will keep investigating this + // expect(icon).toHaveStyle(`width: 1.5rem`) + }) + + it('should render text, icon, no bgcolor with success colors and bg false', () => { + props = { + background: false, + text: 'mockSuccess', + type: 'success', + } + render(props) + const chip = screen.getByTestId('Chip_success') + const chipText = screen.getByText('mockSuccess') + expect(chip).toHaveStyle(`background-color: ${COLORS.transparent}`) + expect(chip).toHaveStyle(`border-radius: ${BORDERS.borderRadius40}`) + expect(chipText).toHaveStyle(`color: ${COLORS.green60}`) + const icon = screen.getByLabelText('icon_mockSuccess') + expect(icon).toHaveStyle(`color: ${COLORS.green60}`) + }) + + it('should render text, icon, bgcolor with warning colors', () => { + props = { + text: 'mockWarning', + type: 'warning', + } + render(props) + const chip = screen.getByTestId('Chip_warning') + const chipText = screen.getByText('mockWarning') + expect(chip).toHaveStyle(`background-color: ${COLORS.yellow35}`) + expect(chip).toHaveStyle(`border-radius: ${BORDERS.borderRadius40}`) + expect(chipText).toHaveStyle(`color: ${COLORS.yellow60}`) + const icon = screen.getByLabelText('icon_mockWarning') + expect(icon).toHaveStyle(`color: ${COLORS.yellow60}`) + }) + + it('should render text, icon, no bgcolor with warning colors and bg false', () => { + props = { + background: false, + text: 'mockWarning', + type: 'warning', + } + render(props) + const chip = screen.getByTestId('Chip_warning') + const chipText = screen.getByText('mockWarning') + expect(chip).toHaveStyle(`background-color: ${COLORS.transparent}`) + expect(chip).toHaveStyle(`border-radius: ${BORDERS.borderRadius40}`) + expect(chipText).toHaveStyle(`color: ${COLORS.yellow60}`) + const icon = screen.getByLabelText('icon_mockWarning') + expect(icon).toHaveStyle(`color: ${COLORS.yellow60}`) + }) + + it('should render text, icon, bgcolor with neutral colors', () => { + props = { + text: 'mockNeutral', + type: 'neutral', + } + render(props) + const chip = screen.getByTestId('Chip_neutral') + const chipText = screen.getByText('mockNeutral') + expect(chip).toHaveStyle( + `background-color: ${COLORS.black90}${COLORS.opacity20HexCode}` + ) + expect(chip).toHaveStyle(`border-radius: ${BORDERS.borderRadius40}`) + expect(chipText).toHaveStyle(`color: ${COLORS.grey60}`) + const icon = screen.getByLabelText('icon_mockNeutral') + expect(icon).toHaveStyle(`color: ${COLORS.grey60}`) + }) + + it('should render text, icon, no bgcolor with neutral colors and bg false', () => { + props = { + background: false, + text: 'mockNeutral', + type: 'neutral', + } + render(props) + const chip = screen.getByTestId('Chip_neutral') + const chipText = screen.getByText('mockNeutral') + expect(chip).toHaveStyle(`background-color: ${COLORS.transparent}`) + expect(chip).toHaveStyle(`border-radius: ${BORDERS.borderRadius40}`) + expect(chipText).toHaveStyle(`color: ${COLORS.grey60}`) + const icon = screen.getByLabelText('icon_mockNeutral') + expect(icon).toHaveStyle(`color: ${COLORS.grey60}`) + }) + + it('should render text, icon, bgcolor with error colors', () => { + props = { + text: 'mockError', + type: 'error', + } + render(props) + const chip = screen.getByTestId('Chip_error') + const chipText = screen.getByText('mockError') + expect(chip).toHaveStyle(`background-color: ${COLORS.red35}`) + expect(chip).toHaveStyle(`border-radius: ${BORDERS.borderRadius40}`) + expect(chipText).toHaveStyle(`color: ${COLORS.red60}`) + const icon = screen.getByLabelText('icon_mockError') + expect(icon).toHaveStyle(`color: ${COLORS.red60}`) + }) + + it('should render text, icon, no bgcolor with error colors and bg false', () => { + props = { + background: false, + text: 'mockError', + type: 'error', + } + render(props) + const chip = screen.getByTestId('Chip_error') + const chipText = screen.getByText('mockError') + expect(chip).toHaveStyle(`background-color: ${COLORS.transparent}`) + expect(chip).toHaveStyle(`border-radius: ${BORDERS.borderRadius40}`) + expect(chipText).toHaveStyle(`color: ${COLORS.red60}`) + const icon = screen.getByLabelText('icon_mockError') + expect(icon).toHaveStyle(`color: ${COLORS.red60}`) + }) + + it('should render text, icon, bgcolor with info colors', () => { + props = { + text: 'mockInfo', + type: 'info', + } + render(props) + const chip = screen.getByTestId('Chip_info') + const chipText = screen.getByText('mockInfo') + expect(chip).toHaveStyle(`background-color: ${COLORS.blue35}`) + expect(chip).toHaveStyle(`border-radius: ${BORDERS.borderRadius40}`) + expect(chipText).toHaveStyle(`color: ${COLORS.blue60}`) + const icon = screen.getByLabelText('icon_mockInfo') + expect(icon).toHaveStyle(`color: ${COLORS.blue60}`) + }) + + it('should render text, icon, no bgcolor with info colors and bg false', () => { + props = { + background: false, + text: 'mockInfo', + type: 'info', + } + render(props) + const chip = screen.getByTestId('Chip_info') + const chipText = screen.getByText('mockInfo') + expect(chip).toHaveStyle(`background-color: ${COLORS.transparent}`) + expect(chip).toHaveStyle(`border-radius: ${BORDERS.borderRadius40}`) + expect(chipText).toHaveStyle(`color: ${COLORS.blue60}`) + const icon = screen.getByLabelText('icon_mockInfo') + expect(icon).toHaveStyle(`color: ${COLORS.blue60}`) + }) + it('renders no icon when hasIcon is false', () => { + props = { + text: 'mockInfo', + hasIcon: false, + type: 'info', + } + render(props) + expect(screen.queryByText('icon_mockInfo')).not.toBeInTheDocument() + }) + + it('render text with smaller padding and smaller icon when chip size is small and background is false', () => { + props = { + background: false, + text: 'mockInfo', + type: 'info', + chipSize: 'small', + } + render(props) + const chip = screen.getByTestId('Chip_info') + expect(chip).toHaveStyle(`padding: ${SPACING.spacing4} 0`) + const icon = screen.getByLabelText('icon_mockInfo') + expect(icon).toHaveStyle(`width: 0.75rem`) + }) + + // ToDo (kk:03/28/2024) seems that jsdom doesn't support switching via media query + // I will keep investigating this + // it('render text with smaller padding and smaller icon when chip size is small and background is true', () => { + // props = { + // background: true, + // text: 'mockInfo', + // type: 'info', + // chipSize: 'small', + // } + // render(props) + // const chip = screen.getByTestId('Chip_info') + // expect(chip).toHaveStyle(`padding: ${SPACING.spacing4} ${SPACING.spacing8}`) + // const icon = screen.getByLabelText('icon_mockInfo') + // expect(icon).toHaveStyle(`width: 1.25rem`) + // }) +}) + +describe('Chip Web', () => { + let props: React.ComponentProps + + beforeEach(() => { + Object.defineProperty(window, 'innerWidth', { + writable: true, + configurable: true, + value: 1024, + }) + + Object.defineProperty(window, 'innerHeight', { + writable: true, + configurable: true, + value: 768, + }) + }) + it('should render text, no icon with basic colors', () => { props = { text: 'mockBasic', @@ -39,9 +290,12 @@ describe('Chip', () => { expect(chip).toHaveStyle(`background-color: ${COLORS.green35}`) expect(chip).toHaveStyle(`border-radius: ${BORDERS.borderRadius40}`) expect(chipText).toHaveStyle(`color: ${COLORS.green60}`) + // expect(chipText).toHaveStyle( + // `padding: ${SPACING.spacing2} ${SPACING.spacing8}` + // ) const icon = screen.getByLabelText('icon_mockSuccess') expect(icon).toHaveStyle(`color: ${COLORS.green60}`) - expect(icon).toHaveStyle(`width: 1.5rem`) + expect(icon).toHaveStyle(`width: 1rem`) }) it('should render text, icon, no bgcolor with success colors and bg false', () => { @@ -206,7 +460,7 @@ describe('Chip', () => { const chip = screen.getByTestId('Chip_info') expect(chip).toHaveStyle(`padding: ${SPACING.spacing4} 0`) const icon = screen.getByLabelText('icon_mockInfo') - expect(icon).toHaveStyle(`width: 1.25rem`) + expect(icon).toHaveStyle(`width: 0.75rem`) }) it('render text with smaller padding and smaller icon when chip size is small and background is true', () => { @@ -218,8 +472,8 @@ describe('Chip', () => { } render(props) const chip = screen.getByTestId('Chip_info') - expect(chip).toHaveStyle(`padding: ${SPACING.spacing4} ${SPACING.spacing8}`) + expect(chip).toHaveStyle(`padding: ${SPACING.spacing4} ${SPACING.spacing6}`) const icon = screen.getByLabelText('icon_mockInfo') - expect(icon).toHaveStyle(`width: 1.25rem`) + expect(icon).toHaveStyle(`width: 0.75rem`) }) }) diff --git a/components/src/atoms/Chip/index.tsx b/components/src/atoms/Chip/index.tsx index 58de500c31b..9737fe2b4c0 100644 --- a/components/src/atoms/Chip/index.tsx +++ b/components/src/atoms/Chip/index.tsx @@ -4,11 +4,9 @@ import { BORDERS, COLORS } from '../../helix-design-system' import { Flex } from '../../primitives' import { StyledText } from '../StyledText' import { ALIGN_CENTER, DIRECTION_ROW } from '../../styles' -import { SPACING, TYPOGRAPHY } from '../../ui-style-constants' +import { RESPONSIVENESS, SPACING, TYPOGRAPHY } from '../../ui-style-constants' import { Icon } from '../../icons' -import { isTouchscreen } from '../../ui-style-constants/responsiveness' -import type { FlattenSimpleInterpolation } from 'styled-components' import type { IconName } from '../../icons' import type { StyleProps } from '../../primitives' @@ -23,8 +21,6 @@ export type ChipType = type ChipSize = 'medium' | 'small' -type ChipConfig = 'web-medium' | 'web-small' | 'touch-medium' | 'touch-small' - interface ChipProps extends StyleProps { /** Display background color? */ background?: boolean @@ -88,17 +84,6 @@ const CHIP_PROPS_BY_TYPE: Record< }, } -const WEB_MEDIUM_TEXT_STYLE = css` - font-size: ${TYPOGRAPHY.fontSizeH4}; - line-height: ${TYPOGRAPHY.lineHeight20}; - font-weight: ${TYPOGRAPHY.fontWeightSemiBold}; -` -const WEB_SMALL_TEXT_STYLE = css` - font-size: ${TYPOGRAPHY.fontSizeLabel}; - line-height: ${TYPOGRAPHY.lineHeight12}; - font-weight: ${TYPOGRAPHY.fontWeightSemiBold}; -` - export function Chip(props: ChipProps): JSX.Element { const { background, @@ -114,61 +99,46 @@ export function Chip(props: ChipProps): JSX.Element { ? COLORS.transparent : CHIP_PROPS_BY_TYPE[type].backgroundColor const icon = iconName ?? CHIP_PROPS_BY_TYPE[type].iconName ?? 'ot-alert' - const chipConfig: ChipConfig = `${ - isTouchscreen ? 'touch' : 'web' - }-${chipSize}` - - console.log(`chipConfig`, chipConfig) - - const TOUCHSCREEN_MEDIUM_CONTAINER_STYLE = css` - padding: ${SPACING.spacing8} ${background === false ? 0 : SPACING.spacing16}; - grid-gap: ${SPACING.spacing8}; - ` - const TOUCHSCREEN_SMALL_CONTAINER_STYLE = css` - padding: ${SPACING.spacing4} ${background === false ? 0 : SPACING.spacing8}; - grid-gap: ${SPACING.spacing4}; - ` - - const WEB_MEDIUM_CONTAINER_STYLE = css` + const MEDIUM_CONTAINER_STYLE = css` padding: ${SPACING.spacing2} ${background === false ? 0 : SPACING.spacing8}; grid-gap: ${SPACING.spacing4}; + @media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} { + padding: ${SPACING.spacing8} + ${background === false ? 0 : SPACING.spacing16}; + grid-gap: ${SPACING.spacing8}; + } ` - const WEB_SMALL_CONTAINER_STYLE = css` + const SMALL_CONTAINER_STYLE = css` padding: ${SPACING.spacing4} ${background === false ? 0 : SPACING.spacing6}; grid-gap: ${SPACING.spacing4}; + @media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} { + padding: ${SPACING.spacing4} + ${background === false ? 0 : SPACING.spacing8}; + grid-gap: ${SPACING.spacing4}; + } ` - const CHIP_PROPS_BY_SIZE_AND_PLATFORM: Record< - ChipConfig, - { - containerStyle: FlattenSimpleInterpolation - textStyle: FlattenSimpleInterpolation - size: string + const ICON_STYLE = css` + width: ${chipSize === 'medium' ? '1rem' : '0.75rem'}; + /* height: ${chipSize === 'medium' ? '1rem' : '0.75rem'}; */ + @media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} { + width: ${chipSize === 'medium' ? '1.5rem' : '1.25rem'}; + /* height: ${chipSize === 'medium' ? '1.5rem' : '1.25rem'}; */ } - > = { - 'web-medium': { - containerStyle: WEB_MEDIUM_CONTAINER_STYLE, - textStyle: WEB_MEDIUM_TEXT_STYLE, - size: '1rem', - }, - 'web-small': { - containerStyle: WEB_SMALL_CONTAINER_STYLE, - textStyle: WEB_SMALL_TEXT_STYLE, - size: '0.75rem', - }, - 'touch-medium': { - containerStyle: TOUCHSCREEN_MEDIUM_CONTAINER_STYLE, - textStyle: TYPOGRAPHY.bodyTextSemiBold, - size: '1.5rem', - }, - 'touch-small': { - containerStyle: TOUCHSCREEN_SMALL_CONTAINER_STYLE, - textStyle: TYPOGRAPHY.smallBodyTextSemiBold, - size: '1.25rem', - }, - } + ` + + const TEXT_STYLE = css` + ${chipSize === 'medium' ? WEB_MEDIUM_TEXT_STYLE : WEB_SMALL_TEXT_STYLE} + @media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} { + ${chipSize === 'medium' + ? TYPOGRAPHY.bodyTextSemiBold + : TYPOGRAPHY.smallBodyTextSemiBold} + } + ` + + console.log(window.innerHeight, innerWidth) return ( @@ -185,15 +157,23 @@ export function Chip(props: ChipProps): JSX.Element { name={icon} color={CHIP_PROPS_BY_TYPE[type].iconColor} aria-label={`icon_${text}`} - size={CHIP_PROPS_BY_SIZE_AND_PLATFORM[chipConfig].size} + css={ICON_STYLE} /> ) : null} - + {text} ) } + +const WEB_MEDIUM_TEXT_STYLE = css` + font-size: ${TYPOGRAPHY.fontSizeH4}; + line-height: ${TYPOGRAPHY.lineHeight20}; + font-weight: ${TYPOGRAPHY.fontWeightSemiBold}; +` +const WEB_SMALL_TEXT_STYLE = css` + font-size: ${TYPOGRAPHY.fontSizeLabel}; + line-height: ${TYPOGRAPHY.lineHeight12}; + font-weight: ${TYPOGRAPHY.fontWeightSemiBold}; +`