123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700 |
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.Recorder = void 0;
- var fs = _interopRequireWildcard(require("fs"));
- var _codeGenerator = require("./recorder/codeGenerator");
- var _utils = require("./recorder/utils");
- var _page = require("./page");
- var _frames = require("./frames");
- var _browserContext = require("./browserContext");
- var _java = require("./recorder/java");
- var _javascript = require("./recorder/javascript");
- var _jsonl = require("./recorder/jsonl");
- var _csharp = require("./recorder/csharp");
- var _python = require("./recorder/python");
- var recorderSource = _interopRequireWildcard(require("../generated/recorderSource"));
- var consoleApiSource = _interopRequireWildcard(require("../generated/consoleApiSource"));
- var _recorderApp = require("./recorder/recorderApp");
- var _utils2 = require("../utils");
- var _recorderUtils = require("./recorder/recorderUtils");
- var _debugger = require("./debugger");
- var _events = require("events");
- var _timeoutRunner = require("../utils/timeoutRunner");
- var _locatorParser = require("../utils/isomorphic/locatorParser");
- var _stringUtils = require("../utils/isomorphic/stringUtils");
- var _eventsHelper = require("./../utils/eventsHelper");
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
- /**
- * 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.
- */
- const recorderSymbol = Symbol('recorderSymbol');
- class Recorder {
- static setAppFactory(recorderAppFactory) {
- Recorder.recorderAppFactory = recorderAppFactory;
- }
- static showInspector(context) {
- const params = {};
- if ((0, _utils2.isUnderTest)()) params.language = process.env.TEST_INSPECTOR_LANGUAGE;
- Recorder.show(context, params).catch(() => {});
- }
- static show(context, params = {}) {
- let recorderPromise = context[recorderSymbol];
- if (!recorderPromise) {
- const recorder = new Recorder(context, params);
- recorderPromise = recorder.install().then(() => recorder);
- context[recorderSymbol] = recorderPromise;
- }
- return recorderPromise;
- }
- constructor(context, params) {
- this._context = void 0;
- this._mode = void 0;
- this._highlightedSelector = '';
- this._overlayState = {
- offsetX: 0
- };
- this._recorderApp = null;
- this._currentCallsMetadata = new Map();
- this._recorderSources = [];
- this._userSources = new Map();
- this._debugger = void 0;
- this._contextRecorder = void 0;
- this._handleSIGINT = void 0;
- this._omitCallTracking = false;
- this._currentLanguage = void 0;
- this._mode = params.mode || 'none';
- this._contextRecorder = new ContextRecorder(context, params);
- this._context = context;
- this._omitCallTracking = !!params.omitCallTracking;
- this._debugger = context.debugger();
- this._handleSIGINT = params.handleSIGINT;
- context.instrumentation.addListener(this, context);
- this._currentLanguage = this._contextRecorder.languageName();
- if ((0, _utils2.isUnderTest)()) {
- // Most of our tests put elements at the top left, so get out of the way.
- this._overlayState.offsetX = 200;
- }
- }
- static async defaultRecorderAppFactory(recorder) {
- if (process.env.PW_CODEGEN_NO_INSPECTOR) return new _recorderApp.EmptyRecorderApp();
- return await _recorderApp.RecorderApp.open(recorder, recorder._context, recorder._handleSIGINT);
- }
- async install() {
- const recorderApp = await (Recorder.recorderAppFactory || Recorder.defaultRecorderAppFactory)(this);
- this._recorderApp = recorderApp;
- recorderApp.once('close', () => {
- this._debugger.resume(false);
- this._recorderApp = null;
- });
- recorderApp.on('event', data => {
- if (data.event === 'setMode') {
- this.setMode(data.params.mode);
- return;
- }
- if (data.event === 'selectorUpdated') {
- this.setHighlightedSelector(this._currentLanguage, data.params.selector);
- return;
- }
- if (data.event === 'step') {
- this._debugger.resume(true);
- return;
- }
- if (data.event === 'fileChanged') {
- this._currentLanguage = this._contextRecorder.languageName(data.params.file);
- this._refreshOverlay();
- return;
- }
- if (data.event === 'resume') {
- this._debugger.resume(false);
- return;
- }
- if (data.event === 'pause') {
- this._debugger.pauseOnNextStatement();
- return;
- }
- if (data.event === 'clear') {
- this._contextRecorder.clearScript();
- return;
- }
- });
- await Promise.all([recorderApp.setMode(this._mode), recorderApp.setPaused(this._debugger.isPaused()), this._pushAllSources()]);
- this._context.once(_browserContext.BrowserContext.Events.Close, () => {
- this._contextRecorder.dispose();
- this._context.instrumentation.removeListener(this);
- recorderApp.close().catch(() => {});
- });
- this._contextRecorder.on(ContextRecorder.Events.Change, data => {
- var _this$_recorderApp;
- this._recorderSources = data.sources;
- this._pushAllSources();
- (_this$_recorderApp = this._recorderApp) === null || _this$_recorderApp === void 0 ? void 0 : _this$_recorderApp.setFileIfNeeded(data.primaryFileName);
- });
- await this._context.exposeBinding('__pw_recorderState', false, source => {
- let actionSelector = '';
- let actionPoint;
- 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;
- }
- }
- }
- const uiState = {
- mode: this._mode,
- actionPoint,
- actionSelector,
- language: this._currentLanguage,
- testIdAttributeName: this._contextRecorder.testIdAttributeName(),
- overlay: this._overlayState
- };
- return uiState;
- });
- await this._context.exposeBinding('__pw_recorderSetSelector', false, async ({
- frame
- }, selector) => {
- var _this$_recorderApp2;
- const selectorPromises = [];
- let currentFrame = frame;
- while (currentFrame) {
- selectorPromises.push(findFrameSelector(currentFrame));
- currentFrame = currentFrame.parentFrame();
- }
- const fullSelector = (await Promise.all(selectorPromises)).filter(Boolean);
- fullSelector.push(selector);
- await ((_this$_recorderApp2 = this._recorderApp) === null || _this$_recorderApp2 === void 0 ? void 0 : _this$_recorderApp2.setSelector(fullSelector.join(' >> internal:control=enter-frame >> '), true));
- });
- await this._context.exposeBinding('__pw_recorderSetMode', false, async ({
- frame
- }, mode) => {
- if (frame.parentFrame()) return;
- this.setMode(mode);
- });
- await this._context.exposeBinding('__pw_recorderSetOverlayState', false, async ({
- frame
- }, state) => {
- if (frame.parentFrame()) return;
- this._overlayState = state;
- });
- await this._context.exposeBinding('__pw_resume', false, () => {
- this._debugger.resume(false);
- });
- await this._context.extendInjectedScript(consoleApiSource.source);
- await this._contextRecorder.install();
- if (this._debugger.isPaused()) this._pausedStateChanged();
- this._debugger.on(_debugger.Debugger.Events.PausedStateChanged, () => this._pausedStateChanged());
- this._context.recorderAppForTest = recorderApp;
- }
- _pausedStateChanged() {
- var _this$_recorderApp3;
- // If we are called upon page.pause, we don't have metadatas, populate them.
- for (const {
- metadata,
- sdkObject
- } of this._debugger.pausedDetails()) {
- if (!this._currentCallsMetadata.has(metadata)) this.onBeforeCall(sdkObject, metadata);
- }
- (_this$_recorderApp3 = this._recorderApp) === null || _this$_recorderApp3 === void 0 ? void 0 : _this$_recorderApp3.setPaused(this._debugger.isPaused());
- this._updateUserSources();
- this.updateCallLog([...this._currentCallsMetadata.keys()]);
- }
- setMode(mode) {
- var _this$_recorderApp4;
- if (this._mode === mode) return;
- this._highlightedSelector = '';
- this._mode = mode;
- (_this$_recorderApp4 = this._recorderApp) === null || _this$_recorderApp4 === void 0 ? void 0 : _this$_recorderApp4.setMode(this._mode);
- 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');
- if (this._mode !== 'none' && this._mode !== 'standby' && this._context.pages().length === 1) this._context.pages()[0].bringToFront().catch(() => {});
- this._refreshOverlay();
- }
- resume() {
- this._debugger.resume(false);
- }
- mode() {
- return this._mode;
- }
- setHighlightedSelector(language, selector) {
- this._highlightedSelector = (0, _locatorParser.locatorOrSelectorAsSelector)(language, selector, this._context.selectors().testIdAttributeName());
- this._refreshOverlay();
- }
- hideHighlightedSelector() {
- this._highlightedSelector = '';
- this._refreshOverlay();
- }
- setOutput(codegenId, outputFile) {
- this._contextRecorder.setOutput(codegenId, outputFile);
- }
- _refreshOverlay() {
- for (const page of this._context.pages()) page.mainFrame().evaluateExpression('window.__pw_refreshOverlay()').catch(() => {});
- }
- async onBeforeCall(sdkObject, metadata) {
- if (this._omitCallTracking || this._mode === 'recording' || this._mode === 'assertingText' || this._mode === 'assertingVisibility' || this._mode === 'assertingValue') return;
- this._currentCallsMetadata.set(metadata, sdkObject);
- this._updateUserSources();
- this.updateCallLog([metadata]);
- if (isScreenshotCommand(metadata)) {
- this.hideHighlightedSelector();
- } else if (metadata.params && metadata.params.selector) {
- var _this$_recorderApp5;
- this._highlightedSelector = metadata.params.selector;
- (_this$_recorderApp5 = this._recorderApp) === null || _this$_recorderApp5 === void 0 ? void 0 : _this$_recorderApp5.setSelector(this._highlightedSelector).catch(() => {});
- }
- }
- async onAfterCall(sdkObject, metadata) {
- if (this._omitCallTracking || this._mode === 'recording' || this._mode === 'assertingText' || this._mode === 'assertingVisibility' || this._mode === 'assertingValue') return;
- if (!metadata.error) this._currentCallsMetadata.delete(metadata);
- this._updateUserSources();
- this.updateCallLog([metadata]);
- }
- _updateUserSources() {
- var _this$_recorderApp6;
- // 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()) {
- if (!metadata.location) continue;
- const {
- file,
- line
- } = metadata.location;
- let source = this._userSources.get(file);
- if (!source) {
- source = {
- isRecorded: false,
- label: file,
- id: file,
- text: this._readSource(file),
- highlight: [],
- language: languageForFile(file)
- };
- 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;
- fileToSelect = source.id;
- }
- }
- this._pushAllSources();
- if (fileToSelect) (_this$_recorderApp6 = this._recorderApp) === null || _this$_recorderApp6 === void 0 ? void 0 : _this$_recorderApp6.setFileIfNeeded(fileToSelect);
- }
- _pushAllSources() {
- var _this$_recorderApp7;
- (_this$_recorderApp7 = this._recorderApp) === null || _this$_recorderApp7 === void 0 ? void 0 : _this$_recorderApp7.setSources([...this._recorderSources, ...this._userSources.values()]);
- }
- async onBeforeInputAction(sdkObject, metadata) {}
- async onCallLog(sdkObject, metadata, logName, message) {
- this.updateCallLog([metadata]);
- }
- updateCallLog(metadatas) {
- var _this$_recorderApp8;
- if (this._mode === 'recording' || this._mode === 'assertingText' || this._mode === 'assertingVisibility' || this._mode === 'assertingValue') return;
- const logs = [];
- for (const metadata of metadatas) {
- if (!metadata.method || metadata.internal) continue;
- let status = 'done';
- if (this._currentCallsMetadata.has(metadata)) status = 'in-progress';
- if (this._debugger.isPaused(metadata)) status = 'paused';
- logs.push((0, _recorderUtils.metadataToCallLog)(metadata, status));
- }
- (_this$_recorderApp8 = this._recorderApp) === null || _this$_recorderApp8 === void 0 ? void 0 : _this$_recorderApp8.updateCallLogs(logs);
- }
- _readSource(fileName) {
- try {
- return fs.readFileSync(fileName, 'utf-8');
- } catch (e) {
- return '// No source available';
- }
- }
- }
- exports.Recorder = Recorder;
- Recorder.recorderAppFactory = void 0;
- class ContextRecorder extends _events.EventEmitter {
- constructor(context, params) {
- super();
- this._generator = void 0;
- this._pageAliases = new Map();
- this._lastPopupOrdinal = 0;
- this._lastDialogOrdinal = -1;
- this._lastDownloadOrdinal = -1;
- this._timers = new Set();
- this._context = void 0;
- this._params = void 0;
- this._recorderSources = void 0;
- this._throttledOutputFile = null;
- this._orderedLanguages = [];
- this._listeners = [];
- this._context = context;
- this._params = params;
- this._recorderSources = [];
- const language = params.language || context.attribution.playwright.options.sdkLanguage;
- this.setOutput(language, params.outputFile);
- const generator = new _codeGenerator.CodeGenerator(context._browser.options.name, params.mode === 'recording', params.launchOptions || {}, params.contextOptions || {}, params.device, params.saveStorage);
- generator.on('change', () => {
- this._recorderSources = [];
- for (const languageGenerator of this._orderedLanguages) {
- var _this$_throttledOutpu;
- const {
- header,
- footer,
- actions,
- text
- } = generator.generateStructure(languageGenerator);
- const source = {
- isRecorded: true,
- label: languageGenerator.name,
- group: languageGenerator.groupName,
- id: languageGenerator.id,
- text,
- header,
- footer,
- actions,
- language: languageGenerator.highlighter,
- highlight: []
- };
- source.revealLine = text.split('\n').length - 1;
- this._recorderSources.push(source);
- if (languageGenerator === this._orderedLanguages[0]) (_this$_throttledOutpu = this._throttledOutputFile) === null || _this$_throttledOutpu === void 0 ? void 0 : _this$_throttledOutpu.setContent(source.text);
- }
- this.emit(ContextRecorder.Events.Change, {
- sources: this._recorderSources,
- primaryFileName: this._orderedLanguages[0].id
- });
- });
- context.on(_browserContext.BrowserContext.Events.BeforeClose, () => {
- var _this$_throttledOutpu2;
- (_this$_throttledOutpu2 = this._throttledOutputFile) === null || _this$_throttledOutpu2 === void 0 ? void 0 : _this$_throttledOutpu2.flush();
- });
- this._listeners.push(_eventsHelper.eventsHelper.addEventListener(process, 'exit', () => {
- var _this$_throttledOutpu3;
- (_this$_throttledOutpu3 = this._throttledOutputFile) === null || _this$_throttledOutpu3 === void 0 ? void 0 : _this$_throttledOutpu3.flush();
- }));
- this._generator = generator;
- }
- setOutput(codegenId, outputFile) {
- var _this$_generator;
- const languages = new Set([new _java.JavaLanguageGenerator(), new _javascript.JavaScriptLanguageGenerator( /* isPlaywrightTest */false), new _javascript.JavaScriptLanguageGenerator( /* isPlaywrightTest */true), new _python.PythonLanguageGenerator( /* isAsync */false, /* isPytest */true), new _python.PythonLanguageGenerator( /* isAsync */false, /* isPytest */false), new _python.PythonLanguageGenerator( /* isAsync */true, /* isPytest */false), new _csharp.CSharpLanguageGenerator('mstest'), new _csharp.CSharpLanguageGenerator('nunit'), new _csharp.CSharpLanguageGenerator('library'), new _jsonl.JsonlLanguageGenerator()]);
- const primaryLanguage = [...languages].find(l => l.id === codegenId);
- if (!primaryLanguage) throw new Error(`\n===============================\nUnsupported language: '${codegenId}'\n===============================\n`);
- languages.delete(primaryLanguage);
- this._orderedLanguages = [primaryLanguage, ...languages];
- this._throttledOutputFile = outputFile ? new ThrottledFile(outputFile) : null;
- (_this$_generator = this._generator) === null || _this$_generator === void 0 ? void 0 : _this$_generator.restart();
- }
- languageName(id) {
- for (const lang of this._orderedLanguages) {
- if (!id || lang.id === id) return lang.highlighter;
- }
- return 'javascript';
- }
- async install() {
- this._context.on(_browserContext.BrowserContext.Events.Page, page => this._onPage(page));
- for (const page of this._context.pages()) this._onPage(page);
- this._context.on(_browserContext.BrowserContext.Events.Dialog, dialog => this._onDialog(dialog.page()));
- // Input actions that potentially lead to navigation are intercepted on the page and are
- // performed by the Playwright.
- await this._context.exposeBinding('__pw_recorderPerformAction', false, (source, action) => this._performAction(source.frame, action));
- // Other non-essential actions are simply being recorded.
- await this._context.exposeBinding('__pw_recorderRecordAction', false, (source, action) => this._recordAction(source.frame, action));
- await this._context.extendInjectedScript(recorderSource.source);
- }
- setEnabled(enabled) {
- this._generator.setEnabled(enabled);
- }
- dispose() {
- for (const timer of this._timers) clearTimeout(timer);
- this._timers.clear();
- _eventsHelper.eventsHelper.removeEventListeners(this._listeners);
- }
- async _onPage(page) {
- // First page is called page, others are called popup1, popup2, etc.
- const frame = page.mainFrame();
- page.on('close', () => {
- this._generator.addAction({
- frame: this._describeMainFrame(page),
- committed: true,
- action: {
- name: 'closePage',
- signals: []
- }
- });
- this._pageAliases.delete(page);
- });
- frame.on(_frames.Frame.Events.InternalNavigation, event => {
- if (event.isPublic) this._onFrameNavigated(frame, page);
- });
- page.on(_page.Page.Events.Download, () => this._onDownload(page));
- const suffix = this._pageAliases.size ? String(++this._lastPopupOrdinal) : '';
- const pageAlias = 'page' + suffix;
- this._pageAliases.set(page, pageAlias);
- if (page.opener()) {
- this._onPopup(page.opener(), page);
- } else {
- this._generator.addAction({
- frame: this._describeMainFrame(page),
- committed: true,
- action: {
- name: 'openPage',
- url: page.mainFrame().url(),
- signals: []
- }
- });
- }
- }
- clearScript() {
- this._generator.restart();
- if (this._params.mode === 'recording') {
- for (const page of this._context.pages()) this._onFrameNavigated(page.mainFrame(), page);
- }
- }
- _describeMainFrame(page) {
- return {
- pageAlias: this._pageAliases.get(page),
- isMainFrame: true
- };
- }
- async _describeFrame(frame) {
- const page = frame._page;
- const pageAlias = this._pageAliases.get(page);
- const chain = [];
- for (let ancestor = frame; ancestor; ancestor = ancestor.parentFrame()) chain.push(ancestor);
- chain.reverse();
- if (chain.length === 1) return this._describeMainFrame(page);
- const selectorPromises = [];
- for (let i = 0; i < chain.length - 1; i++) selectorPromises.push(findFrameSelector(chain[i + 1]));
- const result = await (0, _timeoutRunner.raceAgainstDeadline)(() => Promise.all(selectorPromises), (0, _utils2.monotonicTime)() + 2000);
- if (!result.timedOut && result.result.every(selector => !!selector)) {
- return {
- pageAlias,
- isMainFrame: false,
- selectorsChain: result.result
- };
- }
- // Best effort to find a selector for the frame.
- const selectorsChain = [];
- for (let i = 0; i < chain.length - 1; i++) {
- if (chain[i].name()) selectorsChain.push(`iframe[name=${(0, _stringUtils.quoteCSSAttributeValue)(chain[i].name())}]`);else selectorsChain.push(`iframe[src=${(0, _stringUtils.quoteCSSAttributeValue)(chain[i].url())}]`);
- }
- return {
- pageAlias,
- isMainFrame: false,
- selectorsChain
- };
- }
- testIdAttributeName() {
- return this._params.testIdAttributeName || this._context.selectors().testIdAttributeName() || 'data-testid';
- }
- async _performAction(frame, action) {
- // Commit last action so that no further signals are added to it.
- this._generator.commitLastAction();
- const frameDescription = await this._describeFrame(frame);
- const actionInContext = {
- frame: frameDescription,
- action
- };
- const perform = async (action, params, cb) => {
- const callMetadata = {
- id: `call@${(0, _utils2.createGuid)()}`,
- apiName: 'frame.' + action,
- objectId: frame.guid,
- pageId: frame._page.guid,
- frameId: frame.guid,
- startTime: (0, _utils2.monotonicTime)(),
- endTime: 0,
- wallTime: Date.now(),
- type: 'Frame',
- method: action,
- params,
- log: []
- };
- this._generator.willPerformAction(actionInContext);
- try {
- await frame.instrumentation.onBeforeCall(frame, callMetadata);
- await cb(callMetadata);
- } catch (e) {
- callMetadata.endTime = (0, _utils2.monotonicTime)();
- await frame.instrumentation.onAfterCall(frame, callMetadata);
- this._generator.performedActionFailed(actionInContext);
- return;
- }
- callMetadata.endTime = (0, _utils2.monotonicTime)();
- await frame.instrumentation.onAfterCall(frame, callMetadata);
- const timer = setTimeout(() => {
- // Commit the action after 5 seconds so that no further signals are added to it.
- actionInContext.committed = true;
- this._timers.delete(timer);
- }, 5000);
- this._generator.didPerformAction(actionInContext);
- this._timers.add(timer);
- };
- const kActionTimeout = 5000;
- if (action.name === 'click') {
- const {
- options
- } = (0, _utils.toClickOptions)(action);
- await perform('click', {
- selector: action.selector
- }, callMetadata => frame.click(callMetadata, action.selector, {
- ...options,
- timeout: kActionTimeout,
- strict: true
- }));
- }
- if (action.name === 'press') {
- const modifiers = (0, _utils.toModifiers)(action.modifiers);
- const shortcut = [...modifiers, action.key].join('+');
- await perform('press', {
- selector: action.selector,
- key: shortcut
- }, callMetadata => frame.press(callMetadata, action.selector, shortcut, {
- timeout: kActionTimeout,
- strict: true
- }));
- }
- if (action.name === 'check') await perform('check', {
- selector: action.selector
- }, callMetadata => frame.check(callMetadata, action.selector, {
- timeout: kActionTimeout,
- strict: true
- }));
- if (action.name === 'uncheck') await perform('uncheck', {
- selector: action.selector
- }, callMetadata => frame.uncheck(callMetadata, action.selector, {
- timeout: kActionTimeout,
- strict: true
- }));
- if (action.name === 'select') {
- const values = action.options.map(value => ({
- value
- }));
- await perform('selectOption', {
- selector: action.selector,
- values
- }, callMetadata => frame.selectOption(callMetadata, action.selector, [], values, {
- timeout: kActionTimeout,
- strict: true
- }));
- }
- }
- async _recordAction(frame, action) {
- // Commit last action so that no further signals are added to it.
- this._generator.commitLastAction();
- const frameDescription = await this._describeFrame(frame);
- const actionInContext = {
- frame: frameDescription,
- action
- };
- this._generator.addAction(actionInContext);
- }
- _onFrameNavigated(frame, page) {
- const pageAlias = this._pageAliases.get(page);
- this._generator.signal(pageAlias, frame, {
- name: 'navigation',
- url: frame.url()
- });
- }
- _onPopup(page, popup) {
- const pageAlias = this._pageAliases.get(page);
- const popupAlias = this._pageAliases.get(popup);
- this._generator.signal(pageAlias, page.mainFrame(), {
- name: 'popup',
- popupAlias
- });
- }
- _onDownload(page) {
- const pageAlias = this._pageAliases.get(page);
- ++this._lastDownloadOrdinal;
- this._generator.signal(pageAlias, page.mainFrame(), {
- name: 'download',
- downloadAlias: this._lastDownloadOrdinal ? String(this._lastDownloadOrdinal) : ''
- });
- }
- _onDialog(page) {
- const pageAlias = this._pageAliases.get(page);
- ++this._lastDialogOrdinal;
- this._generator.signal(pageAlias, page.mainFrame(), {
- name: 'dialog',
- dialogAlias: this._lastDialogOrdinal ? String(this._lastDialogOrdinal) : ''
- });
- }
- }
- ContextRecorder.Events = {
- Change: 'change'
- };
- function languageForFile(file) {
- if (file.endsWith('.py')) return 'python';
- if (file.endsWith('.java')) return 'java';
- if (file.endsWith('.cs')) return 'csharp';
- return 'javascript';
- }
- class ThrottledFile {
- constructor(file) {
- this._file = void 0;
- this._timer = void 0;
- this._text = void 0;
- this._file = file;
- }
- setContent(text) {
- this._text = text;
- if (!this._timer) this._timer = setTimeout(() => this.flush(), 250);
- }
- flush() {
- if (this._timer) {
- clearTimeout(this._timer);
- this._timer = undefined;
- }
- if (this._text) fs.writeFileSync(this._file, this._text);
- this._text = undefined;
- }
- }
- function isScreenshotCommand(metadata) {
- return metadata.method.toLowerCase().includes('screenshot');
- }
- async function findFrameSelector(frame) {
- try {
- const parent = frame.parentFrame();
- const frameElement = await frame.frameElement();
- if (!frameElement || !parent) return;
- const utility = await parent._utilityContext();
- const injected = await utility.injectedScript();
- const selector = await injected.evaluate((injected, element) => {
- return injected.generateSelector(element, {
- testIdAttributeName: '',
- omitInternalEngines: true
- });
- }, frameElement);
- return selector;
- } catch (e) {}
- }
|