@dev-blinq/cucumber-js 1.0.30 → 1.0.32-stage

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.
@@ -1,14 +1,23 @@
1
+ import { TableCell } from '@cucumber/messages';
1
2
  declare const generateTestData: (featureFileContent: string, vars?: any, fakeData?: {
2
3
  var: string;
3
4
  fake: string;
4
- }[]) => {
5
+ }[], projectDir?: string) => {
5
6
  newContent: string;
6
7
  variables: any;
7
8
  otherFakeData: {
8
9
  var: string;
9
- fake: string;
10
+ fake: any;
10
11
  }[];
11
12
  changed: boolean;
12
13
  fakeIndex: number;
13
14
  };
14
- export { generateTestData };
15
+ declare const generateExamplesFromFunction: (data: string, feature_path: string, functionName: string, functionFile: string) => {
16
+ newData: string;
17
+ mjsData: any;
18
+ };
19
+ declare const generateExamplesFromFunctionGherkin: (headers: readonly TableCell[], values: readonly TableCell[], mjsData: any) => {
20
+ header: string;
21
+ value: any;
22
+ }[];
23
+ export { generateTestData, generateExamplesFromFunction, generateExamplesFromFunctionGherkin, };
@@ -1,16 +1,35 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateTestData = void 0;
6
+ exports.generateExamplesFromFunctionGherkin = exports.generateExamplesFromFunction = exports.generateTestData = void 0;
4
7
  const faker_1 = require("@faker-js/faker");
5
- const generateTestData = (featureFileContent, vars, fakeData) => {
6
- const regexp = /\{\{([^}]+)\}\}/g;
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const json5_1 = __importDefault(require("json5"));
11
+ const generateTestData = (featureFileContent, vars, fakeData, projectDir) => {
12
+ const regexp = /\{\{([^}]*\([^)]*\))\}\}/g;
7
13
  const variableRegex = /^([a-zA-Z0-9_]*)=(.*)/g;
8
14
  let newContent = featureFileContent;
9
15
  let match;
16
+ if (!projectDir) {
17
+ projectDir = process.cwd();
18
+ }
19
+ const namespacePath = path_1.default.join(projectDir, 'features', 'step_definitions', 'namespaces.json');
20
+ let namespaces = fs_1.default.existsSync(namespacePath)
21
+ ? JSON.parse(fs_1.default.readFileSync(namespacePath, 'utf-8'))
22
+ : [];
23
+ if (!Array.isArray(namespaces)) {
24
+ namespaces = [];
25
+ }
10
26
  const matches = [];
11
27
  // collect all matches
12
28
  while ((match = regexp.exec(featureFileContent)) !== null) {
13
- matches.push(match);
29
+ // match[0] is the full match, match[1] is the first capturing group
30
+ // Eg:- match[0] = {{name}}, match[1] = name
31
+ if (!namespaces.includes(match[1].split('.')[0]))
32
+ matches.push(match);
14
33
  }
15
34
  // find all variables in the matches
16
35
  const variables = { ...vars };
@@ -43,7 +62,7 @@ const generateTestData = (featureFileContent, vars, fakeData) => {
43
62
  }
44
63
  for (const key in variables) {
45
64
  const variable = variables[key];
46
- const fake = faker_1.faker.helpers.fake(`{{${variable.toFake}}}`);
65
+ const fake = getFakeString(variable.toFake.substring(2, variable.toFake.length - 2));
47
66
  newContent = newContent.replaceAll(`{{${variable.var}}}`, fake);
48
67
  variables[key].fake = fake;
49
68
  }
