Repository: Codeception/CodeceptJS
Pull request #1484 (2019-02-02 17:54:51)

Fix bootstrapAll and teardownAll launch with path as argument
Fix for #1346;

global variable with path was not defined for `run-multiple`, so `bootstrapAll` and `teardownAll` were run with error

```
TypeError: Path must be a string. Received undefined
    at assertPath (path.js:28:11)
    at Object.join (path.js:1236:7)
    at module.exports (CodeceptJS/lib/hooks.js:8:31)
    at Command.module.exports (CodeceptJS/lib/command/run-multiple.js:67:3)

```


Patch:
diff --git a/lib/command/interactive.js b/lib/command/interactive.js
index 5f321525..478e9e54 100644
--- a/lib/command/interactive.js
+++ b/lib/command/interactive.js
@@ -23,8 +23,13 @@ module.exports = function (path, options) {
 
     output.print('String interactive shell for current suite...');
     recorder.start();
-    event.emit(event.suite.before, {});
-    event.emit(event.test.before);
+    event.emit(event.suite.before, {
+      fullTitle: () => 'Interactive Shell',
+      tests: [],
+    });
+    event.emit(event.test.before, {
+      title: '',
+    });
     require('../pause')();
     recorder.add(() => event.emit(event.test.after));
     recorder.add(() => event.emit(event.suite.after, {}));
diff --git a/lib/command/run-multiple.js b/lib/command/run-multiple.js
index 41200f6f..57d5ef3a 100644
--- a/lib/command/run-multiple.js
+++ b/lib/command/run-multiple.js
@@ -31,6 +31,7 @@ module.exports = function (selectedRuns, options) {
   let codecept;
 
   const testRoot = getTestRoot(configFile);
+  global.codecept_dir = testRoot;
 
   // copy opts to run
   Object.keys(options)
diff --git a/lib/helper/Nightmare.js b/lib/helper/Nightmare.js
index f95be1aa..27e6cb04 100644
--- a/lib/helper/Nightmare.js
+++ b/lib/helper/Nightmare.js
@@ -401,7 +401,7 @@ class Nightmare extends Helper {
    * ```
    */
   async amOnPage(url, headers = null) {
-    if (url.indexOf('http') !== 0) {
+    if (!(/^\w+\:\/\//.test(url))) {
       url = urlResolve(this.options.url, url);
     }
     const currentUrl = await this.browser.url();
diff --git a/lib/helper/Protractor.js b/lib/helper/Protractor.js
index 3fa9749f..cdadaa90 100644
--- a/lib/helper/Protractor.js
+++ b/lib/helper/Protractor.js
@@ -427,7 +427,7 @@ class Protractor extends Helper {
    * {{> ../webapi/amOnPage }}
    */
   async amOnPage(url) {
-    if (url.indexOf('http') !== 0) {
+    if (!(/^\w+\:\/\//.test(url))) {
       url = this.options.url + url;
     }
     const res = await this.browser.get(url);
diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js
index 98451ab8..5c8c5ff9 100644
--- a/lib/helper/Puppeteer.js
+++ b/lib/helper/Puppeteer.js
@@ -494,7 +494,7 @@ class Puppeteer extends Helper {
    * {{> ../webapi/amOnPage }}
    */
   async amOnPage(url) {
-    if (url.indexOf('http') !== 0) {
+    if (!(/^\w+\:\/\//.test(url))) {
       url = this.options.url + url;
     }
     await this.page.goto(url, { waitUntil: this.options.waitForNavigation });
diff --git a/lib/helper/WebDriver.js b/lib/helper/WebDriver.js
index 573bad4a..a4809f90 100644
--- a/lib/helper/WebDriver.js
+++ b/lib/helper/WebDriver.js
@@ -777,10 +777,9 @@ class WebDriver extends Helper {
    * * *Appium*: supported only for web testing
    */
   async grabHTMLFrom(locator) {
-    const res = await this._locate(locator, true);
-    assertElementExists(res, locator);
-    const elem = usingFirstElement(res);
-    const html = await elem.getHTML();
+    const elems = await this._locate(locator, true);
+    assertElementExists(elems, locator);
+    const html = Promise.all(elems.map(async elem => elem.getHTML(false)));
     this.debugSection('Grab', html);
     return html;
   }
diff --git a/lib/interfaces/scenarioConfig.js b/lib/interfaces/scenarioConfig.js
index 0892749a..568ab7d6 100644
--- a/lib/interfaces/scenarioConfig.js
+++ b/lib/interfaces/scenarioConfig.js
@@ -83,6 +83,16 @@ class ScenarioConfig {
     this.test.title = `${this.test.title.trim()} ${tagName}`;
     return this;
   }
+
+  /**
+   * Dynamically injects dependencies, see https://codecept.io/pageobjects/#dynamic-injection
+   * @param {*} dependencies
+   */
+  injectDependencies(dependencies) {
+    Object.keys(dependencies).forEach((key) => {
+      this.test.inject[key] = dependencies[key];
+    });
+  }
 }
 
 module.exports = ScenarioConfig;
diff --git a/lib/plugin/stepByStepReport.js b/lib/plugin/stepByStepReport.js
index 506323a4..919a8091 100644
--- a/lib/plugin/stepByStepReport.js
+++ b/lib/plugin/stepByStepReport.js
@@ -11,6 +11,7 @@ const { template, clearString, deleteDir } = require('../utils');
 
 const supportedHelpers = [
   'WebDriverIO',
+  'WebDriver',
   'Protractor',
   'Appium',
   'Nightmare',
@@ -172,7 +173,7 @@ module.exports = function (config) {
 
       slideHtml += template(templates.slides, {
         image: i,
-        caption: step.toString(),
+        caption: step.toString().replace(/\[\d{2}m/g, ''), // remove ANSI escape sequence
         isActive: stepNum ? '' : 'active',
         isError: step.status === 'failed' ? 'error' : '',
       });
diff --git a/lib/ui.js b/lib/ui.js
index 2a263190..e76c3ba0 100644
--- a/lib/ui.js
+++ b/lib/ui.js
@@ -46,11 +46,6 @@ module.exports = function (suite) {
       }
       const test = new Test(title, fn);
       test.fullTitle = () => `${suite.title}: ${test.title}`;
-      test.injectDependencies = (deps) => {
-        Object.keys(deps).forEach((key) => {
-          test.inject[key] = deps[key];
-        });
-      };
 
       test.tags = (suite.tags || []).concat(title.match(/(\@[a-zA-Z0-9-_]+)/g)); // match tags from title
       test.file = file;


Test patch:
diff --git a/test/data/sandbox/page_slider.html b/test/data/sandbox/page_slider.html
new file mode 100644
index 00000000..ecd35da0
--- /dev/null
+++ b/test/data/sandbox/page_slider.html
@@ -0,0 +1,35 @@
+<!-- Example based oncode from https://www.w3schools.com/howto/howto_js_rangeslider.asp -->
+
+<div id="slidecontainer">
+  <input
+    type="range"
+    min="1"
+    max="100"
+    value="50"
+    class="slider"
+    id="mySlider"
+  />
+</div>
+<div><span>Value:</span> <span id="demo"></span></div>
+
+<script>
+  var slider = document.getElementById("mySlider");
+  var output = document.getElementById("demo");
+  output.innerHTML = slider.value;
+
+  slider.oninput = function() {
+    output.innerHTML = this.value;
+  };
+</script>
+
+<style>
+  #slidecontainer {
+    width: 100%;
+  }
+  .slider {
+    width: 100%;
+    height: 25px;
+    background: #d3d3d3;
+    outline: none;
+  }
+</style>
diff --git a/test/helper/Puppeteer_test.js b/test/helper/Puppeteer_test.js
index cf9b887a..e591f9dc 100644
--- a/test/helper/Puppeteer_test.js
+++ b/test/helper/Puppeteer_test.js
@@ -550,7 +550,7 @@ describe('Puppeteer', function () {
 
   describe('#dragSlider', () => {
     it('should drag scrubber to given position', async () => {
-      await I.amOnPage('https://www.w3schools.com/howto/howto_js_rangeslider.asp');
+      await I.amOnPage(`file://${path.resolve(__dirname, '../data/sandbox/page_slider.html')}`);
       await I.seeElementInDOM('#slidecontainer input');
       const before = await I.grabValueFrom('#slidecontainer input');
       await I.dragSlider('#slidecontainer input', 20);
diff --git a/test/helper/WebDriver_test.js b/test/helper/WebDriver_test.js
index ea8ba300..2f5d6be9 100644
--- a/test/helper/WebDriver_test.js
+++ b/test/helper/WebDriver_test.js
@@ -167,13 +167,13 @@ describe('WebDriver', function () {
       .then(() => wd.grabSource())
       .then(source => assert.notEqual(source.indexOf('<title>TestEd Beta 2.0</title>'), -1, 'Source html should be retrieved')));
 
-    it('should grab the source for element', () => wd.amOnPage('/')
+    it('should grab the innerHTML for an element', () => wd.amOnPage('/')
       .then(() => wd.grabHTMLFrom('#area1'))
-      .then(source => assert.equal(
+      .then(source => assert.deepEqual(
         source,
-        `<div id="area1" qa-id="test">
+        [`
     <a href="/form/file" qa-id="test" qa-link="test"> Test Link </a>
-</div>`,
+`],
       )));
   });
 
diff --git a/test/unit/ui_test.js b/test/unit/ui_test.js
index 4e591907..4552970a 100644
--- a/test/unit/ui_test.js
+++ b/test/unit/ui_test.js
@@ -110,5 +110,11 @@ describe('ui', () => {
       scenarioConfig.tag('@user');
       scenarioConfig.test.tags.should.include('@user');
     });
+
+    it('should dynamically inject dependencies', () => {
+      scenarioConfig = context.Scenario('scenario');
+      scenarioConfig.injectDependencies({ Data: 'data' });
+      assert.equal(scenarioConfig.test.inject.Data, 'data');
+    });
   });
 });