@gooddata/sdk-e2e-utils 11.60.0-alpha.3 → 11.60.0-alpha.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.
Files changed (89) hide show
  1. package/esm/create-test/feature-hub/mock.d.ts +5 -0
  2. package/esm/create-test/feature-hub/mock.d.ts.map +1 -0
  3. package/esm/create-test/feature-hub/mock.js +15 -0
  4. package/esm/create-test/feature-hub/types.d.ts +21 -0
  5. package/esm/create-test/feature-hub/types.d.ts.map +1 -0
  6. package/esm/create-test/feature-hub/types.js +2 -0
  7. package/esm/create-test/goodmock/admin.d.ts +34 -0
  8. package/esm/create-test/goodmock/admin.d.ts.map +1 -0
  9. package/esm/create-test/goodmock/admin.js +99 -0
  10. package/esm/create-test/goodmock/mode.d.ts +14 -0
  11. package/esm/create-test/goodmock/mode.d.ts.map +1 -0
  12. package/esm/create-test/goodmock/mode.js +17 -0
  13. package/esm/create-test/goodmock/playwright.d.ts +5 -0
  14. package/esm/create-test/goodmock/playwright.d.ts.map +1 -0
  15. package/esm/create-test/goodmock/playwright.js +37 -0
  16. package/esm/create-test/goodmock/snapshot/assert-no-leak-patterns.d.ts +9 -0
  17. package/esm/create-test/goodmock/snapshot/assert-no-leak-patterns.d.ts.map +1 -0
  18. package/esm/create-test/goodmock/snapshot/assert-no-leak-patterns.js +20 -0
  19. package/esm/create-test/goodmock/snapshot/assert-no-secret-leaks.d.ts +4 -0
  20. package/esm/create-test/goodmock/snapshot/assert-no-secret-leaks.d.ts.map +1 -0
  21. package/esm/create-test/goodmock/snapshot/assert-no-secret-leaks.js +14 -0
  22. package/esm/create-test/goodmock/snapshot/build-masked-form-pattern.d.ts +2 -0
  23. package/esm/create-test/goodmock/snapshot/build-masked-form-pattern.d.ts.map +1 -0
  24. package/esm/create-test/goodmock/snapshot/build-masked-form-pattern.js +17 -0
  25. package/esm/create-test/goodmock/snapshot/get-effective-secret-mappings.d.ts +3 -0
  26. package/esm/create-test/goodmock/snapshot/get-effective-secret-mappings.d.ts.map +1 -0
  27. package/esm/create-test/goodmock/snapshot/get-effective-secret-mappings.js +2 -0
  28. package/esm/create-test/goodmock/snapshot/replace-secrets.d.ts +10 -0
  29. package/esm/create-test/goodmock/snapshot/replace-secrets.d.ts.map +1 -0
  30. package/esm/create-test/goodmock/snapshot/replace-secrets.js +23 -0
  31. package/esm/create-test/goodmock/snapshot/sanitize-credentials.d.ts +4 -0
  32. package/esm/create-test/goodmock/snapshot/sanitize-credentials.d.ts.map +1 -0
  33. package/esm/create-test/goodmock/snapshot/sanitize-credentials.js +41 -0
  34. package/esm/create-test/goodmock/snapshot/sanitize-workspace-ids.d.ts +4 -0
  35. package/esm/create-test/goodmock/snapshot/sanitize-workspace-ids.d.ts.map +1 -0
  36. package/esm/create-test/goodmock/snapshot/sanitize-workspace-ids.js +21 -0
  37. package/esm/create-test/goodmock/snapshot/snapshot-and-save-recording.d.ts +50 -0
  38. package/esm/create-test/goodmock/snapshot/snapshot-and-save-recording.d.ts.map +1 -0
  39. package/esm/create-test/goodmock/snapshot/snapshot-and-save-recording.js +64 -0
  40. package/esm/create-test/goodmock/snapshot/snapshot-param.d.ts +11 -0
  41. package/esm/create-test/goodmock/snapshot/snapshot-param.d.ts.map +1 -0
  42. package/esm/create-test/goodmock/snapshot/snapshot-param.js +9 -0
  43. package/esm/create-test/goodmock/types.d.ts +60 -0
  44. package/esm/create-test/goodmock/types.d.ts.map +1 -0
  45. package/esm/create-test/goodmock/types.js +2 -0
  46. package/esm/create-test/playwright/call-original-fn.d.ts +17 -0
  47. package/esm/create-test/playwright/call-original-fn.d.ts.map +1 -0
  48. package/esm/create-test/playwright/call-original-fn.js +25 -0
  49. package/esm/create-test/playwright/describe/factory.d.ts +27 -0
  50. package/esm/create-test/playwright/describe/factory.d.ts.map +1 -0
  51. package/esm/create-test/playwright/describe/factory.js +18 -0
  52. package/esm/create-test/playwright/fixtures.d.ts +7 -0
  53. package/esm/create-test/playwright/fixtures.d.ts.map +1 -0
  54. package/esm/create-test/playwright/fixtures.js +2 -0
  55. package/esm/create-test/playwright/playwright-types.d.ts +42 -0
  56. package/esm/create-test/playwright/playwright-types.d.ts.map +1 -0
  57. package/esm/create-test/playwright/playwright-types.js +2 -0
  58. package/esm/create-test/playwright/test/factory.d.ts +7 -0
  59. package/esm/create-test/playwright/test/factory.d.ts.map +1 -0
  60. package/esm/create-test/playwright/test/factory.js +42 -0
  61. package/esm/create-test/playwright/test/types.d.ts +27 -0
  62. package/esm/create-test/playwright/test/types.d.ts.map +1 -0
  63. package/esm/create-test/playwright/test/types.js +2 -0
  64. package/esm/create-test/playwright/top-level-describe/build-suite-callback.d.ts +9 -0
  65. package/esm/create-test/playwright/top-level-describe/build-suite-callback.d.ts.map +1 -0
  66. package/esm/create-test/playwright/top-level-describe/build-suite-callback.js +17 -0
  67. package/esm/create-test/playwright/top-level-describe/factory.d.ts +8 -0
  68. package/esm/create-test/playwright/top-level-describe/factory.d.ts.map +1 -0
  69. package/esm/create-test/playwright/top-level-describe/factory.js +12 -0
  70. package/esm/create-test/playwright/top-level-describe/types.d.ts +17 -0
  71. package/esm/create-test/playwright/top-level-describe/types.d.ts.map +1 -0
  72. package/esm/create-test/playwright/top-level-describe/types.js +2 -0
  73. package/esm/create-test/playwright/types.d.ts +17 -0
  74. package/esm/create-test/playwright/types.d.ts.map +1 -0
  75. package/esm/create-test/playwright/types.js +2 -0
  76. package/esm/create-test/playwright/with-describe-details.d.ts +6 -0
  77. package/esm/create-test/playwright/with-describe-details.d.ts.map +1 -0
  78. package/esm/create-test/playwright/with-describe-details.js +39 -0
  79. package/esm/index.d.ts +14 -3
  80. package/esm/index.d.ts.map +1 -1
  81. package/esm/index.js +8 -3
  82. package/esm/sdk-e2e-utils.d.ts +112 -38
  83. package/package.json +3 -3
  84. package/esm/goodmock.d.ts +0 -138
  85. package/esm/goodmock.d.ts.map +0 -1
  86. package/esm/goodmock.js +0 -284
  87. package/esm/playwright.d.ts +0 -97
  88. package/esm/playwright.d.ts.map +0 -1
  89. package/esm/playwright.js +0 -189
