Repository: codeceptjs/CodeceptJS (JavaScript)

Issue:
Scenario(...).injectDependencies is not a function
#### What are you trying to achieve?
I would like to try Scenario.injectDependencies(), see https://codecept.io/pageobjects/#dependency-injection
#### What do you get instead?
```bash
$ node_modules/.bin/codeceptjs run Inject_test.js
Scenario(...).injectDependencies is not a function

TypeError:
    at Object.<anonymous> (/home/mira/workspace/mycodeceptjs/Inject_test.js:6:4)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Module.require (module.js:597:17)
    at require (internal/module.js:11:18)
    at /home/mira/workspace/mycodeceptjs/node_modules/mocha/lib/mocha.js:231:27
    at Array.forEach (<anonymous>)
```

> Provide test source code if related

```js
Scenario('test something', (I, Data) => {
    Data.printTxt2("Test");
}).injectDependencies({ Data: require('./pages/common.js') });

```

### Details

* CodeceptJS version: 1.4.6
* NodeJS Version: 8.13
* Operating System: Ubuntu 18.10
* Configuration file:

```js
{
  "output": "./output",
  "helpers": {
    "WebDriverIO": {
      "url": "https://www.rohlik.cz",
      "browser": "chrome",
      "desiredCapabilities": {
        "chromeOptions": {
          "args": [
            "--headless",
            "--disable-gpu",
            "--window-size=800,600"
          ]
        }
      },
      "restart": true,
      "waitForTimeout": 20000
    },
    "REST": {
      "endpoint": "https://localhost/api",
      "resetHeaders": false
    },
    "Rohlik": {
      "require": "./rohlik_helper.js"
    },
    "Mochawesome": {
      "uniqueScreenshotNames": "true"
    },
    "DbHelper": {
      "require": "./node_modules/codeceptjs-dbhelper"
    }
  },
  "include": {
    "I": "./steps_file.js"
  },
  "bootstrap": false,
  "teardown": null,
  "hooks": [],
  "gherkin": {},
  "plugins": {
    "screenshotOnFail": {
      "enabled": true
    }
  },
  "tests": "./*_test.js",
  "timeout": 10000,
  "name": "mycodeceptjs"
}
```

Scenario(...).injectDependencies is not a function
#### What are you trying to achieve?

I would like to try Scenario.injectDependencies(), see https://codecept.io/pageobjects/#dependency-injection

#### What do you get instead?
Scenario(...).injectDependencies is not a function

> Provide console output if related. Use `--verbose` mode for more details.

```bash
lucas@dev03:~/siganet-docker/siganet/siganet-source$
 ./node_modules/codeceptjs/bin/codecept.js run --steps ./test-front-end/financeiro_pagar_test.js --verbose

Scenario(...).injectDependencies is not a function

TypeError: 
    at Object.<anonymous> (/home/bruno/siganet-docker/siganet/siganet-source/test-front-end/financeiro_pagar_test.js:32:4)
    at Module._compile (internal/modules/cjs/loader.js:721:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:732:10)
    at Module.load (internal/modules/cjs/loader.js:620:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:560:12)
    at Function.Module._load (internal/modules/cjs/loader.js:552:3)
    at Module.require (internal/modules/cjs/loader.js:657:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at /home/bruno/siganet-docker/siganet/siganet-source/node_modules/mocha/lib/mocha.js:231:27
    at Array.forEach (<anonymous>)
```

> Provide test source code if related

```js
Feature('A pagar');

//Realiza o login antes de continuar o teste.
Before( (I , paginaLogin, menu) => {
    paginaLogin.realizaLogin();
});

//Realiza o logOut No final de cada cenário.
After( (I, menu) => {
   menu.realizaLogOut();
});

Scenario('Incluindo uma duplicata',async (I, menu, menuFinanceiro,Data) => {
    I.amOnPage('http://siganet.local/home.php');

    menuFinanceiro.aPagarInclusao();

    within({frame: "#principal"}, () => {
        //Fill some fields
        Data.preencheCampos();

        //click save button
        Data.salvar();

        //end operation
        Data.finalizar();

    //inject dynamic depencies for the scenario (here's where the error happen).
    });
}).injectDependencies({ Data: require('./page-objects/siga5011.js') });
```

### Details

* CodeceptJS version: v2.0.4
* NodeJS Version: v11.7.0
* Operating System: Debian GNU/Linux 9 (stretch) 64-bit
* Protractor || WebDriverIO || Nightmare version: we use puppeteer
* Configuration file:

```js
exports.config = {
  output: 'test-front-end/logs',
  helpers: {
    Puppeteer: {
        url: 'siganet.local/site',
        show: true,
        fullPageScreenShots: true,
        keepBrowserState: true,
        restart: false
    },
    customHelper: {
      require: './test-front-end/helpers/customHelper.js',
    },
  },
  include: {
      paginaLogin: './test-front-end/page-objects/PaginaLogin.js',

      //menus
      menu: './test-front-end/page-objects/menus/Menu.js',
      menuFinanceiro: './test-front-end/page-objects/menus/MenuFinanceiro.js',

      //Step Objects
      financeiroSteps: './test-front-end/step-objects/financeiro-steps.js',

      //Page Objects
         //Page Fragments
      siga2289: './test-front-end/page-objects/siga2289.js',
      siga5026: './test-front-end/page-objects/siga5026.js',
      siga7015: './test-front-end/page-objects/siga7015.js',
      siga7020: './test-front-end/page-objects/siga7020.js',
      siga6098: './test-front-end/page-objects/siga6098.js'
  },
  mocha: {},
  bootstrap: null,
  teardown: null,
  hooks: [],
  gherkin: {
    features: './features/*.feature',
    steps: ['./step_definitions/steps.js']
  },
  plugins: {
    screenshotOnFail: {
      enabled: true
    }
  },
  tests: 'test-front-end/*_test.js',
  name: 'siganet-source',
  translation: 'pt-BR'
};
```



Discussion:


Thanks!!



Patch:
diff --git a/lib/interfaces/scenarioConfig.js b/lib/interfaces/scenarioConfig.js
index 0892749a9..568ab7d6b 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/ui.js b/lib/ui.js
index 2a2631909..e76c3ba09 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/unit/ui_test.js b/test/unit/ui_test.js
index 4e5919073..4552970a3 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');
+    });
   });
 });