Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace dependency got with axios #620

Merged
merged 6 commits into from Aug 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 1 addition & 4 deletions package.json
Expand Up @@ -44,20 +44,18 @@
},
"dependencies": {
"@types/form-data": "^2.2.1",
"@types/got": "^7.1.7",
"@types/is-stream": "^1.1.0",
"@types/loglevel": "^1.5.3",
"@types/node": ">=6.0.0",
"@types/p-cancelable": "^0.3.0",
"@types/p-queue": "^2.3.1",
"@types/p-retry": "^1.0.1",
"@types/retry": "^0.10.2",
"@types/url-join": "^0.8.2",
"@types/ws": "^5.1.1",
"axios": "^0.18.0",
"eventemitter3": "^3.0.0",
"finity": "^0.5.4",
"form-data": "^2.3.1",
"got": "^8.0.3",
"is-stream": "^1.1.0",
"loglevel": "^1.6.1",
"object.entries": "^1.0.4",
Expand All @@ -67,7 +65,6 @@
"p-queue": "^2.3.0",
"p-retry": "^2.0.0",
"retry": "^0.12.0",
"url-join": "^4.0.0",
"ws": "^5.2.0"
},
"devDependencies": {
Expand Down
13 changes: 13 additions & 0 deletions src/IncomingWebhook.spec.js
@@ -1,5 +1,6 @@
require('mocha');
const { IncomingWebhook } = require('./IncomingWebhook');
const { ErrorCode } = require('./errors');
const { assert } = require('chai');
const isPromise = require('p-is-promise');
const nock = require('nock');
Expand Down Expand Up @@ -70,6 +71,18 @@ describe('IncomingWebhook', function () {
done();
});
});

it('should fail with IncomingWebhookRequestError when the API request fails', function (done) {
// One known request error is when the node encounters an ECONNREFUSED. In order to simulate this, rather than
// using nock, we send the request to a host:port that is not listening.
const webhook = new IncomingWebhook('https://localhost:8999/api/');
webhook.send('Hello', (error) => {
assert.instanceOf(error, Error);
assert.equal(error.code, ErrorCode.IncomingWebhookRequestError);
assert.instanceOf(error.original, Error);
done();
});
});
});

describe('lifecycle', function () {
Expand Down
47 changes: 14 additions & 33 deletions src/IncomingWebhook.ts
@@ -1,4 +1,4 @@
import got = require('got'); // tslint:disable-line:no-require-imports
import axios, { AxiosResponse, AxiosError } from 'axios';
import { CodedError, errorWithCode, ErrorCode } from './errors';
import { MessageAttachment } from './methods';
import { callbackify } from './util';
Expand Down Expand Up @@ -44,24 +44,18 @@ export class IncomingWebhook {
payload = Object.assign(payload, message);
}

const implementation = () => got.post(this.url, {
body: JSON.stringify(payload),
retries: 0,
})
.catch((error: got.GotError) => {
const implementation = () => axios.post(this.url, payload)
.catch((error: AxiosError) => {
// Wrap errors in this packages own error types (abstract the implementation details' types)
switch (error.name) {
case 'RequestError':
throw requestErrorWithOriginal(error);
case 'ReadError':
throw readErrorWithOriginal(error);
case 'HTTPError':
throw httpErrorWithOriginal(error);
default:
throw error;
if (error.response !== undefined) {
throw httpErrorWithOriginal(error);
} else if (error.request !== undefined) {
throw requestErrorWithOriginal(error);
} else {
throw error;
}
})
.then((response: got.Response<string>) => {
.then((response: AxiosResponse) => {
return this.buildResult(response);
});

Expand All @@ -75,9 +69,9 @@ export class IncomingWebhook {
/**
* Processes an HTTP response into an IncomingWebhookResult.
*/
private buildResult(response: got.Response<string>): IncomingWebhookResult {
private buildResult(response: AxiosResponse): IncomingWebhookResult {
return {
text: response.body,
text: response.data,
};
}
}
Expand Down Expand Up @@ -117,6 +111,7 @@ export interface IncomingWebhookRequestError extends CodedError {
original: Error;
}

// NOTE: this is no longer used, but might once again be used if a more specific means to detect it becomes evident
export interface IncomingWebhookReadError extends CodedError {
code: ErrorCode.IncomingWebhookReadError;
original: Error;
Expand All @@ -137,27 +132,13 @@ export interface IncomingWebhookHTTPError extends CodedError {
*/
function requestErrorWithOriginal(original: Error): IncomingWebhookRequestError {
const error = errorWithCode(
// `any` cast is used because the got definition file doesn't export the got.RequestError type
new Error(`A request error occurred: ${(original as any).code}`),
new Error(`A request error occurred: ${original.message}`),
ErrorCode.IncomingWebhookRequestError,
) as Partial<IncomingWebhookRequestError>;
error.original = original;
return (error as IncomingWebhookRequestError);
}

/**
* A factory to create IncomingWebhookReadError objects
* @param original The original error
*/
function readErrorWithOriginal(original: Error): IncomingWebhookReadError {
const error = errorWithCode(
new Error('A response read error occurred'),
ErrorCode.IncomingWebhookReadError,
) as Partial<IncomingWebhookReadError>;
error.original = original;
return (error as IncomingWebhookReadError);
}

/**
* A factory to create IncomingWebhookHTTPError objects
* @param original The original error
Expand Down
29 changes: 29 additions & 0 deletions src/WebClient.spec.js
Expand Up @@ -531,6 +531,35 @@ describe('WebClient', function () {
throw error;
});
});

it('should use the right custom agent when providing agents for many schemes', function () {
const agent = new Agent({ keepAlive: true });
const spy = sinon.spy(agent, 'addRequest');
const badAgent = { addRequest: sinon.stub().throws() };
const client = new WebClient(token, { agent: {
https: agent,
http: badAgent,
} });
return client.apiCall('method')
.catch(() => {
assert(spy.called);
})
.then(() => {
agent.addRequest.restore();
agent.destroy();
})
.catch((error) => {
agent.addRequest.restore();
agent.destroy();
throw error;
});
});

it('should use accept a boolean agent', function () {
// we don't have any hooks into an agent that node will initialize, so we just make sure that this doesn't throw
new WebClient(token, { agent: false });
return Promise.resolve();
});
});

describe('has an option to set request concurrency', function () {
Expand Down