'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _bluebird = require('bluebird');

var _bluebird2 = _interopRequireDefault(_bluebird);

var _extends2 = require('babel-runtime/helpers/extends');

var _extends3 = _interopRequireDefault(_extends2);

var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');

var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);

var _createClass2 = require('babel-runtime/helpers/createClass');

var _createClass3 = _interopRequireDefault(_createClass2);

var _lodash = require('lodash');

var _lodash2 = _interopRequireDefault(_lodash);

var _helpers = require('./helpers');

var _attachment_manager = require('./attachment_manager');

var _attachment_manager2 = _interopRequireDefault(_attachment_manager);

var _status = require('../status');

var _status2 = _interopRequireDefault(_status);

var _step_runner = require('./step_runner');

var _step_runner2 = _interopRequireDefault(_step_runner);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var TestCaseRunner = function () {
  function TestCaseRunner(_ref) {
    var _this = this;

    var eventBroadcaster = _ref.eventBroadcaster,
        skip = _ref.skip,
        testCase = _ref.testCase,
        supportCodeLibrary = _ref.supportCodeLibrary,
        worldParameters = _ref.worldParameters;
    (0, _classCallCheck3.default)(this, TestCaseRunner);

    var attachmentManager = new _attachment_manager2.default(function (_ref2) {
      var data = _ref2.data,
          media = _ref2.media;

      _this.emit('test-step-attachment', {
        index: _this.testStepIndex,
        data: data,
        media: media
      });
    });
    this.eventBroadcaster = eventBroadcaster;
    this.skip = skip;
    this.testCase = testCase;
    this.supportCodeLibrary = supportCodeLibrary;
    this.world = new supportCodeLibrary.World({
      attach: attachmentManager.create.bind(attachmentManager),
      parameters: worldParameters
    });
    this.beforeHookDefinitions = this.getBeforeHookDefinitions();
    this.afterHookDefinitions = this.getAfterHookDefinitions();
    this.testStepIndex = 0;
    this.result = {
      duration: 0,
      status: this.skip ? _status2.default.SKIPPED : _status2.default.PASSED
    };
    this.testCaseSourceLocation = {
      uri: this.testCase.uri,
      line: this.testCase.pickle.locations[0].line
    };
  }

  (0, _createClass3.default)(TestCaseRunner, [{
    key: 'emit',
    value: function emit(name, data) {
      var eventData = (0, _extends3.default)({}, data);
      if (_lodash2.default.startsWith(name, 'test-case')) {
        eventData.sourceLocation = this.testCaseSourceLocation;
      } else {
        eventData.testCase = { sourceLocation: this.testCaseSourceLocation };
      }
      this.eventBroadcaster.emit(name, eventData);
    }
  }, {
    key: 'emitPrepared',
    value: function emitPrepared() {
      var _this2 = this;

      var steps = [];
      this.beforeHookDefinitions.forEach(function (definition) {
        var actionLocation = { uri: definition.uri, line: definition.line };
        steps.push({ actionLocation: actionLocation });
      });
      this.testCase.pickle.steps.forEach(function (step) {
        var actionLocations = _this2.getStepDefinitions(step).map(function (definition) {
          return {
            uri: definition.uri,
            line: definition.line
          };
        });
        var sourceLocation = {
          uri: _this2.testCase.uri,
          line: _lodash2.default.last(step.locations).line
        };
        var data = { sourceLocation: sourceLocation };
        if (actionLocations.length === 1) {
          data.actionLocation = actionLocations[0];
        }
        steps.push(data);
      });
      this.afterHookDefinitions.forEach(function (definition) {
        var actionLocation = { uri: definition.uri, line: definition.line };
        steps.push({ actionLocation: actionLocation });
      });
      this.emit('test-case-prepared', { steps: steps });
    }
  }, {
    key: 'getAfterHookDefinitions',
    value: function getAfterHookDefinitions() {
      var _this3 = this;

      return this.supportCodeLibrary.afterTestCaseHookDefinitions.filter(function (hookDefinition) {
        return hookDefinition.appliesToTestCase(_this3.testCase);
      });
    }
  }, {
    key: 'getBeforeHookDefinitions',
    value: function getBeforeHookDefinitions() {
      var _this4 = this;

      return this.supportCodeLibrary.beforeTestCaseHookDefinitions.filter(function (hookDefinition) {
        return hookDefinition.appliesToTestCase(_this4.testCase);
      });
    }
  }, {
    key: 'getStepDefinitions',
    value: function getStepDefinitions(step) {
      var _this5 = this;

      return this.supportCodeLibrary.stepDefinitions.filter(function (stepDefinition) {
        return stepDefinition.matchesStepName({
          stepName: step.text,
          parameterTypeRegistry: _this5.supportCodeLibrary.parameterTypeRegistry
        });
      });
    }
  }, {
    key: 'invokeStep',
    value: function invokeStep(step, stepDefinition, hookParameter) {
      return _step_runner2.default.run({
        defaultTimeout: this.supportCodeLibrary.defaultTimeout,
        hookParameter: hookParameter,
        parameterTypeRegistry: this.supportCodeLibrary.parameterTypeRegistry,
        step: step,
        stepDefinition: stepDefinition,
        world: this.world
      });
    }
  }, {
    key: 'isSkippingSteps',
    value: function isSkippingSteps() {
      return this.result.status !== _status2.default.PASSED;
    }
  }, {
    key: 'shouldUpdateStatus',
    value: function shouldUpdateStatus(testStepResult) {
      switch (testStepResult.status) {
        case _status2.default.FAILED:
        case _status2.default.AMBIGUOUS:
          return this.result.status !== _status2.default.FAILED || this.result.status !== _status2.default.AMBIGUOUS;
        default:
          return this.result.status === _status2.default.PASSED || this.result.status === _status2.default.SKIPPED;
      }
    }
  }, {
    key: 'aroundTestStep',
    value: function () {
      var _ref3 = (0, _bluebird.coroutine)(function* (runStepFn) {
        this.emit('test-step-started', { index: this.testStepIndex });
        var testStepResult = yield runStepFn();
        if (testStepResult.duration) {
          this.result.duration += testStepResult.duration;
        }
        if (this.shouldUpdateStatus(testStepResult)) {
          this.result.status = testStepResult.status;
        }
        if (testStepResult.exception) {
          this.result.exception = testStepResult.exception;
        }
        this.emit('test-step-finished', {
          index: this.testStepIndex,
          result: testStepResult
        });
        this.testStepIndex += 1;
      });

      function aroundTestStep(_x) {
        return _ref3.apply(this, arguments);
      }

      return aroundTestStep;
    }()
  }, {
    key: 'run',
    value: function () {
      var _ref4 = (0, _bluebird.coroutine)(function* () {
        this.emitPrepared();
        this.emit('test-case-started', {});
        yield this.runHooks(this.beforeHookDefinitions, {
          sourceLocation: this.testCaseSourceLocation,
          pickle: this.testCase.pickle
        });
        yield this.runSteps();
        yield this.runHooks(this.afterHookDefinitions, {
          sourceLocation: this.testCaseSourceLocation,
          pickle: this.testCase.pickle,
          result: this.result
        });
        this.emit('test-case-finished', { result: this.result });
        return this.result;
      });

      function run() {
        return _ref4.apply(this, arguments);
      }

      return run;
    }()
  }, {
    key: 'runHook',
    value: function () {
      var _ref5 = (0, _bluebird.coroutine)(function* (hookDefinition, hookParameter) {
        if (this.skip) {
          return { status: _status2.default.SKIPPED };
        }
        return this.invokeStep(null, hookDefinition, hookParameter);
      });

      function runHook(_x2, _x3) {
        return _ref5.apply(this, arguments);
      }

      return runHook;
    }()
  }, {
    key: 'runHooks',
    value: function () {
      var _ref6 = (0, _bluebird.coroutine)(function* (hookDefinitions, hookParameter) {
        var _this6 = this;

        yield _bluebird2.default.each(hookDefinitions, function () {
          var _ref7 = (0, _bluebird.coroutine)(function* (hookDefinition) {
            yield _this6.aroundTestStep(function () {
              return _this6.runHook(hookDefinition, hookParameter);
            });
          });

          return function (_x6) {
            return _ref7.apply(this, arguments);
          };
        }());
      });

      function runHooks(_x4, _x5) {
        return _ref6.apply(this, arguments);
      }

      return runHooks;
    }()
  }, {
    key: 'runStep',
    value: function () {
      var _ref8 = (0, _bluebird.coroutine)(function* (step) {
        var stepDefinitions = this.getStepDefinitions(step);
        if (stepDefinitions.length === 0) {
          return { status: _status2.default.UNDEFINED };
        } else if (stepDefinitions.length > 1) {
          return {
            exception: (0, _helpers.getAmbiguousStepException)(stepDefinitions),
            status: _status2.default.AMBIGUOUS
          };
        } else if (this.isSkippingSteps()) {
          return { status: _status2.default.SKIPPED };
        }
        return this.invokeStep(step, stepDefinitions[0]);
      });

      function runStep(_x7) {
        return _ref8.apply(this, arguments);
      }

      return runStep;
    }()
  }, {
    key: 'runSteps',
    value: function () {
      var _ref9 = (0, _bluebird.coroutine)(function* () {
        var _this7 = this;

        yield _bluebird2.default.each(this.testCase.pickle.steps, function () {
          var _ref10 = (0, _bluebird.coroutine)(function* (step) {
            yield _this7.aroundTestStep(function () {
              return _this7.runStep(step);
            });
          });

          return function (_x8) {
            return _ref10.apply(this, arguments);
          };
        }());
      });

      function runSteps() {
        return _ref9.apply(this, arguments);
      }

      return runSteps;
    }()
  }]);
  return TestCaseRunner;
}();

exports.default = TestCaseRunner;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,[encoded data, 17200 characters]