feat(test runner): show screenshot pointer

This commit is contained in:
Simon Knott 2024-09-09 11:34:19 +02:00
parent 718bd9b35f
commit 4ff7b320b4
No known key found for this signature in database
GPG key ID: 8CEDC00028084AEC
2 changed files with 57 additions and 3 deletions

View file

@ -0,0 +1,48 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import 'react';
declare module 'react' {
namespace JSX {
interface IntrinsicElements {
'x-pw-pointer': JSX.IntrinsicElements['div'];
}
}
}
export function ClickPointer({ point }: { point: { x: number; y: number } }) {
return (
<x-pw-pointer
style={{
position: 'fixed',
backgroundColor: '#f44336',
boxShadow: '0px 0px 60px 20px #f44336',
width: '20px',
height: '20px',
borderRadius: '10px',
margin: '-10px 0 0 -10px',
zIndex: 2147483646,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
left: `${point.x}px`,
top: `${point.y}px`,
}}
title='Click positions on screenshots are inaccurate'
/>
);
}

View file

@ -29,6 +29,7 @@ import type { Language } from '@isomorphic/locatorGenerators';
import { locatorOrSelectorAsSelector } from '@isomorphic/locatorParser'; import { locatorOrSelectorAsSelector } from '@isomorphic/locatorParser';
import { TabbedPaneTab } from '@web/components/tabbedPane'; import { TabbedPaneTab } from '@web/components/tabbedPane';
import { BrowserFrame } from './browserFrame'; import { BrowserFrame } from './browserFrame';
import { ClickPointer } from './clickPointer';
function findClosest<T extends { timestamp: number }>(items: T[], target: number) { function findClosest<T extends { timestamp: number }>(items: T[], target: number) {
return items.find((item, index) => { return items.find((item, index) => {
@ -73,7 +74,7 @@ export const SnapshotTab: React.FunctionComponent<{
return { snapshots: { action: actionSnapshot, before: beforeSnapshot, after: afterSnapshot } }; return { snapshots: { action: actionSnapshot, before: beforeSnapshot, after: afterSnapshot } };
}, [action]); }, [action]);
const { snapshotInfoUrl, snapshotUrl, popoutUrl } = React.useMemo(() => { const { snapshotInfoUrl, snapshotUrl, popoutUrl, point } = React.useMemo(() => {
const snapshot = snapshots[snapshotTab]; const snapshot = snapshots[snapshotTab];
if (!snapshot) if (!snapshot)
return { snapshotUrl: kBlankSnapshotUrl }; return { snapshotUrl: kBlankSnapshotUrl };
@ -96,7 +97,7 @@ export const SnapshotTab: React.FunctionComponent<{
popoutParams.set('pointY', String(snapshot.point.y)); popoutParams.set('pointY', String(snapshot.point.y));
} }
const popoutUrl = new URL(`snapshot.html?${popoutParams.toString()}`, window.location.href).toString(); const popoutUrl = new URL(`snapshot.html?${popoutParams.toString()}`, window.location.href).toString();
return { snapshots, snapshotInfoUrl, snapshotUrl, popoutUrl }; return { snapshots, snapshotInfoUrl, snapshotUrl, popoutUrl, point: snapshot.point };
}, [snapshots, snapshotTab]); }, [snapshots, snapshotTab]);
const iframeRef0 = React.useRef<HTMLIFrameElement>(null); const iframeRef0 = React.useRef<HTMLIFrameElement>(null);
@ -230,7 +231,12 @@ export const SnapshotTab: React.FunctionComponent<{
transform: `translate(${translate.x}px, ${translate.y}px) scale(${scale})`, transform: `translate(${translate.x}px, ${translate.y}px) scale(${scale})`,
}}> }}>
<BrowserFrame url={snapshotInfo.url} /> <BrowserFrame url={snapshotInfo.url} />
{(showScreenshotInsteadOfSnapshot && screencastFrame) && <img alt={`Screenshot of ${action?.apiName} > ${renderTitle(snapshotTab)}`} src={`sha1/${screencastFrame.sha1}`} width={screencastFrame.width} height={screencastFrame.height} />} {(showScreenshotInsteadOfSnapshot && screencastFrame) && (
<>
{point && <ClickPointer point={point} />}
<img alt={`Screenshot of ${action?.apiName} > ${renderTitle(snapshotTab)}`} src={`sha1/${screencastFrame.sha1}`} width={screencastFrame.width} height={screencastFrame.height} />
</>
)}
<div className='snapshot-switcher' style={showScreenshotInsteadOfSnapshot ? { display: 'none' } : undefined}> <div className='snapshot-switcher' style={showScreenshotInsteadOfSnapshot ? { display: 'none' } : undefined}>
<iframe ref={iframeRef0} name='snapshot' title='DOM Snapshot' className={clsx(loadingRef.current.visibleIframe === 0 && 'snapshot-visible')}></iframe> <iframe ref={iframeRef0} name='snapshot' title='DOM Snapshot' className={clsx(loadingRef.current.visibleIframe === 0 && 'snapshot-visible')}></iframe>
<iframe ref={iframeRef1} name='snapshot' title='DOM Snapshot' className={clsx(loadingRef.current.visibleIframe === 1 && 'snapshot-visible')}></iframe> <iframe ref={iframeRef1} name='snapshot' title='DOM Snapshot' className={clsx(loadingRef.current.visibleIframe === 1 && 'snapshot-visible')}></iframe>