Source: dsl/interaction.js

'use strict'

import omitBy from 'lodash.omitby'
import isNil from 'lodash.isnil'

const VALID_METHODS = [ 'GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS' ]

/**
 * An Interaction is where you define the state of your interaction with a Provider.
 */
export default class Interaction {

  /**
   * Creates a new Interaction.
   */
  constructor () {
    this.state = {}
    return this
  }

  /**
   * Gives a state the provider should be in for this interaction.
   * @param {string} providerState - The state of the provider.
   * @returns {Interaction}
   */
  given (providerState) {
    if (providerState) {
      this.state['provider_state'] = providerState
    }
    return this
  }

  /**
   * A free style description of the interaction.
   * @param {string} description - A description of the interaction.
   * @returns {Interaction}
   */
  uponReceiving (description) {
    if (isNil(description)) {
      throw new Error('You must provide a description for the interaction.')
    }
    this.state['description'] = description
    return this
  }

  /**
   * The request that represents this interaction triggered by the consumer.
   * @param {string} method - The HTTP method
   * @param {string} path - The path of the URL
   * @param {string} queryString
   * @param {string} headers
   * @param {string} body
   * @returns {Interaction}
   */
  withRequest (method, path, ...other) {
    if (isNil(method)) {
      throw new Error('You must provide a HTTP method.')
    }

    if (VALID_METHODS.indexOf(method.toUpperCase()) < 0) {
      throw new Error('You must provide a valid HTTP method.')
    }

    if (isNil(path)) {
      throw new Error('You must provide a path.')
    }

    this.state['request'] = omitBy({
      method: method.toUpperCase(),
      path: path,
      query: other[0] || undefined,
      headers: other[1] || undefined,
      body: other[2] || undefined
    }, isNil)
    return this
  }

  /**
  * The response expected by the consumer.
  * @param {string} status - The HTTP status
  * @param {string} headers
  * @param {string} body
   */
  willRespondWith (status, ...other) {
    if (isNil(status) || status.toString().trim().length === 0) {
      throw new Error('You must provide a status code.')
    }

    this.state['response'] = omitBy({
      status: status,
      headers: other[0] || undefined,
      body: other[1] || undefined
    }, isNil)
  }

  /**
   * Returns the interaction object created.
   * @returns {Object}
   */
  json () {
    return this.state
  }
}