@zohodesk/testinglibrary 0.0.53-n20-experimental → 0.0.57-n20-experimental
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/build/common/data-generator/steps/DataGeneratorStepsHelper.js +2 -1
- package/build/core/dataGenerator/DataGenerator.js +18 -10
- package/build/core/dataGenerator/DataGeneratorHelper.js +52 -4
- package/build/core/playwright/builtInFixtures/cacheLayer.js +2 -1
- package/build/utils/logger.js +3 -1
- package/npm-shrinkwrap.json +1128 -824
- package/package.json +1 -1
|
@@ -26,10 +26,11 @@ export async function generateAndCacheTestData(executionContext, type, identifie
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
const { response, generators } = await dataGenerator.generate(testInfo, actorInfo, type, identifier, scenarioName, dataTable ? dataTable.hashes() : []);
|
|
29
|
+
const { response, generators } = await dataGenerator.generate(testInfo, actorInfo, type, identifier, scenarioName, dataTable ? dataTable.hashes() : [], cacheLayer);
|
|
30
30
|
if (cacheLayer._trackForCleanup) {
|
|
31
31
|
cacheLayer._trackForCleanup(entityName, response.data, generators, actorInfo, response.logs, identifier);
|
|
32
32
|
} else {
|
|
33
33
|
cacheLayer.set(entityName, response.data);
|
|
34
|
+
cacheLayer.set(`${entityName}_logs`, response.logs);
|
|
34
35
|
}
|
|
35
36
|
}
|
|
@@ -27,7 +27,7 @@ class DataGenerator {
|
|
|
27
27
|
_classPrivateMethodInitSpec(this, _DataGenerator_brand);
|
|
28
28
|
_classPrivateFieldInitSpec(this, _generatorIndex, null);
|
|
29
29
|
}
|
|
30
|
-
async generate(testInfo, actorInfo, generatorType, generatorName, scenarioName, dataTable) {
|
|
30
|
+
async generate(testInfo, actorInfo, generatorType, generatorName, scenarioName, dataTable, cacheLayer) {
|
|
31
31
|
const startMs = Date.now();
|
|
32
32
|
const startLabel = (0, _timeFormat.formatTimestamp)(startMs);
|
|
33
33
|
_logger.Logger.log(_logger.Logger.INFO_TYPE, `Data generation started | generator="${generatorName}" | scenario="${scenarioName}" | startTime=${startLabel}`);
|
|
@@ -38,13 +38,21 @@ class DataGenerator {
|
|
|
38
38
|
} else {
|
|
39
39
|
generators = await _assertClassBrand(_DataGenerator_brand, this, _getGenerator).call(this, generatorName);
|
|
40
40
|
}
|
|
41
|
-
const
|
|
41
|
+
const resolvedDataTable = await (0, _DataGeneratorHelper.resolveCacheReferences)(dataTable, cacheLayer);
|
|
42
|
+
const processedGenerators = await (0, _DataGeneratorHelper.processGenerator)(generators, resolvedDataTable);
|
|
42
43
|
const apiPayload = await _assertClassBrand(_DataGenerator_brand, this, _constructApiPayload).call(this, scenarioName, processedGenerators, actorInfo);
|
|
43
|
-
const
|
|
44
|
+
const featureFlags = process.env.featureflags ? process.env.featureflags : '';
|
|
45
|
+
const headers = {
|
|
46
|
+
'Content-Type': 'application/json',
|
|
47
|
+
'featureflags': featureFlags
|
|
48
|
+
};
|
|
49
|
+
_logger.Logger.log(_logger.Logger.INFO_TYPE, 'Making request headers:', headers);
|
|
50
|
+
_logger.Logger.log(_logger.Logger.INFO_TYPE, `Payload: ${JSON.stringify(apiPayload, null, 4)}`);
|
|
51
|
+
const response = await (0, _DataGeneratorHelper.makeRequest)(process.env.DG_SERVICE_DOMAIN + process.env.DG_SERVICE_API_PATH, apiPayload, headers);
|
|
44
52
|
const endMs = Date.now();
|
|
45
53
|
const endLabel = (0, _timeFormat.formatTimestamp)(endMs);
|
|
46
54
|
const totalLabel = (0, _timeFormat.formatDuration)(endMs - startMs);
|
|
47
|
-
_logger.Logger.log(_logger.Logger.INFO_TYPE, `Generated response for the generator: ${generatorName} for scenario: ${scenarioName}, Response: ${JSON.stringify(response)}`);
|
|
55
|
+
_logger.Logger.log(_logger.Logger.INFO_TYPE, `Generated response for the generator: ${generatorName} for scenario: ${scenarioName}, Response: ${JSON.stringify(response, null, 4)}`);
|
|
48
56
|
_logger.Logger.log(_logger.Logger.INFO_TYPE, `Data generation completed | generator="${generatorName}" | scenario="${scenarioName}" | startTime=${startLabel} | endTime=${endLabel} | totalTime=${totalLabel}`);
|
|
49
57
|
return {
|
|
50
58
|
response,
|
|
@@ -56,16 +64,16 @@ class DataGenerator {
|
|
|
56
64
|
const totalLabel = (0, _timeFormat.formatDuration)(endMs - startMs);
|
|
57
65
|
_logger.Logger.log(_logger.Logger.FAILURE_TYPE, `Data generation failed | generator="${generatorName}" | scenario="${scenarioName}" | startTime=${startLabel} | endTime=${endLabel} | totalTime=${totalLabel}`);
|
|
58
66
|
if (error instanceof _DataGeneratorError.DataGeneratorError) {
|
|
59
|
-
|
|
60
|
-
|
|
67
|
+
_logger.Logger.log(_logger.Logger.FAILURE_TYPE, error.getMessage());
|
|
68
|
+
_logger.Logger.log(_logger.Logger.FAILURE_TYPE, "Stack trace:", error.stack);
|
|
61
69
|
_logger.Logger.log(_logger.Logger.FAILURE_TYPE, error.getMessage());
|
|
62
70
|
} else {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
71
|
+
_logger.Logger.log(_logger.Logger.FAILURE_TYPE, "Error Type:", error.constructor.name);
|
|
72
|
+
_logger.Logger.log(_logger.Logger.FAILURE_TYPE, "Error Message:", error.message);
|
|
73
|
+
_logger.Logger.log(_logger.Logger.FAILURE_TYPE, "Stack trace:", error.stack);
|
|
66
74
|
_logger.Logger.log(_logger.Logger.FAILURE_TYPE, `${error.constructor.name} - Message: ${error.message}`);
|
|
67
75
|
}
|
|
68
|
-
|
|
76
|
+
_logger.Logger.log(_logger.Logger.FAILURE_TYPE, `Data Generation failed for the generator: ${generatorName}\n\nError response: ${error}`);
|
|
69
77
|
throw error;
|
|
70
78
|
}
|
|
71
79
|
}
|
|
@@ -6,6 +6,54 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.getGeneratorFilePath = getGeneratorFilePath;
|
|
7
7
|
exports.makeRequest = makeRequest;
|
|
8
8
|
exports.processGenerator = processGenerator;
|
|
9
|
+
exports.resolveCacheReferences = resolveCacheReferences;
|
|
10
|
+
// Matches a single ${EntityName} or ${EntityName.field.path} cell value.
|
|
11
|
+
// Anchored — values like "foo ${E1.id} bar" are left as-is on purpose.
|
|
12
|
+
const CACHE_REF = /^\$\{([A-Za-z_][\w-]*)(?:\.([A-Za-z_][\w.-]*))?\}$/;
|
|
13
|
+
|
|
14
|
+
// Resolve ${EntityName} / ${EntityName.field.path} references in a dataTable
|
|
15
|
+
// against the cacheLayer. Lets a later `generate ...` step reference an entity
|
|
16
|
+
// that an earlier step cached (e.g. ${E1.id} for an event created in a prior
|
|
17
|
+
// generator invocation).
|
|
18
|
+
async function resolveCacheReferences(rows, cacheLayer) {
|
|
19
|
+
if (!rows || !rows.length || !cacheLayer || typeof cacheLayer.get !== 'function') {
|
|
20
|
+
return rows || [];
|
|
21
|
+
}
|
|
22
|
+
const out = [];
|
|
23
|
+
for (const row of rows) {
|
|
24
|
+
const resolved = {};
|
|
25
|
+
for (const [key, value] of Object.entries(row)) {
|
|
26
|
+
const match = typeof value === 'string' ? value.match(CACHE_REF) : null;
|
|
27
|
+
if (!match) {
|
|
28
|
+
resolved[key] = value;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const [, entityName, fieldPath] = match;
|
|
32
|
+
const entity = await cacheLayer.get(entityName);
|
|
33
|
+
if (entity === undefined || entity === null) {
|
|
34
|
+
throw new Error(`DataGenerator: ${value} references entity "${entityName}" which is not in the cache.`);
|
|
35
|
+
}
|
|
36
|
+
if (!fieldPath) {
|
|
37
|
+
resolved[key] = entity;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
let acc = entity;
|
|
41
|
+
for (const part of fieldPath.split('.')) {
|
|
42
|
+
if (acc === undefined || acc === null) {
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
acc = acc[part];
|
|
46
|
+
}
|
|
47
|
+
if (acc === undefined) {
|
|
48
|
+
throw new Error(`DataGenerator: ${value} resolved to undefined (entity "${entityName}" has no path "${fieldPath}").`);
|
|
49
|
+
}
|
|
50
|
+
resolved[key] = acc;
|
|
51
|
+
}
|
|
52
|
+
out.push(resolved);
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
|
|
9
57
|
//Create payload for the generators
|
|
10
58
|
async function processGenerator(generators, dataTable) {
|
|
11
59
|
if (!dataTable) {
|
|
@@ -29,12 +77,12 @@ async function processGenerator(generators, dataTable) {
|
|
|
29
77
|
return generator;
|
|
30
78
|
});
|
|
31
79
|
}
|
|
32
|
-
async function makeRequest(url, payload
|
|
80
|
+
async function makeRequest(url, payload, headers = {
|
|
81
|
+
'Content-Type': 'application/json'
|
|
82
|
+
}) {
|
|
33
83
|
const response = await fetch(url, {
|
|
34
84
|
method: 'POST',
|
|
35
|
-
headers:
|
|
36
|
-
'Content-Type': 'application/json'
|
|
37
|
-
},
|
|
85
|
+
headers: headers,
|
|
38
86
|
body: JSON.stringify(payload)
|
|
39
87
|
});
|
|
40
88
|
if (!response.ok) {
|
|
@@ -125,6 +125,7 @@ var _default = exports.default = {
|
|
|
125
125
|
const cleanupEntries = [];
|
|
126
126
|
cache._trackForCleanup = (entityName, data, generators, actorInfo, logs, generatorName) => {
|
|
127
127
|
cache.set(entityName, data);
|
|
128
|
+
cache.set(`${entityName}_logs`, logs);
|
|
128
129
|
cleanupEntries.push({
|
|
129
130
|
entityName,
|
|
130
131
|
data,
|
|
@@ -183,7 +184,7 @@ var _default = exports.default = {
|
|
|
183
184
|
const stepEndMs = Date.now();
|
|
184
185
|
const stepEndLabel = (0, _timeFormat.formatTimestamp)(stepEndMs);
|
|
185
186
|
const stepTotalLabel = (0, _timeFormat.formatDuration)(stepEndMs - stepStartMs);
|
|
186
|
-
_logger.Logger.log(_logger.Logger.SUCCESS_TYPE, `Cleanup step success | ${actionDesc} (id: ${entityId}) | response=${JSON.stringify(cleanupResponse)} | startTime=${stepStartLabel} | endTime=${stepEndLabel} | totalTime=${stepTotalLabel}`);
|
|
187
|
+
_logger.Logger.log(_logger.Logger.SUCCESS_TYPE, `Cleanup step success | ${actionDesc} (id: ${entityId}) | response=${JSON.stringify(cleanupResponse, null, 4)} | startTime=${stepStartLabel} | endTime=${stepEndLabel} | totalTime=${stepTotalLabel}`);
|
|
187
188
|
} catch (err) {
|
|
188
189
|
failed++;
|
|
189
190
|
const stepEndMs = Date.now();
|
package/build/utils/logger.js
CHANGED
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.Logger = void 0;
|
|
7
|
+
var _util = require("util");
|
|
7
8
|
class LoggerImpl {
|
|
8
9
|
constructor() {
|
|
9
10
|
this.SUCCESS_TYPE = 'success';
|
|
@@ -20,8 +21,9 @@ class LoggerImpl {
|
|
|
20
21
|
this.consoleLogger.error(err);
|
|
21
22
|
}
|
|
22
23
|
info() {}
|
|
23
|
-
log(type,
|
|
24
|
+
log(type, ...messageParts) {
|
|
24
25
|
const color = this.colors[type];
|
|
26
|
+
const message = (0, _util.format)(...messageParts);
|
|
25
27
|
this.consoleLogger.log(`${color[0]}${message}${color[1]}\n`);
|
|
26
28
|
}
|
|
27
29
|
}
|