Occasional Http requests timeout on AWS Lambda - amazon-web-services

I've got an AWS lambda (as node.js) that is triggered by cron every 3 minutes. it purpose is to monitor some of our API's services, so it is sends http requests. Issue is, in 20% of the cases the http request times out. when I run it locally, or manually (by using the Test feature on AWS console) everything works ok. I tried to increase the timeout option but with no success.
Error Im getting is:
timeout of 5000ms exceeded at createError (/var/task/node_modules/axios/lib/core/createError.js
Error Details:
2021-08-30T09:06:08.029Z 841332b5-d8c1-49dc-8caa-f57215ed5440 ERROR PortalApiSql_Error Error: timeout of 5000ms exceeded
at createError (/var/task/node_modules/axios/lib/core/createError.js:16:15)
at RedirectableRequest.handleRequestTimeout (/var/task/node_modules/axios/lib/adapters/http.js:280:16)
at RedirectableRequest.emit (events.js:400:28)
at Timeout._onTimeout (/var/task/node_modules/follow-redirects/index.js:166:12)
at listOnTimeout (internal/timers.js:557:17)
at processTimers (internal/timers.js:500:7) {
config: {
url: '/health/sql',
method: 'get',
headers: {
Accept: 'application/json, text/plain, /',
ApiToken: '---',
'User-Agent': 'axios/0.21.1'
},
baseURL: 'https://apidev.myportal.com/v1',
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 5000,
adapter: [Function: httpAdapter],
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
validateStatus: [Function: validateStatus],
data: undefined
},
code: 'ECONNABORTED',
request: <ref 1> Writable {
_writableState: WritableState {
objectMode: false,
highWaterMark: 16384,
finalCalled: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
destroyed: false,
decodeStrings: true,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: true,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
afterWriteTickInfo: null,
buffered: [],
bufferedIndex: 0,
allBuffers: true,
allNoop: true,
pendingcb: 0,
prefinished: false,
errorEmitted: false,
emitClose: true,
autoDestroy: true,
errored: null,
closed: false
},
_events: [Object: null prototype] {
response: [Array],
error: [Array],
socket: [Function: destroyOnTimeout]
},
_eventsCount: 3,
_maxListeners: undefined,
_options: {
maxRedirects: 21,
maxBodyLength: 10485760,
protocol: 'https:',
path: '/v1/health/sql',
method: 'GET',
headers: [Object],
agent: undefined,
agents: [Object],
auth: undefined,
hostname: 'apidev.myportal.com',
port: null,
nativeProtocols: [Object],
pathname: '/v1/health/sql'
},
_ended: true,
_ending: true,
_redirectCount: 0,
_redirects: [],
_requestBodyLength: 0,
_requestBodyBuffers: [],
_onNativeResponse: [Function (anonymous)],
_currentRequest: ClientRequest {
_events: [Object: null prototype],
_eventsCount: 2,
_maxListeners: undefined,
outputData: [],
outputSize: 0,
writable: true,
destroyed: true,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: false,
_defaultKeepAlive: true,
useChunkedEncodingByDefault: false,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: 0,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
socket: [TLSSocket],
_header: 'GET /v1/health/sql HTTP/1.1\r\n' +
'Accept: application/json, text/plain, /\r\n' +
'ApiToken: ----\r\n' +
'User-Agent: axios/0.21.1\r\n' +
'Host: apidev.myportal.com\r\n' +
'Connection: close\r\n' +
'\r\n',
_keepAliveTimeout: 0,
_onPendingData: [Function: noopPendingOutput],
agent: [Agent],
socketPath: undefined,
method: 'GET',
maxHeaderSize: undefined,
insecureHTTPParser: undefined,
path: '/v1/health/sql',
_ended: false,
res: null,
aborted: true,
timeoutCb: null,
upgradeOrConnect: false,
parser: [HTTPParser],
maxHeadersCount: null,
reusedSocket: false,
host: 'apidev.myportal.com',
protocol: 'https:',
_redirectable: [Circular *1],
[Symbol(kCapture)]: false,
[Symbol(kNeedDrain)]: false,
[Symbol(corked)]: 0,
[Symbol(kOutHeaders)]: [Object: null prototype]
},
_currentUrl: 'https://apidev.myportal.com/v1/health/sql',
_timeout: Timeout {
_idleTimeout: 5000,
_idlePrev: null,
_idleNext: null,
_idleStart: 149306,
_onTimeout: [Function (anonymous)],
_timerArgs: undefined,
_repeat: null,
_destroyed: true,
[Symbol(refed)]: true,
[Symbol(kHasPrimitive)]: false,
[Symbol(asyncId)]: 63,
[Symbol(triggerId)]: 59
},
[Symbol(kCapture)]: false
},
response: undefined,
isAxiosError: true,
toJSON: [Function: toJSON]
}
I've simplified the code (simplified code also gets the timeout error),
exports.handler = async (event, context) => {
const axiosInstance = axios.create({
baseURL: PortalApiUrl,
timeout: AxiosTimeout,
headers: { ApiToken: PortalApiToken },
});
try {
console.log("before req ");
console.log(WATCHERS_CONFIGURATION.PortalApiSql.Path);
const response = await axiosInstance.get(WATCHERS_CONFIGURATION.PortalApiSql.Path);
console.log(`recieved ${response}`);
return {
statusCode: 200,
};
} catch (error) {
console.error("Error: ", error);
return {
statusCode: 500,
};
}
};

Related

Angular map flower (celery+django) return to list of tasks

I want to map the return of the flower libary (/api/tasks) to a list of objects. Currently it returns multiple objects, but without the "list wrapper", so it's not possible to iterate that.
API: https://flower.readthedocs.io/en/latest/api.html#get--api-tasks
Return is for example:
HTTP/1.1 200 OK
Content-Length: 1109
Content-Type: application/json; charset=UTF-8
Etag: "b2478118015c8b825f7b88ce6b660e5449746c37"
Server: TornadoServer/3.1.1
{
"e42ceb2d-8730-47b5-8b4d-8e0d2a1ef7c9": {
"args": "[3, 4]",
"client": null,
"clock": 1079,
"eta": null,
"exception": null,
"exchange": null,
"expires": null,
"failed": null,
"kwargs": "{}",
"name": "tasks.add",
"received": 1398505411.107885,
"result": "'7'",
"retried": null,
"retries": 0,
"revoked": null,
"routing_key": null,
"runtime": 0.01610181899741292,
"sent": null,
"started": 1398505411.108985,
"state": "SUCCESS",
"succeeded": 1398505411.124802,
"timestamp": 1398505411.124802,
"traceback": null,
"uuid": "e42ceb2d-8730-47b5-8b4d-8e0d2a1ef7c9",
"worker": "celery#worker1"
},
"f67ea225-ae9e-42a8-90b0-5de0b24507e0": {
"args": "[1, 2]",
"client": null,
"clock": 1042,
"eta": null,
"exception": null,
"exchange": null,
"expires": null,
"failed": null,
"kwargs": "{}",
"name": "tasks.add",
"received": 1398505395.327208,
"result": "'3'",
"retried": null,
"retries": 0,
"revoked": null,
"routing_key": null,
"runtime": 0.012884548006695695,
"sent": null,
"started": 1398505395.3289,
"state": "SUCCESS",
"succeeded": 1398505395.341089,
"timestamp": 1398505395.341089,
"traceback": null,
"uuid": "f67ea225-ae9e-42a8-90b0-5de0b24507e0",
"worker": "celery#worker1"
}
}
Any ideas how to do that?
I've tried the following thing:
export interface Tasks {
tasks: TaskWrapper[]
}
export interface TaskWrapper {
[uuid: string]: Task
}
export interface Task {
uuid: string,
state: string,
received: string,
}
Added example of Dragan leads to the following problem:
loadAllTasksFromFlower(): Observable<Task[]> {
return this.http.get<Task[]>("localhost:5566/api/tasks")
.pipe(map(response => Object.entries(response)
.map(entry => ({ uuid: entry[0], state: entry[1].state, received: entry[1].received }))
}
TS2322: Type 'Observable<{ uuid: string; state: TaskState; received:
any; }[]>' is not assignable to type 'Observable<Task[]>'.   Type '{
uuid: string; state: TaskState; received: any; }[]' is not assignable
to type 'Task[]'.     Type '{ uuid: string; state: TaskState;
received: any; }' is missing the following properties from type
'Task': type, source, invoke, callback, and 3 more.
The way you organized the interfaces is good, you can put the items in the array in this way:
const tasks: Task[] = Object.entries(data).map(entry => ({
uuid: entry[0],
state: entry[1].state,
received: entry[1].received
}));

API Gateway - Return XML or JSON

I have a node API Gateway stack and a Node Lambda. I've been trying to get API gateway to return content-type: application/xml OR application/json depending on the request (returnType=xml or returnType=json).
I have tried adding response models and that didn't work. BinaryTypes didn't work either. I have gotten it to do either application/json OR application/xml but I can't get it to do both. Is what I'm trying to do even possible? or should I create two separate endpoints?
This example always returns application/json.
Here is my lambda:
exports.handler = async function (event, context, callback) {
var format = event.format;
if (!format) {
callback(Error("[BadRequest] missing parameters"));
}
const promise = new Promise(function (resolve, reject) {
https
.get("exampleendpoint.com", (res) => {
let body = "";
res.on("data", (chunk) => {
body += chunk;
});
res.on("end", () => {
var results = JSON.parse(body);
if (format && format.toUpperCase() === "XML") {
var response = {
statusCode: 200,
headers: { "content-type": "application/xml" },
body:
'<?xml version="1.0" encoding="UTF-8"?><result>' +
OBJtoXML(results) +
"</result>",
};
resolve(response);
} else {
var response = {
statusCode: 200,
headers: { "content-type": "application/json" },
body: JSON.stringify(results),
};
resolve(response);
}
});
})
.on("error", (e) => {
var response = {
statusCode: 500,
body: "",
errorMessage: "Error from example.com",
};
resolve(response);
});
});
return promise;
};
Here is my api gateway code:
const epqApi = new gateway.RestApi(this, "restApi", {
restApiName: "resultsApi",
cloudWatchRole: true,
description: "Calls the service for the app",
endpointTypes: [gateway.EndpointType.REGIONAL],
deployOptions: {
stageName: "prod",
loggingLevel: gateway.MethodLoggingLevel.OFF,
dataTraceEnabled: false,
},
});
const epqResource = epqApi.root.addResource("v1");
const epqIntegration: gateway.LambdaIntegration =
new gateway.LambdaIntegration(generatePqsResultFunction, {
proxy: false,
allowTestInvoke: true,
passthroughBehavior: gateway.PassthroughBehavior.NEVER,
contentHandling: gateway.ContentHandling.CONVERT_TO_TEXT,
requestTemplates: {
"application/json": `{
"format":"$input.params(\'format\')"
}`,
},
integrationResponses: [
{
statusCode: "200",
responseParameters: {
"method.response.header.Access-Control-Allow-Origin": "'*'",
},
responseTemplates: {
"application/json": "$input.path('$.body')",
"application/xml": "$input.path('$.body')",
},
},
{
statusCode: "400",
selectionPattern: "^\\[BadRequest\\].*",
responseParameters: {
"method.response.header.Access-Control-Allow-Origin": "'*'",
},
responseTemplates: {
"application/javascript":
"#set($inputRoot = $input.path('$')) {\"errorMessage\" : \"$input.path('$.errorMessage')\"}",
},
},
],
});
epqResource.addMethod("GET", epqIntegration, {
requestParameters: {
//all params need to be in here, even if they are not required
"method.request.querystring.x": false,
"method.request.querystring.y": false,
"method.request.querystring.units": false,
"method.request.querystring.format": false,
"method.request.querystring.wkid": false,
"method.request.querystring.includeDate": false,
},
methodResponses: [
// Successful response from the integration
{
statusCode: "200",
responseParameters: {
"method.response.header.Access-Control-Allow-Origin": true,
},
},
{
statusCode: "400",
responseParameters: {
"method.response.header.Access-Control-Allow-Origin": true,
},
},
],
});
}

