Repository: Codeception/CodeceptJS (js)

Issue:
Data sets can't be defined with array in version 1.1.2 but can be in version 1.0.1
#### What are you trying to achieve?
I hope data sets can be defined with array...
#### What do you get instead?

> Provide console output if related. Use `--verbose` mode for more details.

```bash
# paste output here
{ ui-regression-test } master » codeceptjs run --steps --profile cm --verbose
CodeceptJS v1.1.2
Using test root "D:\git\Medicare\ui\ui-regression-test"

ehm --
   [1] Starting recording promises
   Emitted | suite.before ([object Object])
   [1] Queued | hook WebDriverIO._beforeSuite()
 test array | undefined
   Emitted | test.before
   [1] Queued | hook WebDriverIO._before()
   Emitted | test.start ([object Object])
   [1] Queued | throw error Error: Object of type current is not defined in container
   [1] Queued | fire test.passed
   [1] Queued | finish test
   [1] Error | Error: Object of type current is not defined in container
   [1] Starting <teardown> session
   Emitted | test.failed ([object Object])
   [1] <teardown> Queued | hook WebDriverIO._failed()
   [1] <teardown> Queued | () => done(err)
   [1] <teardown> Stopping recording promises
 > Screenshot has been saved to D:\git\Medicare\ui\ui-regression-test\output\test_array___undefined.failed.png
 × FAILED in 363ms

   [2] Starting recording promises
   Emitted | test.after
   [2] Queued | hook WebDriverIO._after()
 test array | undefined
   Emitted | test.before
   [2] Queued | hook WebDriverIO._before()
   Emitted | test.start ([object Object])
   [2] Queued | throw error Error: Object of type current is not defined in container
   [2] Queued | fire test.passed
   [2] Queued | finish test
   [2] Error | Error: Object of type current is not defined in container
   [2] Starting <teardown> session
   Emitted | test.failed ([object Object])
   [2] <teardown> Queued | hook WebDriverIO._failed()
   [2] <teardown> Queued | () => done(err)
   [2] <teardown> Stopping recording promises
 > Screenshot has been saved to D:\git\Medicare\ui\ui-regression-test\output\test_array___undefined.failed.png
 × FAILED in 376ms

   [3] Starting recording promises
   Emitted | test.after
   [3] Queued | hook WebDriverIO._after()
 test array | undefined
   Emitted | test.before
   [3] Queued | hook WebDriverIO._before()
   Emitted | test.start ([object Object])
   [3] Queued | throw error Error: Object of type current is not defined in container
   [3] Queued | fire test.passed
   [3] Queued | finish test
   [3] Error | Error: Object of type current is not defined in container
   [3] Starting <teardown> session
   Emitted | test.failed ([object Object])
   [3] <teardown> Queued | hook WebDriverIO._failed()
   [3] <teardown> Queued | () => done(err)
   [3] <teardown> Stopping recording promises
 > Screenshot has been saved to D:\git\Medicare\ui\ui-regression-test\output\test_array___undefined.failed.png
 × FAILED in 349ms

   [4] Starting recording promises
   Emitted | test.after
   [4] Queued | hook WebDriverIO._after()
   Emitted | suite.after ([object Object])
   [4] Queued | hook WebDriverIO._afterSuite()

-- FAILURES:

  1) ehm
       test array | undefined:
     Object of type current is not defined in container
  rror: Object of type current is not defined in container
      at getInjectedArguments (C:\Users\cherrieg\AppData\Roaming\npm\node_modules\codeceptjs\lib\scenario.js:213:13)
      at Context.test.fn (C:\Users\cherrieg\AppData\Roaming\npm\node_modules\codeceptjs\lib\scenario.js:79:38)

  2) ehm
       test array | undefined:
     Object of type current is not defined in container
  rror: Object of type current is not defined in container
      at getInjectedArguments (C:\Users\cherrieg\AppData\Roaming\npm\node_modules\codeceptjs\lib\scenario.js:213:13)
      at Context.test.fn (C:\Users\cherrieg\AppData\Roaming\npm\node_modules\codeceptjs\lib\scenario.js:79:38)

  3) ehm
       test array | undefined:
     Object of type current is not defined in container
  rror: Object of type current is not defined in container
      at getInjectedArguments (C:\Users\cherrieg\AppData\Roaming\npm\node_modules\codeceptjs\lib\scenario.js:213:13)
      at Context.test.fn (C:\Users\cherrieg\AppData\Roaming\npm\node_modules\codeceptjs\lib\scenario.js:79:38)


  FAIL  | 0 passed, 3 failed   // 15s
   Emitted | global.result ([object Object])
   [4] Queued | hook WebDriverIO._finishTest()

```

> Provide test source code if related

```js
// paste test
Feature('ehm');
Data(['1', '2', '3']).Scenario('test array', (I, current)=>{
	console.log(current);
})
```

### Details

* CodeceptJS version: 1.1.2
* NodeJS Version: 8.9.3
* Operating System: Windows 7
* Protractor || WebDriverIO || Nightmare version (if related)
* Configuration file:
exports.config = {
    "tests": "./test/test_test.js",
    "timeout": 100000,
    "output": "./output",
    "include": {
        "censusPage": "./pages/censusPage.js",
        "phonePage": "./pages/phonePage.js",
        "leadPage": "./pages/leadPage.js",
        "quotePage": "./pages/quotePage.js"
    },
    "helpers": {
        "WebDriverIO": {
            "url": "https://",
            "browser": "chrome",
            "windowSize": "maximize",
            "restart": true,
            "desiredCapabilities": {
                "browserName": "chrome",
                "chromeOptions": {
                    "binary": "D:/software/chrome-win32/chrome.exe",
                    "args": ["--window-size=1800,1600"]
                }
            }
        }
    },
    "name": "layer-x",
    "mocha": {
        "reporterOptions": {
            "reportDir": "output"
        }
    }
}
```js
# paste suite config here
```


Pull request description:
[Data Driven Tests] Accept plain arrays (regression fix)
### Highlights

* Support plain arrays again in the Data Driven Tests. (Fixes #920)

### Background

Plain arrays worked in v1.0.1 but broke some time later.

The docs (advanced.md) already mention that `Data sets can also be defined with array, generator, or a function.`. So no need to update them.

Here is the example which now works again.

```js
Feature('ehm');

// Case 1: Allow plain arrays
Data(['1', '2', '3']).Scenario('data table test array', (I, current) => {
    I.amOnPage('/');
    console.log(current);
});
```

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/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);
   }


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/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');
       });
     }));