Repository: Codeception/CodeceptJS
Pull request #922 (2018-02-09 16:11:57)

add injectDependencies method
As mentioned in https://github.com/Codeception/CodeceptJS/pull/820#issuecomment-352279338
Now test object has injectDependencies method that allow to inject custom deps to test:

usage:
```
require('./common').forEach((t) => t.injectDependencies());
```

DavertMik: Yeah, it's ok. Could you add documentation on how this can be used for reusing test scenarios? 

Also this can be used inside a single test case where you can inject a standalone module:

```js
this.injectDependencies({ myData: './data/users.js' });
// or dynamically load steps
this.injectDependencies({ mySteps: './data/steps.js' });
```

Patch:
diff --git a/lib/data/context.js b/lib/data/context.js
index 7f042ca0..c40c7981 100644
--- a/lib/data/context.js
+++ b/lib/data/context.js
@@ -46,6 +46,11 @@ module.exports = function (context) {
   };
 };
 
+function isTableDataRow(row) {
+  const has = Object.prototype.hasOwnProperty;
+  return has.call(row, 'data') && has.call(row, 'skip');
+}
+
 function detectDataType(dataTable) {
   if (dataTable instanceof DataTable) {
     return dataTable.rows;
@@ -64,7 +69,15 @@ function detectDataType(dataTable) {
     return dataTable();
   }
   if (Array.isArray(dataTable)) {
-    return dataTable;
+    return dataTable.map((item) => {
+      if (isTableDataRow(item)) {
+        return item;
+      }
+      return {
+        data: item,
+        skip: false,
+      };
+    });
   }
 
   throw new Error('Invalid data type. Data accepts either: DataTable || generator || Array || function');
diff --git a/lib/helper/Nightmare.js b/lib/helper/Nightmare.js
index 77b73912..a0f13478 100644
--- a/lib/helper/Nightmare.js
+++ b/lib/helper/Nightmare.js
@@ -480,6 +480,19 @@ class Nightmare extends Helper {
     stringIncludes('HTML source of a page').negate(text, source);
   }
 
+  /**
+   * asserts that an element appears a given number of times in the DOM
+   * Element is located by label or name or CSS or XPath.
+   *
+   * ```js
+   * I.seeNumberOfElements('#submitBtn', 1);
+   * ```
+   */
+  async seeNumberOfElements(selector, num) {
+    const elements = await this._locate(selector);
+    return equals(`expected number of elements (${selector}) is ${num}, but found ${elements.length}`).assert(elements.length, num);
+  }
+
 
   /**
    * {{> ../webapi/click }}
diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js
index e8d9726e..d90d2b1b 100644
--- a/lib/helper/Puppeteer.js
+++ b/lib/helper/Puppeteer.js
@@ -1198,10 +1198,11 @@ class Puppeteer extends Helper {
   /**
    * {{> ../webapi/saveScreenshot }}
    */
-  async saveScreenshot(fileName, fullPage = this.options.fullPageScreenshots) {
+  async saveScreenshot(fileName, fullPage) {
+    const fullPageOption = fullPage || this.options.fullPageScreenshots;
     const outputFile = path.join(global.output_dir, fileName);
     this.debug(`Screenshot is saving to ${outputFile}`);
-    return this.page.screenshot({ path: outputFile, fullPage, type: 'png' });
+    return this.page.screenshot({ path: outputFile, fullPage: fullPageOption, type: 'png' });
   }
 
   async _failed(test) {
diff --git a/lib/helper/REST.js b/lib/helper/REST.js
index d71cb1d2..cfa7034d 100644
--- a/lib/helper/REST.js
+++ b/lib/helper/REST.js
@@ -170,7 +170,6 @@ class REST extends Helper {
    * @param {object} headers
    */
   sendPostRequest(url, payload = {}, headers = {}) {
-    payload = typeof payload === 'object' ? JSON.stringify(payload) : payload;
     request = unirest.post(this._url(url)).headers(headers).send(payload);
     return this._executeRequest(request);
   }
@@ -187,7 +186,6 @@ class REST extends Helper {
    * @param {object} headers
    */
   sendPatchRequest(url, payload = {}, headers = {}) {
-    payload = typeof payload === 'object' ? JSON.stringify(payload) : payload;
     request = unirest.patch(this._url(url)).headers(headers).send(payload);
     return this._executeRequest(request);
   }
@@ -204,7 +202,6 @@ class REST extends Helper {
    * @param {object} headers
    */
   sendPutRequest(url, payload = {}, headers = {}) {
-    payload = typeof payload === 'object' ? JSON.stringify(payload) : payload;
     request = unirest.put(this._url(url)).headers(headers).send(payload);
     return this._executeRequest(request);
   }
diff --git a/lib/interfaces/bdd.js b/lib/interfaces/bdd.js
index a6266573..86fd3d3b 100644
--- a/lib/interfaces/bdd.js
+++ b/lib/interfaces/bdd.js
@@ -60,6 +60,11 @@ module.exports = function (suite) {
       }
       const test = new Test(title, fn);
       test.fullTitle = () => `${suite.title}: ${title}`;
+      test.injectDependencies = (deps) => {
+        Object.keys(deps).forEach((key) => {
+          test.inject[key] = deps[key];
+        });
+      }
       test.file = file;
       test.async = true;
       test.timeout(0);


Test patch:
diff --git a/test/data/rest/db.json b/test/data/rest/db.json
index 838c80ee..9f5474ac 100644
--- a/test/data/rest/db.json
+++ b/test/data/rest/db.json
@@ -1,1 +1,1 @@
-{"comments":[],"posts":[{"id":1,"title":"json-server","author":"davert"}]}
\ No newline at end of file
+{"comments":[],"posts":[{"id":1,"title":"json-server","author":"davert"}]}
diff --git a/test/data/sandbox/ddt_test.ddt.js b/test/data/sandbox/ddt_test.ddt.js
index 6c67ab73..1c832046 100644
--- a/test/data/sandbox/ddt_test.ddt.js
+++ b/test/data/sandbox/ddt_test.ddt.js
@@ -22,3 +22,7 @@ Data(function* () {
 }).Scenario('Should log accounts3', (I, current) => {
   console.log(`Got changed login ${current[0]}`);
 });
+
+Data(['1', '2', '3']).Scenario('Should log array of strings', (I, current) => {
+  console.log(`Got array item ${current}`);
+});
diff --git a/test/helper/Nightmare_test.js b/test/helper/Nightmare_test.js
index 9b850877..0985bfff 100644
--- a/test/helper/Nightmare_test.js
+++ b/test/helper/Nightmare_test.js
@@ -156,4 +156,9 @@ describe('Nightmare', function () {
       assert.equal(url, nextUrl);
     });
   });
+
+  describe('#seeNumberOfElements', () => {
+    it('should return 1 as count', () => I.amOnPage('/')
+      .then(() => I.seeNumberOfElements('#area1', 1)));
+  });
 });
diff --git a/test/rest/REST_test.js b/test/rest/REST_test.js
index 4e5f3482..53ac8fda 100644
--- a/test/rest/REST_test.js
+++ b/test/rest/REST_test.js
@@ -46,22 +46,30 @@ describe('REST', () => {
       response.body.name.should.eql('davert');
     }));
 
-    it('should send PATCH requests', () => I.sendPatchRequest('/user', { email: 'user@user.com' }).then((response) => {
-      const body = JSON.parse(Object.keys(response.body)[1]);
-      body.email.should.eql('user@user.com');
+    it('should send PATCH requests: payload format = json', () => I.sendPatchRequest('/user', { email: 'user@user.com' }).then((response) => {
+      response.body.email.should.eql('user@user.com');
+    }));
+    it('should send PATCH requests: payload format = form urlencoded', () => I.sendPatchRequest('/user', 'email=user@user.com').then((response) => {
+      response.body.email.should.eql('user@user.com');
     }));
 
-    it('should send POST requests', () => I.sendPostRequest('/user', { name: 'john' }).then((response) => {
-      const body = JSON.parse(Object.keys(response.body)[0]);
-      body.name.should.eql('john');
+    it('should send POST requests: payload format = json', () => I.sendPostRequest('/user', { name: 'john' }).then((response) => {
+      response.body.name.should.eql('john');
+    }));
+    it('should send POST requests: payload format = form urlencoded', () => I.sendPostRequest('/user', 'name=john').then((response) => {
+      response.body.name.should.eql('john');
     }));
 
-    it('should send PUT requests', () => I.sendPutRequest('/posts/1', { author: 'john' }).then((response) => {
-      const body = JSON.parse(Object.keys(response.body)[0]);
-      body.author.should.eql('john');
+    it('should send PUT requests: payload format = json', () => I.sendPutRequest('/posts/1', { author: 'john' }).then((response) => {
+      response.body.author.should.eql('john');
+      return I.sendGetRequest('/posts/1').then((response) => {
+        response.body.author.should.eql('john');
+      });
+    }));
+    it('should send PUT requests: payload format = form urlencoded', () => I.sendPutRequest('/posts/1', 'author=john').then((response) => {
+      response.body.author.should.eql('john');
       return I.sendGetRequest('/posts/1').then((response) => {
-        const body = JSON.parse(Object.keys(response.body)[0]);
-        body.author.should.eql('john');
+        response.body.author.should.eql('john');
       });
     }));