201-created/ember-cli-fake-server

View on GitHub
addon/index.js

Summary

Maintainability
B
4 hrs
Test Coverage
import Pretender from 'pretender';
import { assert } from '@ember/debug';
import * as Responses from './lib/responses';
import * as Logging from './lib/logging';
import * as JSONUtils from './lib/json-utils';
import { warn } from './lib/logger';

let currentServer;

let _config = defaultConfig();

function defaultConfig() {
  return {
    preparePath: (path) => path,
    fixtureFactory: () => {
      warn('[FakeServer] `fixture` called but no fixture factory is registered');
    },
    afterResponse: (response) => response
  };
}

function bindResponses(request, responseRef){
  Object.keys(Responses.STATUS_CODES).forEach((key) => {
    request[key] = (...args) => {
      if (responseRef.response) {
        throw new Error(`[FakeServer] Stubbed Request responded with "${key}" after already responding`);
      }
      let response = Responses[key](...args);
      responseRef.response = response;
      return response;
    };
  });
  Object.keys(Responses.RESPONSE_ALIASES).forEach((key) => {
    let aliases = Responses.RESPONSE_ALIASES[key];
    aliases.forEach((alias) => request[alias] = request[key]);
  });
}

export function setupFakeServer(hooks, options = {}) {
  hooks.beforeEach(function() {
    FakeServer.start(options);
  });

  hooks.afterEach(function() {
    FakeServer.stop();
  });
}

export function passthroughRequest(verb, path) {
  path = _config.preparePath(path);
  assert('[FakeServer] cannot passthrough request if FakeServer is not running',
               !!currentServer);

  currentServer[verb.toLowerCase()](path, currentServer.passthrough);
}

export function stubRequest(verb, path, callback){
  path = _config.preparePath(path);
  assert('[FakeServer] cannot stub request if FakeServer is not running',
               !!currentServer);

  let boundCallback = (request) => {
    let responseRef = {};

    bindResponses(request, responseRef);

    request.json = () => JSONUtils.jsonFromRequest(request);
    request.fixture = _config.fixtureFactory;

    let context = {
      json: JSONUtils.jsonFromRequest,
      fixture: _config.fixtureFactory
    };
    Object.keys(Responses.STATUS_CODES).forEach(key => {
      context[key] = Responses[key];
    });
    Object.keys(Responses.RESPONSE_ALIASES).forEach(key => {
      let aliases = Responses.RESPONSE_ALIASES[key];
      aliases.forEach(alias => context[alias] = context[key]);
    });

    let returnValue = callback.call(context, request);
    returnValue = returnValue || responseRef.response;
    if (!returnValue) {
      throw new Error(
        `[FakeServer] No return value for stubbed request for ${verb} ${path}.
         Use \`request.ok(json)\` or similar`);
    }
    return _config.afterResponse(returnValue, request);
  };

  currentServer[verb.toLowerCase()](path, boundCallback);
}

const FakeServer = {
  configure: {
    fixtureFactory(fixtureFactory) {
      _config.fixtureFactory = fixtureFactory;
    },
    preparePath(fn) {
      _config.preparePath = fn;
    },
    afterResponse(fn) {
      _config.afterResponse = fn;
    }
  },


  start(options = {}) {
    assert('[FakeServer] Cannot start FakeServer while already started. ' +
                 'Ensure you call `FakeServer.stop()` first.',
                 !FakeServer.isRunning());

    let logging = typeof options.logging === 'undefined' ? true : options.logging;

    currentServer = this._currentServer = new Pretender();
    currentServer.prepareBody = JSONUtils.stringifyJSON;
    currentServer.unhandledRequest = Logging.unhandledRequest;

    if (logging) {
        currentServer.handledRequest = Logging.handledRequest;
    }
  },

  isRunning() {
    return !!currentServer;
  },

  stop() {
    if (!FakeServer.isRunning()) {
      warn('[FakeServer] called `stop` without having started.');
      return;
    }
    currentServer.shutdown();
    currentServer = this._currentServer = null;

    _config = defaultConfig();
  }
};

export default FakeServer;