@checksum-ai/runtime 1.0.2 → 1.0.4
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/checksum-root/README.md +1 -0
- package/checksum-root/checksum.config.ts +56 -0
- package/checksum-root/login.ts +19 -0
- package/checksum-root/playwright.config.ts +32 -0
- package/checksumlib.js +3 -0
- package/cli.ts +225 -0
- package/index.d.ts +87 -0
- package/index.js +62 -62
- package/package.json +1 -1
- package/cli.js +0 -3
package/cli.ts
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { copyFileSync, existsSync, mkdirSync, rmSync, writeFileSync } from "fs";
|
|
2
|
+
import * as childProcess from "child_process";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
|
|
5
|
+
const ROOT_DIR_NAME = "checksum";
|
|
6
|
+
|
|
7
|
+
class ChecksumCLI {
|
|
8
|
+
checksumConfig = undefined;
|
|
9
|
+
|
|
10
|
+
constructor() {}
|
|
11
|
+
|
|
12
|
+
async execute() {
|
|
13
|
+
switch (process.argv[2]) {
|
|
14
|
+
case "install":
|
|
15
|
+
this.install();
|
|
16
|
+
break;
|
|
17
|
+
case "run":
|
|
18
|
+
if (process.argv?.[3] === "--help") {
|
|
19
|
+
await this.printHelp("run");
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
await this.run(process.argv.slice(3));
|
|
23
|
+
break;
|
|
24
|
+
default:
|
|
25
|
+
await this.printHelp();
|
|
26
|
+
}
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async execCmd(cmdString) {
|
|
31
|
+
const child = await childProcess.spawn(cmdString, {
|
|
32
|
+
shell: true,
|
|
33
|
+
stdio: "inherit",
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const exitPromise = new Promise((resolve, reject) => {
|
|
37
|
+
child.on("exit", (code) => {
|
|
38
|
+
if (code === 0) {
|
|
39
|
+
resolve(true);
|
|
40
|
+
} else {
|
|
41
|
+
reject(
|
|
42
|
+
new Error(
|
|
43
|
+
`Checsum failed execution with code: ${code} for command: "${cmdString}`
|
|
44
|
+
)
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
return exitPromise;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async getCmdOutput(cmdString): Promise<string> {
|
|
54
|
+
return new Promise<string>(function (resolve, reject) {
|
|
55
|
+
childProcess.exec(cmdString, (error, stdout, stderr) => {
|
|
56
|
+
if (error) {
|
|
57
|
+
reject(`Error executing command: ${error.message}`);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
resolve(stdout);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// return promise;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async printHelp(command?: string) {
|
|
69
|
+
switch (command) {
|
|
70
|
+
default:
|
|
71
|
+
console.log(`
|
|
72
|
+
Checksum CLI
|
|
73
|
+
Usage: checksum [command] [options]
|
|
74
|
+
|
|
75
|
+
Commands:
|
|
76
|
+
install installs checksum files and folders
|
|
77
|
+
run runs checksum tests
|
|
78
|
+
help prints this help message
|
|
79
|
+
`);
|
|
80
|
+
break;
|
|
81
|
+
case "run":
|
|
82
|
+
try {
|
|
83
|
+
const cmd = `npx playwright test --help`;
|
|
84
|
+
const testHelp: string = await this.getCmdOutput(cmd);
|
|
85
|
+
console.log(
|
|
86
|
+
testHelp.replace(/npx playwright test/g, "yarn checksum run")
|
|
87
|
+
);
|
|
88
|
+
} catch (e) {
|
|
89
|
+
console.log("Error", e.message);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async run(args: string[]) {
|
|
97
|
+
args = this.getChecksumConfig(args);
|
|
98
|
+
// run shell command and pipe output rhe response to console
|
|
99
|
+
const cmd = `npx playwright test --config ${join(
|
|
100
|
+
this.getRootDirPath(),
|
|
101
|
+
"playwright.config.ts"
|
|
102
|
+
)} ${args.join(" ")}`;
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
this.buildVolatileConfig();
|
|
106
|
+
return this.execCmd(cmd);
|
|
107
|
+
} catch (e) {
|
|
108
|
+
console.log("Error", e.message);
|
|
109
|
+
} finally {
|
|
110
|
+
this.cleanup();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
buildVolatileConfig() {
|
|
115
|
+
if (!this.checksumConfig) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const configPath = this.getVolatileConfigPath();
|
|
120
|
+
const configString = `
|
|
121
|
+
import { RunMode, getChecksumConfig } from "@checksum-ai/runtime";
|
|
122
|
+
|
|
123
|
+
export default getChecksumConfig(${JSON.stringify(
|
|
124
|
+
this.checksumConfig,
|
|
125
|
+
null,
|
|
126
|
+
2
|
|
127
|
+
)});
|
|
128
|
+
`;
|
|
129
|
+
|
|
130
|
+
writeFileSync(configPath, configString);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
cleanup() {
|
|
134
|
+
const configPath = this.getVolatileConfigPath();
|
|
135
|
+
if (existsSync(configPath)) {
|
|
136
|
+
rmSync(configPath);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
getVolatileConfigPath() {
|
|
141
|
+
return join(this.getRootDirPath(), "checksum.config.tmp.ts");
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
getChecksumConfig(args) {
|
|
145
|
+
for (const arg of args) {
|
|
146
|
+
if (arg.startsWith("--checksum-config")) {
|
|
147
|
+
try {
|
|
148
|
+
this.checksumConfig = JSON.parse(arg.split("=")[1]);
|
|
149
|
+
return args.filter((a) => a !== arg);
|
|
150
|
+
} catch (e) {
|
|
151
|
+
console.log("Error parsing checksum config", e.message);
|
|
152
|
+
this.checksumConfig = undefined;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return args;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
install() {
|
|
161
|
+
console.log(
|
|
162
|
+
"Creating Checksum directory and necessary files to run your tests"
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
const checksumRoot = this.getRootDirPath();
|
|
166
|
+
|
|
167
|
+
if (!existsSync(this.getRootDirPath())) {
|
|
168
|
+
mkdirSync(checksumRoot);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (!existsSync(this.getChecksumRootOrigin())) {
|
|
172
|
+
throw new Error(
|
|
173
|
+
"Could not find checksum root directory, please install @checksum-ai/runtime package"
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
// automatically install?
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// copy sources
|
|
180
|
+
[
|
|
181
|
+
"checksum.config.ts",
|
|
182
|
+
"playwright.config.ts",
|
|
183
|
+
"login.ts",
|
|
184
|
+
"README.md",
|
|
185
|
+
].forEach((file) => {
|
|
186
|
+
copyFileSync(
|
|
187
|
+
join(this.getChecksumRootOrigin(), file),
|
|
188
|
+
join(checksumRoot, file)
|
|
189
|
+
);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// create tests folder
|
|
193
|
+
mkdirSync(join(checksumRoot, "tests"), {
|
|
194
|
+
recursive: true,
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// create test data directories
|
|
198
|
+
["esra", "har", "trace", "log"].forEach((folder) => {
|
|
199
|
+
mkdirSync(join(checksumRoot, "test-data", folder), {
|
|
200
|
+
recursive: true,
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
getRootDirPath() {
|
|
206
|
+
return join(process.cwd(), ROOT_DIR_NAME);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
getChecksumRootOrigin() {
|
|
210
|
+
return join(
|
|
211
|
+
process.cwd(),
|
|
212
|
+
"node_modules",
|
|
213
|
+
"@checksum-ai",
|
|
214
|
+
"runtime",
|
|
215
|
+
"checksum-root"
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Trigger the main function
|
|
222
|
+
*/
|
|
223
|
+
(async () => {
|
|
224
|
+
await new ChecksumCLI().execute();
|
|
225
|
+
})();
|
package/index.d.ts
CHANGED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Page } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
export interface IChecksumPage extends Page {
|
|
4
|
+
initWithTest: (testInfo) => Promise<void>;
|
|
5
|
+
checksumId: (id: string) => IChecksumPage;
|
|
6
|
+
checksumStep: (thought: string, testFunction?: () => void) => IChecksumPage;
|
|
7
|
+
testId: (testId: string) => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export enum RunMode {
|
|
11
|
+
Normal = "normal",
|
|
12
|
+
Heal = "heal",
|
|
13
|
+
Refactor = "refactor",
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type RuntimeOptions = {
|
|
17
|
+
/**
|
|
18
|
+
* fallback to ESRA if the action selector is not found
|
|
19
|
+
*/
|
|
20
|
+
actionsESRAfallback: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* use LLM fallback if action selector is not found
|
|
23
|
+
*/
|
|
24
|
+
actionsLLMFallback: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* add new assertions
|
|
27
|
+
*/
|
|
28
|
+
newAssertionsEnabled: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* use mocked data
|
|
31
|
+
*/
|
|
32
|
+
useMockData: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* print logs to console
|
|
35
|
+
*/
|
|
36
|
+
printLogs: boolean;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type ChecksumConfig = {
|
|
40
|
+
/**
|
|
41
|
+
* Checksum runtime running mode -
|
|
42
|
+
* normal - tests run normally
|
|
43
|
+
* heal - checksum will attempt to heal tests that failed using fallback
|
|
44
|
+
* refactor - checksum will attempt to refactor and improve your tests
|
|
45
|
+
*/
|
|
46
|
+
runMode: RunMode;
|
|
47
|
+
/**
|
|
48
|
+
* Checksum API key
|
|
49
|
+
*/
|
|
50
|
+
apiKey: string;
|
|
51
|
+
/**
|
|
52
|
+
* Base URL of the tested app (i.e http://staging.example.com)
|
|
53
|
+
*/
|
|
54
|
+
baseURL: string;
|
|
55
|
+
|
|
56
|
+
apiURL: string;
|
|
57
|
+
/**
|
|
58
|
+
* Account's username that will be used
|
|
59
|
+
* to login into your testing environment
|
|
60
|
+
*/
|
|
61
|
+
username?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Account's password that will be used
|
|
64
|
+
* to login into your testing environment
|
|
65
|
+
*/
|
|
66
|
+
password?: string;
|
|
67
|
+
options?: Partial<RuntimeOptions>;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export function getLogin(): (page: Page) => Promise<void>;
|
|
71
|
+
|
|
72
|
+
export function getChecksumConfig(
|
|
73
|
+
config: Partial<ChecksumConfig>
|
|
74
|
+
): ChecksumConfig;
|
|
75
|
+
|
|
76
|
+
export function init(
|
|
77
|
+
base: TestType<
|
|
78
|
+
PlaywrightTestArgs & PlaywrightTestOptions,
|
|
79
|
+
PlaywrightWorkerArgs & PlaywrightWorkerOptions
|
|
80
|
+
>
|
|
81
|
+
): {
|
|
82
|
+
test: TestType<
|
|
83
|
+
PlaywrightTestArgs & PlaywrightTestOptions,
|
|
84
|
+
PlaywrightWorkerArgs & PlaywrightWorkerOptions
|
|
85
|
+
>;
|
|
86
|
+
login: ReturnType<typeof getLogin>;
|
|
87
|
+
};
|