@@ -1,14 +1,14 @@
1
1
  import { APIResponse } from '@playwright/test';
2
- import { Fixtures } from '@playwright/test';
2
+ import type { Fixtures as Fixtures_2 } from '@playwright/test';
3
3
  import { Locator } from '@playwright/test';
4
4
  import { Page } from '@playwright/test';
5
- import { PlaywrightTestArgs } from '@playwright/test';
6
- import { PlaywrightTestOptions } from '@playwright/test';
7
- import { PlaywrightWorkerArgs } from '@playwright/test';
8
- import { PlaywrightWorkerOptions } from '@playwright/test';
5
+ import type { PlaywrightTestArgs } from '@playwright/test';
6
+ import type { PlaywrightTestOptions } from '@playwright/test';
7
+ import type { PlaywrightWorkerArgs } from '@playwright/test';
8
+ import type { PlaywrightWorkerOptions } from '@playwright/test';
9
9
  import { Route } from '@playwright/test';
10
- import { test } from '@playwright/test';
11
- import { TestDetails } from '@playwright/test';
10
+ import type { test } from '@playwright/test';
11
+ import type { TestDetails } from '@playwright/test';
12
12
 
13
13
  /**
14
14
  * @internal
@@ -45,6 +45,11 @@ export declare type BaseTestArgs = PlaywrightTestArgs & PlaywrightTestOptions;
45
45
  */
46
46
  export declare type BaseWorkerArgs = PlaywrightWorkerArgs & PlaywrightWorkerOptions;
47
47
 
48
+ /**
49
+ * @internal
50
+ */
51
+ export declare type Callback = () => void;
52
+
48
53
  /**
49
54
  * @internal
50
55
  * Click at the center of the bounding box of the given locator.
@@ -61,7 +66,42 @@ export declare function clickByBoundingBox(page: Page, locator: Locator, options
61
66
  * @internal
62
67
  * @param options -
63
68
  */