How to select aws lambda function names using node SDK?

At the CLi I can do
aws lambda list-functions
and get all the functions detail
Also I can do
aws lambda list-functions --query 'Functions[*].[FunctionName]' --output text
and get a simple list of just the function names.
How can I do that in a lambda using the SDK?
I tried
exports.handler = function (event) {
const AWS = require('aws-sdk');
const lambda = new AWS.Lambda({ apiVersion: '2015-03-31' });
var lambs = lambda.listFunctions();
console.log(lambs);
};
and I have aws lambda full access role
But i get the output below
e,
s3DisableBodySigning: true,
computeChecksums: true,
convertResponseTypes: true,
correctClockSkew: false,
customUserAgent: null,
dynamoDbCrc32: true,
systemClockOffset: 0,
signatureVersion: 'v4',
signatureCache: true,
retryDelayOptions: {},
useAccelerateEndpoint: false,
clientSideMonitoring: false,
endpointDiscoveryEnabled: false,
endpointCacheSize: 1000,
hostPrefixEnabled: true,
stsRegionalEndpoints: null
},
isGlobalEndpoint: false,
endpoint: Endpoint {
protocol: 'https:',
host: 'lambda.us-east-2.amazonaws.com',
port: 443,
hostname: 'lambda.us-east-2.amazonaws.com',
pathname: '/',
path: '/',
href: 'https://lambda.us-east-2.amazonaws.com/'
},
_events: { apiCallAttempt: [Array], apiCall: [Array] },
MONITOR_EVENTS_BUBBLE: [Function: EVENTS_BUBBLE],
CALL_EVENTS_BUBBLE: [Function: CALL_EVENTS_BUBBLE],
_clientId: 2
},
operation: 'listFunctions',
params: {},
httpRequest: HttpRequest {
method: 'POST',
path: '/',
headers: {
'User-Agent': 'aws-sdk-nodejs/2.536.0 linux/v12.13.0 exec-env/AWS_Lambda_nodejs12.x'
},
body: '',
endpoint: Endpoint {
protocol: 'https:',
host: 'lambda.us-east-2.amazonaws.com',
port: 443,
hostname: 'lambda.us-east-2.amazonaws.com',
pathname: '/',
path: '/',
href: 'https://lambda.us-east-2.amazonaws.com/',
constructor: [Function]
},
region: 'us-east-2',
_userAgent: 'aws-sdk-nodejs/2.536.0 linux/v12.13.0 exec-env/AWS_Lambda_nodejs12.x'
},
startTime: 2019-12-04T20:30:18.812Z,
response: Response {
request: [Circular],
data: null,
error: null,
retryCount: 0,
redirectCount: 0,
httpResponse: HttpResponse {
statusCode: undefined,
headers: {},
body: undefined,
streaming: false,
stream: null
},
maxRetries: 3,
maxRedirects: 10
},
_asm: AcceptorStateMachine {
currentState: 'validate',
states: {
validate: [Object],
build: [Object],
afterBuild: [Object],
sign: [Object],
retry: [Object],
afterRetry: [Object],
send: [Object],
validateResponse: [Object],
extractError: [Object],
extractData: [Object],
restart: [Object],
success: [Object],
error: [Object],
complete: [Object]
}
},
_haltHandlersOnError: false,
_events: {
validate: [
[Function],
[Function],
[Function: VALIDATE_REGION],
[Function: BUILD_IDEMPOTENCY_TOKENS],
[Function: VALIDATE_PARAMETERS]
],
afterBuild: [
[Function],
[Function: SET_CONTENT_LENGTH],
[Function: SET_HTTP_HOST]
],
restart: [ [Function: RESTART] ],
sign: [ [Function], [Function], [Function] ],
validateResponse: [ [Function: VALIDATE_RESPONSE], [Function] ],
send: [ [Function] ],
httpHeaders: [ [Function: HTTP_HEADERS] ],
httpData: [ [Function: HTTP_DATA] ],
httpDone: [ [Function: HTTP_DONE] ],
retry: [
[Function: FINALIZE_ERROR],
[Function: INVALIDATE_CREDENTIALS],
[Function: EXPIRED_SIGNATURE],
[Function: CLOCK_SKEWED],
[Function: REDIRECT],
[Function: RETRY_CHECK],
[Function: API_CALL_ATTEMPT_RETRY]
],
afterRetry: [ [Function] ],
build: [ [Function: buildRequest] ],
extractData: [ [Function: extractData], [Function: extractRequestId] ],
extractError: [ [Function: extractError], [Function: extractRequestId] ],
httpError: [ [Function: ENOTFOUND_ERROR] ],
success: [ [Function: API_CALL_ATTEMPT] ],
complete: [ [Function: API_CALL] ]
},
emit: [Function: emit],
API_CALL_ATTEMPT: [Function: API_CALL_ATTEMPT],
API_CALL_ATTEMPT_RETRY: [Function: API_CALL_ATTEMPT_RETRY],
API_CALL: [Function: API_CALL]
}END RequestId: dc9caa5c-42b1-47e9-8136-80c3fbdddbc5
REPORT RequestId: dc9caa5c-42b1-47e9-8136-80c3fbdddbc5 Duration: 45.81 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 86 MB
AWS SDK calls return an AWS.Request object, not the response to the actual API call, which typically arrives asynchronously.
You need to add a callback handler like so:
lambda.listFunctions((err, data) => {
if (err) {
console.err(err);
} else {
data.Functions.forEach(func => console.log(func.FunctionName));
}
});
Or simply use async/await, like so (note that the enclosing function must be async):
const AWS = require('aws-sdk');
const lambda = new AWS.Lambda();
exports.handler = async (event) => {
const funcs = await lambda.listFunctions().promise();
funcs.Functions.forEach(func => console.log(func.FunctionName));
}
The data/funcs returned to you will be a JavaScript object including an array of functions. See the SDK reference for specifics.
Ideally, use the async/await form. It's simpler, less prone to error, and more modern.