@@ -53,10 +72,14 @@ const generateTestData = (featureFileContent, vars, fakeData) => {
53
72
  const duplicateFakeData = fakeData ? [...fakeData] : [];
54
73
  let fakeIndex = 0;
55
74
  while ((match = regexp.exec(featureFileContent)) !== null) {
75
+ if (namespaces.includes(match[1].split('.')[0]))
76
+ continue;
56
77
  try {
57
- const fake = duplicateFakeData && duplicateFakeData.length > 0
78
+ const fake = duplicateFakeData &&
79
+ duplicateFakeData.length > 0 &&
80
+ duplicateFakeData[0].var === match[0]
58
81
  ? duplicateFakeData.shift().fake
59
- : faker_1.faker.helpers.fake(match[0]);
82
+ : getFakeString(match[0].substring(2, match[0].length - 2));
60
83
  otherFakeData.push({
61
84
  var: match[0],
62
85
  fake,
@@ -66,7 +89,7 @@ const generateTestData = (featureFileContent, vars, fakeData) => {
66
89
  }
67
90
  catch (err) {
68
91
  // eslint-disable-next-line no-console
69
- console.log('unknown faker variable:' + match[0]);
92
+ //console.log('unknown faker variable:' + match[0])
70
93
  }
71
94
  }
72
95
  return {
@@ -78,4 +101,69 @@ const generateTestData = (featureFileContent, vars, fakeData) => {
78
101
  };
79
102
  };
80
103
  exports.generateTestData = generateTestData;
104
+ const getFakeString = (content) => {
105
+ const faking = content.split('(')[0].split('.');
106
+ const argument = content.substring(content.indexOf('(') + 1, content.indexOf(')'));
107
+ let fakeFunc = faker_1.faker;
108
+ faking.forEach((f) => {
109
+ fakeFunc = fakeFunc[f];
110
+ });
111
+ try {
112
+ return fakeFunc(json5_1.default.parse(argument));
113
+ }
114
+ catch (error) {
115
+ return fakeFunc(argument);
116
+ }
117
+ };
118
+ const getDefinitionFunction = (feature_path, functionName, functionFile) => {
119
+ const mjsFiles = fs_1.default
120
+ .readdirSync(path_1.default.join(feature_path, '../step_definitions'))
121
+ .filter((file) => file === `${functionFile}.js`);
122
+ if (mjsFiles.length === 0) {
123
+ throw new Error(`File ${functionFile} not found in step_definitions folder`);
124
+ }
125
+ const [mjsData] = mjsFiles.map((file) => {
126
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
127
+ const { [functionName]: func } = require(path_1.default.join(feature_path, '../step_definitions', file));
128
+ if (!func)
129
+ throw new Error(`Function ${functionName} not found in file ${file}`);
130
+ return func();
131
+ });
132
+ return mjsData;
133
+ };
134
+ const generateExamplesFromFunction = (data, feature_path, functionName, functionFile) => {
135
+ const examples = data.split('Examples:')[1].split('\n').slice(1);
136
+ const headers = examples[0]
137
+ .split('|')
138
+ .map((header) => header.trim())
139
+ .filter((header) => header !== '');
140
+ const values = examples[1]
141
+ .split('|')
142
+ .map((value) => value.trim())
143
+ .filter((header) => header !== '');
144
+ const mjsData = getDefinitionFunction(feature_path, functionName, functionFile);
145
+ const newExamples = headers.map((header) => {
146
+ if (mjsData[header]) {
147
+ return mjsData[header];
148
+ }
149
+ return values[headers.indexOf(header)];
150
+ });
151
+ let newExamplesString = data.split('Examples:')[1];
152
+ newExamples.forEach((example, index) => {
153
+ newExamplesString = newExamplesString.replace(values[index], example);
154
+ });
155
+ const newData = data.replace(data.split('Examples:')[1], newExamplesString);
156
+ return { newData, mjsData };
157
+ };
158
+ exports.generateExamplesFromFunction = generateExamplesFromFunction;
159
+ const generateExamplesFromFunctionGherkin = (headers, values, mjsData) => {
160
+ const newExamples = headers.map(({ value: header }, index) => {
161
+ if (mjsData[header]) {
162
+ return { header, value: mjsData[header] };
163
+ }
164
+ return { header, value: values[index].value };
165
+ });
166
+ return newExamples;
167
+ };
168
+ exports.generateExamplesFromFunctionGherkin = generateExamplesFromFunctionGherkin;
81
169
  //# sourceMappingURL=feature_data_format.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"feature_data_format.js","sourceRoot":"","sources":["../../src/formatter/feature_data_format.ts"],"names":[],"mappings":"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","sourcesContent":["import { faker } from '@faker-js/faker'\n\nconst generateTestData = (\n featureFileContent: string,\n vars?: any,\n fakeData?: {\n var: string\n fake: string\n }[]\n) => {\n const regexp = /\\{\\{([^}]+)\\}\\}/g\n const variableRegex = /^([a-zA-Z0-9_]*)=(.*)/g\n let newContent = featureFileContent\n let match: RegExpExecArray\n const matches = []\n // collect all matches\n while ((match = regexp.exec(featureFileContent)) !== null) {\n matches.push(match)\n }\n // find all variables in the matches\n const variables: any = { ...vars }\n\n if (Object.keys(variables).length > 0) {\n for (let i = 0; i < matches.length; i++) {\n const _match = matches[i]\n const value = _match[1]\n const variableMatch = variableRegex.exec(value)\n if (variableMatch !== null) {\n newContent = newContent.replaceAll(_match[0], `{{${variableMatch[1]}}}`)\n }\n }\n\n for (const key in variables) {\n const variable = variables[key]\n newContent = newContent.replaceAll(`{{${variable.var}}}`, variable.fake)\n }\n } else {\n for (let i = 0; i < matches.length; i++) {\n const _match = matches[i]\n const value = _match[1]\n const variableMatch = variableRegex.exec(value)\n if (variableMatch !== null) {\n variables[variableMatch[1]] = {\n var: variableMatch[1],\n toFake: variableMatch[2],\n }\n newContent = newContent.replaceAll(_match[0], `{{${variableMatch[1]}}}`)\n }\n }\n\n for (const key in variables) {\n const variable = variables[key]\n const fake = faker.helpers.fake(`{{${variable.toFake}}}`)\n newContent = newContent.replaceAll(`{{${variable.var}}}`, fake)\n variables[key].fake = fake\n }\n }\n\n regexp.lastIndex = 0\n const otherFakeData = []\n const duplicateFakeData = fakeData ? [...fakeData] : []\n let fakeIndex = 0\n\n while ((match = regexp.exec(featureFileContent)) !== null) {\n try {\n const fake =\n duplicateFakeData && duplicateFakeData.length > 0\n ? duplicateFakeData.shift().fake\n : faker.helpers.fake(match[0])\n otherFakeData.push({\n var: match[0],\n fake,\n })\n newContent = newContent.replace(match[0], fake)\n fakeIndex++\n } catch (err) {\n // eslint-disable-next-line no-console\n console.log('unknown faker variable:' + match[0])\n }\n }\n\n return {\n newContent,\n variables,\n otherFakeData,\n changed: newContent !== featureFileContent,\n fakeIndex,\n }\n}\n\n//let result = generateTestData(\"/Users/guyarieli/Documents/GitHub/ai-qa/cucumber_demo/features/create_issues.feature\");\n//console.log(result.newContent);\nexport { generateTestData }\n"]}
1
+ {"version":3,"file":"feature_data_format.js","sourceRoot":"","sources":["../../src/formatter/feature_data_format.ts"],"names":[],"mappings":"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","sourcesContent":["import { faker } from '@faker-js/faker'\nimport fs from 'fs'\nimport path from 'path'\nimport { TableCell } from '@cucumber/messages'\nimport JSON5 from 'json5'\n\nconst generateTestData = (\n featureFileContent: string,\n vars?: any,\n fakeData?: {\n var: string\n fake: string\n }[],\n projectDir?: string\n) => {\n const regexp = /\\{\\{([^}]*\\([^)]*\\))\\}\\}/g\n const variableRegex = /^([a-zA-Z0-9_]*)=(.*)/g\n let newContent = featureFileContent\n let match: RegExpExecArray\n if (!projectDir) {\n projectDir = process.cwd()\n }\n const namespacePath = path.join(\n projectDir,\n 'features',\n 'step_definitions',\n 'namespaces.json'\n )\n let namespaces: string[] = fs.existsSync(namespacePath)\n ? JSON.parse(fs.readFileSync(namespacePath, 'utf-8'))\n : []\n if (!Array.isArray(namespaces)) {\n namespaces = []\n }\n const matches = []\n // collect all matches\n while ((match = regexp.exec(featureFileContent)) !== null) {\n // match[0] is the full match, match[1] is the first capturing group\n // Eg:- match[0] = {{name}}, match[1] = name\n if (!namespaces.includes(match[1].split('.')[0])) matches.push(match)\n }\n // find all variables in the matches\n const variables: any = { ...vars }\n\n if (Object.keys(variables).length > 0) {\n for (let i = 0; i < matches.length; i++) {\n const _match = matches[i]\n const value = _match[1]\n const variableMatch = variableRegex.exec(value)\n if (variableMatch !== null) {\n newContent = newContent.replaceAll(_match[0], `{{${variableMatch[1]}}}`)\n }\n }\n\n for (const key in variables) {\n const variable = variables[key]\n newContent = newContent.replaceAll(`{{${variable.var}}}`, variable.fake)\n }\n } else {\n for (let i = 0; i < matches.length; i++) {\n const _match = matches[i]\n const value = _match[1]\n const variableMatch = variableRegex.exec(value)\n if (variableMatch !== null) {\n variables[variableMatch[1]] = {\n var: variableMatch[1],\n toFake: variableMatch[2],\n }\n newContent = newContent.replaceAll(_match[0], `{{${variableMatch[1]}}}`)\n }\n }\n\n for (const key in variables) {\n const variable = variables[key]\n const fake = getFakeString(\n variable.toFake.substring(2, variable.toFake.length - 2)\n )\n newContent = newContent.replaceAll(`{{${variable.var}}}`, fake)\n variables[key].fake = fake\n }\n }\n\n regexp.lastIndex = 0\n const otherFakeData = []\n const duplicateFakeData = fakeData ? [...fakeData] : []\n let fakeIndex = 0\n while ((match = regexp.exec(featureFileContent)) !== null) {\n if (namespaces.includes(match[1].split('.')[0])) continue\n try {\n const fake =\n duplicateFakeData &&\n duplicateFakeData.length > 0 &&\n duplicateFakeData[0].var === match[0]\n ? duplicateFakeData.shift().fake\n : getFakeString(match[0].substring(2, match[0].length - 2))\n otherFakeData.push({\n var: match[0],\n fake,\n })\n newContent = newContent.replace(match[0], fake)\n fakeIndex++\n } catch (err) {\n // eslint-disable-next-line no-console\n //console.log('unknown faker variable:' + match[0])\n }\n }\n\n return {\n newContent,\n variables,\n otherFakeData,\n changed: newContent !== featureFileContent,\n fakeIndex,\n }\n}\n\nconst getFakeString = (content: string) => {\n const faking = content.split('(')[0].split('.')\n const argument = content.substring(\n content.indexOf('(') + 1,\n content.indexOf(')')\n )\n let fakeFunc: any = faker\n faking.forEach((f: string) => {\n fakeFunc = fakeFunc[f]\n })\n\n try {\n return fakeFunc(JSON5.parse(argument))\n } catch (error) {\n return fakeFunc(argument)\n }\n}\n\nconst getDefinitionFunction = (\n feature_path: string,\n functionName: string,\n functionFile: string\n) => {\n const mjsFiles = fs\n .readdirSync(path.join(feature_path, '../step_definitions'))\n .filter((file) => file === `${functionFile}.js`)\n\n if (mjsFiles.length === 0) {\n throw new Error(`File ${functionFile} not found in step_definitions folder`)\n }\n\n const [mjsData] = mjsFiles.map((file) => {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const { [functionName]: func } = require(path.join(\n feature_path,\n '../step_definitions',\n file\n ))\n if (!func)\n throw new Error(`Function ${functionName} not found in file ${file}`)\n\n return func()\n })\n\n return mjsData\n}\n\nconst generateExamplesFromFunction = (\n data: string,\n feature_path: string,\n functionName: string,\n functionFile: string\n) => {\n const examples = data.split('Examples:')[1].split('\\n').slice(1)\n const headers = examples[0]\n .split('|')\n .map((header) => header.trim())\n .filter((header) => header !== '')\n const values = examples[1]\n .split('|')\n .map((value) => value.trim())\n .filter((header) => header !== '')\n\n const mjsData = getDefinitionFunction(\n feature_path,\n functionName,\n functionFile\n )\n\n const newExamples = headers.map((header) => {\n if (mjsData[header]) {\n return mjsData[header]\n }\n return values[headers.indexOf(header)]\n })\n\n let newExamplesString = data.split('Examples:')[1]\n newExamples.forEach((example, index) => {\n newExamplesString = newExamplesString.replace(values[index], example)\n })\n\n const newData = data.replace(data.split('Examples:')[1], newExamplesString)\n\n return { newData, mjsData }\n}\n\nconst generateExamplesFromFunctionGherkin = (\n headers: readonly TableCell[],\n values: readonly TableCell[],\n mjsData: any\n) => {\n const newExamples = headers.map(({ value: header }, index) => {\n if (mjsData[header]) {\n return { header, value: mjsData[header] }\n }\n return { header, value: values[index].value }\n })\n\n return newExamples\n}\n\nexport {\n generateTestData,\n generateExamplesFromFunction,\n generateExamplesFromFunctionGherkin,\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import * as messages from '@cucumber/messages';
2
2
  type JsonTimestamp = number;
3
- type JsonStepType = 'Unknown' | 'Context' | 'Action' | 'Outcome';
3
+ type JsonStepType = 'Unknown' | 'Context' | 'Action' | 'Outcome' | 'Conjunction';
4
4
  export type JsonResultUnknown = {
5
5
  status: 'UNKNOWN';
6
6
  };
@@ -48,12 +48,22 @@ type JsonCommand = {
48
48
  text: string;
49
49
  screenshotId?: string;
50
50
  result: JsonCommandResult;
51
+ webLog?: webLog[];
52
+ netWorkLog?: any[];
53
+ };
54
+ type webLog = {
55
+ type: string;
56
+ text: string;
57
+ location: string;
58
+ time: string;
51
59
  };
52
60
  export type JsonStep = {
61
+ keyword: string;
53
62
  type: JsonStepType;
54
63
  text: string;
55
64
  commands: JsonCommand[];
56
65
  result: JsonStepResult;
66
+ data?: any;
57
67
  };
58
68
  export type RetrainStats = {
59
69
  result: JsonTestResult;
@@ -70,19 +80,29 @@ export type JsonTestProgress = {
70
80
  steps: JsonStep[];
71
81
  result: JsonTestResult;
72
82
  retrainStats?: RetrainStats;
83
+ webLog: any;
84
+ networkLog: any;
73
85
  };
74
86
  export type JsonReport = {
75
87
  testCases: JsonTestProgress[];
76
88
  result: JsonReportResult;
89
+ env: {
90
+ name: string;
91
+ baseUrl: string;
92
+ };
77
93
  };
78
94
  export default class ReportGenerator {
79
95
  private report;
80
96
  private gherkinDocumentMap;
97
+ private stepMap;
81
98
  private pickleMap;
82
99
  private testCaseMap;
83
100
  private testStepMap;
84
- private stepProgressMap;
85
- private testProgressMap;
101
+ private stepReportMap;
102
+ private testCaseReportMap;
103
+ private scenarioIterationCountMap;
104
+ private logs;
105
+ private networkLog;
86
106
  reportFolder: null | string;
87
107
  handleMessage(envelope: messages.Envelope): void;
88
108
  getReport(): JsonReport;
@@ -92,10 +112,13 @@ export default class ReportGenerator {
92
112
  private getTimeStamp;
93
113
  private onTestRunStarted;
94
114
  private onTestCase;
115
+ private _findScenario;
116
+ private _getParameters;
95
117
  private onTestCaseStarted;
96
118
  private onTestStepStarted;
97
119
  private onAttachment;
98
120
  private onTestStepFinished;
121
+ getLogFileContent(): any;
99
122
  private getTestCaseResult;
100
123
  private onTestCaseFinished;
101
124
  private onTestRunFinished;
@@ -1,5 +1,10 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ const fs_1 = __importDefault(require("fs"));
7
+ const path_1 = __importDefault(require("path"));
3
8
  class ReportGenerator {
4
9
  constructor() {
5
10
  this.report = {
@@ -7,13 +12,21 @@ class ReportGenerator {
7
12
  status: 'UNKNOWN',
8
13
  },
9
14
  testCases: [],
15
+ env: {
16
+ name: '',
17
+ baseUrl: '',
18
+ },
10
19
  };
11
20
  this.gherkinDocumentMap = new Map();
21
+ this.stepMap = new Map();
12
22
  this.pickleMap = new Map();
13
23
  this.testCaseMap = new Map();
14
24
  this.testStepMap = new Map();
15
- this.stepProgressMap = new Map();
16
- this.testProgressMap = new Map();
25
+ this.stepReportMap = new Map();
26
+ this.testCaseReportMap = new Map();
27
+ this.scenarioIterationCountMap = new Map();
28
+ this.logs = [];
29
+ this.networkLog = [];
17
30
  this.reportFolder = null;
18
31
  }
19
32
  handleMessage(envelope) {
@@ -87,7 +100,7 @@ class ReportGenerator {
87
100
  return this.report;
88
101
  }
89
102
  handleParseError(parseError) {
90
- const { message, source } = parseError;
103
+ const { message } = parseError;
91
104
  const timestamp = new Date().getTime();
92
105
  this.report.result = {
93
106
  status: 'FAILED',
@@ -98,6 +111,32 @@ class ReportGenerator {
98
111
  }
99
112
  onGherkinDocument(doc) {
100
113
  this.gherkinDocumentMap.set(doc.uri, doc);
114
+ doc.feature.children.forEach((child) => {
115
+ if (child.scenario) {
116
+ child.scenario.steps.forEach((step) => {
117
+ this.stepMap.set(step.id, step);
118
+ });
119
+ }
120
+ else if (child.background) {
121
+ child.background.steps.forEach((step) => {
122
+ this.stepMap.set(step.id, step);
123
+ });
124
+ }
125
+ else if (child.rule) {
126
+ child.rule.children.forEach((child) => {
127
+ if (child.scenario) {
128
+ child.scenario.steps.forEach((step) => {
129
+ this.stepMap.set(step.id, step);
130
+ });
131
+ }
132
+ else if (child.background) {
133
+ child.background.steps.forEach((step) => {
134
+ this.stepMap.set(step.id, step);
135
+ });
136
+ }
137
+ });
138
+ }
139
+ });
101
140
  }
102
141
  onPickle(pickle) {
103
142
  this.pickleMap.set(pickle.id, pickle);
@@ -117,6 +156,37 @@ class ReportGenerator {
117
156
  this.testStepMap.set(testStep.id, testStep);
118
157
  });
119
158
  }
159
+ _findScenario(doc, scenarioId) {
160
+ for (const child of doc.feature.children) {
161
+ if (child.scenario && child.scenario.id === scenarioId) {
162
+ return child.scenario;
163
+ }
164
+ if (child.rule) {
165
+ for (const scenario of child.rule.children) {
166
+ if (scenario.scenario && scenario.scenario.id === scenarioId) {
167
+ return scenario.scenario;
168
+ }
169
+ }
170
+ }
171
+ }
172
+ throw new Error(`scenario "${scenarioId}" not found`);
173
+ }
174
+ _getParameters(scenario, exampleId) {
175
+ const parameters = {};
176
+ if (scenario.examples.length === 0)
177
+ return parameters;
178
+ for (const examples of scenario.examples) {
179
+ for (const tableRow of examples.tableBody) {
180
+ if (tableRow.id === exampleId) {
181
+ for (let i = 0; i < examples.tableHeader.cells.length; i++) {
182
+ parameters[examples.tableHeader.cells[i].value] =
183
+ tableRow.cells[i].value;
184
+ }
185
+ }
186
+ }
187
+ }
188
+ return parameters;
189
+ }
120
190
  onTestCaseStarted(testCaseStarted) {
121
191
  const { testCaseId, id, timestamp } = testCaseStarted;
122
192
  const testCase = this.testCaseMap.get(testCaseId);
@@ -129,67 +199,112 @@ class ReportGenerator {
129
199
  if (doc === undefined)
130
200
  throw new Error(`gherkinDocument with uri ${pickle.uri} not found`);
131
201
  const featureName = doc.feature.name;
132
- const scenarioName = pickle.name;
133
- const steps = pickle.steps.map((step) => {
134
- this.stepProgressMap.set(step.id, {
135
- type: step.type,
202
+ const scenarioId = pickle.astNodeIds[0];
203
+ const scenario = this._findScenario(doc, scenarioId);
204
+ const scenarioName = scenario.name;
205
+ if (!this.scenarioIterationCountMap.has(scenarioId)) {
206
+ this.scenarioIterationCountMap.set(scenarioId, 1);
207
+ }
208
+ const parameters = this._getParameters(scenario, pickle.astNodeIds[1]);
209
+ console.log(`Running scenario ${scenarioName} iteration ${this.scenarioIterationCountMap.get(scenarioId)} with parameters:\n${JSON.stringify(parameters, null, 4)}\n
210
+ `);
211
+ this.scenarioIterationCountMap.set(scenarioId, this.scenarioIterationCountMap.get(scenarioId) + 1);
212
+ const steps = pickle.steps.map((pickleStep) => {
213
+ const stepId = pickleStep.astNodeIds[0];
214
+ const step = this.stepMap.get(stepId);
215
+ this.stepReportMap.set(pickleStep.id, {
216
+ type: step.keywordType,
217
+ keyword: step.keyword,
136
218
  text: step.text,
137
219
  commands: [],
138
220
  result: {
139
221
  status: 'UNKNOWN',
140
222
  },
141
223
  });
142
- return this.stepProgressMap.get(step.id);
224
+ return this.stepReportMap.get(pickleStep.id);
143
225
  });
144
- this.testProgressMap.set(id, {
226
+ this.testCaseReportMap.set(id, {
145
227
  id,
146
228
  uri: pickle.uri,
147
229
  featureName,
148
230
  scenarioName,
149
- // TODO: compute parameters
150
- parameters: {},
231
+ parameters,
151
232
  steps,
152
233
  result: {
153
234
  status: 'STARTED',
154
235
  startTime: this.getTimeStamp(timestamp),
155
236
  },
237
+ webLog: [],
238
+ networkLog: [],
156
239
  });
157
- this.report.testCases.push(this.testProgressMap.get(id));
240
+ this.report.testCases.push(this.testCaseReportMap.get(id));
158
241
  }
159
242
  onTestStepStarted(testStepStarted) {
160
- const { testStepId, timestamp, testCaseStartedId } = testStepStarted;
243
+ const { testStepId, timestamp } = testStepStarted;
161
244
  const testStep = this.testStepMap.get(testStepId);
162
245
  if (testStep === undefined)
163
246
  throw new Error(`testStep with id ${testStepId} not found`);
164
247
  if (testStep.pickleStepId === undefined)
165
248
  return;
166
- const stepProgess = this.stepProgressMap.get(testStep.pickleStepId);
249
+ const stepProgess = this.stepReportMap.get(testStep.pickleStepId);
167
250
  stepProgess.result = {
168
251
  status: 'STARTED',
169
252
  startTime: this.getTimeStamp(timestamp),
170
253
  };
171
254
  }
172
255
  onAttachment(attachment) {
173
- const { testCaseStartedId, testStepId, body, mediaType, contentEncoding, fileName, source, url, } = attachment;
256
+ const { testStepId, body, mediaType } = attachment;
174
257
  if (mediaType === 'text/plain') {
175
258
  this.reportFolder = body.replaceAll('\\', '/');
259
+ return;
260
+ }
261
+ if (mediaType === 'application/json+env') {
262
+ const data = JSON.parse(body);
263
+ this.report.env = data;
264
+ }
265
+ if (mediaType === 'application/json+log') {
266
+ const log = JSON.parse(body);
267
+ if (this.logs.length < 1000)
268
+ this.logs.push(log);
269
+ }
270
+ if (mediaType === 'application/json+network') {
271
+ const networkLog = JSON.parse(body);
272
+ if (this.networkLog.length < 1000)
273
+ this.networkLog.push(networkLog);
176
274
  }
177
275
  const testStep = this.testStepMap.get(testStepId);
178
276
  if (testStep.pickleStepId === undefined)
179
277
  return;
180
- const stepProgess = this.stepProgressMap.get(testStep.pickleStepId);
278
+ const stepProgess = this.stepReportMap.get(testStep.pickleStepId);
181
279
  if (mediaType === 'application/json') {
182
280
  const command = JSON.parse(body);
183
281
  stepProgess.commands.push(command);
184
282
  }
185
283
  }
186
284
  onTestStepFinished(testStepFinished) {
187
- const { testStepId, testCaseStartedId, testStepResult, timestamp } = testStepFinished;
285
+ const { testStepId, testStepResult, timestamp } = testStepFinished;
188
286
  const testStep = this.testStepMap.get(testStepId);
189
- if (testStep.pickleStepId === undefined)
287
+ if (testStep.pickleStepId === undefined) {
288
+ if (testStepResult.status === 'FAILED') {
289
+ console.error(`Before/After hook failed with message: ${testStepResult.message}`);
290
+ }
190
291
  return;
191
- const stepProgess = this.stepProgressMap.get(testStep.pickleStepId);
292
+ }
293
+ const stepProgess = this.stepReportMap.get(testStep.pickleStepId);
192
294
  const prevStepResult = stepProgess.result;
295
+ let data = {};
296
+ const reportFolder = this.reportFolder;
297
+ if (reportFolder === null) {
298
+ throw new Error('"reportFolder" is "null". Failed to run BVT hooks. Please retry after running "Generate All" or "Record Scenario" ');
299
+ }
300
+ try {
301
+ if (fs_1.default.existsSync(path_1.default.join(reportFolder, 'data.json'))) {
302
+ data = JSON.parse(fs_1.default.readFileSync(path_1.default.join(reportFolder, 'data.json'), 'utf8'));
303
+ }
304
+ }
305
+ catch (error) {
306
+ console.log('Error reading data.json');
307
+ }
193
308
  stepProgess.result = {
194
309
  status: testStepResult.status,
195
310
  startTime: prevStepResult.startTime,
@@ -197,6 +312,33 @@ class ReportGenerator {
197
312
  message: testStepResult.message,
198
313
  // exception: testStepResult.exception,
199
314
  };
315
+ if (Object.keys(data).length > 0) {
316
+ stepProgess.data = data;
317
+ }
318
+ }
319
+ getLogFileContent() {
320
+ let projectPath = process.cwd();
321
+ if (process.env.PROJECT_PATH) {
322
+ projectPath = process.env.PROJECT_PATH;
323
+ }
324
+ const logFolder = path_1.default.join(projectPath, 'logs', 'web');
325
+ if (!fs_1.default.existsSync(logFolder)) {
326
+ return [];
327
+ }
328
+ let nextId = 1;
329
+ while (fs_1.default.existsSync(path_1.default.join(logFolder, `${nextId}.json`))) {
330
+ nextId++;
331
+ }
332
+ if (nextId === 1) {
333
+ return [];
334
+ }
335
+ try {
336
+ const logFileContent = fs_1.default.readFileSync(path_1.default.join(logFolder, `${nextId - 1}.json`), 'utf8');
337
+ return JSON.parse(logFileContent);
338
+ }
339
+ catch (error) {
340
+ return [];
341
+ }
200
342
  }
201
343
  getTestCaseResult(steps) {
202
344
  for (const step of steps) {
@@ -222,7 +364,7 @@ class ReportGenerator {
222
364
  }
223
365
  onTestCaseFinished(testCaseFinished) {
224
366
  const { testCaseStartedId, timestamp } = testCaseFinished;
225
- const testProgress = this.testProgressMap.get(testCaseStartedId);
367
+ const testProgress = this.testCaseReportMap.get(testCaseStartedId);
226
368
  const prevResult = testProgress.result;
227
369
  const steps = Object.values(testProgress.steps);
228
370
  const result = this.getTestCaseResult(steps);
@@ -231,9 +373,13 @@ class ReportGenerator {
231
373
  startTime: prevResult.startTime,
232
374
  endTime: this.getTimeStamp(timestamp),
233
375
  };
376
+ testProgress.webLog = this.logs;
377
+ testProgress.networkLog = this.networkLog;
378
+ this.networkLog = [];
379
+ this.logs = [];
234
380
  }
235
381
  onTestRunFinished(testRunFinished) {
236
- const { timestamp, success, exception, message } = testRunFinished;
382
+ const { timestamp, success, message } = testRunFinished;
237
383
  const prevResult = this.report.result;
238
384
  this.report.result = {
239
385
  status: success ? 'PASSED' : 'FAILED',