2020-12-28 23:50:12 +01:00
|
|
|
/**
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
|
2022-09-21 03:41:51 +02:00
|
|
|
import type * as channels from '@protocol/channels';
|
2024-08-27 23:10:21 +02:00
|
|
|
import type { CallLog, CallLogStatus, EventData, Mode, OverlayState, Source, UIState } from '@recorder/recorderTypes';
|
|
|
|
|
import * as fs from 'fs';
|
|
|
|
|
import type { Point } from '../common/types';
|
2022-04-08 21:52:40 +02:00
|
|
|
import * as consoleApiSource from '../generated/consoleApiSource';
|
2024-08-27 23:10:21 +02:00
|
|
|
import { isUnderTest } from '../utils';
|
|
|
|
|
import { locatorOrSelectorAsSelector } from '../utils/isomorphic/locatorParser';
|
|
|
|
|
import { BrowserContext } from './browserContext';
|
|
|
|
|
import { type Language } from './codegen/types';
|
|
|
|
|
import { Debugger } from './debugger';
|
2022-04-08 21:52:40 +02:00
|
|
|
import type { CallMetadata, InstrumentationListener, SdkObject } from './instrumentation';
|
2024-08-27 23:10:21 +02:00
|
|
|
import { ContextRecorder, generateFrameSelector } from './recorder/contextRecorder';
|
2024-09-12 22:39:44 +02:00
|
|
|
import type { IRecorderAppFactory, IRecorderApp, IRecorder } from './recorder/recorderFrontend';
|
2024-09-28 02:52:03 +02:00
|
|
|
import { metadataToCallLog } from './recorder/recorderUtils';
|
2024-09-26 23:50:09 +02:00
|
|
|
import type * as actions from '@recorder/actions';
|
2024-09-28 02:52:03 +02:00
|
|
|
import { buildFullSelector } from '../utils/isomorphic/recorderUtils';
|
2021-01-25 23:49:26 +01:00
|
|
|
|
2022-08-06 04:34:57 +02:00
|
|
|
const recorderSymbol = Symbol('recorderSymbol');
|
2021-01-25 23:49:26 +01:00
|
|
|
|
2024-09-12 22:39:44 +02:00
|
|
|
export class Recorder implements InstrumentationListener, IRecorder {
|
2021-01-25 04:21:19 +01:00
|
|
|
private _context: BrowserContext;
|
2021-02-05 23:24:27 +01:00
|
|
|
private _mode: Mode;
|
2021-02-19 16:25:08 +01:00
|
|
|
private _highlightedSelector = '';
|
2023-11-07 21:58:41 +01:00
|
|
|
private _overlayState: OverlayState = { offsetX: 0 };
|
2022-02-11 06:23:16 +01:00
|
|
|
private _recorderApp: IRecorderApp | null = null;
|
2021-02-13 07:06:45 +01:00
|
|
|
private _currentCallsMetadata = new Map<CallMetadata, SdkObject>();
|
2021-10-01 21:07:35 +02:00
|
|
|
private _recorderSources: Source[] = [];
|
2021-02-13 03:53:46 +01:00
|
|
|
private _userSources = new Map<string, Source>();
|
2021-04-24 03:34:52 +02:00
|
|
|
private _debugger: Debugger;
|
2021-10-01 21:07:35 +02:00
|
|
|
private _contextRecorder: ContextRecorder;
|
2022-08-10 01:42:55 +02:00
|
|
|
private _omitCallTracking = false;
|
2022-10-06 02:59:34 +02:00
|
|
|
private _currentLanguage: Language;
|
2021-04-24 03:34:52 +02:00
|
|
|
|
2024-09-21 00:25:49 +02:00
|
|
|
static async showInspector(context: BrowserContext, params: channels.BrowserContextEnableRecorderParams, recorderAppFactory: IRecorderAppFactory) {
|
2023-10-22 13:02:14 +02:00
|
|
|
if (isUnderTest())
|
|
|
|
|
params.language = process.env.TEST_INSPECTOR_LANGUAGE;
|
2024-09-21 00:25:49 +02:00
|
|
|
return await Recorder.show('actions', context, recorderAppFactory, params);
|
2021-04-24 03:34:52 +02:00
|
|
|
}
|
2021-01-25 23:49:26 +01:00
|
|
|
|
2024-09-21 00:25:49 +02:00
|
|
|
static showInspectorNoReply(context: BrowserContext, recorderAppFactory: IRecorderAppFactory) {
|
|
|
|
|
Recorder.showInspector(context, {}, recorderAppFactory).catch(() => {});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static show(codegenMode: 'actions' | 'trace-events', context: BrowserContext, recorderAppFactory: IRecorderAppFactory, params: channels.BrowserContextEnableRecorderParams): Promise<Recorder> {
|
2022-08-06 04:34:57 +02:00
|
|
|
let recorderPromise = (context as any)[recorderSymbol] as Promise<Recorder>;
|
2021-01-25 23:49:26 +01:00
|
|
|
if (!recorderPromise) {
|
2024-09-21 00:25:49 +02:00
|
|
|
recorderPromise = Recorder._create(codegenMode, context, recorderAppFactory, params);
|
2022-08-06 04:34:57 +02:00
|
|
|
(context as any)[recorderSymbol] = recorderPromise;
|
2021-01-25 23:49:26 +01:00
|
|
|
}
|
|
|
|
|
return recorderPromise;
|
|
|
|
|
}
|
2021-01-25 04:21:19 +01:00
|
|
|
|
2024-09-21 00:25:49 +02:00
|
|
|
private static async _create(codegenMode: 'actions' | 'trace-events', context: BrowserContext, recorderAppFactory: IRecorderAppFactory, params: channels.BrowserContextEnableRecorderParams = {}): Promise<Recorder> {
|
|
|
|
|
const recorder = new Recorder(codegenMode, context, params);
|
2024-08-28 05:24:19 +02:00
|
|
|
const recorderApp = await recorderAppFactory(recorder);
|
|
|
|
|
await recorder._install(recorderApp);
|
|
|
|
|
return recorder;
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-21 00:25:49 +02:00
|
|
|
constructor(codegenMode: 'actions' | 'trace-events', context: BrowserContext, params: channels.BrowserContextEnableRecorderParams) {
|
2022-08-06 04:34:57 +02:00
|
|
|
this._mode = params.mode || 'none';
|
2024-09-21 00:25:49 +02:00
|
|
|
this._contextRecorder = new ContextRecorder(codegenMode, context, params, {});
|
2021-01-25 04:21:19 +01:00
|
|
|
this._context = context;
|
2022-08-10 01:42:55 +02:00
|
|
|
this._omitCallTracking = !!params.omitCallTracking;
|
2022-11-22 20:06:45 +01:00
|
|
|
this._debugger = context.debugger();
|
2022-01-12 16:37:48 +01:00
|
|
|
context.instrumentation.addListener(this, context);
|
2022-10-06 02:59:34 +02:00
|
|
|
this._currentLanguage = this._contextRecorder.languageName();
|
2023-11-05 05:18:27 +01:00
|
|
|
|
|
|
|
|
if (isUnderTest()) {
|
|
|
|
|
// Most of our tests put elements at the top left, so get out of the way.
|
2023-11-07 21:58:41 +01:00
|
|
|
this._overlayState.offsetX = 200;
|
2023-11-05 05:18:27 +01:00
|
|
|
}
|
2021-01-25 04:21:19 +01:00
|
|
|
}
|
2020-12-28 23:50:12 +01:00
|
|
|
|
2024-08-28 05:24:19 +02:00
|
|
|
private async _install(recorderApp: IRecorderApp) {
|
2021-02-05 23:24:27 +01:00
|
|
|
this._recorderApp = recorderApp;
|
|
|
|
|
recorderApp.once('close', () => {
|
2021-06-05 03:43:54 +02:00
|
|
|
this._debugger.resume(false);
|
2021-02-05 23:24:27 +01:00
|
|
|
this._recorderApp = null;
|
|
|
|
|
});
|
|
|
|
|
recorderApp.on('event', (data: EventData) => {
|
|
|
|
|
if (data.event === 'setMode') {
|
2022-08-06 04:34:57 +02:00
|
|
|
this.setMode(data.params.mode);
|
2021-02-19 16:25:08 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (data.event === 'selectorUpdated') {
|
2023-10-22 13:02:14 +02:00
|
|
|
this.setHighlightedSelector(this._currentLanguage, data.params.selector);
|
2021-02-26 23:16:32 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2021-02-12 19:11:30 +01:00
|
|
|
if (data.event === 'step') {
|
2021-04-24 03:34:52 +02:00
|
|
|
this._debugger.resume(true);
|
2021-02-12 19:11:30 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2022-10-06 02:59:34 +02:00
|
|
|
if (data.event === 'fileChanged') {
|
|
|
|
|
this._currentLanguage = this._contextRecorder.languageName(data.params.file);
|
|
|
|
|
this._refreshOverlay();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-02-05 23:24:27 +01:00
|
|
|
if (data.event === 'resume') {
|
2021-04-24 03:34:52 +02:00
|
|
|
this._debugger.resume(false);
|
2021-02-12 19:11:30 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (data.event === 'pause') {
|
2021-04-24 03:34:52 +02:00
|
|
|
this._debugger.pauseOnNextStatement();
|
2021-02-05 23:24:27 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (data.event === 'clear') {
|
2021-10-01 21:07:35 +02:00
|
|
|
this._contextRecorder.clearScript();
|
2021-02-05 23:24:27 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await Promise.all([
|
|
|
|
|
recorderApp.setMode(this._mode),
|
2021-04-24 03:34:52 +02:00
|
|
|
recorderApp.setPaused(this._debugger.isPaused()),
|
2021-02-13 03:53:46 +01:00
|
|
|
this._pushAllSources()
|
2021-02-05 23:24:27 +01:00
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
this._context.once(BrowserContext.Events.Close, () => {
|
2021-10-01 21:07:35 +02:00
|
|
|
this._contextRecorder.dispose();
|
2022-05-09 18:34:00 +02:00
|
|
|
this._context.instrumentation.removeListener(this);
|
2024-08-28 05:24:19 +02:00
|
|
|
this._recorderApp?.close().catch(() => {});
|
2021-01-25 04:21:19 +01:00
|
|
|
});
|
2024-09-26 23:50:09 +02:00
|
|
|
this._contextRecorder.on(ContextRecorder.Events.Change, (data: { sources: Source[], actions: actions.ActionInContext[] }) => {
|
2021-10-01 21:07:35 +02:00
|
|
|
this._recorderSources = data.sources;
|
2024-09-28 06:18:30 +02:00
|
|
|
recorderApp.setActions(data.actions, data.sources);
|
2024-10-14 23:04:24 +02:00
|
|
|
recorderApp.setRunningFile(undefined);
|
2021-10-01 21:07:35 +02:00
|
|
|
this._pushAllSources();
|
|
|
|
|
});
|
2020-12-28 23:50:12 +01:00
|
|
|
|
2022-05-09 16:44:20 +02:00
|
|
|
await this._context.exposeBinding('__pw_recorderState', false, source => {
|
2022-11-07 22:53:15 +01:00
|
|
|
let actionSelector = '';
|
2021-02-26 23:16:32 +01:00
|
|
|
let actionPoint: Point | undefined;
|
2022-11-07 22:53:15 +01:00
|
|
|
const hasActiveScreenshotCommand = [...this._currentCallsMetadata.keys()].some(isScreenshotCommand);
|
|
|
|
|
if (!hasActiveScreenshotCommand) {
|
|
|
|
|
actionSelector = this._highlightedSelector;
|
|
|
|
|
for (const [metadata, sdkObject] of this._currentCallsMetadata) {
|
|
|
|
|
if (source.page === sdkObject.attribution.page) {
|
|
|
|
|
actionPoint = metadata.point || actionPoint;
|
|
|
|
|
actionSelector = actionSelector || metadata.params.selector;
|
|
|
|
|
}
|
2021-02-13 03:53:46 +01:00
|
|
|
}
|
2021-02-12 19:11:30 +01:00
|
|
|
}
|
2021-02-26 23:16:32 +01:00
|
|
|
const uiState: UIState = {
|
|
|
|
|
mode: this._mode,
|
|
|
|
|
actionPoint,
|
|
|
|
|
actionSelector,
|
2022-11-08 21:04:43 +01:00
|
|
|
language: this._currentLanguage,
|
2023-04-29 21:04:33 +02:00
|
|
|
testIdAttributeName: this._contextRecorder.testIdAttributeName(),
|
2023-11-07 01:40:33 +01:00
|
|
|
overlay: this._overlayState,
|
2021-02-26 23:16:32 +01:00
|
|
|
};
|
2021-02-12 19:11:30 +01:00
|
|
|
return uiState;
|
2021-09-08 23:27:05 +02:00
|
|
|
});
|
2021-01-25 23:49:26 +01:00
|
|
|
|
2023-09-07 03:35:32 +02:00
|
|
|
await this._context.exposeBinding('__pw_recorderSetSelector', false, async ({ frame }, selector: string) => {
|
2024-08-26 19:28:54 +02:00
|
|
|
const selectorChain = await generateFrameSelector(frame);
|
2024-08-28 02:17:57 +02:00
|
|
|
await this._recorderApp?.setSelector(buildFullSelector(selectorChain, selector), true);
|
2021-09-08 23:27:05 +02:00
|
|
|
});
|
2021-02-19 16:25:08 +01:00
|
|
|
|
2023-11-01 23:56:49 +01:00
|
|
|
await this._context.exposeBinding('__pw_recorderSetMode', false, async ({ frame }, mode: Mode) => {
|
|
|
|
|
if (frame.parentFrame())
|
|
|
|
|
return;
|
|
|
|
|
this.setMode(mode);
|
|
|
|
|
});
|
|
|
|
|
|
2023-11-07 01:40:33 +01:00
|
|
|
await this._context.exposeBinding('__pw_recorderSetOverlayState', false, async ({ frame }, state: OverlayState) => {
|
2023-11-05 05:18:27 +01:00
|
|
|
if (frame.parentFrame())
|
|
|
|
|
return;
|
2023-11-07 01:40:33 +01:00
|
|
|
this._overlayState = state;
|
2023-11-05 05:18:27 +01:00
|
|
|
});
|
|
|
|
|
|
2022-05-09 16:44:20 +02:00
|
|
|
await this._context.exposeBinding('__pw_resume', false, () => {
|
2021-04-24 03:34:52 +02:00
|
|
|
this._debugger.resume(false);
|
2021-09-08 23:27:05 +02:00
|
|
|
});
|
|
|
|
|
await this._context.extendInjectedScript(consoleApiSource.source);
|
2021-04-22 05:46:45 +02:00
|
|
|
|
2021-10-01 21:07:35 +02:00
|
|
|
await this._contextRecorder.install();
|
|
|
|
|
|
2021-04-24 03:34:52 +02:00
|
|
|
if (this._debugger.isPaused())
|
2021-04-22 05:46:45 +02:00
|
|
|
this._pausedStateChanged();
|
2021-04-24 03:34:52 +02:00
|
|
|
this._debugger.on(Debugger.Events.PausedStateChanged, () => this._pausedStateChanged());
|
2021-04-22 05:46:45 +02:00
|
|
|
|
2024-08-28 05:24:19 +02:00
|
|
|
(this._context as any).recorderAppForTest = this._recorderApp;
|
2021-01-25 23:49:26 +01:00
|
|
|
}
|
|
|
|
|
|
2021-04-22 05:46:45 +02:00
|
|
|
_pausedStateChanged() {
|
|
|
|
|
// If we are called upon page.pause, we don't have metadatas, populate them.
|
2021-04-24 03:34:52 +02:00
|
|
|
for (const { metadata, sdkObject } of this._debugger.pausedDetails()) {
|
2021-04-22 05:46:45 +02:00
|
|
|
if (!this._currentCallsMetadata.has(metadata))
|
|
|
|
|
this.onBeforeCall(sdkObject, metadata);
|
|
|
|
|
}
|
2021-06-05 03:43:54 +02:00
|
|
|
this._recorderApp?.setPaused(this._debugger.isPaused());
|
2021-02-13 03:53:46 +01:00
|
|
|
this._updateUserSources();
|
2021-04-22 05:46:45 +02:00
|
|
|
this.updateCallLog([...this._currentCallsMetadata.keys()]);
|
2021-02-26 23:16:32 +01:00
|
|
|
}
|
|
|
|
|
|
2022-08-06 04:34:57 +02:00
|
|
|
setMode(mode: Mode) {
|
|
|
|
|
if (this._mode === mode)
|
|
|
|
|
return;
|
2022-08-08 19:39:54 +02:00
|
|
|
this._highlightedSelector = '';
|
2021-02-19 16:25:08 +01:00
|
|
|
this._mode = mode;
|
|
|
|
|
this._recorderApp?.setMode(this._mode);
|
2023-11-15 00:17:42 +01:00
|
|
|
this._contextRecorder.setEnabled(this._mode === 'recording' || this._mode === 'assertingText' || this._mode === 'assertingVisibility' || this._mode === 'assertingValue');
|
|
|
|
|
this._debugger.setMuted(this._mode === 'recording' || this._mode === 'assertingText' || this._mode === 'assertingVisibility' || this._mode === 'assertingValue');
|
2023-11-14 01:39:14 +01:00
|
|
|
if (this._mode !== 'none' && this._mode !== 'standby' && this._context.pages().length === 1)
|
2021-02-19 16:25:08 +01:00
|
|
|
this._context.pages()[0].bringToFront().catch(() => {});
|
2022-08-08 19:39:54 +02:00
|
|
|
this._refreshOverlay();
|
2021-02-19 16:25:08 +01:00
|
|
|
}
|
|
|
|
|
|
2022-11-10 21:15:29 +01:00
|
|
|
resume() {
|
|
|
|
|
this._debugger.resume(false);
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-05 05:18:27 +01:00
|
|
|
mode() {
|
|
|
|
|
return this._mode;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-03 23:17:08 +01:00
|
|
|
setHighlightedSelector(language: Language, selector: string) {
|
2022-11-29 20:43:47 +01:00
|
|
|
this._highlightedSelector = locatorOrSelectorAsSelector(language, selector, this._context.selectors().testIdAttributeName());
|
2022-11-03 23:17:08 +01:00
|
|
|
this._refreshOverlay();
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-05 04:56:42 +02:00
|
|
|
hideHighlightedSelector() {
|
2022-11-03 23:17:08 +01:00
|
|
|
this._highlightedSelector = '';
|
2022-08-06 04:34:57 +02:00
|
|
|
this._refreshOverlay();
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-25 18:55:20 +02:00
|
|
|
setOutput(codegenId: string, outputFile: string | undefined) {
|
|
|
|
|
this._contextRecorder.setOutput(codegenId, outputFile);
|
2022-08-09 02:16:13 +02:00
|
|
|
}
|
|
|
|
|
|
2021-02-26 23:16:32 +01:00
|
|
|
private _refreshOverlay() {
|
|
|
|
|
for (const page of this._context.pages())
|
2023-05-31 23:08:44 +02:00
|
|
|
page.mainFrame().evaluateExpression('window.__pw_refreshOverlay()').catch(() => {});
|
2021-02-26 23:16:32 +01:00
|
|
|
}
|
|
|
|
|
|
2021-10-01 21:07:35 +02:00
|
|
|
async onBeforeCall(sdkObject: SdkObject, metadata: CallMetadata) {
|
2023-11-15 00:17:42 +01:00
|
|
|
if (this._omitCallTracking || this._mode === 'recording' || this._mode === 'assertingText' || this._mode === 'assertingVisibility' || this._mode === 'assertingValue')
|
2021-10-01 21:07:35 +02:00
|
|
|
return;
|
|
|
|
|
this._currentCallsMetadata.set(metadata, sdkObject);
|
|
|
|
|
this._updateUserSources();
|
|
|
|
|
this.updateCallLog([metadata]);
|
2022-11-07 22:53:15 +01:00
|
|
|
if (isScreenshotCommand(metadata)) {
|
2023-10-05 04:56:42 +02:00
|
|
|
this.hideHighlightedSelector();
|
2022-11-07 22:53:15 +01:00
|
|
|
} else if (metadata.params && metadata.params.selector) {
|
2021-10-01 21:07:35 +02:00
|
|
|
this._highlightedSelector = metadata.params.selector;
|
|
|
|
|
this._recorderApp?.setSelector(this._highlightedSelector).catch(() => {});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async onAfterCall(sdkObject: SdkObject, metadata: CallMetadata) {
|
2023-11-15 00:17:42 +01:00
|
|
|
if (this._omitCallTracking || this._mode === 'recording' || this._mode === 'assertingText' || this._mode === 'assertingVisibility' || this._mode === 'assertingValue')
|
2021-10-01 21:07:35 +02:00
|
|
|
return;
|
|
|
|
|
if (!metadata.error)
|
|
|
|
|
this._currentCallsMetadata.delete(metadata);
|
|
|
|
|
this._updateUserSources();
|
|
|
|
|
this.updateCallLog([metadata]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private _updateUserSources() {
|
|
|
|
|
// Remove old decorations.
|
|
|
|
|
for (const source of this._userSources.values()) {
|
|
|
|
|
source.highlight = [];
|
|
|
|
|
source.revealLine = undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Apply new decorations.
|
|
|
|
|
let fileToSelect = undefined;
|
|
|
|
|
for (const metadata of this._currentCallsMetadata.keys()) {
|
2023-02-23 06:08:47 +01:00
|
|
|
if (!metadata.location)
|
2021-10-01 21:07:35 +02:00
|
|
|
continue;
|
2023-02-23 06:08:47 +01:00
|
|
|
const { file, line } = metadata.location;
|
2021-10-01 21:07:35 +02:00
|
|
|
let source = this._userSources.get(file);
|
|
|
|
|
if (!source) {
|
2022-08-15 19:44:46 +02:00
|
|
|
source = { isRecorded: false, label: file, id: file, text: this._readSource(file), highlight: [], language: languageForFile(file) };
|
2021-10-01 21:07:35 +02:00
|
|
|
this._userSources.set(file, source);
|
|
|
|
|
}
|
|
|
|
|
if (line) {
|
|
|
|
|
const paused = this._debugger.isPaused(metadata);
|
|
|
|
|
source.highlight.push({ line, type: metadata.error ? 'error' : (paused ? 'paused' : 'running') });
|
|
|
|
|
source.revealLine = line;
|
2022-08-15 19:44:46 +02:00
|
|
|
fileToSelect = source.id;
|
2021-10-01 21:07:35 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
this._pushAllSources();
|
|
|
|
|
if (fileToSelect)
|
2024-10-14 23:04:24 +02:00
|
|
|
this._recorderApp?.setRunningFile(fileToSelect);
|
2021-10-01 21:07:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private _pushAllSources() {
|
|
|
|
|
this._recorderApp?.setSources([...this._recorderSources, ...this._userSources.values()]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async onBeforeInputAction(sdkObject: SdkObject, metadata: CallMetadata) {
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-12 16:37:48 +01:00
|
|
|
async onCallLog(sdkObject: SdkObject, metadata: CallMetadata, logName: string, message: string): Promise<void> {
|
2021-10-01 21:07:35 +02:00
|
|
|
this.updateCallLog([metadata]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateCallLog(metadatas: CallMetadata[]) {
|
2023-11-15 00:17:42 +01:00
|
|
|
if (this._mode === 'recording' || this._mode === 'assertingText' || this._mode === 'assertingVisibility' || this._mode === 'assertingValue')
|
2021-10-01 21:07:35 +02:00
|
|
|
return;
|
|
|
|
|
const logs: CallLog[] = [];
|
|
|
|
|
for (const metadata of metadatas) {
|
2021-12-17 02:17:24 +01:00
|
|
|
if (!metadata.method || metadata.internal)
|
2021-10-01 21:07:35 +02:00
|
|
|
continue;
|
|
|
|
|
let status: CallLogStatus = 'done';
|
|
|
|
|
if (this._currentCallsMetadata.has(metadata))
|
|
|
|
|
status = 'in-progress';
|
|
|
|
|
if (this._debugger.isPaused(metadata))
|
|
|
|
|
status = 'paused';
|
|
|
|
|
logs.push(metadataToCallLog(metadata, status));
|
|
|
|
|
}
|
|
|
|
|
this._recorderApp?.updateCallLogs(logs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private _readSource(fileName: string): string {
|
|
|
|
|
try {
|
|
|
|
|
return fs.readFileSync(fileName, 'utf-8');
|
|
|
|
|
} catch (e) {
|
|
|
|
|
return '// No source available';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-27 23:10:21 +02:00
|
|
|
function isScreenshotCommand(metadata: CallMetadata) {
|
|
|
|
|
return metadata.method.toLowerCase().includes('screenshot');
|
2020-12-28 23:50:12 +01:00
|
|
|
}
|
2021-02-13 03:53:46 +01:00
|
|
|
|
|
|
|
|
function languageForFile(file: string) {
|
|
|
|
|
if (file.endsWith('.py'))
|
|
|
|
|
return 'python';
|
|
|
|
|
if (file.endsWith('.java'))
|
|
|
|
|
return 'java';
|
|
|
|
|
if (file.endsWith('.cs'))
|
|
|
|
|
return 'csharp';
|
|
|
|
|
return 'javascript';
|
2021-02-19 18:33:24 +01:00
|
|
|
}
|