angular2 unit testing with dependent services

I'm new to angular2 and trying to write tests for services. I have a userservice in my application which is a dependent service on multiple other services and params. The user service is making an rest-api call in the backend to pull user information.
I'm having a hard time to understand what is the correct way to inject the dependent services to this user service, so it can make a http call and get response.
user-service.ts
export class UserService extends HttpService {
private _authToken: string;
private _persistent: boolean;
constructor(http: Http, private sessionService: SessionService, private router: Router) {
super(http);
this._authToken = localStorage.getItem(AUTH_TOKEN_KEY);
}
get authToken(): string {
return this._authToken;
}
session-service.ts
export class SessionService extends HttpService {
constructor(http: Http) {
super(http);
this.rootUrl = Constants.API_ROOT;
}
addSession(authToken: string, persistent:boolean=false): Observable<any> {
return this.post(SESSIONS_ROOT, {persistent: persistent}, TokenService.AuthHeader(authToken));
}
user-service.spec.ts
describe(' ####### User Service Test Cases ####### ', () => beforeEach(() => {
TestBed.configureTestingModule({
providers: [
// {
// provide: Router,
// useClass: class { navigate = jasmine.createSpy("navigate")},
// },
BaseRequestOptions,
MockBackend,
{
provide: Http,
useFactory: (backend: MockBackend, defaultOptions: BaseRequestOptions) => {
return new Http(backend, defaultOptions);
},
deps: [MockBackend, BaseRequestOptions],
},
SessionService,
UserService
],
imports: [RouterTestingModule]
}); }); it('test method', inject([UserService], (userService: UserService) => {
expect(userService.isEmailAvailable('a#a.com')).toBe('true');
}));
});
But, I'm getting error when executing.
####### User Service Test Cases #######
×should return response when email is already subsribed
Expected AnonymousSubject({ _isScalar: false, observers: [ ], closed: false, isStopped: false, hasError: false, thrownError: null, destination: AnonymousSubject({ _isScalar: false, observers: [ ], closed: false, isStopped: false, hasError: false, thrownError: null, destination: AnonymousSubject({ _isScalar: false, observers: [ ], closed: false, isStopped: false, hasError: false, thrownError: null, destination: ReplaySubject({ _isScalar: false, observers: [ ], closed: false, isStopped: false, hasError: false, thrownError: null, scheduler: undefined, _events: [ ], _bufferSize: 1, _windowTime: Infinity }), source: ReplaySubject({ _isScalar: false, observers: [ ], closed: false, isStopped: false, hasError: false, thrownError: null, scheduler: undefined, _events: [ ], _bufferSize: 1, _windowTime: Infinity }), operator: TakeOperator({ total: 1 }) }), source: AnonymousSubject({ _isScalar: false, observers: [ ], closed: false, isStopped: false, hasError: false, thrownError: null, destination: ReplaySubject({ _isScalar: false, observers: [ ], closed: false, isStopped: false, hasError: false, thrownError: null, scheduler: undefined, _events: [ ], _bufferSize: 1, _windowTime: Infinity }), source: ReplaySubject({ _isScalar: false, observers: [ ], closed: false, isStopped: false, hasError: false, thrownError: null, scheduler: undefined, _events: [ ], _bufferSize: 1, _windowTime: Infinity }), operator: TakeOperator({ total: 1 }) }), operator: MapOperator({ project: Function, thisArg: undefined }) }), source: AnonymousSubject({ _isScalar: false, observers: [ ], closed: false, isStopped: false, hasError: false, thrownError: null, destination: AnonymousSubject({ _isScalar: false, observers: [ ], closed: false, isStopped: false, hasError: false, thrownError: null, destination: ReplaySubject({ _isScalar: false, observers: [ ], closed: false, isStopped: false, hasError: false, thrownError: null, scheduler: undefined, _events: [ ], _bufferSize: 1, _windowTime: Infinity }), source: ReplaySubject({ _isScalar: false, observers: [ ], closed: false, isStopped: false, hasError: false, thrownError: null, scheduler: undefined, _events: [ ], _bufferSize: 1, _windowTime: Infinity }), operator: TakeOperator({ total: 1 }) }), source: AnonymousSubject({ _isScalar: false, observers: [ ], closed: false, isStopped: false, hasError: false, thrownError: null, destination: ReplaySubject({ _isScalar: false, observers: [ ], closed: false, isStopped: false, hasError: false, thrownError: null, scheduler: undefined, _events: [ ], _bufferSize: 1, _windowTime: Infinity }), source: ReplaySubject({ _isScalar: false, observers: [ ], closed: false, isStopped: false, hasError: false, thrownError: null, scheduler: undefined, _events: [ ], _bufferSize: 1, _windowTime: Infinity }), operator: TakeOperator({ total: 1 }) }), operator: MapOperator({ project: Function, thisArg: undefined }) }), operator: CatchOperator({ selector: Function, caught: }) }) to be 'true'.
at webpack:///src/app/test/user.spec.ts:75:69 <- config/karma-test-shim.js:87887:71 [ProxyZone]
I'm not sure what to understand from the error. Any help on how to proceed or inject dependent services correctly and create there instances will be help.
Thank you so much. Appreciate the help.

Redux Promise Middleware + Redux Mock Store Testing

I tried to test an action creator that returns a promise, using also redux mock store.
import promiseMiddleware from 'redux-promise-middleware';
import nock from 'nock';
import configureStore from 'redux-mock-store';
import { domain, port } from '../../config/environment';
import { GET_ITEMS_START,
GET_ITEMS_SUCCESS } from '../../constants/items';
import { getItems } from './items';
const promise = promiseMiddleware({
promiseTypeSuffixes: ['START', 'SUCCESS', 'ERROR']
});
describe('Get Items', () => {
it('should create GET_ITEMS_SUCCESS action after successfully getting items', (done) => {
nock(`${domain}:${port}`)
.get('/api/items')
.reply(200, {
_id: '1',
text: 'Make Eggs',
completed: false
});
const expectedActions = [
{ type: GET_ITEMS_START },
{ type: GET_ITEMS_SUCCESS, payload: {
data: { _id: '1', text: 'Make Eggs', completed: false }
}}
];
const store = mockStore({}, expectedActions, done);
store.dispatch(getItems());
});
});
and here is my action creator code
export function getItems() {
return {
type: GET_ITEMS,
payload: {
promise: axios.get(`${domain}:${port}/api/items`)
}
};
}
but the result is mismatch because the promise resolved a deep nested objects
Error: Expected { payload: { config: { headers: {}, method: 'get', timeout: 0, transformRequest: [ [Function] ], transformResponse: [ [Function] ], url: 'http://localhost:3000/api/items', withCredentials: undefined }, data: { _id: '1', completed: false, text: 'Make Eggs' }, headers: {}, status: 200, statusText: 'OK' }, type: 'GET_ITEMS_SUCCESS' } to equal { payload: { data: { _id: '1', completed: false, text: 'Make Eggs' } }, type: 'GET_ITEMS_SUCCESS' }
+ expected - actual
{
"payload": {
- "config": {
- "headers": {}
- "method": "get"
- "timeout": 0
- "transformRequest": [
- [Function]
- ]
- "transformResponse": [
- [Function]
- ]
- "url": "http://localhost:3000/api/items"
- "withCredentials": [undefined]
- }
"data": {
"_id": "1"
"completed": false
"text": "Make Eggs"
}
- "headers": {}
- "status": 200
- "statusText": "OK"
}
"type": "GET_ITEMS_SUCCESS"
}
I obviously don't want to copy all of those deep nested properties into my test suite.
Is there a better way of doing this?
If you're writing a unit test, you probably don't need to call the actual REST API. Instead you can mock axios and make it return some fake data which won't be so deep.