diff --git a/packages/ibm-products/src/components/Coachmark/Coachmark.test.js b/packages/ibm-products/src/components/Coachmark/Coachmark.test.js index 5ec8084cb6..57fe87bd23 100644 --- a/packages/ibm-products/src/components/Coachmark/Coachmark.test.js +++ b/packages/ibm-products/src/components/Coachmark/Coachmark.test.js @@ -5,14 +5,9 @@ * LICENSE file in the root directory of this source tree. */ -import React from 'react'; -import { - render, - screen, - act, - waitFor, - fireEvent, -} from '@testing-library/react'; // https://testing-library.com/docs/react-testing-library/intro +import React, { act } from 'react'; +import { render, screen, waitFor, fireEvent } from '@testing-library/react'; // https://testing-library.com/docs/react-testing-library/intro + import userEvent from '@testing-library/user-event'; import { pkg } from '../../settings'; import uuidv4 from '../../global/js/utils/uuidv4'; @@ -23,8 +18,14 @@ import { CoachmarkOverlayElement, CoachmarkOverlayElements, } from '..'; -import { BEACON_KIND } from './utils/enums'; +import { + BEACON_KIND, + COACHMARK_ALIGNMENT, + COACHMARK_OVERLAY_KIND, +} from './utils/enums'; import { CoachmarkDragbar } from './CoachmarkDragbar'; +import { getOffsetTune } from './utils/constants'; +import { clamp } from './utils/helpers'; const blockClass = `${pkg.prefix}--coachmark`; const componentName = Coachmark.displayName; @@ -74,6 +75,14 @@ describe(componentName, () => { expect(screen.getByTestId(dataTestId)).toHaveClass(blockClass); }); + it('Check coachmark can be open by default', () => { + renderCoachmark({ + 'data-testid': dataTestId, + isOpenByDefault: true, + }); + expect(isCoachmarkVisible()).toBeTruthy(); + }); + it('has no accessibility violations', async () => { const { container } = renderCoachmark(); await expect(container).toBeAccessible(componentName); @@ -211,11 +220,108 @@ describe(componentName, () => { ); }); - it('Check coachmark can be open by default', () => { + it('renders the theme prop', async () => { renderCoachmark({ 'data-testid': dataTestId, - isOpenByDefault: true, + theme: 'dark', }); - expect(isCoachmarkVisible()).toBeTruthy(); + + await expect(screen.getByTestId(dataTestId)).toHaveClass( + `${pkg.prefix}--coachmark__dark` + ); + }); + + it('tests getOffsetTune util', async () => { + let result; + const distanceOffset = 24; + const coachmarkTarget = { + targetRect: { + width: 200, + height: 200, + }, + align: COACHMARK_ALIGNMENT.TOP, + }; + + // Test case when it is a tooltip + result = getOffsetTune(coachmarkTarget, COACHMARK_OVERLAY_KIND.TOOLTIP); + expect(result.left).toBe(0); + expect(result.top).toBe(0); + + // Test top alignment + coachmarkTarget.align = COACHMARK_ALIGNMENT.TOP; + result = getOffsetTune(coachmarkTarget, COACHMARK_OVERLAY_KIND.FLOATING); + expect(result.left).toBe(100); + expect(result.top).toBe(0); + + // Test top left alignment + coachmarkTarget.align = COACHMARK_ALIGNMENT.TOP_LEFT; + result = getOffsetTune(coachmarkTarget, COACHMARK_OVERLAY_KIND.FLOATING); + expect(result.left).toBe(distanceOffset); + expect(result.top).toBe(0); + + // Test top right alignment + coachmarkTarget.align = COACHMARK_ALIGNMENT.TOP_RIGHT; + result = getOffsetTune(coachmarkTarget, COACHMARK_OVERLAY_KIND.FLOATING); + expect(result.left).toBe(200 - distanceOffset); + expect(result.top).toBe(0); + + // Test bottom alignment + coachmarkTarget.align = COACHMARK_ALIGNMENT.BOTTOM; + result = getOffsetTune(coachmarkTarget, COACHMARK_OVERLAY_KIND.FLOATING); + expect(result.left).toBe(100); + expect(result.top).toBe(200); + + // Test bottom left alignment + coachmarkTarget.align = COACHMARK_ALIGNMENT.BOTTOM_LEFT; + result = getOffsetTune(coachmarkTarget, COACHMARK_OVERLAY_KIND.FLOATING); + expect(result.left).toBe(distanceOffset); + expect(result.top).toBe(200); + + // Test bottom right alignment + coachmarkTarget.align = COACHMARK_ALIGNMENT.BOTTOM_RIGHT; + result = getOffsetTune(coachmarkTarget, COACHMARK_OVERLAY_KIND.FLOATING); + expect(result.left).toBe(200 - distanceOffset); + expect(result.top).toBe(200); + + // Test left alignment + coachmarkTarget.align = COACHMARK_ALIGNMENT.LEFT; + result = getOffsetTune(coachmarkTarget, COACHMARK_OVERLAY_KIND.FLOATING); + expect(result.left).toBe(0); + expect(result.top).toBe(100); + + // Test left top alignment + coachmarkTarget.align = COACHMARK_ALIGNMENT.LEFT_TOP; + result = getOffsetTune(coachmarkTarget, COACHMARK_OVERLAY_KIND.FLOATING); + expect(result.left).toBe(0); + expect(result.top).toBe(distanceOffset); + + // Test left bottom alignment + coachmarkTarget.align = COACHMARK_ALIGNMENT.LEFT_BOTTOM; + result = getOffsetTune(coachmarkTarget, COACHMARK_OVERLAY_KIND.FLOATING); + expect(result.left).toBe(0); + expect(result.top).toBe(200 - distanceOffset); + + // Test right alignment + coachmarkTarget.align = COACHMARK_ALIGNMENT.RIGHT; + result = getOffsetTune(coachmarkTarget, COACHMARK_OVERLAY_KIND.FLOATING); + expect(result.left).toBe(200); + expect(result.top).toBe(100); + + // Test right top alignment + coachmarkTarget.align = COACHMARK_ALIGNMENT.RIGHT_TOP; + result = getOffsetTune(coachmarkTarget, COACHMARK_OVERLAY_KIND.FLOATING); + expect(result.left).toBe(200); + expect(result.top).toBe(distanceOffset); + + // Test right bottom alignment + coachmarkTarget.align = COACHMARK_ALIGNMENT.RIGHT_BOTTOM; + result = getOffsetTune(coachmarkTarget, COACHMARK_OVERLAY_KIND.FLOATING); + expect(result.left).toBe(200); + expect(result.top).toBe(200 - distanceOffset); + }); + + it('tests clamp helper function', () => { + expect(clamp(100, 50, 20)).toBe(50); + expect(clamp(40, 10, 50)).toBe(40); }); }); diff --git a/packages/ibm-products/src/components/Coachmark/CoachmarkOverlay.tsx b/packages/ibm-products/src/components/Coachmark/CoachmarkOverlay.tsx index 0e0f29d3aa..4b20c4b738 100644 --- a/packages/ibm-products/src/components/Coachmark/CoachmarkOverlay.tsx +++ b/packages/ibm-products/src/components/Coachmark/CoachmarkOverlay.tsx @@ -105,6 +105,7 @@ export let CoachmarkOverlay = forwardRef( const handleKeyPress = (event) => { const { shiftKey, key } = event; + /* istanbul ignore next */ if (key === 'Enter' || key === ' ') { setA11yDragMode((prevVal) => !prevVal); } else if (a11yDragMode) { @@ -151,6 +152,7 @@ export let CoachmarkOverlay = forwardRef( return style; }, [isBeacon, isDraggable, coachmark, kind]); + /* istanbul ignore next */ function handleDragBounds(x, y) { let xRes = x; let yRes = y; @@ -254,6 +256,7 @@ const useWindowDimensions = () => { ); useEffect(() => { + /* istanbul ignore next */ function handleResize() { setWindowDimensions(getWindowDimensions()); } diff --git a/packages/ibm-products/src/components/CoachmarkStack/CoachmarkStack.test.js b/packages/ibm-products/src/components/CoachmarkStack/CoachmarkStack.test.js index dd67b208f2..f46f0cdc3e 100644 --- a/packages/ibm-products/src/components/CoachmarkStack/CoachmarkStack.test.js +++ b/packages/ibm-products/src/components/CoachmarkStack/CoachmarkStack.test.js @@ -5,8 +5,8 @@ * LICENSE file in the root directory of this source tree. */ -import React from 'react'; -import { render, screen, act } from '@testing-library/react'; // https://testing-library.com/docs/react-testing-library/intro +import React, { act } from 'react'; +import { render, screen } from '@testing-library/react'; // https://testing-library.com/docs/react-testing-library/intro import { pkg } from '../../settings'; import uuidv4 from '../../global/js/utils/uuidv4'; @@ -131,4 +131,74 @@ describe(componentName, () => { componentName ); }); + + it('calls the onClose prop', async () => { + const onClose = jest.fn(); + renderCoachmarkStack({ + title: 'Coachmark Stack', + description: 'Coachmark Stack Description', + navLinkLabels: ['Label 1', 'Label 2', 'Label 3'], + tagline: 'Test Tagline', + 'data-testid': dataTestId, + onClose, + }); + expect(onClose).not.toHaveBeenCalled(); + + const coachmarkStackButton = screen.getByRole('button', { + name: /Test Tagline/, + }); + + await act(() => userEvent.click(coachmarkStackButton)); + + const closeButton = screen.getAllByRole('button', { + name: /Close/, + })[0]; + + await act(() => userEvent.click(closeButton)); + + expect(onClose).toHaveBeenCalled(); + }); + + it('opens a stacked coachmark', async () => { + const onClose = jest.fn(); + renderCoachmarkStack({ + title: 'Coachmark Stack', + description: 'Coachmark Stack Description', + navLinkLabels: ['Label 1', 'Label 2', 'Label 3'], + tagline: 'Test Tagline', + 'data-testid': dataTestId, + onClose, + }); + + // gets the trigger to open the overlay + const coachmarkStackButton = screen.getByRole('button', { + name: /Test Tagline/, + }); + await act(() => userEvent.click(coachmarkStackButton)); + + // Gets the label button to open a stacked item + const labelButton = screen.getByRole('button', { + name: /Label 1/, + }); + await act(() => userEvent.click(labelButton)); + + // Gets the overlay element + const coachmarkOverlay = document.querySelector( + `.${pkg.prefix}--coachmark-overlay` + ); + + // tests to see if the element has the is-stacked class + expect(coachmarkOverlay).toHaveClass( + `${pkg.prefix}--coachmark-stack-element--is-stacked` + ); + + // pressing escape should close the stacked item + await act(() => userEvent.keyboard('{Escape}')); + + expect(coachmarkOverlay).not.toHaveClass( + `${pkg.prefix}--coachmark-stack-element--is-stacked` + ); + + await act(() => userEvent.keyboard('{Escape}')); + }); });