@elliemae/encw-leak-runner 1.0.2
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/.eslintrc.cjs +10 -0
- package/.stylelintignore +4 -0
- package/CHANGELOG.md +51 -0
- package/README.md +309 -0
- package/babel.config.cjs +2 -0
- package/bin/leak-runner.ts +9 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/bin/leak-runner.js +792 -0
- package/dist/cjs/analysis/thresholdEvaluator.js +46 -0
- package/dist/cjs/browser/iframeHeapProfiler.js +46 -0
- package/dist/cjs/cli/command.js +16 -0
- package/dist/cjs/cli/commands/listCommand.js +47 -0
- package/dist/cjs/cli/commands/runCommand.js +111 -0
- package/dist/cjs/cli/index.js +42 -0
- package/dist/cjs/config/missingRequiredParamError.js +34 -0
- package/dist/cjs/config/requiredEnvParams.js +57 -0
- package/dist/cjs/config/runnerConfigLoader.js +73 -0
- package/dist/cjs/config/runnerConfigSchema.js +40 -0
- package/dist/cjs/config/sources/cliOverrideConfigSource.js +44 -0
- package/dist/cjs/config/sources/configSource.js +35 -0
- package/dist/cjs/config/sources/envVarConfigSource.js +41 -0
- package/dist/cjs/config/sources/fileConfigSource.js +62 -0
- package/dist/cjs/index.js +52 -0
- package/dist/cjs/package.json +7 -0
- package/dist/cjs/registry/scenarioRegistry.js +51 -0
- package/dist/cjs/reporting/consoleReporter.js +60 -0
- package/dist/cjs/reporting/junitReporter.js +75 -0
- package/dist/cjs/reporting/reporter.js +16 -0
- package/dist/cjs/runner/aiEnhancementStep.js +39 -0
- package/dist/cjs/runner/batchRunner.js +76 -0
- package/dist/cjs/runner/scenarioRunner.js +165 -0
- package/dist/cjs/scenarios/index.js +29 -0
- package/dist/cjs/scenarios/one-admin/export-navigation.scenario.js +50 -0
- package/dist/cjs/scenarios/one-admin/index.js +27 -0
- package/dist/cjs/scenarios/one-admin/page-models/ExportPageModel.js +43 -0
- package/dist/cjs/scenarios/one-admin/page-models/SelectSettingsPageModel.js +47 -0
- package/dist/cjs/scenarios/one-admin/page-models/index.js +26 -0
- package/dist/cjs/types/config.js +27 -0
- package/dist/cjs/types/results.js +16 -0
- package/dist/cjs/types/scenario.js +16 -0
- package/dist/esm/analysis/thresholdEvaluator.js +26 -0
- package/dist/esm/browser/iframeHeapProfiler.js +26 -0
- package/dist/esm/cli/command.js +0 -0
- package/dist/esm/cli/commands/listCommand.js +27 -0
- package/dist/esm/cli/commands/runCommand.js +93 -0
- package/dist/esm/cli/index.js +22 -0
- package/dist/esm/config/missingRequiredParamError.js +14 -0
- package/dist/esm/config/requiredEnvParams.js +37 -0
- package/dist/esm/config/runnerConfigLoader.js +53 -0
- package/dist/esm/config/runnerConfigSchema.js +20 -0
- package/dist/esm/config/sources/cliOverrideConfigSource.js +24 -0
- package/dist/esm/config/sources/configSource.js +15 -0
- package/dist/esm/config/sources/envVarConfigSource.js +21 -0
- package/dist/esm/config/sources/fileConfigSource.js +34 -0
- package/dist/esm/index.js +35 -0
- package/dist/esm/package.json +7 -0
- package/dist/esm/registry/scenarioRegistry.js +31 -0
- package/dist/esm/reporting/consoleReporter.js +40 -0
- package/dist/esm/reporting/junitReporter.js +45 -0
- package/dist/esm/reporting/reporter.js +0 -0
- package/dist/esm/runner/aiEnhancementStep.js +22 -0
- package/dist/esm/runner/batchRunner.js +56 -0
- package/dist/esm/runner/scenarioRunner.js +137 -0
- package/dist/esm/scenarios/index.js +9 -0
- package/dist/esm/scenarios/one-admin/export-navigation.scenario.js +33 -0
- package/dist/esm/scenarios/one-admin/index.js +7 -0
- package/dist/esm/scenarios/one-admin/page-models/ExportPageModel.js +23 -0
- package/dist/esm/scenarios/one-admin/page-models/SelectSettingsPageModel.js +27 -0
- package/dist/esm/scenarios/one-admin/page-models/index.js +6 -0
- package/dist/esm/types/config.js +7 -0
- package/dist/esm/types/results.js +0 -0
- package/dist/esm/types/scenario.js +0 -0
- package/dist/types/bin/leak-runner.d.ts +2 -0
- package/dist/types/lib/analysis/tests/thresholdEvaluator.test.d.ts +1 -0
- package/dist/types/lib/analysis/thresholdEvaluator.d.ts +6 -0
- package/dist/types/lib/browser/iframeHeapProfiler.d.ts +9 -0
- package/dist/types/lib/browser/tests/iframeHeapProfiler.test.d.ts +1 -0
- package/dist/types/lib/cli/command.d.ts +17 -0
- package/dist/types/lib/cli/commands/listCommand.d.ts +5 -0
- package/dist/types/lib/cli/commands/runCommand.d.ts +7 -0
- package/dist/types/lib/cli/index.d.ts +4 -0
- package/dist/types/lib/config/missingRequiredParamError.d.ts +4 -0
- package/dist/types/lib/config/requiredEnvParams.d.ts +16 -0
- package/dist/types/lib/config/runnerConfigLoader.d.ts +13 -0
- package/dist/types/lib/config/runnerConfigSchema.d.ts +78 -0
- package/dist/types/lib/config/sources/cliOverrideConfigSource.d.ts +14 -0
- package/dist/types/lib/config/sources/configSource.d.ts +14 -0
- package/dist/types/lib/config/sources/envVarConfigSource.d.ts +7 -0
- package/dist/types/lib/config/sources/fileConfigSource.d.ts +9 -0
- package/dist/types/lib/config/tests/cliOverrideConfigSource.test.d.ts +1 -0
- package/dist/types/lib/config/tests/envVarConfigSource.test.d.ts +1 -0
- package/dist/types/lib/config/tests/fileConfigSource.test.d.ts +1 -0
- package/dist/types/lib/config/tests/requiredEnvParams.test.d.ts +1 -0
- package/dist/types/lib/config/tests/runnerConfigLoader.test.d.ts +1 -0
- package/dist/types/lib/index.d.ts +18 -0
- package/dist/types/lib/registry/scenarioRegistry.d.ts +18 -0
- package/dist/types/lib/registry/tests/scenarioRegistry.test.d.ts +1 -0
- package/dist/types/lib/reporting/consoleReporter.d.ts +5 -0
- package/dist/types/lib/reporting/junitReporter.d.ts +5 -0
- package/dist/types/lib/reporting/reporter.d.ts +4 -0
- package/dist/types/lib/reporting/tests/consoleReporter.test.d.ts +1 -0
- package/dist/types/lib/reporting/tests/junitReporter.test.d.ts +1 -0
- package/dist/types/lib/runner/aiEnhancementStep.d.ts +15 -0
- package/dist/types/lib/runner/batchRunner.d.ts +14 -0
- package/dist/types/lib/runner/scenarioRunner.d.ts +15 -0
- package/dist/types/lib/runner/tests/aiEnhancementStep.test.d.ts +1 -0
- package/dist/types/lib/runner/tests/batchRunner.test.d.ts +1 -0
- package/dist/types/lib/runner/tests/scenarioRunner.test.d.ts +1 -0
- package/dist/types/lib/scenarios/index.d.ts +2 -0
- package/dist/types/lib/scenarios/one-admin/export-navigation.scenario.d.ts +2 -0
- package/dist/types/lib/scenarios/one-admin/index.d.ts +2 -0
- package/dist/types/lib/scenarios/one-admin/page-models/ExportPageModel.d.ts +8 -0
- package/dist/types/lib/scenarios/one-admin/page-models/SelectSettingsPageModel.d.ts +10 -0
- package/dist/types/lib/scenarios/one-admin/page-models/index.d.ts +2 -0
- package/dist/types/lib/types/config.d.ts +26 -0
- package/dist/types/lib/types/results.d.ts +19 -0
- package/dist/types/lib/types/scenario.d.ts +17 -0
- package/jest.config.cjs +9 -0
- package/leak-runner.config.json +13 -0
- package/leak-runner.schema.json +27 -0
- package/lib/analysis/tests/thresholdEvaluator.test.ts +125 -0
- package/lib/analysis/thresholdEvaluator.ts +36 -0
- package/lib/browser/iframeHeapProfiler.ts +30 -0
- package/lib/browser/tests/iframeHeapProfiler.test.ts +71 -0
- package/lib/cli/command.ts +19 -0
- package/lib/cli/commands/listCommand.ts +36 -0
- package/lib/cli/commands/runCommand.ts +126 -0
- package/lib/cli/index.ts +25 -0
- package/lib/config/missingRequiredParamError.ts +10 -0
- package/lib/config/requiredEnvParams.ts +50 -0
- package/lib/config/runnerConfigLoader.ts +84 -0
- package/lib/config/runnerConfigSchema.ts +27 -0
- package/lib/config/sources/cliOverrideConfigSource.ts +30 -0
- package/lib/config/sources/configSource.ts +27 -0
- package/lib/config/sources/envVarConfigSource.ts +23 -0
- package/lib/config/sources/fileConfigSource.ts +39 -0
- package/lib/config/tests/cliOverrideConfigSource.test.ts +25 -0
- package/lib/config/tests/envVarConfigSource.test.ts +57 -0
- package/lib/config/tests/fileConfigSource.test.ts +49 -0
- package/lib/config/tests/requiredEnvParams.test.ts +113 -0
- package/lib/config/tests/runnerConfigLoader.test.ts +59 -0
- package/lib/index.ts +37 -0
- package/lib/registry/scenarioRegistry.ts +48 -0
- package/lib/registry/tests/scenarioRegistry.test.ts +96 -0
- package/lib/reporting/consoleReporter.ts +48 -0
- package/lib/reporting/junitReporter.ts +62 -0
- package/lib/reporting/reporter.ts +5 -0
- package/lib/reporting/tests/consoleReporter.test.ts +82 -0
- package/lib/reporting/tests/junitReporter.test.ts +103 -0
- package/lib/runner/aiEnhancementStep.ts +39 -0
- package/lib/runner/batchRunner.ts +71 -0
- package/lib/runner/scenarioRunner.ts +189 -0
- package/lib/runner/tests/aiEnhancementStep.test.ts +174 -0
- package/lib/runner/tests/batchRunner.test.ts +133 -0
- package/lib/runner/tests/scenarioRunner.test.ts +162 -0
- package/lib/scenarios/index.ts +8 -0
- package/lib/scenarios/one-admin/export-navigation.scenario.ts +38 -0
- package/lib/scenarios/one-admin/index.ts +6 -0
- package/lib/scenarios/one-admin/page-models/ExportPageModel.ts +26 -0
- package/lib/scenarios/one-admin/page-models/SelectSettingsPageModel.ts +30 -0
- package/lib/scenarios/one-admin/page-models/index.ts +2 -0
- package/lib/types/config.ts +34 -0
- package/lib/types/results.ts +22 -0
- package/lib/types/scenario.ts +18 -0
- package/package.json +46 -0
- package/reports/analysis/index.html +116 -0
- package/reports/analysis/thresholdEvaluator.ts.html +193 -0
- package/reports/base.css +224 -0
- package/reports/block-navigation.js +87 -0
- package/reports/browser/iframeHeapProfiler.ts.html +175 -0
- package/reports/browser/index.html +116 -0
- package/reports/cli/commands/index.html +131 -0
- package/reports/cli/commands/listCommand.ts.html +193 -0
- package/reports/cli/commands/runCommand.ts.html +463 -0
- package/reports/cli/index.html +116 -0
- package/reports/cli/index.ts.html +160 -0
- package/reports/config/index.html +161 -0
- package/reports/config/missingRequiredParamError.ts.html +115 -0
- package/reports/config/requiredEnvParams.ts.html +235 -0
- package/reports/config/runnerConfigLoader.ts.html +337 -0
- package/reports/config/runnerConfigSchema.ts.html +166 -0
- package/reports/config/sources/cliOverrideConfigSource.ts.html +175 -0
- package/reports/config/sources/configSource.ts.html +166 -0
- package/reports/config/sources/envVarConfigSource.ts.html +154 -0
- package/reports/config/sources/fileConfigSource.ts.html +202 -0
- package/reports/config/sources/index.html +161 -0
- package/reports/favicon.png +0 -0
- package/reports/index.html +296 -0
- package/reports/lcov-report/analysis/index.html +116 -0
- package/reports/lcov-report/analysis/thresholdEvaluator.ts.html +193 -0
- package/reports/lcov-report/base.css +224 -0
- package/reports/lcov-report/block-navigation.js +87 -0
- package/reports/lcov-report/browser/iframeHeapProfiler.ts.html +175 -0
- package/reports/lcov-report/browser/index.html +116 -0
- package/reports/lcov-report/cli/commands/index.html +131 -0
- package/reports/lcov-report/cli/commands/listCommand.ts.html +193 -0
- package/reports/lcov-report/cli/commands/runCommand.ts.html +463 -0
- package/reports/lcov-report/cli/index.html +116 -0
- package/reports/lcov-report/cli/index.ts.html +160 -0
- package/reports/lcov-report/config/index.html +161 -0
- package/reports/lcov-report/config/missingRequiredParamError.ts.html +115 -0
- package/reports/lcov-report/config/requiredEnvParams.ts.html +235 -0
- package/reports/lcov-report/config/runnerConfigLoader.ts.html +337 -0
- package/reports/lcov-report/config/runnerConfigSchema.ts.html +166 -0
- package/reports/lcov-report/config/sources/cliOverrideConfigSource.ts.html +175 -0
- package/reports/lcov-report/config/sources/configSource.ts.html +166 -0
- package/reports/lcov-report/config/sources/envVarConfigSource.ts.html +154 -0
- package/reports/lcov-report/config/sources/fileConfigSource.ts.html +202 -0
- package/reports/lcov-report/config/sources/index.html +161 -0
- package/reports/lcov-report/favicon.png +0 -0
- package/reports/lcov-report/index.html +296 -0
- package/reports/lcov-report/prettify.css +1 -0
- package/reports/lcov-report/prettify.js +2 -0
- package/reports/lcov-report/registry/index.html +116 -0
- package/reports/lcov-report/registry/scenarioRegistry.ts.html +229 -0
- package/reports/lcov-report/reporting/consoleReporter.ts.html +229 -0
- package/reports/lcov-report/reporting/index.html +131 -0
- package/reports/lcov-report/reporting/junitReporter.ts.html +271 -0
- package/reports/lcov-report/runner/aiEnhancementStep.ts.html +202 -0
- package/reports/lcov-report/runner/batchRunner.ts.html +298 -0
- package/reports/lcov-report/runner/index.html +146 -0
- package/reports/lcov-report/runner/scenarioRunner.ts.html +652 -0
- package/reports/lcov-report/scenarios/index.html +116 -0
- package/reports/lcov-report/scenarios/index.ts.html +109 -0
- package/reports/lcov-report/scenarios/one-admin/export-navigation.scenario.ts.html +199 -0
- package/reports/lcov-report/scenarios/one-admin/index.html +131 -0
- package/reports/lcov-report/scenarios/one-admin/index.ts.html +103 -0
- package/reports/lcov-report/scenarios/one-admin/page-models/ExportPageModel.ts.html +163 -0
- package/reports/lcov-report/scenarios/one-admin/page-models/SelectSettingsPageModel.ts.html +175 -0
- package/reports/lcov-report/scenarios/one-admin/page-models/index.html +131 -0
- package/reports/lcov-report/sort-arrow-sprite.png +0 -0
- package/reports/lcov-report/sorter.js +210 -0
- package/reports/lcov-report/types/config.ts.html +187 -0
- package/reports/lcov-report/types/index.html +116 -0
- package/reports/lcov.info +883 -0
- package/reports/prettify.css +1 -0
- package/reports/prettify.js +2 -0
- package/reports/registry/index.html +116 -0
- package/reports/registry/scenarioRegistry.ts.html +229 -0
- package/reports/reporting/consoleReporter.ts.html +229 -0
- package/reports/reporting/index.html +131 -0
- package/reports/reporting/junitReporter.ts.html +271 -0
- package/reports/runner/aiEnhancementStep.ts.html +202 -0
- package/reports/runner/batchRunner.ts.html +298 -0
- package/reports/runner/index.html +146 -0
- package/reports/runner/scenarioRunner.ts.html +652 -0
- package/reports/scenarios/index.html +116 -0
- package/reports/scenarios/index.ts.html +109 -0
- package/reports/scenarios/one-admin/export-navigation.scenario.ts.html +199 -0
- package/reports/scenarios/one-admin/index.html +131 -0
- package/reports/scenarios/one-admin/index.ts.html +103 -0
- package/reports/scenarios/one-admin/page-models/ExportPageModel.ts.html +163 -0
- package/reports/scenarios/one-admin/page-models/SelectSettingsPageModel.ts.html +175 -0
- package/reports/scenarios/one-admin/page-models/index.html +131 -0
- package/reports/sort-arrow-sprite.png +0 -0
- package/reports/sorter.js +210 -0
- package/reports/types/config.ts.html +187 -0
- package/reports/types/index.html +116 -0
- package/stylelint.config.cjs +2 -0
- package/test-report.xml +100 -0
- package/tsconfig.json +12 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const runnerOptionsSchema: z.ZodObject<{
|
|
3
|
+
headless: z.ZodOptional<z.ZodBoolean>;
|
|
4
|
+
outputDir: z.ZodOptional<z.ZodString>;
|
|
5
|
+
topN: z.ZodOptional<z.ZodNumber>;
|
|
6
|
+
}, "strip", z.ZodTypeAny, {
|
|
7
|
+
headless?: boolean | undefined;
|
|
8
|
+
outputDir?: string | undefined;
|
|
9
|
+
topN?: number | undefined;
|
|
10
|
+
}, {
|
|
11
|
+
headless?: boolean | undefined;
|
|
12
|
+
outputDir?: string | undefined;
|
|
13
|
+
topN?: number | undefined;
|
|
14
|
+
}>;
|
|
15
|
+
export declare const aiConfigFileSchema: z.ZodObject<{
|
|
16
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
17
|
+
model: z.ZodOptional<z.ZodString>;
|
|
18
|
+
temperature: z.ZodOptional<z.ZodNumber>;
|
|
19
|
+
}, "strip", z.ZodTypeAny, {
|
|
20
|
+
enabled?: boolean | undefined;
|
|
21
|
+
model?: string | undefined;
|
|
22
|
+
temperature?: number | undefined;
|
|
23
|
+
}, {
|
|
24
|
+
enabled?: boolean | undefined;
|
|
25
|
+
model?: string | undefined;
|
|
26
|
+
temperature?: number | undefined;
|
|
27
|
+
}>;
|
|
28
|
+
export declare const runnerConfigFileSchema: z.ZodObject<{
|
|
29
|
+
runner: z.ZodOptional<z.ZodObject<{
|
|
30
|
+
headless: z.ZodOptional<z.ZodBoolean>;
|
|
31
|
+
outputDir: z.ZodOptional<z.ZodString>;
|
|
32
|
+
topN: z.ZodOptional<z.ZodNumber>;
|
|
33
|
+
}, "strip", z.ZodTypeAny, {
|
|
34
|
+
headless?: boolean | undefined;
|
|
35
|
+
outputDir?: string | undefined;
|
|
36
|
+
topN?: number | undefined;
|
|
37
|
+
}, {
|
|
38
|
+
headless?: boolean | undefined;
|
|
39
|
+
outputDir?: string | undefined;
|
|
40
|
+
topN?: number | undefined;
|
|
41
|
+
}>>;
|
|
42
|
+
ai: z.ZodOptional<z.ZodObject<{
|
|
43
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
44
|
+
model: z.ZodOptional<z.ZodString>;
|
|
45
|
+
temperature: z.ZodOptional<z.ZodNumber>;
|
|
46
|
+
}, "strip", z.ZodTypeAny, {
|
|
47
|
+
enabled?: boolean | undefined;
|
|
48
|
+
model?: string | undefined;
|
|
49
|
+
temperature?: number | undefined;
|
|
50
|
+
}, {
|
|
51
|
+
enabled?: boolean | undefined;
|
|
52
|
+
model?: string | undefined;
|
|
53
|
+
temperature?: number | undefined;
|
|
54
|
+
}>>;
|
|
55
|
+
}, "strict", z.ZodTypeAny, {
|
|
56
|
+
runner?: {
|
|
57
|
+
headless?: boolean | undefined;
|
|
58
|
+
outputDir?: string | undefined;
|
|
59
|
+
topN?: number | undefined;
|
|
60
|
+
} | undefined;
|
|
61
|
+
ai?: {
|
|
62
|
+
enabled?: boolean | undefined;
|
|
63
|
+
model?: string | undefined;
|
|
64
|
+
temperature?: number | undefined;
|
|
65
|
+
} | undefined;
|
|
66
|
+
}, {
|
|
67
|
+
runner?: {
|
|
68
|
+
headless?: boolean | undefined;
|
|
69
|
+
outputDir?: string | undefined;
|
|
70
|
+
topN?: number | undefined;
|
|
71
|
+
} | undefined;
|
|
72
|
+
ai?: {
|
|
73
|
+
enabled?: boolean | undefined;
|
|
74
|
+
model?: string | undefined;
|
|
75
|
+
temperature?: number | undefined;
|
|
76
|
+
} | undefined;
|
|
77
|
+
}>;
|
|
78
|
+
export type RawRunnerConfigFile = z.infer<typeof runnerConfigFileSchema>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { RawRunnerConfigFile } from '../runnerConfigSchema.js';
|
|
2
|
+
import type { ConfigSource } from './configSource.js';
|
|
3
|
+
export interface CliRunnerOverrides {
|
|
4
|
+
headless?: boolean;
|
|
5
|
+
outputDir?: string;
|
|
6
|
+
topN?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare class CliOverrideConfigSource implements ConfigSource {
|
|
9
|
+
private readonly overrides;
|
|
10
|
+
readonly priority = 3;
|
|
11
|
+
readonly name = "cli";
|
|
12
|
+
constructor(overrides: CliRunnerOverrides);
|
|
13
|
+
load(): Partial<RawRunnerConfigFile>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { RawRunnerConfigFile } from '../runnerConfigSchema.js';
|
|
2
|
+
/**
|
|
3
|
+
* Strategy interface — each source produces a partial config payload.
|
|
4
|
+
* Higher `priority` overrides lower when merged by `RunnerConfigLoader`.
|
|
5
|
+
*/
|
|
6
|
+
export interface ConfigSource {
|
|
7
|
+
readonly priority: number;
|
|
8
|
+
readonly name: string;
|
|
9
|
+
load(): Partial<RawRunnerConfigFile>;
|
|
10
|
+
}
|
|
11
|
+
export declare const BUILT_IN_DEFAULTS: Required<{
|
|
12
|
+
runner: NonNullable<RawRunnerConfigFile['runner']>;
|
|
13
|
+
ai: NonNullable<RawRunnerConfigFile['ai']>;
|
|
14
|
+
}>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RawRunnerConfigFile } from '../runnerConfigSchema.js';
|
|
2
|
+
import type { ConfigSource } from './configSource.js';
|
|
3
|
+
export declare class EnvVarConfigSource implements ConfigSource {
|
|
4
|
+
readonly priority = 2;
|
|
5
|
+
readonly name = "env";
|
|
6
|
+
load(): Partial<RawRunnerConfigFile>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type RawRunnerConfigFile } from '../runnerConfigSchema.js';
|
|
2
|
+
import type { ConfigSource } from './configSource.js';
|
|
3
|
+
export declare class FileConfigSource implements ConfigSource {
|
|
4
|
+
private readonly filePath;
|
|
5
|
+
readonly priority = 1;
|
|
6
|
+
readonly name = "file";
|
|
7
|
+
constructor(filePath: string);
|
|
8
|
+
load(): Partial<RawRunnerConfigFile>;
|
|
9
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type { MicroappLeakScenario } from './types/scenario.js';
|
|
2
|
+
export type { EnvironmentParams, RunnerOptions, AiConfig, RunnerConfig, ResolvedThresholds, } from './types/config.js';
|
|
3
|
+
export { DEFAULT_THRESHOLDS } from './types/config.js';
|
|
4
|
+
export type { ScenarioGroup, ScenarioEntry, } from './registry/scenarioRegistry.js';
|
|
5
|
+
export type { ThresholdResult, ScenarioResult, RunSummary, } from './types/results.js';
|
|
6
|
+
export { ScenarioRegistry } from './registry/scenarioRegistry.js';
|
|
7
|
+
export { BatchRunner } from './runner/batchRunner.js';
|
|
8
|
+
export { ScenarioRunner } from './runner/scenarioRunner.js';
|
|
9
|
+
export { IframeHeapProfiler } from './browser/iframeHeapProfiler.js';
|
|
10
|
+
export { ThresholdEvaluator } from './analysis/thresholdEvaluator.js';
|
|
11
|
+
export { ConsoleReporter } from './reporting/consoleReporter.js';
|
|
12
|
+
export { JunitReporter } from './reporting/junitReporter.js';
|
|
13
|
+
export { RunnerConfigLoader } from './config/runnerConfigLoader.js';
|
|
14
|
+
export { FileConfigSource } from './config/sources/fileConfigSource.js';
|
|
15
|
+
export { EnvVarConfigSource } from './config/sources/envVarConfigSource.js';
|
|
16
|
+
export { CliOverrideConfigSource } from './config/sources/cliOverrideConfigSource.js';
|
|
17
|
+
export { RequiredEnvParamsResolver, MissingRequiredParamError, } from './config/requiredEnvParams.js';
|
|
18
|
+
export { buildProgram, defaultDeps } from './cli/index.js';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { MicroappLeakScenario } from '../types/scenario.js';
|
|
2
|
+
export interface ScenarioGroup {
|
|
3
|
+
readonly microapp: string;
|
|
4
|
+
readonly scenarios: readonly MicroappLeakScenario[];
|
|
5
|
+
}
|
|
6
|
+
export interface ScenarioEntry {
|
|
7
|
+
readonly key: string;
|
|
8
|
+
readonly scenario: MicroappLeakScenario;
|
|
9
|
+
}
|
|
10
|
+
export declare class ScenarioRegistry {
|
|
11
|
+
private readonly entries;
|
|
12
|
+
register(group: ScenarioGroup): this;
|
|
13
|
+
get(key: string): MicroappLeakScenario | undefined;
|
|
14
|
+
has(key: string): boolean;
|
|
15
|
+
size(): number;
|
|
16
|
+
list(): readonly ScenarioEntry[];
|
|
17
|
+
filterByTag(tag: string): readonly ScenarioEntry[];
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ComparisonReport } from '@elliemae/encw-heap-doctor';
|
|
2
|
+
import type { RunnerConfig } from '../types/config.js';
|
|
3
|
+
/**
|
|
4
|
+
* If the config carries an AI config, run the AiEnhancer over the report's leak
|
|
5
|
+
* results and return freshly-rendered markdown. If the AI call fails, log a
|
|
6
|
+
* single-line warning to stderr and return the report's original markdown so
|
|
7
|
+
* the scenario result is unaffected.
|
|
8
|
+
*
|
|
9
|
+
* If the config carries no AI config, return the report's original markdown
|
|
10
|
+
* untouched (no AI module loaded).
|
|
11
|
+
* @param report
|
|
12
|
+
* @param config
|
|
13
|
+
* @param scenarioName
|
|
14
|
+
*/
|
|
15
|
+
export declare function enhanceMarkdownIfConfigured(report: ComparisonReport, config: RunnerConfig, scenarioName: string): Promise<string>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { RunnerConfig } from '../types/config.js';
|
|
2
|
+
import type { RunSummary } from '../types/results.js';
|
|
3
|
+
import type { ScenarioRegistry } from '../registry/scenarioRegistry.js';
|
|
4
|
+
export declare class BatchRunner {
|
|
5
|
+
private readonly config;
|
|
6
|
+
private readonly registry;
|
|
7
|
+
private readonly scenarioRunner;
|
|
8
|
+
constructor(config: RunnerConfig, registry: ScenarioRegistry);
|
|
9
|
+
runAll(): Promise<RunSummary>;
|
|
10
|
+
runByTag(tag: string): Promise<RunSummary>;
|
|
11
|
+
runByName(key: string): Promise<RunSummary>;
|
|
12
|
+
private executeScenarios;
|
|
13
|
+
private runOne;
|
|
14
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Browser } from '@playwright/test';
|
|
2
|
+
import type { RunnerConfig } from '../types/config.js';
|
|
3
|
+
import type { MicroappLeakScenario } from '../types/scenario.js';
|
|
4
|
+
import type { ScenarioResult } from '../types/results.js';
|
|
5
|
+
export declare class ScenarioRunner {
|
|
6
|
+
private readonly config;
|
|
7
|
+
constructor(config: RunnerConfig);
|
|
8
|
+
launchBrowser(): Promise<Browser>;
|
|
9
|
+
run(scenario: MicroappLeakScenario, browser: Browser): Promise<ScenarioResult>;
|
|
10
|
+
private runScenarioInPage;
|
|
11
|
+
private setupAndProfile;
|
|
12
|
+
private repeatScenarioActions;
|
|
13
|
+
private writeReport;
|
|
14
|
+
private buildResult;
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Frame, Locator, Page } from '@playwright/test';
|
|
2
|
+
export declare class ExportPageModel {
|
|
3
|
+
private readonly frame;
|
|
4
|
+
constructor(frame: Frame);
|
|
5
|
+
get sourceDataTab(): Locator;
|
|
6
|
+
get dataTable(): Locator;
|
|
7
|
+
static clickBackAndWaitForSettings(page: Page): Promise<void>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Frame, Locator } from '@playwright/test';
|
|
2
|
+
export declare class SelectSettingsPageModel {
|
|
3
|
+
private readonly frame;
|
|
4
|
+
constructor(frame: Frame);
|
|
5
|
+
get container(): Locator;
|
|
6
|
+
get exportButton(): Locator;
|
|
7
|
+
expandTreeItem(name: string): Promise<void>;
|
|
8
|
+
selectTreeItem(name: string): Promise<void>;
|
|
9
|
+
clickExport(): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface EnvironmentParams {
|
|
2
|
+
readonly baseUrl: string;
|
|
3
|
+
readonly instanceId: string;
|
|
4
|
+
readonly userId: string;
|
|
5
|
+
readonly password: string;
|
|
6
|
+
}
|
|
7
|
+
export interface RunnerOptions {
|
|
8
|
+
readonly headless: boolean;
|
|
9
|
+
readonly outputDir: string;
|
|
10
|
+
readonly topN: number;
|
|
11
|
+
}
|
|
12
|
+
export interface AiConfig {
|
|
13
|
+
readonly model: string;
|
|
14
|
+
readonly temperature: number;
|
|
15
|
+
readonly apiKey: string;
|
|
16
|
+
}
|
|
17
|
+
export interface RunnerConfig {
|
|
18
|
+
readonly env: EnvironmentParams;
|
|
19
|
+
readonly runner: RunnerOptions;
|
|
20
|
+
readonly ai?: AiConfig;
|
|
21
|
+
}
|
|
22
|
+
export interface ResolvedThresholds {
|
|
23
|
+
maxRetainedSizeDeltaBytes: number;
|
|
24
|
+
maxNewLeakGroups: number;
|
|
25
|
+
}
|
|
26
|
+
export declare const DEFAULT_THRESHOLDS: ResolvedThresholds;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ComparisonReport } from '@elliemae/encw-heap-doctor';
|
|
2
|
+
export interface ThresholdResult {
|
|
3
|
+
readonly passed: boolean;
|
|
4
|
+
readonly reason: string | null;
|
|
5
|
+
}
|
|
6
|
+
export interface ScenarioResult {
|
|
7
|
+
readonly name: string;
|
|
8
|
+
readonly passed: boolean;
|
|
9
|
+
readonly thresholdResult: ThresholdResult;
|
|
10
|
+
readonly report: ComparisonReport | null;
|
|
11
|
+
readonly durationMs: number;
|
|
12
|
+
readonly error: Error | null;
|
|
13
|
+
}
|
|
14
|
+
export interface RunSummary {
|
|
15
|
+
readonly results: readonly ScenarioResult[];
|
|
16
|
+
readonly totalDurationMs: number;
|
|
17
|
+
readonly passCount: number;
|
|
18
|
+
readonly failCount: number;
|
|
19
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Page, Frame } from '@playwright/test';
|
|
2
|
+
export interface MicroappLeakScenario {
|
|
3
|
+
/** Kebab-case identifier used as the scenario portion of the registry key. */
|
|
4
|
+
readonly id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
tags?: string[];
|
|
8
|
+
microappSelector: string;
|
|
9
|
+
url(): string;
|
|
10
|
+
action(page: Page, frame: Frame): Promise<void>;
|
|
11
|
+
back?(page: Page): Promise<void>;
|
|
12
|
+
repeat?(): number;
|
|
13
|
+
thresholds?: {
|
|
14
|
+
maxRetainedSizeDeltaBytes?: number;
|
|
15
|
+
maxNewLeakGroups?: number;
|
|
16
|
+
};
|
|
17
|
+
}
|
package/jest.config.cjs
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const { jestConfig } = require('@elliemae/pui-cli');
|
|
2
|
+
module.exports = {
|
|
3
|
+
...jestConfig,
|
|
4
|
+
// This is a Node.js library package; use node environment and skip
|
|
5
|
+
// browser-specific setup (axe-core, matchMedia polyfill, etc.).
|
|
6
|
+
testEnvironment: 'node',
|
|
7
|
+
setupFiles: [],
|
|
8
|
+
setupFilesAfterEnv: [],
|
|
9
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "leak-runner config",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"additionalProperties": false,
|
|
6
|
+
"properties": {
|
|
7
|
+
"$schema": { "type": "string" },
|
|
8
|
+
"runner": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"additionalProperties": false,
|
|
11
|
+
"properties": {
|
|
12
|
+
"headless": { "type": "boolean" },
|
|
13
|
+
"outputDir": { "type": "string", "minLength": 1 },
|
|
14
|
+
"topN": { "type": "integer", "minimum": 1 }
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"ai": {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"additionalProperties": false,
|
|
20
|
+
"properties": {
|
|
21
|
+
"enabled": { "type": "boolean" },
|
|
22
|
+
"model": { "type": "string", "minLength": 1 },
|
|
23
|
+
"temperature": { "type": "number", "minimum": 0, "maximum": 2 }
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ComparisonReport,
|
|
3
|
+
LeakGroup,
|
|
4
|
+
NodeIndex,
|
|
5
|
+
} from '@elliemae/encw-heap-doctor';
|
|
6
|
+
import { ThresholdEvaluator } from '../thresholdEvaluator.js';
|
|
7
|
+
import { DEFAULT_THRESHOLDS } from '../../types/config.js';
|
|
8
|
+
|
|
9
|
+
function makeLeakGroup(label: string, retainedSize: number): LeakGroup {
|
|
10
|
+
return {
|
|
11
|
+
reason: 'detached-dom',
|
|
12
|
+
label,
|
|
13
|
+
nodeIndices: [],
|
|
14
|
+
count: 1,
|
|
15
|
+
totalSelfSize: 0,
|
|
16
|
+
topElements: [],
|
|
17
|
+
representativeIndex: 0 as unknown as NodeIndex,
|
|
18
|
+
retainedSize,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function makeReport(
|
|
23
|
+
retainedSizeDelta: number,
|
|
24
|
+
newLeakGroupCount: number,
|
|
25
|
+
): ComparisonReport {
|
|
26
|
+
const perGroupRetainedSize =
|
|
27
|
+
retainedSizeDelta / Math.max(newLeakGroupCount, 1);
|
|
28
|
+
return {
|
|
29
|
+
beforePath: '/tmp/before.heapsnapshot',
|
|
30
|
+
afterPath: '/tmp/after.heapsnapshot',
|
|
31
|
+
beforeNodeCount: 100,
|
|
32
|
+
afterNodeCount: 100 + newLeakGroupCount,
|
|
33
|
+
delta: {
|
|
34
|
+
newNodeCount: newLeakGroupCount * 10,
|
|
35
|
+
removedNodeCount: 0,
|
|
36
|
+
retainedSizeDelta,
|
|
37
|
+
newLeakGroups: Array.from({ length: newLeakGroupCount }, (_, i) =>
|
|
38
|
+
makeLeakGroup(`LeakGroup${i}`, perGroupRetainedSize),
|
|
39
|
+
),
|
|
40
|
+
detachedDomDelta: new Map(),
|
|
41
|
+
},
|
|
42
|
+
afterAnalysis: {
|
|
43
|
+
filePath: '/tmp/after.heapsnapshot',
|
|
44
|
+
nodeCount: 0,
|
|
45
|
+
edgeCount: 0,
|
|
46
|
+
leakResults: [],
|
|
47
|
+
fixPriority: [],
|
|
48
|
+
markdown: '',
|
|
49
|
+
},
|
|
50
|
+
markdown: '',
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
describe('ThresholdEvaluator', () => {
|
|
55
|
+
describe('with defaults (10 MB / 0 new leak groups)', () => {
|
|
56
|
+
it('passes when delta is zero', () => {
|
|
57
|
+
const result = ThresholdEvaluator.evaluate(
|
|
58
|
+
makeReport(0, 0),
|
|
59
|
+
DEFAULT_THRESHOLDS,
|
|
60
|
+
);
|
|
61
|
+
expect(result.passed).toBe(true);
|
|
62
|
+
expect(result.reason).toBeNull();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('passes when delta is under 10 MB with no new groups', () => {
|
|
66
|
+
const result = ThresholdEvaluator.evaluate(
|
|
67
|
+
makeReport(5 * 1024 * 1024, 0),
|
|
68
|
+
DEFAULT_THRESHOLDS,
|
|
69
|
+
);
|
|
70
|
+
expect(result.passed).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('fails when retained size delta exceeds 10 MB', () => {
|
|
74
|
+
const result = ThresholdEvaluator.evaluate(
|
|
75
|
+
makeReport(11 * 1024 * 1024, 0),
|
|
76
|
+
DEFAULT_THRESHOLDS,
|
|
77
|
+
);
|
|
78
|
+
expect(result.passed).toBe(false);
|
|
79
|
+
expect(result.reason).toMatch(
|
|
80
|
+
/retained size delta 11\.0 MB exceeds threshold 10\.0 MB/i,
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('fails when new leak groups are detected', () => {
|
|
85
|
+
const result = ThresholdEvaluator.evaluate(
|
|
86
|
+
makeReport(0, 2),
|
|
87
|
+
DEFAULT_THRESHOLDS,
|
|
88
|
+
);
|
|
89
|
+
expect(result.passed).toBe(false);
|
|
90
|
+
expect(result.reason).toMatch(
|
|
91
|
+
/2 new leak groups detected \(threshold: 0\)/i,
|
|
92
|
+
);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('fails and includes both violations in reason when both breach', () => {
|
|
96
|
+
const result = ThresholdEvaluator.evaluate(
|
|
97
|
+
makeReport(20 * 1024 * 1024, 3),
|
|
98
|
+
DEFAULT_THRESHOLDS,
|
|
99
|
+
);
|
|
100
|
+
expect(result.passed).toBe(false);
|
|
101
|
+
expect(result.reason).toBeTruthy();
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe('with custom thresholds', () => {
|
|
106
|
+
it('passes when delta is under custom threshold', () => {
|
|
107
|
+
const result = ThresholdEvaluator.evaluate(
|
|
108
|
+
makeReport(3 * 1024 * 1024, 0),
|
|
109
|
+
{
|
|
110
|
+
maxRetainedSizeDeltaBytes: 5 * 1024 * 1024,
|
|
111
|
+
maxNewLeakGroups: 0,
|
|
112
|
+
},
|
|
113
|
+
);
|
|
114
|
+
expect(result.passed).toBe(true);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('allows non-zero leak groups when threshold is raised', () => {
|
|
118
|
+
const result = ThresholdEvaluator.evaluate(makeReport(0, 2), {
|
|
119
|
+
maxRetainedSizeDeltaBytes: 10 * 1024 * 1024,
|
|
120
|
+
maxNewLeakGroups: 3,
|
|
121
|
+
});
|
|
122
|
+
expect(result.passed).toBe(true);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ComparisonReport } from '@elliemae/encw-heap-doctor';
|
|
2
|
+
import type { ResolvedThresholds } from '../types/config.js';
|
|
3
|
+
import type { ThresholdResult } from '../types/results.js';
|
|
4
|
+
|
|
5
|
+
function toMB(bytes: number): string {
|
|
6
|
+
return (bytes / (1024 * 1024)).toFixed(1);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class ThresholdEvaluator {
|
|
10
|
+
static evaluate(
|
|
11
|
+
report: ComparisonReport,
|
|
12
|
+
thresholds: ResolvedThresholds,
|
|
13
|
+
): ThresholdResult {
|
|
14
|
+
const reasons: string[] = [];
|
|
15
|
+
|
|
16
|
+
if (report.delta.retainedSizeDelta > thresholds.maxRetainedSizeDeltaBytes) {
|
|
17
|
+
reasons.push(
|
|
18
|
+
`Retained size delta ${toMB(report.delta.retainedSizeDelta)} MB ` +
|
|
19
|
+
`exceeds threshold ${toMB(thresholds.maxRetainedSizeDeltaBytes)} MB`,
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const newLeakCount = report.delta.newLeakGroups.length;
|
|
24
|
+
if (newLeakCount > thresholds.maxNewLeakGroups) {
|
|
25
|
+
reasons.push(
|
|
26
|
+
`${newLeakCount} new leak groups detected (threshold: ${thresholds.maxNewLeakGroups})`,
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (reasons.length === 0) {
|
|
31
|
+
return { passed: true, reason: null };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return { passed: false, reason: reasons.join('; ') };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { HeapMemoryProfiler } from '@elliemae/smoked-suite';
|
|
2
|
+
import type { Page, Frame } from '@playwright/test';
|
|
3
|
+
|
|
4
|
+
export class IframeHeapProfiler extends HeapMemoryProfiler {
|
|
5
|
+
constructor(
|
|
6
|
+
private readonly profiledPage: Page,
|
|
7
|
+
private readonly frame: Frame,
|
|
8
|
+
outputDir: string,
|
|
9
|
+
) {
|
|
10
|
+
super(profiledPage, outputDir);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
protected override getCDPTarget(): Page | Frame {
|
|
14
|
+
// Same-origin iframes share the parent's V8 isolate and CDP session;
|
|
15
|
+
// Chromium refuses newCDPSession(frame) for them. Cross-origin iframes
|
|
16
|
+
// (OOPIFs) run in their own process and accept a dedicated session.
|
|
17
|
+
return this.isSameOriginAsPage(this.frame) ? this.profiledPage : this.frame;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
private isSameOriginAsPage(frame: Frame): boolean {
|
|
21
|
+
const frameUrl = frame.url();
|
|
22
|
+
const pageUrl = this.profiledPage.url();
|
|
23
|
+
if (!frameUrl || frameUrl === 'about:blank') return true;
|
|
24
|
+
try {
|
|
25
|
+
return new URL(frameUrl).origin === new URL(pageUrl).origin;
|
|
26
|
+
} catch {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|