diff --git a/types/moxios/index.d.ts b/types/moxios/index.d.ts
new file mode 100644
index 0000000000..aa3b82e9f1
--- /dev/null
+++ b/types/moxios/index.d.ts
@@ -0,0 +1,192 @@
+// Type definitions for moxios v0.4.0
+// Project: https://github.com/mzabriskie/moxios
+// Definitions by: Asuka Ito
+// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
+
+import {AxiosInstance} from "axios";
+
+interface Item {
+ response?: any;
+ responseText?: string;
+ status?: number;
+ statusText?: string;
+ headers?: any;
+}
+
+declare class Tracker {
+ constructor();
+
+ /**
+ * Reset all the items being tracked
+ */
+ reset(): void;
+
+ /**
+ * Add an item to be tracked
+ *
+ * @param {Object} item An item to be tracked
+ */
+ track(item: Item): void;
+
+ /**
+ * The count of items being tracked
+ *
+ * @return {number}
+ */
+ count(): number;
+
+ /**
+ * Get an item being tracked at a given index
+ *
+ * @param {number} index The index for the item to retrieve
+ * @return {Object}
+ */
+ at(index: number): Request;
+
+ /**
+ * Get the first item being tracked
+ *
+ * @return {Object}
+ */
+ first(): Request;
+
+ /**
+ * Get the most recent (last) item being tracked
+ *
+ * @return {Object}
+ */
+ mostRecent(): Request;
+
+ /**
+ * Dump the items being tracked to the console.
+ */
+ debug(): void;
+
+ /**
+ * Find and return element given the HTTP method and the URL.
+ */
+ get(method: string, url?: string): Request;
+
+ /**
+ * Stop an element from being tracked by removing it. Finds and returns the element,
+ * given the HTTP method and the URL.
+ */
+ remove(method: string, url: string): Request;
+}
+
+declare class Request {
+ /**
+ * Create a new Request object
+ *
+ * @param {Function} resolve The function to call when Promise is resolved
+ * @param {Function} reject The function to call when Promise is rejected
+ * @param {Object} config The config object to be used for the request
+ */
+ constructor(resolve: (arg: any) => void, reject: (arg: any) => void, config: any);
+
+ /**
+ * Respond to this request with a timeout result
+ *
+ * @return {Promise} A Promise that rejects with a timeout result
+ */
+ respondWithTimeout(): Promise;
+
+ /**
+ * Respond to this request with a specified result
+ *
+ * @param {Object} res The data representing the result of the request
+ * @return {Promise} A Promise that resolves once the response is ready
+ */
+ respondWith(res: Item): Promise;
+}
+
+declare class Response {
+ /**
+ * Create a new Response object
+ *
+ * @param {Request} req The Request that this Response is associated with
+ * @param {Object} res The data representing the result of the request
+ */
+ constructor(req: Request, res: any);
+
+ config: any;
+ data?: any;
+ status?: number;
+ statusText?: string;
+ headers: any;
+ request: Request;
+}
+
+declare let moxios: {
+ stubs: Tracker;
+ requests: Tracker;
+ delay: number;
+ timeoutException: Error;
+
+ /**
+ * Install the mock adapter for axios
+ */
+ install(instance?: AxiosInstance): void;
+
+ /**
+ * Uninstall the mock adapter and reset state
+ */
+ uninstall(instance?: AxiosInstance): void;
+
+ /**
+ * Stub a response to be used to respond to a request matching a URL or RegExp
+ *
+ * @param {string|RegExp} urlOrRegExp A URL or RegExp to test against
+ * @param {Object} response The response to use when a match is made
+ */
+ stubRequest(urlOrRegExp: string | RegExp, response: Item): void;
+
+ /**
+ * Stub a response to be used one or more times to respond to a request matching a
+ * method and a URL or RegExp.
+ *
+ * @param {string} method An axios command
+ * @param {string|RegExp} urlOrRegExp A URL or RegExp to test against
+ * @param {Object} response The response to use when a match is made
+ */
+ stubOnce(method: string, urlOrRegExp: string | RegExp, response: Item): Promise;
+
+ /**
+ * Stub a timed response to a request matching a method and a URL or RegExp. If
+ * timer fires, reject with a TimeoutException for simple assertions. The goal is
+ * to show that a certain request was not made.
+ *
+ * @param {string} method An axios command
+ * @param {string|RegExp} urlOrRegExp A URL or RegExp to test against
+ * @param {Object} response The response to use when a match is made
+ */
+ stubFailure(method: string, urlOrRegExp: string | RegExp, response: Item): Promise;
+
+ /**
+ * Stub a timeout to be used to respond to a request matching a URL or RegExp
+ *
+ * @param {string|RegExp} urlOrRegExp A URL or RegExp to test against
+ */
+ stubTimeout(urlOrRegExp: string | RegExp): string;
+
+ /**
+ * Run a single test with mock adapter installed.
+ * This will install the mock adapter, execute the function provided,
+ * then uninstall the mock adapter once complete.
+ *
+ * @param {Function} fn The function to be executed
+ */
+ withMock(fn: () => void): void;
+
+ /**
+ * Wait for request to be made before proceding.
+ * This is naively using a `setTimeout`.
+ * May need to beef this up a bit in the future.
+ *
+ * @param {Function} fn The function to execute once waiting is over
+ * @param {number} delay How much time in milliseconds to wait
+ */
+ wait(fn: () => void, delay?: number): void;
+};
+
+export default moxios;
diff --git a/types/moxios/moxios-tests.ts b/types/moxios/moxios-tests.ts
new file mode 100644
index 0000000000..82ceb8535b
--- /dev/null
+++ b/types/moxios/moxios-tests.ts
@@ -0,0 +1,308 @@
+// from https://github.com/mzabriskie/moxios/blob/master/test.js
+import {equal, notEqual, deepEqual} from 'power-assert'; // compatible with 'assert';
+import axios from 'axios';
+import moxios from 'moxios';
+
+declare const sinon: any;
+declare const describe: any;
+declare function it(testName: string, test: (done: () => void) => void|Promise): void;
+declare const beforeEach: any;
+declare const afterEach: any;
+
+const USER_FRED = {
+ id: 12345,
+ firstName: 'Fred',
+ lastName: 'Flintstone'
+};
+
+describe('moxios', () => {
+ it('should install', () => {
+ let defaultAdapter = axios.defaults.adapter;
+ moxios.install();
+ notEqual(axios.defaults.adapter, defaultAdapter);
+ moxios.uninstall();
+ });
+
+ it('should uninstall', () => {
+ let defaultAdapter = axios.defaults.adapter;
+ moxios.install();
+ moxios.uninstall();
+ equal(axios.defaults.adapter, defaultAdapter);
+ });
+
+ describe('requests', () => {
+ let onFulfilled: any;
+ let onRejected: any;
+
+ beforeEach(() => {
+ moxios.install();
+ onFulfilled = sinon.spy();
+ onRejected = sinon.spy();
+ });
+
+ afterEach(() => {
+ moxios.uninstall();
+ });
+
+ it('should intercept requests', (done) => {
+ axios.get('/users/12345');
+
+ moxios.wait(() => {
+ let request = moxios.requests.mostRecent();
+ equal(moxios.requests.count(), 1);
+ done();
+ });
+ });
+
+ it('should mock responses', (done) => {
+ axios.get('/users/12345').then(onFulfilled);
+
+ moxios.wait(() => {
+ let request = moxios.requests.mostRecent();
+ request.respondWith({
+ status: 200,
+ response: USER_FRED
+ }).then(() => {
+ let response = onFulfilled.getCall(0).args[0];
+ equal(onFulfilled.called, true);
+ equal(response.status, 200);
+ deepEqual(response.data, USER_FRED);
+ done();
+ });
+ });
+ });
+
+ it('should mock responses Error', (done) => {
+ axios.get('/users/12346').then(onFulfilled, onRejected);
+
+ moxios.wait(() => {
+ let request = moxios.requests.mostRecent();
+ request.respondWith({
+ status: 404
+ }).then(() => {
+ equal(onFulfilled.called, false);
+ equal(onRejected.called, true);
+ done();
+ });
+ });
+ });
+
+ it('should mock one time', (done) => {
+ moxios.uninstall();
+
+ moxios.withMock(() => {
+ axios.get('/users/12345').then(onFulfilled);
+
+ moxios.wait(() => {
+ let request = moxios.requests.mostRecent();
+ request.respondWith({
+ status: 200,
+ response: USER_FRED
+ }).then(() => {
+ equal(onFulfilled.called, true);
+ done();
+ });
+ });
+ });
+ });
+
+ it('should timeout requests one time', (done) => {
+ moxios.uninstall();
+
+ moxios.withMock(() => {
+ axios.get('/users/12345');
+
+ moxios.wait(() => {
+ let request = moxios.requests.mostRecent();
+ request.respondWithTimeout().catch((err: any) => {
+ equal(err.code, 'ECONNABORTED');
+ done();
+ });
+ });
+ });
+ });
+
+ it('should stub requests', (done) => {
+ moxios.stubRequest('/users/12345', {
+ status: 200,
+ response: USER_FRED
+ });
+
+ axios.get('/users/12345').then(onFulfilled);
+
+ moxios.wait(() => {
+ let response = onFulfilled.getCall(0).args[0];
+ deepEqual(response.data, USER_FRED);
+ done();
+ });
+ });
+
+ it('should stub timeout', (done) => {
+ moxios.stubTimeout('/users/12345');
+
+ axios.get('/users/12345').catch(onRejected);
+
+ moxios.wait(() => {
+ let err = onRejected.getCall(0).args[0];
+ deepEqual(err.code, 'ECONNABORTED');
+ done();
+ });
+ });
+
+ it('should stub requests RegExp', (done) => {
+ moxios.stubRequest(/\/users\/\d*/, {
+ status: 200,
+ response: USER_FRED
+ });
+
+ axios.get('/users/12345').then(onFulfilled);
+
+ moxios.wait(() => {
+ let response = onFulfilled.getCall(0).args[0];
+ deepEqual(response.data, USER_FRED);
+ done();
+ });
+ });
+
+ describe('stubs', () => {
+ it('should track multiple stub requests', () => {
+ moxios.stubOnce('PUT', '/users/12345', {
+ status: 204
+ });
+
+ moxios.stubOnce('GET', '/users/12346', {
+ status: 200,
+ response: USER_FRED
+ });
+
+ equal(moxios.stubs.count(), 2);
+ });
+
+ it('should find single stub by method', () => {
+ moxios.stubOnce('PUT', '/users/12345', {
+ status: 204
+ });
+
+ moxios.stubOnce('GET', '/users/12346', {
+ status: 200,
+ response: USER_FRED
+ });
+
+ let request = moxios.stubs.get('PUT', '/users/12345');
+
+ notEqual(request, undefined);
+ });
+
+ it('should remove a single stub by method', () => {
+ moxios.stubOnce('PUT', '/users/12346', {
+ status: 204
+ });
+
+ moxios.stubOnce('GET', '/users/12346', {
+ status: 200,
+ response: USER_FRED
+ });
+
+ moxios.stubOnce('PUT', '/users/12345', {
+ status: 204
+ });
+
+ moxios.stubOnce('GET', '/users/12345', {
+ status: 200,
+ response: USER_FRED
+ });
+
+ moxios.stubs.remove('PUT', '/users/12345');
+ equal(moxios.stubs.count(), 3);
+ });
+
+ it('should not find stub with invalid method', () => {
+ moxios.stubOnce('PUT', '/users/12345', {
+ status: 204
+ });
+
+ moxios.stubOnce('GET', '/users/12346', {
+ status: 200,
+ response: USER_FRED
+ });
+
+ let request = moxios.stubs.get('GET', '/users/12345');
+
+ equal(request, undefined);
+ });
+
+ it('should not find request on invalid method', () => {
+ moxios.stubOnce('PUT', '/users/12345', {
+ status: 204
+ });
+
+ moxios.stubOnce('GET', '/users/12346', {
+ status: 200,
+ response: USER_FRED
+ });
+
+ axios.put('/users/12346', USER_FRED);
+ let request = moxios.requests.get('TEST');
+
+ equal(request, undefined);
+ });
+
+ it('should find request after multiple stubs using same URI', (done) => {
+ moxios.stubOnce('POST', '/users/12345', {
+ status: 204
+ });
+
+ moxios.stubOnce('PUT', '/users/12345', {
+ status: 204
+ });
+
+ moxios.stubOnce('GET', '/users/12345', {
+ status: 200,
+ response: USER_FRED
+ });
+
+ axios.put('/users/12345', USER_FRED).then(onFulfilled);
+
+ moxios.wait(() => {
+ let response = onFulfilled.getCall(0).args[0];
+ equal(response.status, 204);
+ let request = moxios.requests.get('PUT', '/users/12345');
+ notEqual(request, undefined);
+ done();
+ });
+ });
+
+ it('Should stub and find multiple requests by method', (done) => {
+ moxios.stubOnce('PUT', '/users/12345', {
+ status: 204
+ });
+
+ moxios.stubOnce('GET', '/users/12346', {
+ status: 200,
+ response: USER_FRED
+ });
+
+ axios.put('/users/12345', USER_FRED).then(onFulfilled);
+ axios.get('/users/12346', {}).then(onFulfilled);
+
+ moxios.wait(() => {
+ equal(onFulfilled.calledTwice, true);
+
+ let response1 = onFulfilled.getCall(0).args[0];
+ let response2 = onFulfilled.getCall(1).args[0];
+ equal(response1.status, 204);
+ equal(response2.status, 200);
+ equal(response2.data.firstName, 'Fred');
+
+ let request = moxios.requests.get('PUT', '/users/12345');
+ notEqual(request, undefined);
+
+ request = moxios.requests.get('GET', '/users/12346');
+ notEqual(request, undefined);
+
+ done();
+ });
+ });
+ });
+ });
+});
diff --git a/types/moxios/package.json b/types/moxios/package.json
new file mode 100644
index 0000000000..2886d8e5fc
--- /dev/null
+++ b/types/moxios/package.json
@@ -0,0 +1,5 @@
+{
+ "dependencies": {
+ "axios": "^0.16.1"
+ }
+}
diff --git a/types/moxios/tsconfig.json b/types/moxios/tsconfig.json
new file mode 100644
index 0000000000..ae7c3788f9
--- /dev/null
+++ b/types/moxios/tsconfig.json
@@ -0,0 +1,22 @@
+{
+ "compilerOptions": {
+ "module": "commonjs",
+ "lib": [
+ "es6"
+ ],
+ "noImplicitAny": true,
+ "noImplicitThis": true,
+ "strictNullChecks": true,
+ "baseUrl": "../",
+ "typeRoots": [
+ "../"
+ ],
+ "types": [],
+ "noEmit": true,
+ "forceConsistentCasingInFileNames": true
+ },
+ "files": [
+ "index.d.ts",
+ "moxios-tests.ts"
+ ]
+}
diff --git a/types/moxios/tslint.json b/types/moxios/tslint.json
new file mode 100644
index 0000000000..377cc837d4
--- /dev/null
+++ b/types/moxios/tslint.json
@@ -0,0 +1 @@
+{ "extends": "../tslint.json" }