Skip to content

Commit b2227c1

Browse files
authored
feat(inspector): allow selecting file (#5483)
1 parent 8f3a6c6 commit b2227c1

17 files changed

+420
-140
lines changed

src/server/supplements/recorder/recorderActions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ export type Action = ClickAction | CheckAction | ClosesPageAction | OpenPageActi
9494

9595
export type BaseSignal = {
9696
isAsync?: boolean,
97-
}
97+
};
9898

9999
export type NavigationSignal = BaseSignal & {
100100
name: 'navigation',

src/server/supplements/recorder/recorderApp.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const readFileAsync = util.promisify(fs.readFile);
3131

3232
declare global {
3333
interface Window {
34+
playwrightSetFile: (file: string) => void;
3435
playwrightSetMode: (mode: Mode) => void;
3536
playwrightSetPaused: (paused: boolean) => void;
3637
playwrightSetSources: (sources: Source[]) => void;
@@ -123,6 +124,12 @@ export class RecorderApp extends EventEmitter {
123124
}).toString(), true, mode, 'main').catch(() => {});
124125
}
125126

127+
async setFile(file: string): Promise<void> {
128+
await this._page.mainFrame()._evaluateExpression(((file: string) => {
129+
window.playwrightSetFile(file);
130+
}).toString(), true, file, 'main').catch(() => {});
131+
}
132+
126133
async setPaused(paused: boolean): Promise<void> {
127134
await this._page.mainFrame()._evaluateExpression(((paused: boolean) => {
128135
window.playwrightSetPaused(paused);

src/server/supplements/recorderSupplement.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export class RecorderSupplement {
4949
private _params: channels.BrowserContextRecorderSupplementEnableParams;
5050
private _currentCallsMetadata = new Map<CallMetadata, SdkObject>();
5151
private _pausedCallsMetadata = new Map<CallMetadata, () => void>();
52-
private _pauseOnNextStatement = true;
52+
private _pauseOnNextStatement = false;
5353
private _recorderSources: Source[];
5454
private _userSources = new Map<string, Source>();
5555

@@ -104,6 +104,7 @@ export class RecorderSupplement {
104104
text = source.text;
105105
}
106106
this._pushAllSources();
107+
this._recorderApp?.setFile(primaryLanguage.fileName);
107108
});
108109
if (params.outputFile) {
109110
context.on(BrowserContext.Events.BeforeClose, () => {
@@ -216,12 +217,12 @@ export class RecorderSupplement {
216217

217218
private async _resume(step: boolean) {
218219
this._pauseOnNextStatement = step;
220+
this._recorderApp?.setPaused(false);
219221

220222
for (const callback of this._pausedCallsMetadata.values())
221223
callback();
222224
this._pausedCallsMetadata.clear();
223225

224-
this._recorderApp?.setPaused(false);
225226
this._updateUserSources();
226227
this.updateCallLog([...this._currentCallsMetadata.keys()]);
227228
}
@@ -369,6 +370,7 @@ export class RecorderSupplement {
369370
}
370371

371372
// Apply new decorations.
373+
let fileToSelect = undefined;
372374
for (const metadata of this._currentCallsMetadata.keys()) {
373375
if (!metadata.stack || !metadata.stack[0])
374376
continue;
@@ -381,11 +383,13 @@ export class RecorderSupplement {
381383
if (line) {
382384
const paused = this._pausedCallsMetadata.has(metadata);
383385
source.highlight.push({ line, type: metadata.error ? 'error' : (paused ? 'paused' : 'running') });
384-
if (paused)
385-
source.revealLine = line;
386+
source.revealLine = line;
387+
fileToSelect = source.file;
386388
}
387389
}
388390
this._pushAllSources();
391+
if (fileToSelect)
392+
this._recorderApp?.setFile(fileToSelect);
389393
}
390394

391395
private _pushAllSources() {

src/web/components/source.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,12 @@
5151

5252
.source-line-paused {
5353
background-color: #b3dbff7f;
54-
outline: 1px solid #009aff;
54+
outline: 1px solid #008aff;
5555
z-index: 2;
5656
}
5757

5858
.source-line-error {
5959
background-color: #fff0f0;
60-
outline: 1px solid #ffd6d6;
60+
outline: 1px solid #ff5656;
6161
z-index: 2;
6262
}

src/web/components/source.stories.tsx

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import { Story, Meta } from '@storybook/react/types-6-0';
1818
import React from 'react';
1919
import { Source, SourceProps } from './source';
20-
import { exampleText } from './exampleText';
20+
import { exampleText } from './source.example';
2121

2222
export default {
2323
title: 'Components/Source',
@@ -37,9 +37,29 @@ Primary.args = {
3737
text: exampleText()
3838
};
3939

40-
export const HighlightLine = Template.bind({});
41-
HighlightLine.args = {
40+
export const RunningOnLine = Template.bind({});
41+
RunningOnLine.args = {
4242
language: 'javascript',
4343
text: exampleText(),
44-
highlightedLine: 11
44+
highlight: [
45+
{ line: 15, type: 'running' },
46+
]
47+
};
48+
49+
export const PausedOnLine = Template.bind({});
50+
PausedOnLine.args = {
51+
language: 'javascript',
52+
text: exampleText(),
53+
highlight: [
54+
{ line: 15, type: 'paused' },
55+
]
56+
};
57+
58+
export const ErrorOnLine = Template.bind({});
59+
ErrorOnLine.args = {
60+
language: 'javascript',
61+
text: exampleText(),
62+
highlight: [
63+
{ line: 15, type: 'error' },
64+
]
4565
};

src/web/recorder/callLog.css

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
Copyright (c) Microsoft Corporation.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
.call-log {
18+
display: flex;
19+
flex-direction: column;
20+
flex: auto;
21+
line-height: 20px;
22+
white-space: pre;
23+
background: white;
24+
overflow: auto;
25+
}
26+
27+
.call-log-message {
28+
flex: none;
29+
padding: 3px 0 3px 36px;
30+
display: flex;
31+
align-items: center;
32+
}
33+
34+
.call-log-header {
35+
color: var(--toolbar-color);
36+
box-shadow: var(--box-shadow);
37+
background-color: var(--toolbar-bg-color);
38+
height: 32px;
39+
display: flex;
40+
align-items: center;
41+
padding: 0 9px;
42+
z-index: 10;
43+
}
44+
45+
.call-log-call {
46+
display: flex;
47+
flex: none;
48+
flex-direction: column;
49+
border-top: 1px solid #eee;
50+
}
51+
52+
.call-log-call-header {
53+
height: 24px;
54+
display: flex;
55+
align-items: center;
56+
padding: 0 2px;
57+
z-index: 2;
58+
}
59+
60+
.call-log-call .codicon {
61+
padding: 0 4px;
62+
}
63+
64+
.call-log .codicon-check {
65+
color: #21a945;
66+
font-weight: bold;
67+
}
68+
69+
.call-log-call.error {
70+
background-color: #fff0f0;
71+
border-top: 1px solid #ffd6d6;
72+
}
73+
74+
.call-log-call.error .call-log-call-header,
75+
.call-log-message.error,
76+
.call-log .codicon-error {
77+
color: red;
78+
}

src/web/recorder/callLog.example.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
Copyright (c) Microsoft Corporation.
3+
4+
Licensed under the Apache License, Version 2.0 (the 'License');
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an 'AS IS' BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import { CallLog } from '../../server/supplements/recorder/recorderTypes';
18+
19+
export function exampleCallLog(): CallLog[] {
20+
return [
21+
{
22+
'id': 3,
23+
'messages': [],
24+
'title': 'newPage',
25+
'status': 'done'
26+
},
27+
{
28+
'id': 4,
29+
'messages': [
30+
'navigating to "https://github.com/microsoft", waiting until "load"',
31+
],
32+
'title': 'goto',
33+
'status': 'done'
34+
},
35+
{
36+
'id': 5,
37+
'messages': [
38+
'waiting for selector "input[aria-label="Find a repository…"]"',
39+
' selector resolved to visible <input name="q" value=" type="search" autocomplete="of…/>',
40+
'attempting click action',
41+
' waiting for element to be visible, enabled and stable',
42+
' element is visible, enabled and stable',
43+
' scrolling into view if needed',
44+
' done scrolling',
45+
' checking that element receives pointer events at (351.6,291)',
46+
' element does receive pointer events',
47+
' performing click action'
48+
],
49+
'title': 'click',
50+
'status': 'paused'
51+
},
52+
{
53+
'id': 5,
54+
'messages': [
55+
'navigating to "https://github.com/microsoft", waiting until "load"',
56+
],
57+
'error': 'Error occured',
58+
'title': 'error',
59+
'status': 'error'
60+
},
61+
];
62+
}

src/web/recorder/callLog.stories.tsx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
Copyright (c) Microsoft Corporation.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import { Story, Meta } from '@storybook/react/types-6-0';
18+
import React from 'react';
19+
import { CallLogProps, CallLogView } from './callLog';
20+
import { exampleCallLog } from './callLog.example';
21+
22+
export default {
23+
title: 'Recorder/CallLog',
24+
component: CallLogView,
25+
parameters: {
26+
viewport: {
27+
defaultViewport: 'recorder'
28+
}
29+
}
30+
} as Meta;
31+
32+
const Template: Story<CallLogProps> = args => <CallLogView {...args} />;
33+
34+
export const Primary = Template.bind({});
35+
Primary.args = {
36+
log: exampleCallLog()
37+
};

src/web/recorder/callLog.tsx

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
Copyright (c) Microsoft Corporation.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import './callLog.css';
18+
import * as React from 'react';
19+
import type { CallLog } from '../../server/supplements/recorder/recorderTypes';
20+
21+
export interface CallLogProps {
22+
log: CallLog[]
23+
}
24+
25+
export const CallLogView: React.FC<CallLogProps> = ({
26+
log
27+
}) => {
28+
const messagesEndRef = React.createRef<HTMLDivElement>();
29+
React.useLayoutEffect(() => {
30+
messagesEndRef.current?.scrollIntoView({ block: 'center', inline: 'nearest' });
31+
}, [messagesEndRef]);
32+
33+
return <div className='vbox'>
34+
<div className='call-log-header' style={{flex: 'none'}}>Log</div>
35+
<div className='call-log' style={{flex: 'auto'}}>
36+
{log.map(callLog => {
37+
return <div className={`call-log-call ${callLog.status}`} key={callLog.id}>
38+
<div className='call-log-call-header'>
39+
<span className={'codicon ' + iconClass(callLog)}></span>{ callLog.title }
40+
</div>
41+
{ callLog.messages.map((message, i) => {
42+
return <div className='call-log-message' key={i}>
43+
{ message.trim() }
44+
</div>;
45+
})}
46+
{ callLog.error ? <div className='call-log-message error'>
47+
{ callLog.error }
48+
</div> : undefined }
49+
</div>
50+
})}
51+
<div ref={messagesEndRef}></div>
52+
</div>
53+
</div>;
54+
};
55+
56+
function iconClass(callLog: CallLog): string {
57+
switch (callLog.status) {
58+
case 'done': return 'codicon-check';
59+
case 'in-progress': return 'codicon-clock';
60+
case 'paused': return 'codicon-debug-pause';
61+
case 'error': return 'codicon-error';
62+
}
63+
}

0 commit comments

Comments
 (0)