<NME> index.js
<BEF> const { serenity } = require('@serenity-js/core');
const { Path } = require('@serenity-js/core/lib/io');
const {
    ProtractorFrameworkAdapter,
    TestRunnerDetector,
    TestRunnerLoader
} = require('@serenity-js/protractor/lib/adapter');

/**
 * Execute the Runner's test cases through Cucumber.
 *
 * @param {Runner} runner The current Protractor Runner.
 * @param {string[]} specs Array of Directory Path Strings.
 * @return {Promise<void>>} Promise resolved with the test results
 */
exports.run = function (runner, specs) {
    return new ProtractorFrameworkAdapter(
        serenity,
        runner,
        new TestRunnerDetector(new TestRunnerLoader(
            testModeOrDefaultCwd(runner.getConfig().configDir),
            process.pid
        ))
    ).run(specs);
}

function testModeOrDefaultCwd(defaulValue) {

      Cucumber.Cli(cliArguments).run(function (isSuccessful) {
        try {
          if (runner.getConfig().onComplete) {
            runner.getConfig().onComplete();
          }
          resolve(results);
        } catch (err) {
          reject(err);
        }

<MSG> Allow config.onComplete to return a promise.

See https://github.com/angular/protractor/pull/2890

<DFF> @@ -28,10 +28,13 @@ exports.run = function(runner, specs) {
 
       Cucumber.Cli(cliArguments).run(function (isSuccessful) {
         try {
+          var complete = q();
           if (runner.getConfig().onComplete) {
-            runner.getConfig().onComplete();
+            complete = q(runner.getConfig().onComplete());
           }
-          resolve(results);
+          complete.then(function() {
+            resolve(results);
+          });
         } catch (err) {
           reject(err);
         }

Allow config.onComplete to return a promise.