diff --git a/test/e2e.spec.ts b/test/e2e.spec.ts
new file mode 100644
index 00000000..6cfe94d7
--- /dev/null
+++ b/test/e2e.spec.ts
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2019 StApps
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+import {
+ SCBulkAddResponse,
+ SCBulkAddRoute,
+ SCBulkDoneResponse,
+ SCBulkDoneRoute,
+ SCBulkResponse,
+ SCBulkRoute,
+ SCThing,
+} from '@openstapps/core';
+import * as chai from 'chai';
+import * as chaiAsPromised from 'chai-as-promised';
+import * as chaiSpies from 'chai-spies';
+import {suite, test} from 'mocha-typescript';
+import {getItemsFromSamples, indexSamples} from '../src/e2e';
+import {ApiError} from '../src/errors';
+import {HttpClient, RequestOptions, Response} from '../src/httpClient';
+import {RecursivePartial} from './client.spec';
+
+chai.should();
+chai.use(chaiSpies);
+chai.use(chaiAsPromised);
+
+const sandbox = chai.spy.sandbox();
+
+const bulkRoute = new SCBulkRoute();
+const bulkAddRoute = new SCBulkAddRoute();
+const bulkDoneRoute = new SCBulkDoneRoute();
+
+const httpClient = new HttpClient();
+
+@suite
+export class E2EConnectorSpec {
+ async after() {
+ sandbox.restore();
+ }
+
+ @test
+ getCoreTestSamples() {
+ return getItemsFromSamples('./node_modules/@openstapps/core/test/resources')
+ .then((items: T[]) => {
+ // tslint:disable-next-line: no-unused-expression
+ chai.expect(items).to.not.be.a.instanceof(Error);
+ // tslint:disable-next-line: no-unused-expression
+ chai.expect(items).to.not.be.empty;
+ });
+ }
+
+ @test
+ getCoreTestSamplesShouldFail() {
+ return getItemsFromSamples('./nonexistantdirectory')
+ .then((items: T[]) => {
+ // tslint:disable-next-line: no-unused-expression
+ chai.expect(items).to.be.a.instanceof(Error);
+ });
+ }
+
+ @test
+ async index() {
+ type responses = Response;
+
+ sandbox.on(httpClient, 'request', async (request: RequestOptions): Promise> => {
+ if (request.url.toString() === 'http://localhost' + bulkRoute.getUrlFragment().toString()) {
+ return {
+ body: {
+ state: 'in progress',
+ uid: 'foo',
+ },
+ statusCode: bulkRoute.statusCodeSuccess,
+ };
+ } else if (request.url.toString() === 'http://localhost' + bulkAddRoute.getUrlFragment({
+ UID: 'foo',
+ }).toString()) {
+ return {
+ body: {},
+ statusCode: bulkAddRoute.statusCodeSuccess,
+ };
+ }
+
+ return {
+ body: {},
+ statusCode: bulkDoneRoute.statusCodeSuccess,
+ };
+ });
+ await indexSamples(httpClient, {to: 'http://localhost', samples: './node_modules/@openstapps/core/test/resources'});
+ }
+
+ @test
+ async indexShouldFail() {
+ type responses = Response;
+
+ sandbox.on(httpClient, 'request', async (): Promise> => {
+ return {
+ body: {},
+ statusCode: Number.MAX_SAFE_INTEGER,
+ };
+ });
+ return indexSamples(httpClient, {to: 'http://localhost', samples: './node_modules/@openstapps/core/test/resources'})
+ .should.be.rejectedWith(ApiError);
+ }
+}