@memlab/e2e 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/dist/BaseSynthesizer.d.ts +63 -0
- package/dist/BaseSynthesizer.d.ts.map +1 -0
- package/dist/BaseSynthesizer.js +433 -0
- package/dist/E2EInteractionManager.d.ts +41 -0
- package/dist/E2EInteractionManager.d.ts.map +1 -0
- package/dist/E2EInteractionManager.js +347 -0
- package/dist/TestRunnerLoader.d.ts +16 -0
- package/dist/TestRunnerLoader.d.ts.map +1 -0
- package/dist/TestRunnerLoader.js +41 -0
- package/dist/TypesThirdParty.d.ts +25 -0
- package/dist/TypesThirdParty.d.ts.map +1 -0
- package/dist/TypesThirdParty.js +10 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/lib/E2EUtils.d.ts +59 -0
- package/dist/lib/E2EUtils.d.ts.map +1 -0
- package/dist/lib/E2EUtils.js +286 -0
- package/dist/lib/SynthesisUtils.d.ts +25 -0
- package/dist/lib/SynthesisUtils.d.ts.map +1 -0
- package/dist/lib/SynthesisUtils.js +30 -0
- package/dist/lib/operations/BackOperation.d.ts +17 -0
- package/dist/lib/operations/BackOperation.d.ts.map +1 -0
- package/dist/lib/operations/BackOperation.js +37 -0
- package/dist/lib/operations/BackspaceOperation.d.ts +18 -0
- package/dist/lib/operations/BackspaceOperation.d.ts.map +1 -0
- package/dist/lib/operations/BackspaceOperation.js +36 -0
- package/dist/lib/operations/BaseOperation.d.ts +22 -0
- package/dist/lib/operations/BaseOperation.d.ts.map +1 -0
- package/dist/lib/operations/BaseOperation.js +67 -0
- package/dist/lib/operations/CachePageContent.d.ts +22 -0
- package/dist/lib/operations/CachePageContent.d.ts.map +1 -0
- package/dist/lib/operations/CachePageContent.js +46 -0
- package/dist/lib/operations/ClickOperation.d.ts +36 -0
- package/dist/lib/operations/ClickOperation.d.ts.map +1 -0
- package/dist/lib/operations/ClickOperation.js +131 -0
- package/dist/lib/operations/CompoundOperation.d.ts +20 -0
- package/dist/lib/operations/CompoundOperation.d.ts.map +1 -0
- package/dist/lib/operations/CompoundOperation.js +39 -0
- package/dist/lib/operations/EnterOperation.d.ts +18 -0
- package/dist/lib/operations/EnterOperation.d.ts.map +1 -0
- package/dist/lib/operations/EnterOperation.js +36 -0
- package/dist/lib/operations/EscOperation.d.ts +17 -0
- package/dist/lib/operations/EscOperation.d.ts.map +1 -0
- package/dist/lib/operations/EscOperation.js +36 -0
- package/dist/lib/operations/HoverOperation.d.ts +28 -0
- package/dist/lib/operations/HoverOperation.d.ts.map +1 -0
- package/dist/lib/operations/HoverOperation.js +73 -0
- package/dist/lib/operations/InteractionUtils.d.ts +33 -0
- package/dist/lib/operations/InteractionUtils.d.ts.map +1 -0
- package/dist/lib/operations/InteractionUtils.js +207 -0
- package/dist/lib/operations/Operations.d.ts +25 -0
- package/dist/lib/operations/Operations.d.ts.map +1 -0
- package/dist/lib/operations/Operations.js +45 -0
- package/dist/lib/operations/RevertOperation.d.ts +18 -0
- package/dist/lib/operations/RevertOperation.d.ts.map +1 -0
- package/dist/lib/operations/RevertOperation.js +55 -0
- package/dist/lib/operations/RunJSCode.d.ts +25 -0
- package/dist/lib/operations/RunJSCode.d.ts.map +1 -0
- package/dist/lib/operations/RunJSCode.js +51 -0
- package/dist/lib/operations/ScrollOperation.d.ts +27 -0
- package/dist/lib/operations/ScrollOperation.d.ts.map +1 -0
- package/dist/lib/operations/ScrollOperation.js +85 -0
- package/dist/lib/operations/TargetExtraOperation.d.ts +18 -0
- package/dist/lib/operations/TargetExtraOperation.d.ts.map +1 -0
- package/dist/lib/operations/TargetExtraOperation.js +28 -0
- package/dist/lib/operations/TestPlanner.d.ts +46 -0
- package/dist/lib/operations/TestPlanner.d.ts.map +1 -0
- package/dist/lib/operations/TestPlanner.js +182 -0
- package/dist/lib/operations/TypeOperation.d.ts +29 -0
- package/dist/lib/operations/TypeOperation.d.ts.map +1 -0
- package/dist/lib/operations/TypeOperation.js +64 -0
- package/dist/lib/operations/UploadOperation.d.ts +25 -0
- package/dist/lib/operations/UploadOperation.d.ts.map +1 -0
- package/dist/lib/operations/UploadOperation.js +56 -0
- package/dist/lib/operations/WaitForElementOperation.d.ts +32 -0
- package/dist/lib/operations/WaitForElementOperation.d.ts.map +1 -0
- package/dist/lib/operations/WaitForElementOperation.js +67 -0
- package/dist/lib/operations/WaitOperation.d.ts +19 -0
- package/dist/lib/operations/WaitOperation.d.ts.map +1 -0
- package/dist/lib/operations/WaitOperation.js +42 -0
- package/dist/lib/operations/WithCachedPageContent.d.ts +26 -0
- package/dist/lib/operations/WithCachedPageContent.d.ts.map +1 -0
- package/dist/lib/operations/WithCachedPageContent.js +53 -0
- package/dist/lib/operations/XVirtualFrameBuffer.d.ts +15 -0
- package/dist/lib/operations/XVirtualFrameBuffer.d.ts.map +1 -0
- package/dist/lib/operations/XVirtualFrameBuffer.js +44 -0
- package/dist/plugins/DefaultScenarioSynthesizer.d.ts +23 -0
- package/dist/plugins/DefaultScenarioSynthesizer.d.ts.map +1 -0
- package/dist/plugins/DefaultScenarioSynthesizer.js +61 -0
- package/dist/plugins/TestSPAVisitSynthesizer.d.ts +23 -0
- package/dist/plugins/TestSPAVisitSynthesizer.d.ts.map +1 -0
- package/dist/plugins/TestSPAVisitSynthesizer.js +72 -0
- package/dist/plugins/scenarios/test-airbnb.d.ts +14 -0
- package/dist/plugins/scenarios/test-airbnb.d.ts.map +1 -0
- package/dist/plugins/scenarios/test-airbnb.js +48 -0
- package/dist/plugins/scenarios/test-databricks.d.ts +14 -0
- package/dist/plugins/scenarios/test-databricks.d.ts.map +1 -0
- package/dist/plugins/scenarios/test-databricks.js +40 -0
- package/dist/plugins/scenarios/test-ebay.d.ts +14 -0
- package/dist/plugins/scenarios/test-ebay.d.ts.map +1 -0
- package/dist/plugins/scenarios/test-ebay.js +48 -0
- package/dist/plugins/scenarios/test-google-maps.d.ts +14 -0
- package/dist/plugins/scenarios/test-google-maps.d.ts.map +1 -0
- package/dist/plugins/scenarios/test-google-maps.js +41 -0
- package/dist/plugins/scenarios/test-shopify.d.ts +14 -0
- package/dist/plugins/scenarios/test-shopify.d.ts.map +1 -0
- package/dist/plugins/scenarios/test-shopify.js +40 -0
- package/dist/plugins/scenarios/test-youtube.d.ts +14 -0
- package/dist/plugins/scenarios/test-youtube.d.ts.map +1 -0
- package/dist/plugins/scenarios/test-youtube.js +40 -0
- package/package.json +53 -0
- package/static/links/index.html +18 -0
- package/static/links/min.js +3 -0
- package/static/links/package.json +36 -0
- package/static/links/src/App.js +48 -0
- package/static/links/src/index.js +20 -0
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @lightSyntaxTransform
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
import type { AnyOptions, Config, E2EOperation, E2EStepInfo, IE2EScenarioVisitPlan, E2ESynthesizerOptions, IScenario, IE2EStepBasic, IE2EScenarioSynthesizer, CheckPageLoadCallback, Nullable } from '@memlab/core';
|
|
12
|
+
declare class BaseSynthesizer implements IE2EScenarioSynthesizer {
|
|
13
|
+
protected config: Config;
|
|
14
|
+
protected steps: Map<string, IE2EStepBasic>;
|
|
15
|
+
private _repeatIntermediate;
|
|
16
|
+
protected plans: Map<string, IE2EScenarioVisitPlan>;
|
|
17
|
+
constructor(config: Config);
|
|
18
|
+
private injectBuiltInSteps;
|
|
19
|
+
private repeatIntermediate;
|
|
20
|
+
protected init(): void;
|
|
21
|
+
protected postInit(): void;
|
|
22
|
+
getAppName(): string;
|
|
23
|
+
getOrigin(): Nullable<string>;
|
|
24
|
+
getDomain(): string;
|
|
25
|
+
getDomainPrefixes(): string[];
|
|
26
|
+
getCookieFile(_visitPlan: IE2EScenarioVisitPlan): string | null;
|
|
27
|
+
getAvailableSteps(): IE2EStepBasic[];
|
|
28
|
+
getNodeNameBlocklist(): string[];
|
|
29
|
+
getEdgeNameBlocklist(): string[];
|
|
30
|
+
getDefaultStartStepName(): string;
|
|
31
|
+
injectPlan(stepName: string, scenario: IScenario): void;
|
|
32
|
+
synthesisForTarget(stepName: string): IE2EScenarioVisitPlan;
|
|
33
|
+
getAvailableVisitPlans(): IE2EScenarioVisitPlan[];
|
|
34
|
+
getAvailableTargetNames(opt?: AnyOptions & {
|
|
35
|
+
filterCb?: (node: IE2EScenarioVisitPlan) => boolean;
|
|
36
|
+
}): string[];
|
|
37
|
+
getNumberOfWarmup(): number;
|
|
38
|
+
getBaseURL(_options?: AnyOptions): string;
|
|
39
|
+
private getNormalizedBaseURL;
|
|
40
|
+
getURLParameters(_options?: AnyOptions): string;
|
|
41
|
+
getDevice(): string;
|
|
42
|
+
getExtraOperationsForStep(_stepInfo: E2EStepInfo): E2EOperation[];
|
|
43
|
+
getPageLoadChecker(): CheckPageLoadCallback;
|
|
44
|
+
synthesis(baseline: string, target: string, intermediates: string[], options?: E2ESynthesizerOptions): IE2EScenarioVisitPlan;
|
|
45
|
+
private getActualNumberOfWarmup;
|
|
46
|
+
private synthesisInitPart;
|
|
47
|
+
private synthesisFinalPart;
|
|
48
|
+
private synthesisRepeat;
|
|
49
|
+
private synthesisStandard;
|
|
50
|
+
private processStepUrl;
|
|
51
|
+
private synthesisForScenario;
|
|
52
|
+
private synthesisSimple;
|
|
53
|
+
private synthesisInitialPageLoad;
|
|
54
|
+
private getActionFromStep;
|
|
55
|
+
private getAction;
|
|
56
|
+
protected shouldTakeSnapshot(option: AnyOptions & {
|
|
57
|
+
type?: string;
|
|
58
|
+
}): boolean;
|
|
59
|
+
protected shouldTakeScreenshot(_option: AnyOptions): boolean;
|
|
60
|
+
private fillInInfo;
|
|
61
|
+
}
|
|
62
|
+
export default BaseSynthesizer;
|
|
63
|
+
//# sourceMappingURL=BaseSynthesizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseSynthesizer.d.ts","sourceRoot":"","sources":["../src/BaseSynthesizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EACV,UAAU,EACV,MAAM,EACN,YAAY,EACZ,WAAW,EACX,qBAAqB,EACrB,qBAAqB,EACrB,SAAS,EACT,aAAa,EAEb,uBAAuB,EACvB,qBAAqB,EACrB,QAAQ,EACT,MAAM,cAAc,CAAC;AAWtB,cAAM,eAAgB,YAAW,uBAAuB;IACtD,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC5C,OAAO,CAAC,mBAAmB,CAAS;IACpC,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;gBAExC,MAAM,EAAE,MAAM;IAkB1B,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,kBAAkB;IAI1B,SAAS,CAAC,IAAI,IAAI,IAAI;IAItB,SAAS,CAAC,QAAQ,IAAI,IAAI;IAI1B,UAAU,IAAI,MAAM;IAMpB,SAAS,IAAI,QAAQ,CAAC,MAAM,CAAC;IAW7B,SAAS,IAAI,MAAM;IAMnB,iBAAiB,IAAI,MAAM,EAAE;IAK7B,aAAa,CAAC,UAAU,EAAE,qBAAqB,GAAG,MAAM,GAAG,IAAI;IAM/D,iBAAiB,IAAI,aAAa,EAAE;IAQpC,oBAAoB,IAAI,MAAM,EAAE;IAIhC,oBAAoB,IAAI,MAAM,EAAE;IAIhC,uBAAuB,IAAI,MAAM;IAQjC,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,GAAG,IAAI;IAKvD,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,qBAAqB;IAQ3D,sBAAsB,IAAI,qBAAqB,EAAE;IAQjD,uBAAuB,CACrB,GAAG,GAAE,UAAU,GAAG;QAChB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,qBAAqB,KAAK,OAAO,CAAC;KAChD,GACL,MAAM,EAAE;IAUX,iBAAiB,IAAI,MAAM;IAM3B,UAAU,CAAC,QAAQ,GAAE,UAAe;IAIpC,OAAO,CAAC,oBAAoB;IAO5B,gBAAgB,CAAC,QAAQ,GAAE,UAAe;IAM1C,SAAS,IAAI,MAAM;IAMnB,yBAAyB,CAAC,SAAS,EAAE,WAAW,GAAG,YAAY,EAAE;IAKjE,kBAAkB,IAAI,qBAAqB;IAQ3C,SAAS,CACP,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EAAE,EACvB,OAAO,GAAE,qBAA0B,GAClC,qBAAqB;IAiBxB,OAAO,CAAC,uBAAuB;IAI/B,OAAO,CAAC,iBAAiB;IA6BzB,OAAO,CAAC,kBAAkB;IA2B1B,OAAO,CAAC,eAAe;IAkDvB,OAAO,CAAC,iBAAiB;IA6BzB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,oBAAoB;IAyD5B,OAAO,CAAC,eAAe;IA2BvB,OAAO,CAAC,wBAAwB;IAuChC,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,SAAS;IAcjB,SAAS,CAAC,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAC,GAAG,OAAO;IAO3E,SAAS,CAAC,oBAAoB,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO;IAI5D,OAAO,CAAC,UAAU;CAoCnB;AAED,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const core_1 = require("@memlab/core");
|
|
16
|
+
const SynthesisUtils_1 = __importDefault(require("./lib/SynthesisUtils"));
|
|
17
|
+
const InteractionUtils_1 = __importDefault(require("./lib/operations/InteractionUtils"));
|
|
18
|
+
const E2EUtils_1 = __importDefault(require("./lib/E2EUtils"));
|
|
19
|
+
// for debugging only
|
|
20
|
+
const skipAllScreenshot = false;
|
|
21
|
+
class BaseSynthesizer {
|
|
22
|
+
constructor(config) {
|
|
23
|
+
this.config = config;
|
|
24
|
+
this.init();
|
|
25
|
+
this.postInit();
|
|
26
|
+
// define steps
|
|
27
|
+
this.steps = new Map();
|
|
28
|
+
for (const step of this.getAvailableSteps()) {
|
|
29
|
+
this.steps.set(step.name, step);
|
|
30
|
+
}
|
|
31
|
+
this.injectBuiltInSteps();
|
|
32
|
+
this._repeatIntermediate = 1;
|
|
33
|
+
// define visit plans
|
|
34
|
+
this.plans = new Map();
|
|
35
|
+
for (const plan of this.getAvailableVisitPlans()) {
|
|
36
|
+
this.plans.set(plan.name, plan);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
injectBuiltInSteps() {
|
|
40
|
+
const backStep = SynthesisUtils_1.default.backStep;
|
|
41
|
+
this.steps.set(backStep.name, backStep);
|
|
42
|
+
const revertStep = SynthesisUtils_1.default.revertStep;
|
|
43
|
+
this.steps.set(revertStep.name, revertStep);
|
|
44
|
+
}
|
|
45
|
+
repeatIntermediate(n) {
|
|
46
|
+
this._repeatIntermediate = n;
|
|
47
|
+
}
|
|
48
|
+
init() {
|
|
49
|
+
this.repeatIntermediate(this.config.repeatIntermediateTabs);
|
|
50
|
+
}
|
|
51
|
+
postInit() {
|
|
52
|
+
// for overriding
|
|
53
|
+
}
|
|
54
|
+
getAppName() {
|
|
55
|
+
const error = new Error('BaseSynthesizer.getAppName is not implemented');
|
|
56
|
+
error.stack;
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
getOrigin() {
|
|
60
|
+
const domain = this.getDomain();
|
|
61
|
+
if (domain === '' || domain == null) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
if (domain.startsWith('.')) {
|
|
65
|
+
return `https://${domain.substring(1)}`;
|
|
66
|
+
}
|
|
67
|
+
return `https://${domain}`;
|
|
68
|
+
}
|
|
69
|
+
getDomain() {
|
|
70
|
+
const error = new Error('BaseSynthesizer.getDomain is not implemented');
|
|
71
|
+
error.stack;
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
getDomainPrefixes() {
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
78
|
+
getCookieFile(_visitPlan) {
|
|
79
|
+
const error = new Error('BaseSynthesizer.getCookieFile is not implemented');
|
|
80
|
+
error.stack;
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
getAvailableSteps() {
|
|
84
|
+
const error = new Error('BaseSynthesizer.getAvailableSteps is not implemented');
|
|
85
|
+
error.stack;
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
getNodeNameBlocklist() {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
getEdgeNameBlocklist() {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
getDefaultStartStepName() {
|
|
95
|
+
const error = new Error('BaseSynthesizer.getDefaultStartStepName is not implemented');
|
|
96
|
+
error.stack;
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
injectPlan(stepName, scenario) {
|
|
100
|
+
this.plans.set(stepName, this.synthesisForScenario(scenario));
|
|
101
|
+
}
|
|
102
|
+
// given a target step name, returns the visit order sequence
|
|
103
|
+
synthesisForTarget(stepName) {
|
|
104
|
+
if (!this.plans.has(stepName)) {
|
|
105
|
+
core_1.utils.haltOrThrow(`target ${stepName} is unknown to synthesizers`);
|
|
106
|
+
}
|
|
107
|
+
return this.plans.get(stepName);
|
|
108
|
+
}
|
|
109
|
+
// return a list of visit plans for the target app
|
|
110
|
+
getAvailableVisitPlans() {
|
|
111
|
+
const error = new Error('BaseSynthesizer.getAvailableVisitPlans is not implemented');
|
|
112
|
+
error.stack;
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
getAvailableTargetNames(opt = {}) {
|
|
116
|
+
const filterCb = opt.filterCb;
|
|
117
|
+
let plans = Array.from(this.plans.values());
|
|
118
|
+
if (filterCb) {
|
|
119
|
+
plans = plans.filter(filterCb);
|
|
120
|
+
}
|
|
121
|
+
return plans.map(plan => plan.name);
|
|
122
|
+
}
|
|
123
|
+
// get the default number of warmups
|
|
124
|
+
getNumberOfWarmup() {
|
|
125
|
+
return 1;
|
|
126
|
+
}
|
|
127
|
+
// get the URL of the target app
|
|
128
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/explicit-module-boundary-types
|
|
129
|
+
getBaseURL(_options = {}) {
|
|
130
|
+
return 'https://www.facebook.com';
|
|
131
|
+
}
|
|
132
|
+
getNormalizedBaseURL(options = {}) {
|
|
133
|
+
const url = core_1.utils.normalizeBaseUrl(this.getBaseURL(options));
|
|
134
|
+
return url;
|
|
135
|
+
}
|
|
136
|
+
// get URL parameters
|
|
137
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/explicit-module-boundary-types
|
|
138
|
+
getURLParameters(_options = {}) {
|
|
139
|
+
return '';
|
|
140
|
+
}
|
|
141
|
+
// get default (mobile) device name
|
|
142
|
+
// if nothing specified, it's considered running in desktop / laptop
|
|
143
|
+
getDevice() {
|
|
144
|
+
return 'pc';
|
|
145
|
+
}
|
|
146
|
+
// append additional interactions based on step info
|
|
147
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
148
|
+
getExtraOperationsForStep(_stepInfo) {
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
// get default callback for checking page load
|
|
152
|
+
getPageLoadChecker() {
|
|
153
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
154
|
+
return (_page) => __awaiter(this, void 0, void 0, function* () {
|
|
155
|
+
yield InteractionUtils_1.default.waitFor(this.config.delayWhenNoPageLoadCheck);
|
|
156
|
+
return true;
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
synthesis(baseline, target, intermediates, options = {}) {
|
|
160
|
+
const type = options.type;
|
|
161
|
+
if (!type || type === 'standard') {
|
|
162
|
+
return this.synthesisStandard(baseline, target, intermediates, options);
|
|
163
|
+
}
|
|
164
|
+
if (type === 'simple') {
|
|
165
|
+
return this.synthesisSimple(baseline, target, options);
|
|
166
|
+
}
|
|
167
|
+
if (type === 'repeat') {
|
|
168
|
+
return this.synthesisRepeat(baseline, target, intermediates, options);
|
|
169
|
+
}
|
|
170
|
+
if (type === 'init-page-load') {
|
|
171
|
+
return this.synthesisInitialPageLoad(target, intermediates, options);
|
|
172
|
+
}
|
|
173
|
+
throw core_1.utils.haltOrThrow(`unknown visit plan type: ${type}`);
|
|
174
|
+
}
|
|
175
|
+
getActualNumberOfWarmup() {
|
|
176
|
+
return this.getNumberOfWarmup() + (this.config.isContinuousTest ? 1 : 0);
|
|
177
|
+
}
|
|
178
|
+
synthesisInitPart(baseline, target, options) {
|
|
179
|
+
// default start from the home tab
|
|
180
|
+
const start = options.start || this.getDefaultStartStepName();
|
|
181
|
+
const visitOrder = [];
|
|
182
|
+
// first visit the start step
|
|
183
|
+
visitOrder.push(this.getAction(start, 'init'));
|
|
184
|
+
// if provided, some initial setup to prepare states or data
|
|
185
|
+
if (options.setupSteps) {
|
|
186
|
+
for (const stepName of options.setupSteps) {
|
|
187
|
+
visitOrder.push(this.getAction(stepName));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// if provided, warm up with specified steps
|
|
191
|
+
if (options.warmupSteps) {
|
|
192
|
+
for (const stepName of options.warmupSteps) {
|
|
193
|
+
visitOrder.push(this.getAction(stepName));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
// by default, warm up the baseline and target onces
|
|
198
|
+
visitOrder.push(this.getAction(baseline));
|
|
199
|
+
visitOrder.push(this.getAction(target));
|
|
200
|
+
}
|
|
201
|
+
return visitOrder;
|
|
202
|
+
}
|
|
203
|
+
synthesisFinalPart(visitOrder, baseline, intermediates, options = {}) {
|
|
204
|
+
// visit intermediate steps twice
|
|
205
|
+
for (let i = 0; i < this._repeatIntermediate; i++) {
|
|
206
|
+
for (const step of intermediates) {
|
|
207
|
+
visitOrder.push(this.getAction(step));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// visit the final step
|
|
211
|
+
const final = options.final || baseline;
|
|
212
|
+
visitOrder.push(this.getAction(final, 'final'));
|
|
213
|
+
// if provided, some cleanup to restore states
|
|
214
|
+
if (options.cleanupSteps) {
|
|
215
|
+
for (const stepName of options.cleanupSteps) {
|
|
216
|
+
visitOrder.push(this.getAction(stepName));
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// synthesis for a new type of memory stress testing
|
|
221
|
+
// that repeats a series of steps
|
|
222
|
+
synthesisRepeat(baseline, target, _, options = {}) {
|
|
223
|
+
const visitOrder = this.synthesisInitPart(baseline, target, options);
|
|
224
|
+
// visit baseline
|
|
225
|
+
visitOrder.push(this.getAction(baseline, 'baseline'));
|
|
226
|
+
let repeat = options.repeat != null ? options.repeat : this.config.stressTestRepeat;
|
|
227
|
+
if (options.repeatSteps) {
|
|
228
|
+
while (repeat-- > 0) {
|
|
229
|
+
for (const step of options.repeatSteps) {
|
|
230
|
+
visitOrder.push(this.getAction(step));
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
while (repeat-- > 0) {
|
|
236
|
+
// repeatedly visit the baseline and target
|
|
237
|
+
visitOrder.push(this.getAction(target));
|
|
238
|
+
visitOrder.push(this.getAction(baseline));
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
visitOrder.push(this.getAction(target, 'target'));
|
|
242
|
+
// if provided, some cleanup to restore states
|
|
243
|
+
if (options.cleanupSteps) {
|
|
244
|
+
for (const stepName of options.cleanupSteps) {
|
|
245
|
+
visitOrder.push(this.getAction(stepName));
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return {
|
|
249
|
+
name: options.name || `${baseline}-${target}`,
|
|
250
|
+
appName: this.getAppName(),
|
|
251
|
+
type: 'repeat',
|
|
252
|
+
newTestUser: !!options.newTestUser,
|
|
253
|
+
device: this.getDevice(),
|
|
254
|
+
baseURL: this.getNormalizedBaseURL(options),
|
|
255
|
+
URLParameters: this.getURLParameters(options),
|
|
256
|
+
tabsOrder: visitOrder,
|
|
257
|
+
numOfWarmup: this.getActualNumberOfWarmup(),
|
|
258
|
+
dataBuilder: options.dataBuilder,
|
|
259
|
+
isPageLoaded: this.getPageLoadChecker(),
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
synthesisStandard(baseline, target, intermediates, options = {}) {
|
|
263
|
+
const visitOrder = this.synthesisInitPart(baseline, target, options);
|
|
264
|
+
// actually visit the baseline and target
|
|
265
|
+
visitOrder.push(this.getAction(baseline, 'baseline'));
|
|
266
|
+
visitOrder.push(this.getAction(target, 'target'));
|
|
267
|
+
// intermediate steps, final step, and cleanup steps
|
|
268
|
+
this.synthesisFinalPart(visitOrder, baseline, intermediates, options);
|
|
269
|
+
return {
|
|
270
|
+
name: options.name || target,
|
|
271
|
+
appName: this.getAppName(),
|
|
272
|
+
type: 'standard',
|
|
273
|
+
newTestUser: !!options.newTestUser,
|
|
274
|
+
device: this.getDevice(),
|
|
275
|
+
baseURL: this.getNormalizedBaseURL(options),
|
|
276
|
+
URLParameters: this.getURLParameters(options),
|
|
277
|
+
tabsOrder: visitOrder,
|
|
278
|
+
numOfWarmup: this.getActualNumberOfWarmup(),
|
|
279
|
+
dataBuilder: options.dataBuilder,
|
|
280
|
+
isPageLoaded: this.getPageLoadChecker(),
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
processStepUrl(url) {
|
|
284
|
+
let ret = url;
|
|
285
|
+
while (ret.startsWith('/')) {
|
|
286
|
+
ret = ret.substring(1);
|
|
287
|
+
}
|
|
288
|
+
return ret;
|
|
289
|
+
}
|
|
290
|
+
synthesisForScenario(scenario) {
|
|
291
|
+
var _a;
|
|
292
|
+
const visitOrder = [];
|
|
293
|
+
const url = this.processStepUrl(scenario.url());
|
|
294
|
+
const startStep = {
|
|
295
|
+
name: 'page-load',
|
|
296
|
+
url,
|
|
297
|
+
interactions: [],
|
|
298
|
+
};
|
|
299
|
+
if (!scenario.action) {
|
|
300
|
+
visitOrder.push(this.getActionFromStep(startStep, 'target'));
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
// first visit the start step
|
|
304
|
+
visitOrder.push(this.getActionFromStep(startStep, 'baseline'));
|
|
305
|
+
const actionStep = {
|
|
306
|
+
name: 'action-on-page',
|
|
307
|
+
url,
|
|
308
|
+
interactions: [scenario.action],
|
|
309
|
+
};
|
|
310
|
+
const revertStep = {
|
|
311
|
+
name: 'revert',
|
|
312
|
+
url,
|
|
313
|
+
interactions: [scenario.back],
|
|
314
|
+
};
|
|
315
|
+
const getRevertStep = (stepType) => scenario.back
|
|
316
|
+
? this.getActionFromStep(revertStep, stepType)
|
|
317
|
+
: this.getAction(SynthesisUtils_1.default.revertStep.name, stepType);
|
|
318
|
+
const repeat = scenario.repeat ? scenario.repeat() : 0;
|
|
319
|
+
for (let i = 0; i < repeat; ++i) {
|
|
320
|
+
visitOrder.push(this.getActionFromStep(actionStep));
|
|
321
|
+
visitOrder.push(getRevertStep());
|
|
322
|
+
}
|
|
323
|
+
visitOrder.push(this.getActionFromStep(actionStep, 'target'));
|
|
324
|
+
visitOrder.push(getRevertStep('final'));
|
|
325
|
+
}
|
|
326
|
+
return {
|
|
327
|
+
name: core_1.utils.getScenarioName(scenario),
|
|
328
|
+
appName: E2EUtils_1.default.getScenarioAppName(scenario),
|
|
329
|
+
type: 'scenario',
|
|
330
|
+
newTestUser: false,
|
|
331
|
+
device: this.getDevice(),
|
|
332
|
+
baseURL: this.getNormalizedBaseURL(),
|
|
333
|
+
URLParameters: this.getURLParameters(),
|
|
334
|
+
tabsOrder: visitOrder,
|
|
335
|
+
numOfWarmup: this.getActualNumberOfWarmup(),
|
|
336
|
+
dataBuilder: null,
|
|
337
|
+
isPageLoaded: (_a = scenario.isPageLoaded) !== null && _a !== void 0 ? _a : this.getPageLoadChecker(),
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
synthesisSimple(start, target, options = {}) {
|
|
341
|
+
const visitOrder = [];
|
|
342
|
+
// first visit the start step
|
|
343
|
+
visitOrder.push(this.getAction(start, 'baseline'));
|
|
344
|
+
visitOrder.push(this.getAction(target, 'target'));
|
|
345
|
+
visitOrder.push(this.getAction(SynthesisUtils_1.default.revertStep.name, 'final'));
|
|
346
|
+
return {
|
|
347
|
+
name: options.name || target,
|
|
348
|
+
appName: this.getAppName(),
|
|
349
|
+
type: 'simple',
|
|
350
|
+
newTestUser: !!options.newTestUser,
|
|
351
|
+
device: this.getDevice(),
|
|
352
|
+
baseURL: this.getNormalizedBaseURL(options),
|
|
353
|
+
URLParameters: this.getURLParameters(options),
|
|
354
|
+
tabsOrder: visitOrder,
|
|
355
|
+
numOfWarmup: this.getActualNumberOfWarmup(),
|
|
356
|
+
dataBuilder: options.dataBuilder,
|
|
357
|
+
isPageLoaded: this.getPageLoadChecker(),
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
synthesisInitialPageLoad(target, intermediates, options = {}) {
|
|
361
|
+
const visitOrder = [];
|
|
362
|
+
// visit the target page/tab
|
|
363
|
+
visitOrder.push(this.getAction(target, 'target'));
|
|
364
|
+
if (intermediates.length > 0) {
|
|
365
|
+
// intermediate steps, final step, and cleanup steps
|
|
366
|
+
if (!options.final) {
|
|
367
|
+
throw core_1.utils.haltOrThrow(`${target}-init-load doesn't have a final step`);
|
|
368
|
+
}
|
|
369
|
+
this.synthesisFinalPart(visitOrder, options.final, intermediates, options);
|
|
370
|
+
}
|
|
371
|
+
return {
|
|
372
|
+
name: options.name || `${target}-init-load`,
|
|
373
|
+
appName: this.getAppName(),
|
|
374
|
+
type: 'init-page-load',
|
|
375
|
+
newTestUser: !!options.newTestUser,
|
|
376
|
+
device: this.getDevice(),
|
|
377
|
+
baseURL: this.getNormalizedBaseURL(options),
|
|
378
|
+
URLParameters: this.getURLParameters(options),
|
|
379
|
+
tabsOrder: visitOrder,
|
|
380
|
+
numOfWarmup: this.getActualNumberOfWarmup(),
|
|
381
|
+
dataBuilder: options.dataBuilder,
|
|
382
|
+
isPageLoaded: this.getPageLoadChecker(),
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
getActionFromStep(step, type, snapshot, screenshot) {
|
|
386
|
+
const action = Object.assign({}, step);
|
|
387
|
+
return this.fillInInfo(action, type, snapshot, screenshot);
|
|
388
|
+
}
|
|
389
|
+
getAction(stepName, type, snapshot, screenshot) {
|
|
390
|
+
const step = this.steps.get(stepName);
|
|
391
|
+
if (!step) {
|
|
392
|
+
throw core_1.utils.haltOrThrow(`step ${stepName} doesn't exist`);
|
|
393
|
+
}
|
|
394
|
+
return this.getActionFromStep(step, type, snapshot, screenshot);
|
|
395
|
+
}
|
|
396
|
+
// by default take snapshot for baseline, target, and final step
|
|
397
|
+
shouldTakeSnapshot(option) {
|
|
398
|
+
const type = option.type;
|
|
399
|
+
return type === 'baseline' || type === 'target' || type === 'final';
|
|
400
|
+
}
|
|
401
|
+
// by default every step takes one screenshot
|
|
402
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
403
|
+
shouldTakeScreenshot(_option) {
|
|
404
|
+
return true;
|
|
405
|
+
}
|
|
406
|
+
fillInInfo(actionBasic, type, snapshot, screenshot) {
|
|
407
|
+
const action = Object.assign({}, actionBasic);
|
|
408
|
+
// fill in snapshot and screenshot instructions
|
|
409
|
+
if (typeof snapshot !== 'boolean') {
|
|
410
|
+
snapshot = this.shouldTakeSnapshot({ action, type });
|
|
411
|
+
}
|
|
412
|
+
if (typeof screenshot !== 'boolean') {
|
|
413
|
+
screenshot = this.shouldTakeScreenshot({ action, type });
|
|
414
|
+
}
|
|
415
|
+
action.snapshot = this.config.skipSnapshot ? false : snapshot;
|
|
416
|
+
action.screenshot = skipAllScreenshot ? false : screenshot;
|
|
417
|
+
if (type && type !== 'init') {
|
|
418
|
+
action.type = type;
|
|
419
|
+
}
|
|
420
|
+
const interactions = action.interactions;
|
|
421
|
+
// fill in extra interactions
|
|
422
|
+
if (!Array.isArray(interactions)) {
|
|
423
|
+
action.interactions = [interactions];
|
|
424
|
+
}
|
|
425
|
+
action.interactions = action.interactions.concat(this.getExtraOperationsForStep(action));
|
|
426
|
+
// make sure action.url is normalized
|
|
427
|
+
while (action.url.startsWith('/')) {
|
|
428
|
+
action.url = action.url.substring(1);
|
|
429
|
+
}
|
|
430
|
+
return action;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
exports.default = BaseSynthesizer;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
import type { AnyFunction, OperationArgs, MemLabConfig } from '@memlab/core';
|
|
11
|
+
import type { CDPSession, Page } from 'puppeteer';
|
|
12
|
+
import { TestPlanner } from './lib/operations/TestPlanner';
|
|
13
|
+
declare type PageInteractOptions = {
|
|
14
|
+
config?: MemLabConfig;
|
|
15
|
+
testPlanner?: TestPlanner;
|
|
16
|
+
};
|
|
17
|
+
export default class E2EInteractionManager {
|
|
18
|
+
private cdpsession;
|
|
19
|
+
private page;
|
|
20
|
+
private pageHistoryLength;
|
|
21
|
+
private evalFuncAfterInitLoad;
|
|
22
|
+
constructor(page: Page);
|
|
23
|
+
getCDPSession(): Promise<CDPSession>;
|
|
24
|
+
clearCDPSession(): void;
|
|
25
|
+
setEvalFuncAfterInitLoad(func: AnyFunction | null): void;
|
|
26
|
+
protected initialLoad(page: Page, url: string, opArgs?: OperationArgs): Promise<void>;
|
|
27
|
+
private beforeInteractions;
|
|
28
|
+
visitAndGetSnapshots(options?: PageInteractOptions): Promise<void>;
|
|
29
|
+
warmupInPage(): Promise<void>;
|
|
30
|
+
private visitPage;
|
|
31
|
+
private getPageStatistics;
|
|
32
|
+
private interactWithPage;
|
|
33
|
+
private startTrackingHeap;
|
|
34
|
+
private writeSnapshotFileFromCDPSession;
|
|
35
|
+
private saveHeapSnapshotToFile;
|
|
36
|
+
private fullGC;
|
|
37
|
+
private forceGC;
|
|
38
|
+
private collectMetrics;
|
|
39
|
+
}
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=E2EInteractionManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2EInteractionManager.d.ts","sourceRoot":"","sources":["../src/E2EInteractionManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,WAAW,EAIX,aAAa,EAEb,YAAY,EACb,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAC,UAAU,EAAE,IAAI,EAAC,MAAM,WAAW,CAAC;AAOhD,OAA2B,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAC;AAK7E,aAAK,mBAAmB,GAAG;IACzB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B,CAAC;AAoBF,MAAM,CAAC,OAAO,OAAO,qBAAqB;IACxC,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,iBAAiB,CAAgB;IACzC,OAAO,CAAC,qBAAqB,CAA4B;gBAE7C,IAAI,EAAE,IAAI;IAIT,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC;IAO1C,eAAe,IAAI,IAAI;IAIvB,wBAAwB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI;cAI/C,WAAW,CACzB,IAAI,EAAE,IAAI,EACV,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,aAAkB,GACzB,OAAO,CAAC,IAAI,CAAC;YAmBF,kBAAkB;IASnB,oBAAoB,CAC/B,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,IAAI,CAAC;IA0DH,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;YA4C5B,SAAS;YAeT,iBAAiB;YAgEjB,gBAAgB;YAoBhB,iBAAiB;YAQjB,+BAA+B;YAwC/B,sBAAsB;YActB,MAAM;YAeN,OAAO;YAUP,cAAc;CA4B7B"}
|