64
- export declare function createTest<T extends Record<string, unknown> = {}, W extends Record<string, unknown> = {}>(options?: ICreateTestOptions<T, W>): IE2eTest;
69
+ export declare function createTest<T extends {} = {}, W extends {} = {}>(options: ICreateTestOptions<T, W>): ITest;
70
+
71
+ /**
72
+ * @internal
73
+ */
74
+ export declare type DescribeConfigure = typeof test.describe.configure;
75
+
76
+ /**
77
+ * @internal
78
+ */
79
+ export declare type DescribeFixme = typeof test.describe.fixme;
80
+
81
+ /**
82
+ * @internal
83
+ */
84
+ export declare type DescribeOnly = typeof test.describe.only;
85
+
86
+ /**
87
+ * @internal
88
+ */
89
+ export declare type DescribeParallel = typeof test.describe.parallel;
90
+
91
+ /**
92
+ * @internal
93
+ */
94
+ export declare type DescribeSerial = typeof test.describe.serial;
95
+
96
+ /**
97
+ * @internal
98
+ */
99
+ export declare type DescribeSkip = typeof test.describe.skip;
100
+
101
+ /**
102
+ * @internal
103
+ */
104
+ export declare type Fixtures<T extends {} = {}, W extends {} = {}> = Fixtures_2<T, W, BaseTestArgs, BaseWorkerArgs>;
65
105
 
66
106
  /**
67
107
  * @internal
@@ -115,50 +155,37 @@ export declare function hoverByBoundingBox(page: Page, locator: Locator, options
115
155
  /**
116
156
  * @internal
117
157
  */
