@testsmith/perfornium 0.1.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 +360 -0
- package/dist/cli/cli.d.ts +2 -0
- package/dist/cli/cli.js +192 -0
- package/dist/cli/commands/distributed.d.ts +11 -0
- package/dist/cli/commands/distributed.js +179 -0
- package/dist/cli/commands/import.d.ts +23 -0
- package/dist/cli/commands/import.js +461 -0
- package/dist/cli/commands/init.d.ts +7 -0
- package/dist/cli/commands/init.js +923 -0
- package/dist/cli/commands/mock.d.ts +7 -0
- package/dist/cli/commands/mock.js +281 -0
- package/dist/cli/commands/report.d.ts +5 -0
- package/dist/cli/commands/report.js +70 -0
- package/dist/cli/commands/run.d.ts +12 -0
- package/dist/cli/commands/run.js +260 -0
- package/dist/cli/commands/validate.d.ts +3 -0
- package/dist/cli/commands/validate.js +35 -0
- package/dist/cli/commands/worker.d.ts +27 -0
- package/dist/cli/commands/worker.js +320 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.js +20 -0
- package/dist/config/parser.d.ts +19 -0
- package/dist/config/parser.js +330 -0
- package/dist/config/types/global-config.d.ts +74 -0
- package/dist/config/types/global-config.js +2 -0
- package/dist/config/types/hooks.d.ts +58 -0
- package/dist/config/types/hooks.js +3 -0
- package/dist/config/types/import-types.d.ts +33 -0
- package/dist/config/types/import-types.js +2 -0
- package/dist/config/types/index.d.ts +11 -0
- package/dist/config/types/index.js +27 -0
- package/dist/config/types/load-config.d.ts +32 -0
- package/dist/config/types/load-config.js +9 -0
- package/dist/config/types/output-config.d.ts +10 -0
- package/dist/config/types/output-config.js +2 -0
- package/dist/config/types/report-config.d.ts +10 -0
- package/dist/config/types/report-config.js +2 -0
- package/dist/config/types/runtime-types.d.ts +6 -0
- package/dist/config/types/runtime-types.js +2 -0
- package/dist/config/types/scenario-config.d.ts +30 -0
- package/dist/config/types/scenario-config.js +2 -0
- package/dist/config/types/step-types.d.ts +139 -0
- package/dist/config/types/step-types.js +2 -0
- package/dist/config/types/test-configuration.d.ts +18 -0
- package/dist/config/types/test-configuration.js +2 -0
- package/dist/config/types/worker-config.d.ts +12 -0
- package/dist/config/types/worker-config.js +2 -0
- package/dist/config/validator.d.ts +19 -0
- package/dist/config/validator.js +198 -0
- package/dist/core/csv-data-provider.d.ts +47 -0
- package/dist/core/csv-data-provider.js +265 -0
- package/dist/core/hooks-manager.d.ts +33 -0
- package/dist/core/hooks-manager.js +129 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.js +11 -0
- package/dist/core/script-executor.d.ts +14 -0
- package/dist/core/script-executor.js +290 -0
- package/dist/core/step-executor.d.ts +41 -0
- package/dist/core/step-executor.js +680 -0
- package/dist/core/test-runner.d.ts +34 -0
- package/dist/core/test-runner.js +465 -0
- package/dist/core/threshold-evaluator.d.ts +43 -0
- package/dist/core/threshold-evaluator.js +170 -0
- package/dist/core/virtual-user-pool.d.ts +42 -0
- package/dist/core/virtual-user-pool.js +136 -0
- package/dist/core/virtual-user.d.ts +51 -0
- package/dist/core/virtual-user.js +488 -0
- package/dist/distributed/coordinator.d.ts +34 -0
- package/dist/distributed/coordinator.js +158 -0
- package/dist/distributed/health-monitor.d.ts +18 -0
- package/dist/distributed/health-monitor.js +72 -0
- package/dist/distributed/load-distributor.d.ts +17 -0
- package/dist/distributed/load-distributor.js +106 -0
- package/dist/distributed/remote-worker.d.ts +37 -0
- package/dist/distributed/remote-worker.js +241 -0
- package/dist/distributed/result-aggregator.d.ts +43 -0
- package/dist/distributed/result-aggregator.js +146 -0
- package/dist/dsl/index.d.ts +3 -0
- package/dist/dsl/index.js +11 -0
- package/dist/dsl/test-builder.d.ts +111 -0
- package/dist/dsl/test-builder.js +514 -0
- package/dist/importers/har-importer.d.ts +17 -0
- package/dist/importers/har-importer.js +172 -0
- package/dist/importers/open-api-importer.d.ts +23 -0
- package/dist/importers/open-api-importer.js +181 -0
- package/dist/importers/wsdl-importer.d.ts +42 -0
- package/dist/importers/wsdl-importer.js +440 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +17 -0
- package/dist/load-patterns/arrivals.d.ts +7 -0
- package/dist/load-patterns/arrivals.js +118 -0
- package/dist/load-patterns/base.d.ts +9 -0
- package/dist/load-patterns/base.js +2 -0
- package/dist/load-patterns/basic.d.ts +7 -0
- package/dist/load-patterns/basic.js +117 -0
- package/dist/load-patterns/stepping.d.ts +6 -0
- package/dist/load-patterns/stepping.js +122 -0
- package/dist/metrics/collector.d.ts +72 -0
- package/dist/metrics/collector.js +662 -0
- package/dist/metrics/types.d.ts +135 -0
- package/dist/metrics/types.js +2 -0
- package/dist/outputs/base.d.ts +7 -0
- package/dist/outputs/base.js +2 -0
- package/dist/outputs/csv.d.ts +13 -0
- package/dist/outputs/csv.js +163 -0
- package/dist/outputs/graphite.d.ts +13 -0
- package/dist/outputs/graphite.js +126 -0
- package/dist/outputs/influxdb.d.ts +12 -0
- package/dist/outputs/influxdb.js +82 -0
- package/dist/outputs/json.d.ts +14 -0
- package/dist/outputs/json.js +107 -0
- package/dist/outputs/streaming-csv.d.ts +37 -0
- package/dist/outputs/streaming-csv.js +254 -0
- package/dist/outputs/streaming-json.d.ts +43 -0
- package/dist/outputs/streaming-json.js +353 -0
- package/dist/outputs/webhook.d.ts +16 -0
- package/dist/outputs/webhook.js +96 -0
- package/dist/protocols/base.d.ts +33 -0
- package/dist/protocols/base.js +2 -0
- package/dist/protocols/rest/handler.d.ts +67 -0
- package/dist/protocols/rest/handler.js +776 -0
- package/dist/protocols/soap/handler.d.ts +12 -0
- package/dist/protocols/soap/handler.js +165 -0
- package/dist/protocols/web/core-web-vitals.d.ts +121 -0
- package/dist/protocols/web/core-web-vitals.js +373 -0
- package/dist/protocols/web/handler.d.ts +50 -0
- package/dist/protocols/web/handler.js +706 -0
- package/dist/recorder/native-recorder.d.ts +14 -0
- package/dist/recorder/native-recorder.js +533 -0
- package/dist/recorder/scenario-recorder.d.ts +55 -0
- package/dist/recorder/scenario-recorder.js +296 -0
- package/dist/reporting/constants.d.ts +94 -0
- package/dist/reporting/constants.js +82 -0
- package/dist/reporting/enhanced-html-generator.d.ts +55 -0
- package/dist/reporting/enhanced-html-generator.js +965 -0
- package/dist/reporting/generator.d.ts +42 -0
- package/dist/reporting/generator.js +1217 -0
- package/dist/reporting/statistics.d.ts +144 -0
- package/dist/reporting/statistics.js +742 -0
- package/dist/reporting/templates/enhanced-report.hbs +2812 -0
- package/dist/reporting/templates/html.hbs +2453 -0
- package/dist/utils/faker-manager.d.ts +55 -0
- package/dist/utils/faker-manager.js +166 -0
- package/dist/utils/file-manager.d.ts +33 -0
- package/dist/utils/file-manager.js +154 -0
- package/dist/utils/handlebars-manager.d.ts +42 -0
- package/dist/utils/handlebars-manager.js +172 -0
- package/dist/utils/logger.d.ts +16 -0
- package/dist/utils/logger.js +46 -0
- package/dist/utils/template.d.ts +80 -0
- package/dist/utils/template.js +513 -0
- package/dist/utils/test-output-writer.d.ts +56 -0
- package/dist/utils/test-output-writer.js +643 -0
- package/dist/utils/time.d.ts +3 -0
- package/dist/utils/time.js +23 -0
- package/dist/utils/timestamp-helper.d.ts +17 -0
- package/dist/utils/timestamp-helper.js +53 -0
- package/dist/workers/manager.d.ts +18 -0
- package/dist/workers/manager.js +95 -0
- package/dist/workers/server.d.ts +21 -0
- package/dist/workers/server.js +205 -0
- package/dist/workers/worker.d.ts +19 -0
- package/dist/workers/worker.js +147 -0
- package/package.json +102 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.testData = exports.faker = exports.load = exports.test = exports.LoadBuilder = exports.ScenarioBuilder = exports.TestBuilder = void 0;
|
|
4
|
+
var test_builder_1 = require("./test-builder");
|
|
5
|
+
Object.defineProperty(exports, "TestBuilder", { enumerable: true, get: function () { return test_builder_1.TestBuilder; } });
|
|
6
|
+
Object.defineProperty(exports, "ScenarioBuilder", { enumerable: true, get: function () { return test_builder_1.ScenarioBuilder; } });
|
|
7
|
+
Object.defineProperty(exports, "LoadBuilder", { enumerable: true, get: function () { return test_builder_1.LoadBuilder; } });
|
|
8
|
+
Object.defineProperty(exports, "test", { enumerable: true, get: function () { return test_builder_1.test; } });
|
|
9
|
+
Object.defineProperty(exports, "load", { enumerable: true, get: function () { return test_builder_1.load; } });
|
|
10
|
+
Object.defineProperty(exports, "faker", { enumerable: true, get: function () { return test_builder_1.faker; } });
|
|
11
|
+
Object.defineProperty(exports, "testData", { enumerable: true, get: function () { return test_builder_1.testData; } });
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { TestConfiguration, Scenario, Step, LoadConfig, LoadPhase, GlobalConfig, OutputConfig } from '../config';
|
|
2
|
+
import { getFaker } from '../utils/faker-manager';
|
|
3
|
+
export interface ScenarioContext {
|
|
4
|
+
vu_id: number | string;
|
|
5
|
+
iteration: number;
|
|
6
|
+
variables: Record<string, any>;
|
|
7
|
+
page?: any;
|
|
8
|
+
request?: any;
|
|
9
|
+
[key: string]: any;
|
|
10
|
+
}
|
|
11
|
+
export declare class ScenarioBuilder {
|
|
12
|
+
private parent;
|
|
13
|
+
private scenario;
|
|
14
|
+
constructor(parent: TestBuilder, name: string, weight: number);
|
|
15
|
+
description(desc: string): this;
|
|
16
|
+
loop(count: number): this;
|
|
17
|
+
thinkTime(time: string | number): this;
|
|
18
|
+
variables(vars: Record<string, any>): this;
|
|
19
|
+
withCSV(file: string, options?: any): this;
|
|
20
|
+
beforeScenario(script: string | ((context: ScenarioContext) => Promise<void>)): this;
|
|
21
|
+
afterScenario(script: string | ((context: ScenarioContext) => Promise<void>)): this;
|
|
22
|
+
goto(url: string): this;
|
|
23
|
+
click(selector: string): this;
|
|
24
|
+
fill(selector: string, value: any): this;
|
|
25
|
+
select(selector: string, value: string): this;
|
|
26
|
+
expectVisible(selector: string, name?: string): this;
|
|
27
|
+
expectText(selector: string, text: string, name?: string): this;
|
|
28
|
+
expectNotVisible(selector: string, name?: string): this;
|
|
29
|
+
wait(duration: string | number): this;
|
|
30
|
+
get(path: string, options?: any): this;
|
|
31
|
+
post(path: string, body?: any, options?: any): this;
|
|
32
|
+
put(path: string, body?: any, options?: any): this;
|
|
33
|
+
patch(path: string, body?: any, options?: any): this;
|
|
34
|
+
delete(path: string, options?: any): this;
|
|
35
|
+
request(method: string, path: string, options?: any): this;
|
|
36
|
+
withBasicAuth(username: string, password: string): this;
|
|
37
|
+
withBearerToken(token: string): this;
|
|
38
|
+
withHeaders(headers: Record<string, string>): this;
|
|
39
|
+
withQuery(params: Record<string, string | number | boolean>): this;
|
|
40
|
+
withThinkTime(time: string | number): this;
|
|
41
|
+
extract(name: string, expression: string, type?: 'json_path' | 'regex'): this;
|
|
42
|
+
check(type: string, value: any, description?: string): this;
|
|
43
|
+
soap(operation: string, args: any, wsdl?: string): this;
|
|
44
|
+
step(name: string, script: string | ((context: ScenarioContext) => Promise<void>)): this;
|
|
45
|
+
addStep(step: Step): this;
|
|
46
|
+
done(): TestBuilder;
|
|
47
|
+
endScenario(): TestBuilder;
|
|
48
|
+
}
|
|
49
|
+
export declare class LoadBuilder {
|
|
50
|
+
private loadConfig;
|
|
51
|
+
name(name: string): this;
|
|
52
|
+
pattern(pattern: 'basic' | 'stepping' | 'arrivals'): this;
|
|
53
|
+
virtualUsers(count: number): this;
|
|
54
|
+
vus(count: number): this;
|
|
55
|
+
rampUp(duration: string): this;
|
|
56
|
+
duration(duration: string): this;
|
|
57
|
+
rate(requestsPerSecond: number): this;
|
|
58
|
+
steps(steps: any[]): this;
|
|
59
|
+
build(): LoadPhase;
|
|
60
|
+
}
|
|
61
|
+
export declare function test(name: string): TestBuilder;
|
|
62
|
+
export declare function load(): LoadBuilder;
|
|
63
|
+
/**
|
|
64
|
+
* Fluent DSL for building test configurations
|
|
65
|
+
*
|
|
66
|
+
* Usage:
|
|
67
|
+
* const config = test('My Test')
|
|
68
|
+
* .baseUrl('https://example.com')
|
|
69
|
+
* .withBrowser('chromium', { headless: false })
|
|
70
|
+
* .scenario('User Journey')
|
|
71
|
+
* .goto('/')
|
|
72
|
+
* .click('#login')
|
|
73
|
+
* .fill('#username', 'test@example.com')
|
|
74
|
+
* .expectVisible('#dashboard')
|
|
75
|
+
* .done()
|
|
76
|
+
* .withLoad({ pattern: 'basic', virtualUsers: 10 })
|
|
77
|
+
* .build();
|
|
78
|
+
*/
|
|
79
|
+
export declare class TestBuilder {
|
|
80
|
+
private config;
|
|
81
|
+
constructor(name: string);
|
|
82
|
+
configuration(confis: GlobalConfig): this;
|
|
83
|
+
description(desc: string): this;
|
|
84
|
+
baseUrl(url: string): this;
|
|
85
|
+
timeout(ms: number): this;
|
|
86
|
+
thinkTime(time: string | number): this;
|
|
87
|
+
headers(headers: Record<string, string>): this;
|
|
88
|
+
withBrowser(type: 'chromium' | 'firefox' | 'webkit', options?: any): this;
|
|
89
|
+
withWSDL(url: string): this;
|
|
90
|
+
variables(vars: Record<string, any>): this;
|
|
91
|
+
scenario(name: string, weight?: number): ScenarioBuilder;
|
|
92
|
+
addScenario(scenario: Scenario): this;
|
|
93
|
+
withLoad(load: LoadConfig | LoadBuilder | LoadBuilder[]): this;
|
|
94
|
+
withLoadPhases(...phases: (LoadPhase | LoadBuilder)[]): this;
|
|
95
|
+
withOutput(type: string, options: Partial<OutputConfig>): this;
|
|
96
|
+
withJSONOutput(file: string): this;
|
|
97
|
+
withCSVOutput(file: string): this;
|
|
98
|
+
withReport(output?: string): this;
|
|
99
|
+
build(): TestConfiguration;
|
|
100
|
+
run(): Promise<void>;
|
|
101
|
+
}
|
|
102
|
+
export { getFaker as faker };
|
|
103
|
+
export declare const testData: {
|
|
104
|
+
email: () => string;
|
|
105
|
+
password: () => string;
|
|
106
|
+
firstName: () => string;
|
|
107
|
+
lastName: () => string;
|
|
108
|
+
phone: () => string;
|
|
109
|
+
uuid: () => string;
|
|
110
|
+
randomInt: (min: number, max: number) => number;
|
|
111
|
+
};
|
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.testData = exports.faker = exports.TestBuilder = exports.LoadBuilder = exports.ScenarioBuilder = void 0;
|
|
37
|
+
exports.test = test;
|
|
38
|
+
exports.load = load;
|
|
39
|
+
const faker_manager_1 = require("../utils/faker-manager");
|
|
40
|
+
Object.defineProperty(exports, "faker", { enumerable: true, get: function () { return faker_manager_1.getFaker; } });
|
|
41
|
+
class ScenarioBuilder {
|
|
42
|
+
constructor(parent, name, weight) {
|
|
43
|
+
this.scenario = {
|
|
44
|
+
steps: []
|
|
45
|
+
};
|
|
46
|
+
this.parent = parent;
|
|
47
|
+
this.scenario.name = name;
|
|
48
|
+
this.scenario.weight = weight;
|
|
49
|
+
}
|
|
50
|
+
description(desc) {
|
|
51
|
+
this.scenario.description = desc;
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
loop(count) {
|
|
55
|
+
this.scenario.loop = count;
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
thinkTime(time) {
|
|
59
|
+
this.scenario.think_time = time;
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
variables(vars) {
|
|
63
|
+
this.scenario.variables = { ...this.scenario.variables, ...vars };
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
withCSV(file, options) {
|
|
67
|
+
this.scenario.csv_data = { file, ...options };
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
70
|
+
// Updated hook methods with context parameter
|
|
71
|
+
beforeScenario(script) {
|
|
72
|
+
const scriptStr = typeof script === 'function' ? script.toString() : script;
|
|
73
|
+
this.scenario.hooks = {
|
|
74
|
+
...this.scenario.hooks,
|
|
75
|
+
beforeScenario: { script: scriptStr }
|
|
76
|
+
};
|
|
77
|
+
return this;
|
|
78
|
+
}
|
|
79
|
+
afterScenario(script) {
|
|
80
|
+
const scriptStr = typeof script === 'function' ? script.toString() : script;
|
|
81
|
+
this.scenario.hooks = {
|
|
82
|
+
...this.scenario.hooks,
|
|
83
|
+
afterScenario: { script: scriptStr }
|
|
84
|
+
};
|
|
85
|
+
return this;
|
|
86
|
+
}
|
|
87
|
+
// Web step methods
|
|
88
|
+
goto(url) {
|
|
89
|
+
return this.addStep({
|
|
90
|
+
name: `Navigate to ${url}`,
|
|
91
|
+
type: 'web',
|
|
92
|
+
action: { command: 'goto', url }
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
click(selector) {
|
|
96
|
+
return this.addStep({
|
|
97
|
+
name: `Click ${selector}`,
|
|
98
|
+
type: 'web',
|
|
99
|
+
action: { command: 'click', selector }
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
fill(selector, value) {
|
|
103
|
+
const actualValue = typeof value === 'string' ? value : value.toString();
|
|
104
|
+
return this.addStep({
|
|
105
|
+
name: `Fill ${selector}`,
|
|
106
|
+
type: 'web',
|
|
107
|
+
action: { command: 'fill', selector, value: actualValue }
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
select(selector, value) {
|
|
111
|
+
return this.addStep({
|
|
112
|
+
name: `Select ${value} in ${selector}`,
|
|
113
|
+
type: 'web',
|
|
114
|
+
action: { command: 'select', selector, value }
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
// press(selector: string, key: string): this {
|
|
118
|
+
// return this.addStep({
|
|
119
|
+
// name: `Press ${key} on ${selector}`,
|
|
120
|
+
// type: 'web',
|
|
121
|
+
// action: { command: 'press', selector, key }
|
|
122
|
+
// });
|
|
123
|
+
// }
|
|
124
|
+
expectVisible(selector, name) {
|
|
125
|
+
return this.addStep({
|
|
126
|
+
name: name || `Verify ${selector} is visible`,
|
|
127
|
+
type: 'web',
|
|
128
|
+
action: {
|
|
129
|
+
command: 'verify_visible',
|
|
130
|
+
selector,
|
|
131
|
+
...(name && { name })
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
expectText(selector, text, name) {
|
|
136
|
+
return this.addStep({
|
|
137
|
+
name: name || `Verify ${selector} contains ${text}`,
|
|
138
|
+
type: 'web',
|
|
139
|
+
action: {
|
|
140
|
+
command: 'verify_text',
|
|
141
|
+
selector,
|
|
142
|
+
expected_text: text,
|
|
143
|
+
...(name && { name })
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
expectNotVisible(selector, name) {
|
|
148
|
+
return this.addStep({
|
|
149
|
+
name: name || `Verify ${selector} is not visible`,
|
|
150
|
+
type: 'web',
|
|
151
|
+
action: {
|
|
152
|
+
command: 'verify_not_exists',
|
|
153
|
+
selector,
|
|
154
|
+
...(name && { name })
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
wait(duration) {
|
|
159
|
+
const durationStr = typeof duration === 'number' ? `${duration}s` : duration;
|
|
160
|
+
return this.addStep({
|
|
161
|
+
name: `Wait ${durationStr}`,
|
|
162
|
+
type: 'wait',
|
|
163
|
+
duration: durationStr
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
// REST API step methods
|
|
167
|
+
get(path, options) {
|
|
168
|
+
return this.request('GET', path, options);
|
|
169
|
+
}
|
|
170
|
+
post(path, body, options) {
|
|
171
|
+
return this.request('POST', path, { ...options, json: body });
|
|
172
|
+
}
|
|
173
|
+
put(path, body, options) {
|
|
174
|
+
return this.request('PUT', path, { ...options, json: body });
|
|
175
|
+
}
|
|
176
|
+
patch(path, body, options) {
|
|
177
|
+
return this.request('PATCH', path, { ...options, json: body });
|
|
178
|
+
}
|
|
179
|
+
delete(path, options) {
|
|
180
|
+
return this.request('DELETE', path, options);
|
|
181
|
+
}
|
|
182
|
+
request(method, path, options) {
|
|
183
|
+
const step = {
|
|
184
|
+
name: options?.name || `${method} ${path}`,
|
|
185
|
+
type: 'rest',
|
|
186
|
+
method,
|
|
187
|
+
path
|
|
188
|
+
};
|
|
189
|
+
if (options?.headers)
|
|
190
|
+
step.headers = options.headers;
|
|
191
|
+
if (options?.json)
|
|
192
|
+
step.json = options.json;
|
|
193
|
+
if (options?.body)
|
|
194
|
+
step.body = options.body;
|
|
195
|
+
if (options?.xml)
|
|
196
|
+
step.xml = options.xml;
|
|
197
|
+
if (options?.form)
|
|
198
|
+
step.form = options.form;
|
|
199
|
+
if (options?.multipart)
|
|
200
|
+
step.multipart = options.multipart;
|
|
201
|
+
if (options?.query)
|
|
202
|
+
step.query = options.query;
|
|
203
|
+
if (options?.auth)
|
|
204
|
+
step.auth = options.auth;
|
|
205
|
+
if (options?.extract)
|
|
206
|
+
step.extract = options.extract;
|
|
207
|
+
if (options?.checks)
|
|
208
|
+
step.checks = options.checks;
|
|
209
|
+
if (options?.timeout)
|
|
210
|
+
step.timeout = options.timeout;
|
|
211
|
+
return this.addStep(step);
|
|
212
|
+
}
|
|
213
|
+
// Enhanced methods for different auth types
|
|
214
|
+
withBasicAuth(username, password) {
|
|
215
|
+
const lastStep = this.scenario.steps[this.scenario.steps.length - 1];
|
|
216
|
+
if (lastStep.type === 'rest') {
|
|
217
|
+
lastStep.auth = { type: 'basic', username, password };
|
|
218
|
+
}
|
|
219
|
+
return this;
|
|
220
|
+
}
|
|
221
|
+
withBearerToken(token) {
|
|
222
|
+
const lastStep = this.scenario.steps[this.scenario.steps.length - 1];
|
|
223
|
+
if (lastStep.type === 'rest') {
|
|
224
|
+
lastStep.auth = { type: 'bearer', token };
|
|
225
|
+
}
|
|
226
|
+
return this;
|
|
227
|
+
}
|
|
228
|
+
withHeaders(headers) {
|
|
229
|
+
const lastStep = this.scenario.steps[this.scenario.steps.length - 1];
|
|
230
|
+
if (lastStep.type === 'rest') {
|
|
231
|
+
lastStep.headers = { ...lastStep.headers, ...headers };
|
|
232
|
+
}
|
|
233
|
+
return this;
|
|
234
|
+
}
|
|
235
|
+
withQuery(params) {
|
|
236
|
+
const lastStep = this.scenario.steps[this.scenario.steps.length - 1];
|
|
237
|
+
if (lastStep.type === 'rest') {
|
|
238
|
+
lastStep.query = params;
|
|
239
|
+
}
|
|
240
|
+
return this;
|
|
241
|
+
}
|
|
242
|
+
// Add think time to the last step
|
|
243
|
+
withThinkTime(time) {
|
|
244
|
+
const lastStep = this.scenario.steps[this.scenario.steps.length - 1];
|
|
245
|
+
lastStep.think_time = time;
|
|
246
|
+
return this;
|
|
247
|
+
}
|
|
248
|
+
extract(name, expression, type = 'json_path') {
|
|
249
|
+
const lastStep = this.scenario.steps[this.scenario.steps.length - 1];
|
|
250
|
+
if (!lastStep.extract)
|
|
251
|
+
lastStep.extract = [];
|
|
252
|
+
lastStep.extract.push({ name, expression, type });
|
|
253
|
+
return this;
|
|
254
|
+
}
|
|
255
|
+
check(type, value, description) {
|
|
256
|
+
const lastStep = this.scenario.steps[this.scenario.steps.length - 1];
|
|
257
|
+
if (!lastStep.checks)
|
|
258
|
+
lastStep.checks = [];
|
|
259
|
+
lastStep.checks.push({ type, value, description });
|
|
260
|
+
return this;
|
|
261
|
+
}
|
|
262
|
+
// SOAP step method
|
|
263
|
+
soap(operation, args, wsdl) {
|
|
264
|
+
return this.addStep({
|
|
265
|
+
name: `SOAP ${operation}`,
|
|
266
|
+
type: 'soap',
|
|
267
|
+
operation,
|
|
268
|
+
args,
|
|
269
|
+
...(wsdl && { wsdl })
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
// Custom step method
|
|
273
|
+
// Updated custom step method with context
|
|
274
|
+
step(name, script) {
|
|
275
|
+
const scriptStr = typeof script === 'function' ?
|
|
276
|
+
`(${script.toString()})(context)` : script;
|
|
277
|
+
return this.addStep({
|
|
278
|
+
name,
|
|
279
|
+
type: 'custom',
|
|
280
|
+
script: scriptStr
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
// Add a raw step
|
|
284
|
+
addStep(step) {
|
|
285
|
+
this.scenario.steps = [...(this.scenario.steps || []), step];
|
|
286
|
+
return this;
|
|
287
|
+
}
|
|
288
|
+
// Finish scenario and return to parent
|
|
289
|
+
done() {
|
|
290
|
+
this.parent.addScenario(this.scenario);
|
|
291
|
+
return this.parent;
|
|
292
|
+
}
|
|
293
|
+
// Alias for done()
|
|
294
|
+
endScenario() {
|
|
295
|
+
return this.done();
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
exports.ScenarioBuilder = ScenarioBuilder;
|
|
299
|
+
class LoadBuilder {
|
|
300
|
+
constructor() {
|
|
301
|
+
this.loadConfig = {};
|
|
302
|
+
}
|
|
303
|
+
name(name) {
|
|
304
|
+
this.loadConfig.name = name;
|
|
305
|
+
return this;
|
|
306
|
+
}
|
|
307
|
+
pattern(pattern) {
|
|
308
|
+
this.loadConfig.pattern = pattern;
|
|
309
|
+
return this;
|
|
310
|
+
}
|
|
311
|
+
virtualUsers(count) {
|
|
312
|
+
this.loadConfig.virtual_users = count;
|
|
313
|
+
return this;
|
|
314
|
+
}
|
|
315
|
+
vus(count) {
|
|
316
|
+
this.loadConfig.vus = count;
|
|
317
|
+
return this;
|
|
318
|
+
}
|
|
319
|
+
rampUp(duration) {
|
|
320
|
+
this.loadConfig.ramp_up = duration;
|
|
321
|
+
return this;
|
|
322
|
+
}
|
|
323
|
+
duration(duration) {
|
|
324
|
+
this.loadConfig.duration = duration;
|
|
325
|
+
return this;
|
|
326
|
+
}
|
|
327
|
+
rate(requestsPerSecond) {
|
|
328
|
+
this.loadConfig.rate = requestsPerSecond;
|
|
329
|
+
return this;
|
|
330
|
+
}
|
|
331
|
+
steps(steps) {
|
|
332
|
+
this.loadConfig.steps = steps;
|
|
333
|
+
return this;
|
|
334
|
+
}
|
|
335
|
+
build() {
|
|
336
|
+
if (!this.loadConfig.pattern) {
|
|
337
|
+
this.loadConfig.pattern = 'basic';
|
|
338
|
+
}
|
|
339
|
+
if (!this.loadConfig.duration) {
|
|
340
|
+
this.loadConfig.duration = '1m'; // Default duration
|
|
341
|
+
}
|
|
342
|
+
return this.loadConfig;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
exports.LoadBuilder = LoadBuilder;
|
|
346
|
+
// Factory functions for convenience
|
|
347
|
+
function test(name) {
|
|
348
|
+
return new TestBuilder(name);
|
|
349
|
+
}
|
|
350
|
+
function load() {
|
|
351
|
+
return new LoadBuilder();
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Fluent DSL for building test configurations
|
|
355
|
+
*
|
|
356
|
+
* Usage:
|
|
357
|
+
* const config = test('My Test')
|
|
358
|
+
* .baseUrl('https://example.com')
|
|
359
|
+
* .withBrowser('chromium', { headless: false })
|
|
360
|
+
* .scenario('User Journey')
|
|
361
|
+
* .goto('/')
|
|
362
|
+
* .click('#login')
|
|
363
|
+
* .fill('#username', 'test@example.com')
|
|
364
|
+
* .expectVisible('#dashboard')
|
|
365
|
+
* .done()
|
|
366
|
+
* .withLoad({ pattern: 'basic', virtualUsers: 10 })
|
|
367
|
+
* .build();
|
|
368
|
+
*/
|
|
369
|
+
class TestBuilder {
|
|
370
|
+
constructor(name) {
|
|
371
|
+
this.config = {
|
|
372
|
+
scenarios: [],
|
|
373
|
+
outputs: [],
|
|
374
|
+
global: {}
|
|
375
|
+
};
|
|
376
|
+
this.config.name = name;
|
|
377
|
+
}
|
|
378
|
+
configuration(confis) {
|
|
379
|
+
this.config = confis;
|
|
380
|
+
return this;
|
|
381
|
+
}
|
|
382
|
+
description(desc) {
|
|
383
|
+
this.config.description = desc;
|
|
384
|
+
return this;
|
|
385
|
+
}
|
|
386
|
+
// Global configuration methods
|
|
387
|
+
baseUrl(url) {
|
|
388
|
+
this.config.global = { ...this.config.global, base_url: url };
|
|
389
|
+
return this;
|
|
390
|
+
}
|
|
391
|
+
timeout(ms) {
|
|
392
|
+
this.config.global = { ...this.config.global, timeout: ms };
|
|
393
|
+
return this;
|
|
394
|
+
}
|
|
395
|
+
thinkTime(time) {
|
|
396
|
+
this.config.global = { ...this.config.global, think_time: time };
|
|
397
|
+
return this;
|
|
398
|
+
}
|
|
399
|
+
headers(headers) {
|
|
400
|
+
this.config.global = {
|
|
401
|
+
...this.config.global,
|
|
402
|
+
headers: { ...(this.config.global?.headers || {}), ...headers }
|
|
403
|
+
};
|
|
404
|
+
return this;
|
|
405
|
+
}
|
|
406
|
+
withBrowser(type, options) {
|
|
407
|
+
this.config.global = {
|
|
408
|
+
...this.config.global,
|
|
409
|
+
browser: {
|
|
410
|
+
type,
|
|
411
|
+
...options
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
return this;
|
|
415
|
+
}
|
|
416
|
+
withWSDL(url) {
|
|
417
|
+
this.config.global = { ...this.config.global, wsdl_url: url };
|
|
418
|
+
return this;
|
|
419
|
+
}
|
|
420
|
+
variables(vars) {
|
|
421
|
+
if (!this.config.global) {
|
|
422
|
+
this.config.global = {};
|
|
423
|
+
}
|
|
424
|
+
this.config.global = {
|
|
425
|
+
...this.config.global,
|
|
426
|
+
variables: { ...(this.config.global.variables || {}), ...vars }
|
|
427
|
+
};
|
|
428
|
+
return this;
|
|
429
|
+
}
|
|
430
|
+
// Create a new scenario
|
|
431
|
+
scenario(name, weight = 100) {
|
|
432
|
+
return new ScenarioBuilder(this, name, weight);
|
|
433
|
+
}
|
|
434
|
+
// Add a complete scenario
|
|
435
|
+
addScenario(scenario) {
|
|
436
|
+
this.config.scenarios = [...(this.config.scenarios || []), scenario];
|
|
437
|
+
return this;
|
|
438
|
+
}
|
|
439
|
+
// Load configuration - supports single phase or array of phases
|
|
440
|
+
withLoad(load) {
|
|
441
|
+
if (Array.isArray(load)) {
|
|
442
|
+
// Array of LoadBuilders - build each one
|
|
443
|
+
this.config.load = load.map(lb => lb instanceof LoadBuilder ? lb.build() : lb);
|
|
444
|
+
}
|
|
445
|
+
else if (load instanceof LoadBuilder) {
|
|
446
|
+
this.config.load = load.build();
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
this.config.load = load;
|
|
450
|
+
}
|
|
451
|
+
return this;
|
|
452
|
+
}
|
|
453
|
+
// Add multiple load phases (sequential execution)
|
|
454
|
+
withLoadPhases(...phases) {
|
|
455
|
+
this.config.load = phases.map(phase => phase instanceof LoadBuilder ? phase.build() : phase);
|
|
456
|
+
return this;
|
|
457
|
+
}
|
|
458
|
+
// Output configuration
|
|
459
|
+
withOutput(type, options) {
|
|
460
|
+
this.config.outputs = [
|
|
461
|
+
...(this.config.outputs || []),
|
|
462
|
+
{ type, ...options }
|
|
463
|
+
];
|
|
464
|
+
return this;
|
|
465
|
+
}
|
|
466
|
+
withJSONOutput(file) {
|
|
467
|
+
return this.withOutput('json', { file });
|
|
468
|
+
}
|
|
469
|
+
withCSVOutput(file) {
|
|
470
|
+
return this.withOutput('csv', { file });
|
|
471
|
+
}
|
|
472
|
+
// Report configuration
|
|
473
|
+
withReport(output = 'report.html') {
|
|
474
|
+
this.config.report = {
|
|
475
|
+
generate: true,
|
|
476
|
+
output
|
|
477
|
+
};
|
|
478
|
+
return this;
|
|
479
|
+
}
|
|
480
|
+
// Build the final configuration
|
|
481
|
+
build() {
|
|
482
|
+
if (!this.config.name)
|
|
483
|
+
throw new Error('Test name is required');
|
|
484
|
+
if (!this.config.load) {
|
|
485
|
+
// Default load configuration
|
|
486
|
+
this.config.load = {
|
|
487
|
+
pattern: 'basic',
|
|
488
|
+
virtual_users: 1,
|
|
489
|
+
ramp_up: '10s',
|
|
490
|
+
duration: '1m'
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
if (!this.config.scenarios || this.config.scenarios.length === 0) {
|
|
494
|
+
throw new Error('At least one scenario is required');
|
|
495
|
+
}
|
|
496
|
+
return this.config;
|
|
497
|
+
}
|
|
498
|
+
// Run the test directly
|
|
499
|
+
async run() {
|
|
500
|
+
const { TestRunner } = await Promise.resolve().then(() => __importStar(require('../core/test-runner')));
|
|
501
|
+
const runner = new TestRunner(this.build());
|
|
502
|
+
await runner.run();
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
exports.TestBuilder = TestBuilder;
|
|
506
|
+
exports.testData = {
|
|
507
|
+
email: () => (0, faker_manager_1.getFaker)().internet.email(),
|
|
508
|
+
password: () => (0, faker_manager_1.getFaker)().internet.password(),
|
|
509
|
+
firstName: () => (0, faker_manager_1.getFaker)().person.firstName(),
|
|
510
|
+
lastName: () => (0, faker_manager_1.getFaker)().person.lastName(),
|
|
511
|
+
phone: () => (0, faker_manager_1.getFaker)().phone.number(),
|
|
512
|
+
uuid: () => (0, faker_manager_1.getFaker)().string.uuid(),
|
|
513
|
+
randomInt: (min, max) => (0, faker_manager_1.getFaker)().number.int({ min, max })
|
|
514
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ImportableEndpoint } from "../config/types/import-types";
|
|
2
|
+
export declare class HARImporter {
|
|
3
|
+
private har;
|
|
4
|
+
constructor(harContent: any);
|
|
5
|
+
extractEndpoints(): ImportableEndpoint[];
|
|
6
|
+
generateScenarios(selectedEndpoints: ImportableEndpoint[]): any[];
|
|
7
|
+
private isAPIRequest;
|
|
8
|
+
private extractPath;
|
|
9
|
+
private extractParametersFromHAR;
|
|
10
|
+
private extractRequestBodyFromHAR;
|
|
11
|
+
private extractContentType;
|
|
12
|
+
private deduplicateEndpoints;
|
|
13
|
+
private extractHeadersFromEndpoint;
|
|
14
|
+
private parseRequestBody;
|
|
15
|
+
private generateHARExtractions;
|
|
16
|
+
private hasField;
|
|
17
|
+
}
|