Skip to content

Commit

Permalink
fix(designer): Render copied tooltip properly (#6463)
Browse files Browse the repository at this point in the history
* Update component to render properly

* Add unit tests

* Update unit tests

* Update e2e tests

* update unit tests
  • Loading branch information
ccastrotrejo authored Jan 27, 2025
1 parent b304e4f commit d32e904
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 21 deletions.
2 changes: 2 additions & 0 deletions e2e/designer/mock-copypastescope.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ test(
});
await page.getByTestId('msla-copy-menu-option').click();

await expect(page.getByRole('tooltip', { name: 'Copied!' })).toBeVisible();
await expect(page.getByTestId('msla-tooltip-location-condition')).toBeVisible();
await page.getByTestId('msla-plus-button-initialize_variable-condition').click();
await page.getByTestId('msla-paste-button-initialize_variable-condition').click();
await page.waitForTimeout(1000);
Expand Down
2 changes: 1 addition & 1 deletion libs/designer/src/lib/ui/CustomNodes/OperationCardNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ const DefaultNode = ({ targetPosition = Position.Top, sourcePosition = Position.
isLoadingDynamicData={isLoadingDynamicData}
nodeIndex={nodeIndex}
/>
{showCopyCallout ? <CopyTooltip targetRef={ref} hideTooltip={clearCopyTooltip} /> : null}
{showCopyCallout ? <CopyTooltip id={id} targetRef={ref} hideTooltip={clearCopyTooltip} /> : null}
<Handle className="node-handle bottom" type="source" position={sourcePosition} isConnectable={false} />
</div>
{showLeafComponents ? (
Expand Down
2 changes: 1 addition & 1 deletion libs/designer/src/lib/ui/CustomNodes/ScopeCardNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ const ScopeCardNode = ({ data, targetPosition = Position.Top, sourcePosition = P
setFocus={shouldFocus}
nodeIndex={nodeIndex}
/>
{showCopyCallout ? <CopyTooltip targetRef={rootRef} hideTooltip={clearCopyCallout} /> : null}
{showCopyCallout ? <CopyTooltip id={scopeId} targetRef={rootRef} hideTooltip={clearCopyCallout} /> : null}
{normalizedType === constants.NODE.TYPE.FOREACH && isMonitoringView ? renderLoopsPager : null}
<Handle className="node-handle bottom" type="source" position={sourcePosition} isConnectable={false} />
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
/* eslint-disable react/display-name */
import { Tooltip } from '@fluentui/react-components';
import { replaceWhiteSpaceWithUnderscore } from '@microsoft/logic-apps-shared';
import { useOnViewportChange } from '@xyflow/react';
import { useMemo, useRef } from 'react';
import { useRef } from 'react';
import { useIntl } from 'react-intl';

export interface CopyTooltipProps {
targetRef?: React.RefObject<HTMLElement>;
location?: { x: number; y: number };
hideTooltip: () => void;
id: string;
}

export const CopyTooltip = ({ targetRef: ref, location, hideTooltip }: CopyTooltipProps) => {
export const CopyTooltip = ({ targetRef: ref, location, hideTooltip, id }: CopyTooltipProps) => {
useOnViewportChange({ onStart: () => hideTooltip() });

const intl = useIntl();
Expand All @@ -22,21 +23,20 @@ export const CopyTooltip = ({ targetRef: ref, location, hideTooltip }: CopyToolt

const locationRef = useRef<HTMLDivElement>(null);

const TooltipComponent = useMemo(
() => () => (
<Tooltip
positioning={{ target: (ref ?? locationRef)?.current, position: 'below', align: 'start' }}
content={copiedText}
relationship="description"
visible={true}
/>
),
[copiedText, ref]
);

return (
<div ref={locationRef} style={{ position: 'absolute', top: location?.y ?? 0, left: location?.x ?? 0 }}>
<TooltipComponent />
</div>
<Tooltip
key={id}
positioning={{ target: (ref ?? locationRef)?.current ?? undefined, position: 'below', align: 'start' }}
content={copiedText}
relationship="description"
visible={true}
>
<div
data-testid={`msla-tooltip-location-${replaceWhiteSpaceWithUnderscore(id)}`}
data-automation-id={`msla-tooltip-location-${replaceWhiteSpaceWithUnderscore(id)}`}
ref={locationRef}
style={{ width: '1px', height: '1px', position: 'absolute', top: location?.y ?? 0, left: location?.x ?? 0 }}
/>
</Tooltip>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ export const DesignerContextualMenu = () => {
title={title}
setOpen={(o) => setOpen(o)}
/>
{showCopyCallout ? <CopyTooltip location={menuData?.location} hideTooltip={clearCopyCallout} /> : null}
{showCopyCallout ? <CopyTooltip id={nodeId} location={menuData?.location} hideTooltip={clearCopyCallout} /> : null}
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { render, screen } from '@testing-library/react';
import { CopyTooltip, CopyTooltipProps } from '../CopyTooltip';
import { describe, it, expect, vi, afterEach, beforeAll } from 'vitest';
import React from 'react';

const hideTooltipMock = vi.fn();

vi.mock('@xyflow/react', async () => {
const actualIntl = await vi.importActual('@xyflow/react');
return {
...actualIntl,
useOnViewportChange: vi.fn(() => ({ onStart: hideTooltipMock })),
};
});

vi.mock('react-intl', async () => {
const actualIntl = await vi.importActual('react-intl');
return {
...actualIntl,
useIntl: () => ({
formatMessage: vi.fn(() => 'Copied!'),
}),
};
});

describe('CopyTooltip', () => {
beforeAll(() => {
const portalRoot = document.createElement('div');
portalRoot.setAttribute('id', 'root');
document.body.appendChild(portalRoot);
});

afterEach(() => {
vi.clearAllMocks();
});

const renderComponent = (props: Partial<CopyTooltipProps> = {}) => {
const defaultProps: CopyTooltipProps = {
hideTooltip: hideTooltipMock,
id: 'test-id',
...props,
};

return render(<CopyTooltip {...defaultProps} />);
};

it('should render the tooltip with the correct content', () => {
const copiedText = 'Copied!';
const location = { x: 100, y: 100 };

// Render the Tooltip component
const { baseElement } = renderComponent({ location });

// Get the tooltip div and the location div
const tooltipDiv = screen.getByRole('tooltip');
const tooltipLocationDiv = screen.getByTestId('msla-tooltip-location-test_id');

// Assert that the tooltip and location div are rendered correctly
expect(tooltipDiv).toBeInTheDocument();
expect(screen.getByText(copiedText)).toBeVisible();
expect(tooltipLocationDiv).toBeInTheDocument();
expect(baseElement).toMatchSnapshot();
});

it('should position the tooltip based on the provided location', () => {
const location = { x: 100, y: 100 };

// Render the Tooltip component
const { baseElement } = renderComponent({ location });

// Get the tooltip location div
const tooltipLocationDiv = screen.getByTestId('msla-tooltip-location-test_id');

// Assert that the location div are rendered correctly
expect(tooltipLocationDiv).toBeInTheDocument();
expect(tooltipLocationDiv).toHaveStyle({ position: 'absolute', top: '100px', left: '100px' });
expect(baseElement).toMatchSnapshot();
});

it('should default to locationRef if targetRef is not provided', () => {
renderComponent();

const tooltipDiv = screen.getByRole('tooltip').parentElement;
expect(tooltipDiv).toHaveStyle({ position: 'absolute', top: '0px', left: '0px' });
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`CopyTooltip > should position the tooltip based on the provided location 1`] = `
<body>
<div
id="root"
/>
<div>
<div
aria-describedby="tooltip-r1"
data-automation-id="msla-tooltip-location-test_id"
data-testid="msla-tooltip-location-test_id"
style="width: 1px; height: 1px; position: absolute; top: 100px; left: 100px;"
/>
<span
hidden=""
/>
</div>
<div
class="___1uxlrft_djprso0 f1euv43f f15twtuk f1vgc2s3 f1e31b4d f494woh"
data-portal-node="true"
dir="ltr"
>
<div
class="fui-Tooltip__content ___1iilip3_omhya70 ftgm304 f1ewtqcl f132xexn f158kwzp fk6fouc fy9rknc fwrc4pm fokg9q4 ft85np5 f9ggezi f1bzqsji fxugw4r f19n0e5 fxeb0a7"
id="tooltip-r1"
role="tooltip"
style="position: fixed; left: 0px; top: 0px; margin: 0px;"
>
Copied!
</div>
</div>
</body>
`;

exports[`CopyTooltip > should render the tooltip with the correct content 1`] = `
<body>
<div
id="root"
/>
<div>
<div
aria-describedby="tooltip-r0"
data-automation-id="msla-tooltip-location-test_id"
data-testid="msla-tooltip-location-test_id"
style="width: 1px; height: 1px; position: absolute; top: 100px; left: 100px;"
/>
<span
hidden=""
/>
</div>
<div
class="___1uxlrft_djprso0 f1euv43f f15twtuk f1vgc2s3 f1e31b4d f494woh"
data-portal-node="true"
dir="ltr"
>
<div
class="fui-Tooltip__content ___1iilip3_omhya70 ftgm304 f1ewtqcl f132xexn f158kwzp fk6fouc fy9rknc fwrc4pm fokg9q4 ft85np5 f9ggezi f1bzqsji fxugw4r f19n0e5 fxeb0a7"
id="tooltip-r0"
role="tooltip"
style="position: fixed; left: 0px; top: 0px; margin: 0px;"
>
Copied!
</div>
</div>
</body>
`;

0 comments on commit d32e904

Please sign in to comment.