Repository: nightwatchjs/nightwatch
Pull request #3680 (2023-04-05 09:33:50)

Added describe name, hook timestamps to reporter
**Changes (For Observability)**

- Added httpoutput for each testcase (Available in completedSections)
- Added describe block name, test level tags
- Added timestamps to hooks and test sections (Available in completedSections)


Patch:
diff --git a/lib/reporter/index.js b/lib/reporter/index.js
index a0f967ba..0ef8fde8 100644
--- a/lib/reporter/index.js
+++ b/lib/reporter/index.js
@@ -127,10 +127,18 @@ class Reporter extends SimplifiedReporter {
     this.testResults.setElapsedTime();
   }
 
+  setTestSectionElapsedTime() {
+    this.testResults.setTestSectionElapsedTime();
+  }
+
   setTestStatus() {
     this.testResults.setTestStatus();
   }
 
+  collectTestSectionOutput() {
+    this.testResults.collectTestSectionOutput();
+  }
+
   testSuiteFinished() {
     this.testResults.setTotalElapsedTime();
   }
diff --git a/lib/reporter/results.js b/lib/reporter/results.js
index 3776b985..055a3a28 100644
--- a/lib/reporter/results.js
+++ b/lib/reporter/results.js
@@ -49,6 +49,8 @@ module.exports = class Results {
     this.buildName = capabilities.buildName || desiredCapabilities.buildName || '';
     const {webdriver = {}} = settings;
     this.host = webdriver.host || '';
+    this.name = opts.suiteName || '';
+    this.tags = opts.tags || [];
     this.__retryTest = false;
 
     this.initCount(tests);
@@ -237,6 +239,8 @@ module.exports = class Results {
     suiteResults.results.status = this.getTestStatus();
     suiteResults.results.seleniumLog = this.seleniumLog;
     suiteResults.results.host = this.host;
+    suiteResults.results.name = this.name;
+    suiteResults.results.tags = this.tags;
 
     // Backwards compat
     suiteResults.results.tests = this.testsCount;
@@ -295,7 +299,9 @@ module.exports = class Results {
       retries: testcase.retriesCount,
       skipped: 0,
       tests: 0,
-      status: Results.TEST_PASS
+      status: Results.TEST_PASS,
+      startTimestamp: new Date().getTime(),
+      httpOutput: []
     };
 
     if (this.retryTest && this.testSections[testcase.testName]) {
@@ -433,6 +439,26 @@ module.exports = class Results {
     return this;
   }
 
+  setTestSectionElapsedTime() {
+    const currentSection = this.getTestSection(this.currentSectionName);
+    const startTime = currentSection ? currentSection.startTimestamp : this.globalStartTime;
+    const endTime = new Date().getTime();
+    const elapsedTime = endTime - startTime;
+    this.endTimestamp = endTime;
+
+    this.time += elapsedTime;
+
+    if (currentSection) {
+      currentSection.time = (elapsedTime/1000).toPrecision(4);
+      currentSection.timeMs = elapsedTime;
+      currentSection.startTimestamp = startTime;
+      currentSection.endTimestamp = endTime;
+
+    }
+
+    return this;
+  }
+
   setTestStatus() {
     const currentTest = this.getCurrentTest();
     const currentSection = this.getTestSection(this.currentSectionName);
@@ -449,6 +475,15 @@ module.exports = class Results {
     }
   }
 
+  collectTestSectionOutput() {
+    const currentSection = this.getTestSection(this.currentSectionName);
+    if (!currentSection) {
+      return;
+    }
+
+    currentSection.httpOutput = Logger.collectTestSectionOutput();
+  }
+
   setTotalElapsedTime() {
     this.timeMs = this.time;
     this.time = (this.time/1000).toPrecision(4);
diff --git a/lib/utils/logger/index.js b/lib/utils/logger/index.js
index 100c86a2..1941a624 100644
--- a/lib/utils/logger/index.js
+++ b/lib/utils/logger/index.js
@@ -168,6 +168,7 @@ function logRequest(message, params) {
   const instance = Logger.getInstance();
 
   instance.output.push([timeIso, lodashEscape(message), lodashEscape(inspectObject(params))]);
+  instance.testSectionOutput.push([timeIso, lodashEscape(message), lodashEscape(inspectObject(params))]);
 }
 
 function logError(severity, errOrMessage, args) {
@@ -183,6 +184,7 @@ class Logger {
   constructor() {
     this.colors = colors;
     this.output = [];
+    this.testSectionOutput = [];
   }
 
   logMessage(...args) {
@@ -467,3 +469,16 @@ module.exports.collectOutput = function() {
 
   return output;
 };
+
+module.exports.collectTestSectionOutput = function() {
+  const instance = Logger.getInstance();
+
+  if (!instance) {
+    return [];
+  }
+
+  const {testSectionOutput} = instance;
+  instance.testSectionOutput = [];
+
+  return testSectionOutput;
+};


Test patch:
diff --git a/lib/testsuite/index.js b/lib/testsuite/index.js
index 72ebd0bc..4a670263 100644
--- a/lib/testsuite/index.js
+++ b/lib/testsuite/index.js
@@ -229,7 +229,8 @@ class TestSuite {
         reportPrefix: '',
         reportFileName: this.argv['report-filename'],
         groupName,
-        isMobile: this.client.api.isMobile()
+        isMobile: this.client.api.isMobile(),
+        tags: this.context.getTags()
       }
     });
   }
@@ -473,7 +474,11 @@ class TestSuite {
         await this.globalsInstance.runPluginHook(hookName, [this.settings]);
       }
 
-      return this.globalHooks[hookName].run(this.client);
+      const result = await this.globalHooks[hookName].run(this.client);
+      
+      this.onTestSectionFinished();
+
+      return result;
     });
   }
 
@@ -538,8 +543,8 @@ class TestSuite {
     return this.startTestSuite()
       .then(() => this.runHook('before'))
       .then(result => {
-        this.reporter.setTestStatus();
-
+        this.onTestSectionFinished();
+        
         if (result instanceof Error) {
           Logger.error(result);
         }
@@ -577,6 +582,7 @@ class TestSuite {
             if ((possibleError instanceof Error) && this.failFastMode) {
               throw possibleError;
             }
+            this.onTestSectionFinished();
 
             return result;
           });
@@ -588,6 +594,12 @@ class TestSuite {
       .then((errorOrFailures) => this.onTestSuiteFinished(errorOrFailures));
   }
 
+  onTestSectionFinished() {
+    this.reporter.setTestStatus();
+    this.reporter.setTestSectionElapsedTime();
+    this.reporter.collectTestSectionOutput();
+  }
+
   onTestSuiteFinished(errorOrFailures = false) {
     this.__snapShot = undefined;
 
@@ -811,7 +823,7 @@ class TestSuite {
 
   testCaseFinished() {
     this.reporter.setElapsedTime();
-    this.reporter.setTestStatus();
+    this.onTestSectionFinished();
 
     if (!this.testcase) {
       return Promise.resolve();
diff --git a/test/src/runner/testReporter.js b/test/src/runner/testReporter.js
index 1a69b234..b75ba5d4 100644
--- a/test/src/runner/testReporter.js
+++ b/test/src/runner/testReporter.js
@@ -252,6 +252,9 @@ describe('testReporter', function() {
             assert.ok(Object.keys(module).includes('startTimestamp'));
             assert.ok(Object.keys(module).includes('endTimestamp'));
             assert.ok(Object.keys(module).includes('host'));
+            assert.ok(Object.keys(module).includes('name'));
+            assert.ok(Object.keys(module).includes('tags'));
+
             // check for individual test properties
             const test = module.completed['demoTest'];
             assert.ok(Object.keys(test).includes('status'));
@@ -292,12 +295,17 @@ describe('testReporter', function() {
 
             const completedSections = module['completedSections'];
 
-            // check for module properties
-            assert.ok(Object.keys(completedSections).includes('__after_hook'));
-            assert.ok(Object.keys(completedSections).includes('__before_hook'));
-            assert.ok(Object.keys(completedSections).includes('__global_afterEach_hook'));
-            assert.ok(Object.keys(completedSections).includes('__global_beforeEach_hook'));
-            assert.ok(Object.keys(completedSections).includes('demoTest'));
+            // check module properties all for hooks
+            const hooks = ['__after_hook', '__before_hook', '__global_afterEach_hook', '__global_beforeEach_hook', 'demoTest'];
+
+            hooks.forEach(hook => {
+              assert.ok(Object.keys(completedSections).includes(hook));
+
+              const sectionData = completedSections[hook];
+              assert.ok(Object.keys(sectionData).includes('startTimestamp'));
+              assert.ok(Object.keys(sectionData).includes('endTimestamp'));
+              assert.ok(Object.keys(sectionData).includes('httpOutput'));
+            });
             
             assert.strictEqual(completedSections['__after_hook']['commands'].length, 1);
             assert.strictEqual(completedSections['__after_hook']['commands'][0].name, 'end');