118
- export declare interface ICreateTestOptions<T extends Record<string, unknown> = {}, W extends Record<string, unknown> = {}> {
119
- goodmock?: IGoodmockOptions;
120
- fixtures?: Fixtures<T, W, BaseTestArgs & T, BaseWorkerArgs & W>;
121
- featureHubResponse?: IFeatureHubEnvironment[];
158
+ export declare interface ICreateTestOptions<T extends {} = {}, W extends {} = {}> extends ICustomCreateTestOptions {
159
+ fixtures?: Fixtures<T, W>;
122
160
  }
123
161
 
124
162
  /**
125
163
  * @internal
126
164
  */
127
- export declare interface IDescribeFunction {
128
- (suiteName: string, specName: string, fn: () => void): void;
129
- (suiteName: string, specName: string, details: IE2eTestDetails, fn: () => void): void;
130
- skip: {
131
- (suiteName: string, specName: string, fn: () => void): void;
132
- (suiteName: string, specName: string, details: IE2eTestDetails, fn: () => void): void;
133
- };
165
+ export declare interface ICustomCreateTestOptions {
166
+ featureHubResponse: IFeatureHubEnvironment[];
167
+ goodmock?: IGoodmockOptions;
134
168
  }
135
169
 
136
170
  /**
137
171
  * @internal
138
172
  */
139
- export declare type IE2eTest = typeof test & {
140
- topLevelDescribe: IDescribeFunction;
141
- describe: {
142
- (title: string, callback: () => void): void;
143
- (title: string, details: IE2eTestDetails, callback: () => void): void;
144
- skip: {
145
- (title: string, callback: () => void): void;
146
- (title: string, details: IE2eTestDetails, callback: () => void): void;
147
- };
148
- only: (typeof test)["describe"]["only"];
149
- configure: (typeof test)["describe"]["configure"];
150
- fixme: (typeof test)["describe"]["fixme"];
151
- serial: (typeof test)["describe"]["serial"];
152
- parallel: (typeof test)["describe"]["parallel"];
153
- };
154
- };
173
+ export declare interface IDescribe extends IDescribeFunction {
174
+ skip: IDescribeFunction;
175
+ only: DescribeOnly;
176
+ configure: DescribeConfigure;
177
+ fixme: DescribeFixme;
178
+ serial: DescribeSerial;
179
+ parallel: DescribeParallel;
180
+ }
155
181
 
156
182
  /**
157
183
  * @internal
184
+ * Call signatures of the overridden `test.describe` and `test.describe.skip`.
158
185
  */
159
- export declare interface IE2eTestDetails extends TestDetails {
160
- workspaceSettings?: Record<string, unknown>;
161
- additionalWindowProperties?: Record<string, unknown>;
186
+ export declare interface IDescribeFunction {
187
+ (title: string, callback: Callback): void;
188
+ (title: string, details: ITestDetails, callback: Callback): void;
162
189
  }
163
190
 
164
191
  /**
@@ -280,6 +307,38 @@ export declare interface ISnapshotAndSaveRecordingOptions {
280
307
  sanitizeMappings?: (mappings: IGoodmockMapping[]) => IGoodmockMapping[];
281
308
  }
282
309
 
310
+ /**
311
+ * @internal
312
+ */
313
+ export declare type ITest = Test & {
314
+ topLevelDescribe: ITopLevelDescribe;
315
+ describe: IDescribe;
316
+ };
317
+
318
+ /**
319
+ * @internal
320
+ */
321
+ export declare interface ITestDetails extends TestDetails {
322
+ workspaceSettings?: WorkspaceSettings;
323
+ additionalWindowProperties?: WindowProperties;
324
+ }
325
+
326
+ /**
327
+ * @internal
328
+ */
329
+ export declare interface ITopLevelDescribe extends ITopLevelDescribeFunction {
330
+ skip: ITopLevelDescribeFunction;
331
+ }
332
+
333
+ /**
334
+ * @internal
335
+ * Call signatures of the overridden `test.describe` and `test.describe.skip`.
336
+ */
337
+ export declare interface ITopLevelDescribeFunction {
338
+ (suiteName: string, specName: string, fn: Callback): void;
339
+ (suiteName: string, specName: string, details: ITestDetails, fn: Callback): void;
340
+ }
341
+
283
342
  /**
284
343
  * @internal
285
344
  */
@@ -341,4 +400,19 @@ export declare function snapshotAndSaveRecording(host: string, mappingFilePath:
341
400
  */
342
401
  export declare function startRecording(host: string, backendHost: string): Promise<void>;
343
402
 
403
+ /**
404
+ * @internal
405
+ */
406
+ export declare type Test = typeof test;
407
+
408
+ /**
409
+ * @internal
410
+ */
411
+ export declare type WindowProperties = Record<string, unknown>;
412
+
413
+ /**
414
+ * @internal
415
+ */
416
+ export declare type WorkspaceSettings = Record<string, unknown>;
417
+
344
418
  export { }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gooddata/sdk-e2e-utils",
3
- "version": "11.60.0-alpha.3",
3
+ "version": "11.60.0-alpha.4",
4
4
  "description": "GoodData utility functions for Playwright E2E tests",
5
5
  "license": "MIT",
6
6
  "author": "GoodData",
@@ -49,8 +49,8 @@
49
49
  "oxlint-plugin-eslint": "1.82.0",
50
50
  "oxlint-tsgolint": "7.0.2001",
51
51
  "typescript": "7.0.2",
52
- "@gooddata/eslint-config": "11.60.0-alpha.3",
53
- "@gooddata/oxlint-config": "11.60.0-alpha.3"
52
+ "@gooddata/eslint-config": "11.60.0-alpha.4",
53
+ "@gooddata/oxlint-config": "11.60.0-alpha.4"
54
54
  },
55
55
  "scripts": {
56
56
  "_phase:build": "npm run build",
package/esm/goodmock.d.ts DELETED
@@ -1,138 +0,0 @@
1
- /**
2
- * @internal
3
- * Load goodmock stub mappings from a JSON file on disk.
4
- *
5
- * @param host - Goodmock host:port (e.g. "backend-mock:8080")
6
- * @param mappingFilePath - Absolute path to the mapping JSON file
7
- */
8
- export declare function loadMappings(host: string, mappingFilePath: string): Promise<void>;
9
- /**
10
- * @internal
11
- * Reset goodmock scenario state (sequence counters) without clearing mappings.
12
- * Must be called between tests so scenario-driven stubs start from the
13
- * beginning for every test — mirrors the Cypress `resetRecordingsScenarios` task.
14
- */
15
- export declare function resetScenarios(host: string): Promise<void>;
16
- /**
17
- * @internal
18
- * Clear all goodmock stub mappings.
19
- */
20
- export declare function resetMappings(host: string): Promise<void>;
21
- /**
22
- * @internal
23
- * Add a goodmock stub that mocks log requests (POST /gdc/app/projects/.../log).
24
- * This prevents the app from failing when it tries to send logs.
25
- */
26
- export declare function mockLogRequests(host: string): Promise<void>;
27
- /**
28
- * @internal
29
- * Which mode goodmock is running in
30
- */
31
- export declare enum GoodmockMode {
32
- Replay = "replay",
33
- Record = "record",
34
- Proxy = "proxy"
35
- }
36
- /**
37
- * @internal
38
- */
39
- export declare function goodmockMode(): GoodmockMode;
40
- /**
41
- * @internal
42
- * Add a catch-all proxy mapping so goodmock forwards every request to the
43
- * real backend and records the interactions. Must be called after
44
- * {@link resetMappings} in recording mode.
45
- */
46
- export declare function startRecording(host: string, backendHost: string): Promise<void>;
47
- /**
48
- * @internal
49
- */
50
- export interface IGoodmockMapping {
51
- request: {
52
- url?: string;
53
- urlPath?: string;
54
- bodyPatterns?: unknown;
55
- };
56
- response: {
57
- headers?: Record<string, string>;
58
- jsonBody?: unknown;
59
- body?: string;
60
- };
61
- }
62
- /**
63
- * @internal
64
- */
65
- export interface IWorkspaceIdMapping {
66
- sourceWorkspaceId: string;
67
- targetWorkspaceId: string;
68
- }
69
- /**
70
- * @internal
71
- * Rewrite of a secret value in saved recordings. Every occurrence of `secret` (request bodies,
72
- * response bodies, URLs) is replaced with `placeholder`, so tests can type the placeholder at
73
- * replay time and still match the recorded request exactly.
74
- */
75
- export interface ISecretMapping {
76
- secret: string;
77
- placeholder: string;
78
- }
79
- /**
80
- * @internal
81
- * A credential shape that must never appear in a saved recording (checked against the fully
82
- * serialized output). Provide domain-specific shapes (e.g. a provider's API key format) via
83
- * {@link ISnapshotAndSaveRecordingOptions.leakPatterns} — this module has no built-in patterns of
84
- * its own, since it has no knowledge of what a given consumer's traffic considers a secret.
85
- */
86
- export interface ILeakPattern {
87
- label: string;
88
- pattern: RegExp;
89
- }
90
- /**
91
- * @internal
92
- */
93
- export interface ISnapshotAndSaveRecordingOptions {
94
- /** Source/target workspace ID rewrite(s) applied before mappings are saved. */
95
- workspaceIdMappings?: IWorkspaceIdMapping | IWorkspaceIdMapping[];
96
- /**
97
- * Real backend URL (e.g. "https://example.gooddata.com"). When provided together with
98
- * baseUrl, all occurrences are replaced in the saved mappings so that recorded responses
99
- * (e.g. geo tile URLs) resolve correctly during replay.
100
- */
101
- backendHost?: string;
102
- /** App base URL (e.g. "http://kpi-dashboards-ui:9500") that replaces backendHost references. */
103
- baseUrl?: string;
104
- /**
105
- * Secret rewrites. Each secret value is replaced by its placeholder everywhere in the saved
106
- * mappings (request bodyPatterns included, and masked variants such as "sk-prox***abcd").
107
- * Saving fails hard if any secret still remains afterwards.
108
- */
109
- secretMappings?: ISecretMapping[];
110
- /**
111
- * Credential-shaped patterns that must never appear anywhere in the saved output, regardless
112
- * of which field they came from. A backstop for secrets `secretMappings` doesn't know about
113
- * (e.g. a value a backend echoed back that the test never typed). Saving fails hard on a match.
114
- */
115
- leakPatterns?: ILeakPattern[];
116
- /**
117
- * Consumer-supplied hook to redact domain-specific secrets from the collected mappings (e.g.
118
- * blank a `content.apiKey` field on a settings entity) before they're merged and written out.
119
- * Runs once, right after the built-in credential handling (login cookie, resolveSettings map
120
- * tokens) and before workspace-id rewriting.
121
- */
122
- sanitizeMappings?: (mappings: IGoodmockMapping[]) => IGoodmockMapping[];
123
- }
124
- /**
125
- * @internal
126
- * Snapshot goodmock recordings, save the combined mappings to a JSON file
127
- * on disk, and sanitize any credentials from the output.
128
- *
129
- * A single snapshot is taken with repeatsAsScenarios enabled: goodmock turns a
130
- * request into a scenario chain only when its responses differ across the
131
- * recording, so stateful sequences are preserved and everything else stays flat.
132
- *
133
- * @param host - Goodmock host:port (e.g. "backend-mock:8080")
134
- * @param mappingFilePath - Absolute path to write the mapping JSON file to
135
- * @param options - See {@link ISnapshotAndSaveRecordingOptions}.
136
- */
137
- export declare function snapshotAndSaveRecording(host: string, mappingFilePath: string, options?: ISnapshotAndSaveRecordingOptions): Promise<void>;
138
- //# sourceMappingURL=goodmock.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"goodmock.d.ts","sourceRoot":"","sources":["../src/goodmock.ts"],"names":[],"mappings":"AAKA;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBvF;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMhE;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM/D;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBjE;AAED;;;GAGG;AACH,oBAAY,YAAY;IACpB,MAAM,WAAW;IACjB,MAAM,WAAW;IACjB,KAAK,UAAU;CAClB;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,YAAY,CAE3C;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWrF;AAWD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,OAAO,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACpE,QAAQ,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACrF;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAChC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,gCAAgC;IAC7C,+EAA+E;IAC/E,mBAAmB,CAAC,EAAE,mBAAmB,GAAG,mBAAmB,EAAE,CAAC;IAClE;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gGAAgG;IAChG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,cAAc,CAAC,EAAE,cAAc,EAAE,CAAC;IAClC;;;;OAIG;IACH,YAAY,CAAC,EAAE,YAAY,EAAE,CAAC;IAC9B;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,CAAC;CAC3E;AAqBD;;;;;;;;;;;;GAYG;AACH,wBAAsB,wBAAwB,CAC1C,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,MAAM,EACvB,OAAO,GAAE,gCAAqC,GAC/C,OAAO,CAAC,IAAI,CAAC,CAkKf"}
package/esm/goodmock.js DELETED
@@ -1,284 +0,0 @@
1
- // (C) 2026 GoodData Corporation
2
- import { mkdirSync, readFileSync, writeFileSync } from "fs";
3
- import { dirname } from "path";
4
- /**
5
- * @internal
6
- * Load goodmock stub mappings from a JSON file on disk.
7
- *
8
- * @param host - Goodmock host:port (e.g. "backend-mock:8080")
9
- * @param mappingFilePath - Absolute path to the mapping JSON file
10
- */
11
- export async function loadMappings(host, mappingFilePath) {
12
- let mappings;
13
- try {
14
- mappings = readFileSync(mappingFilePath, "utf-8");
15
- }
16
- catch {
17
- console.warn(`No mapping file found: ${mappingFilePath}, skipping`);
18
- return;
19
- }
20
- let json;
21
- try {
22
- json = JSON.parse(mappings);
23
- }
24
- catch {
25
- console.error(`Failed to parse mapping file: ${mappingFilePath}`);
26
- return;
27
- }
28
- const response = await fetch(`http://${host}/__admin/mappings/import`, {
29
- method: "POST",
30
- headers: { "Content-Type": "application/json" },
31
- body: JSON.stringify(json),
32
- });
33
- // oxlint-disable-next-line eslint-js/no-console
34
- console.log(`Goodmock mappings loaded from ${mappingFilePath} (status: ${response.status})`);
35
- }
36
- /**
37
- * @internal
38
- * Reset goodmock scenario state (sequence counters) without clearing mappings.
39
- * Must be called between tests so scenario-driven stubs start from the
40
- * beginning for every test — mirrors the Cypress `resetRecordingsScenarios` task.
41
- */
42
- export async function resetScenarios(host) {
43
- const response = await fetch(`http://${host}/__admin/scenarios/reset`, {
44
- method: "POST",
45
- });
46
- // oxlint-disable-next-line eslint-js/no-console
47
- console.log(`Goodmock scenarios reset (status: ${response.status})`);
48
- }
49
- /**
50
- * @internal
51
- * Clear all goodmock stub mappings.
52
- */
53
- export async function resetMappings(host) {
54
- const response = await fetch(`http://${host}/__admin/reset`, {
55
- method: "POST",
56
- });
57
- // oxlint-disable-next-line eslint-js/no-console
58
- console.log(`Goodmock mappings reset (status: ${response.status})`);
59
- }
60
- /**
61
- * @internal
62
- * Add a goodmock stub that mocks log requests (POST /gdc/app/projects/.../log).
63
- * This prevents the app from failing when it tries to send logs.
64
- */
65
- export async function mockLogRequests(host) {
66
- const response = await fetch(`http://${host}/__admin/mappings`, {
67
- method: "POST",
68
- headers: { "Content-Type": "application/json" },
69
- body: JSON.stringify({
70
- request: {
71
- method: "POST",
72
- urlPattern: "/gdc/app/projects/.*/log",
73
- },
74
- response: {
75
- body: "",
76
- status: 200,
77
- },
78
- }),
79
- });
80
- // oxlint-disable-next-line eslint-js/no-console
81
- console.log(`Goodmock log requests mocked (status: ${response.status})`);
82
- }
83
- /**
84
- * @internal
85
- * Which mode goodmock is running in
86
- */
87
- export var GoodmockMode;
88
- (function (GoodmockMode) {
89
- GoodmockMode["Replay"] = "replay";
90
- GoodmockMode["Record"] = "record";
91
- GoodmockMode["Proxy"] = "proxy";
92
- })(GoodmockMode || (GoodmockMode = {}));
93
- /**
94
- * @internal
95
- */
96
- export function goodmockMode() {
97
- return process.env["GOODMOCK_MODE"];
98
- }
99
- /**
100
- * @internal
101
- * Add a catch-all proxy mapping so goodmock forwards every request to the
102
- * real backend and records the interactions. Must be called after
103
- * {@link resetMappings} in recording mode.
104
- */
105
- export async function startRecording(host, backendHost) {
106
- const response = await fetch(`http://${host}/__admin/mappings`, {
107
- method: "POST",
108
- headers: { "Content-Type": "application/json" },
109
- body: JSON.stringify({
110
- request: { method: "ANY", urlPattern: ".*" },
111
- response: { proxyBaseUrl: backendHost },
112
- }),
113
- });
114
- // oxlint-disable-next-line eslint-js/no-console
115
- console.log(`Goodmock recording started, proxying to ${backendHost} (status: ${response.status})`);
116
- }
117
- const snapshotParams = {
118
- captureHeaders: { "X-GDC-TEST-NAME": {} },
119
- requestBodyPattern: {
120
- matcher: "equalToJson",
121
- ignoreArrayOrder: false,
122
- ignoreExtraElements: false,
123
- },
124
- };
125
- function sanitizeWorkspaceId(mappings, sourceWorkspaceId, targetWorkspaceId) {
126
- if (sourceWorkspaceId === targetWorkspaceId) {
127
- return mappings;
128
- }
129
- const dataString = JSON.stringify({ mappings });
130
- const sanitizedDataString = dataString.split(sourceWorkspaceId).join(targetWorkspaceId);
131
- const sanitizedData = JSON.parse(sanitizedDataString);
132
- // oxlint-disable-next-line eslint-js/no-console
133
- console.log(`Sanitized workspaceId in mappings (${sourceWorkspaceId} -> ${targetWorkspaceId})`);
134
- return sanitizedData.mappings;
135
- }
136
- /**
137
- * @internal
138
- * Snapshot goodmock recordings, save the combined mappings to a JSON file
139
- * on disk, and sanitize any credentials from the output.
140
- *
141
- * A single snapshot is taken with repeatsAsScenarios enabled: goodmock turns a
142
- * request into a scenario chain only when its responses differ across the
143
- * recording, so stateful sequences are preserved and everything else stays flat.
144
- *
145
- * @param host - Goodmock host:port (e.g. "backend-mock:8080")
146
- * @param mappingFilePath - Absolute path to write the mapping JSON file to
147
- * @param options - See {@link ISnapshotAndSaveRecordingOptions}.
148
- */
149
- export async function snapshotAndSaveRecording(host, mappingFilePath, options = {}) {
150
- const { workspaceIdMappings, backendHost, baseUrl, secretMappings, leakPatterns, sanitizeMappings } = options;
151
- // Snapshot everything with scenarios enabled. goodmock only emits a scenario
152
- // chain when a given request produced *different* responses across the
153
- // recording; identical repeats collapse to a single mapping. This captures
154
- // stateful sequences (e.g. a GET whose result changes after a POST) that the
155
- // old per-URL dedup path silently dropped, while keeping idempotent traffic flat.
156
- const snapshotRes = await fetch(`http://${host}/__admin/recordings/snapshot`, {
157
- method: "POST",
158
- headers: { "Content-Type": "application/json" },
159
- body: JSON.stringify({
160
- repeatsAsScenarios: true,
161
- persist: false,
162
- ...snapshotParams,
163
- }),
164
- });
165
- const snapshotData = (await snapshotRes.json());
166
- const mappings = [...snapshotData.mappings];
167
- // An empty snapshot means the recording journal was lost (e.g. a worker crash re-ran the
168
- // beforeAll reset mid-spec) or the spec made no requests at all. Never overwrite a previous
169
- // recording with an empty one, and fail the run so the broken recording cannot go unnoticed.
170
- if (mappings.length === 0) {
171
- throw new Error(`Recording snapshot for ${mappingFilePath} is empty — keeping the existing mapping ` +
172
- `file. Investigate (worker crash mid-spec? goodmock proxy misconfigured?) and re-record.`);
173
- }
174
- // Sanitize credentials
175
- for (const mapping of mappings) {
176
- if (mapping?.request?.url === "/gdc/account/login") {
177
- delete mapping.request.bodyPatterns;
178
- if (mapping.response.headers) {
179
- delete mapping.response.headers["Set-Cookie"];
180
- }
181
- }
182
- // Sanitize secrets from resolveSettings responses. Match both org-level
183
- // (/api/v1/actions/resolveSettings) and workspace-level variants, via either `url`
184
- // (no query) or `urlPath` (with query params).
185
- const requestPath = mapping?.request?.url ?? mapping?.request?.urlPath;
186
- if (typeof requestPath === "string" && requestPath.includes("/resolveSettings")) {
187
- try {
188
- const body = mapping?.response?.jsonBody;
189
- const settings = Array.isArray(body)
190
- ? body
191
- : Array.isArray(body?.data)
192
- ? body.data
193
- : null;
194
- if (settings) {
195
- for (const setting of settings) {
196
- const content = setting?.content;
197
- if (!content || typeof content !== "object") {
198
- continue;
199
- }
200
- // Map tokens (agGrid, mapbox) are stored under content.value.
201
- if (setting?.id === "agGridToken" || setting?.id === "mapboxToken") {
202
- content["value"] = "";
203
- }
204
- }
205
- }
206
- }
207
- catch {
208
- console.warn(`sanitizeCredentials – resolveSettings body is not valid JSON for: ${requestPath}`);
209
- }
210
- }
211
- }
212
- // Consumer-supplied redaction for secrets this module has no knowledge of (e.g. an LLM
213
- // provider's API key echoed back on a settings entity).
214
- const sanitizedByCaller = sanitizeMappings ? sanitizeMappings(mappings) : mappings;
215
- const mappingsToApply = Array.isArray(workspaceIdMappings)
216
- ? workspaceIdMappings
217
- : workspaceIdMappings
218
- ? [workspaceIdMappings]
219
- : [];
220
- const sanitizedMappings = mappingsToApply.reduce((acc, { sourceWorkspaceId, targetWorkspaceId }) => sanitizeWorkspaceId(acc, sourceWorkspaceId, targetWorkspaceId), sanitizedByCaller);
221
- let output = JSON.stringify({ mappings: sanitizedMappings }, null, 4) + "\n";
222
- if (backendHost && baseUrl) {
223
- output = output.replaceAll(backendHost, baseUrl);
224
- }
225
- // Replace secrets typed into the UI / sent by API helpers during recording with their
226
- // replay-time placeholders. JSON-escape both sides so values containing characters that
227
- // JSON.stringify escapes (quotes, backslashes) are still found in the serialized output.
228
- // Provider error messages echo keys in a masked form ("sk-prox***********abcd"), so that
229
- // shape is rewritten too — it still leaks the ends of a real key.
230
- const escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
231
- // Below this, prefix/suffix would overlap or leave nothing to mask — there's no safe
232
- // "partial reveal" shape to detect, so such secrets rely on the exact-match replace above.
233
- const MIN_MASKABLE_SECRET_LENGTH = 6;
234
- // Masking keeps a variable-length prefix/suffix of the key around the asterisks; scale how
235
- // much we match by the secret's own length instead of assuming a fixed provider convention
236
- // (e.g. OpenAI's "sk-prox***********abcd") so shorter secrets and other providers' masking
237
- // shapes are still caught.
238
- const buildMaskedFormPattern = (escapedSecret) => {
239
- if (escapedSecret.length < MIN_MASKABLE_SECRET_LENGTH) {
240
- return undefined;
241
- }
242
- const prefixLength = Math.min(7, Math.floor(escapedSecret.length / 3));
243
- const suffixLength = Math.min(4, Math.floor(escapedSecret.length / 4));
244
- return new RegExp(`${escapeRegex(escapedSecret.slice(0, prefixLength))}[^"*\\\\]*[*]+[^"*\\\\]*${escapeRegex(escapedSecret.slice(-suffixLength))}`, "g");
245
- };
246
- const effectiveSecretMappings = (secretMappings ?? []).filter(({ secret, placeholder }) => secret && secret !== placeholder);
247
- for (const { secret, placeholder } of effectiveSecretMappings) {
248
- const escapedSecret = JSON.stringify(secret).slice(1, -1);
249
- const escapedPlaceholder = JSON.stringify(placeholder).slice(1, -1);
250
- output = output.replaceAll(escapedSecret, escapedPlaceholder);
251
- const maskedForm = buildMaskedFormPattern(escapedSecret);
252
- if (maskedForm) {
253
- output = output.replace(maskedForm, escapedPlaceholder);
254
- }
255
- }
256
- // Leak guard: never write a recording that still contains a real secret (full or masked).
257
- for (const { secret } of effectiveSecretMappings) {
258
- const escapedSecret = JSON.stringify(secret).slice(1, -1);
259
- const maskedForm = buildMaskedFormPattern(escapedSecret);
260
- if (output.includes(escapedSecret) || output.includes(secret) || maskedForm?.test(output)) {
261
- throw new Error(`Recording for ${mappingFilePath} still contains a secret after sanitization ` +
262
- `(e.g. in an encoded form). Refusing to save the mapping file.`);
263
- }
264
- }
265
- // Pattern guard: catch credential-shaped values from ANY source (not just the ones the
266
- // tests typed), e.g. a real key stored in a backend org setting under an unexpected field.
267
- // Patterns are consumer-supplied — this module has no built-in notion of what a secret
268
- // looks like for a given domain (see ISnapshotAndSaveRecordingOptions.leakPatterns).
269
- for (const { label, pattern } of leakPatterns ?? []) {
270
- // Reset lastIndex in case pattern carries the g/y flag — exec() on a stateful regex
271
- // would otherwise resume from wherever a previous call (e.g. a prior recording) left off.
272
- pattern.lastIndex = 0;
273
- const match = pattern.exec(output);
274
- if (match) {
275
- throw new Error(`Recording for ${mappingFilePath} contains a value shaped like a ${label} ` +
276
- `("${match[0].slice(0, 8)}…"). Refusing to save the mapping file — extend ` +
277
- `sanitizeMappings / secretMappings so it gets sanitized.`);
278
- }
279
- }
280
- mkdirSync(dirname(mappingFilePath), { recursive: true });
281
- writeFileSync(mappingFilePath, output);
282
- // oxlint-disable-next-line eslint-js/no-console
283
- console.log(`Recording saved to ${mappingFilePath} (${sanitizedMappings.length} mappings)`);
284
- }