Jest - Testing for AWS Lambda - javascript

I'm trying to use Jest with my NodeJS based AWS Lambda function to test that the Lambda handler function is returning specific status codes. It seems like using lambda-tester is the easiest way to achieve this.
handler.test.js
const handler = require('../src/handler.js');
const LambdaTester = require('lambda-tester');
test('should return a StatusCode of 400 due to requirement not being met', function (done) {
return LambdaTester(handler.run)
.event({})
.expectResult(result => {
expect(result.statusCode).toBe(400);
});
});
I thought that would be pretty straightforward however I get this as a result:
expect(received).toBe(expected) // Object.is equality
Expected: 400
Received: 500
7 | .event({})
8 | .expectResult(result => {
> 9 | expect(result.statusCode).toBe(400);
| ^
10 | });
11 | });
12 |
at tests/handler.test.js:9:33
at runVerifier (node_modules/lambda-tester/lib/runner.js:121:16)
at LambdaRunner.run (node_modules/lambda-tester/lib/runner.js:277:23)
If I change the expect line to check for a statuscode of 500 I get an Async timeout:
Timeout - Async callback was not invoked within the 5000 ms timeout
specified by jest.setTimeout.Timeout
Any ideas as to why this isn't working?
The lambda should fail instantly because the event being passed in doesnt have a required attribute and it indeed does when tested via Postman.
Edit:
This lambda is part of a serverless application and could be tested locally, how could I use Jest to do that?

I was over thinking it, the below is working well:
test('should return a StatusCode of 400 due to requirement not being met', async () => {
const event = {};
const context = {};
const result = await handler.run(event, context);
expect(result.statusCode).toBe(400)
expect(result.headers)
});

Related

Jest mock function is called but expect.toHaveBeenCalled() fails

I know that there are already questions about this but I can't find a definite answer. I am using SvelteKit and I tried to mock $app/navigation likes this in setup file.
jest.mock('$app/navigation', () => {
return {
__esModule: true,
goto: jest.fn().mockImplementation((target) => console.log(target))
};
});
I test a component that call goto. It is indeed called because there is a console.log call in the test output. When I tried to test it with expect(goto).toHaveBeenCalled(), it fails.
// SvelteKit
import * as navigations from '$app/navigation';
it('show error when account does not exists', async () => {
// render is in before Each
await fireEvent.change(screen.getByLabelText('Email'), {
target: { value: 'example#email.com' }
});
await fireEvent.change(screen.getByLabelText('Password'), {
target: { value: 'B#adPass0rd' }
});
await fireEvent.click(screen.getByRole('button'));
// There is no problem. It should redirect.
expect(navigations.goto).toHaveBeenCalled();
});
Output
console.log
/success
at log (jest-setup.js:6:58)
FAIL src/lib/routes-tests/login.test.js
Login
✕ show error when account does not exists (23 ms)
● Login › show error when account does not exists
expect(jest.fn()).toHaveBeenCalled()
Expected number of calls: >= 1
Received number of calls: 0
24 | await fireEvent.click(screen.getByRole('button'));
25 | // expect(screen.queryByText('Account does not exist')).not.toBeNull();
> 26 | expect(navigations.goto).toHaveBeenCalled();
| ^
27 | });
28 | });
29 |
at toHaveBeenCalled (src/lib/routes-tests/login.test.js:26:28)
at tryCatch (src/lib/routes-tests/login.test.js:23:2404)
at Generator._invoke (src/lib/routes-tests/login.test.js:23:1964)
at Generator.next (src/lib/routes-tests/login.test.js:23:3255)
at asyncGeneratorStep (src/lib/routes-tests/login.test.js:25:103)
at _next (src/lib/routes-tests/login.test.js:27:194)
It turns out that I called goto in async function. I must use waitFor to expect the change.
await waitFor(() => expect(navigations.goto).toHaveBeenCalled())

Why does Jest rise this error while testing `Colyseus` game?

I am testing a game functionality with Jest as a testing framework and assertion library.
This is my test setup:
const { Server } = require("colyseus")
const { ColyseusTestServer, boot } = require("#colyseus/testing");
const Game = require("./index");
describe("Game", () => {
let colyseus;
let TestServer = new Server()
TestServer.define("my_game", Game)
const User_1 = {
key: "token_header.token_payload.and_oh"
}
beforeAll(async () => colyseus = await boot(TestServer));
afterAll(async () => await colyseus.shutdown());
beforeEach(async () => await colyseus.cleanup());
test("Should connect", async () => {
try {
// `room` is the server-side Room instance reference.
const room = await colyseus.sdk.joinOrCreate("my_game", {...User_1});
await room.waitForNextPatch();
await room.waitForNextMessage();
// `client1` is the client-side `Room` instance reference (same as JavaScript SDK)
// make your assertions
expect(room.sessionId).toEqual(room.clients[0].sessionId);
} catch(err) {
console.log("errr",err)
}
})
})
So every time that I run my tests Jest logs these errors:
Game
✕ Should connect (8003 ms)
● Game › Should connect
TypeError: decode[type] is not a function
at decodePrimitiveType (node_modules/#colyseus/schema/src/Schema.ts:109:34)
at _.Object.<anonymous>.Schema.decode (node_modules/#colyseus/schema/src/Schema.ts:352:25)
at SchemaSerializer.Object.<anonymous>.SchemaSerializer.setState (node_modules/colyseus.js/src/serializer/SchemaSerializer.ts:10:20)
at Room.Object.<anonymous>.Room.setState (node_modules/colyseus.js/src/Room.ts:225:25)
at Room.Object.<anonymous>.Room.onMessageCallback (node_modules/colyseus.js/src/Room.ts:203:18)
at WebSocket.onMessage (node_modules/ws/lib/event-target.js:132:16)
at Receiver.receiverOnMessage (node_modules/ws/lib/websocket.js:983:20)
at Receiver.dataMessage (node_modules/ws/lib/receiver.js:502:14)
at Receiver.getData (node_modules/ws/lib/receiver.js:435:17)
at Receiver.startLoop (node_modules/ws/lib/receiver.js:143:22)
at Receiver._write (node_modules/ws/lib/receiver.js:78:10)
at Socket.socketOnData (node_modules/ws/lib/websocket.js:1077:35)
● Game › Should connect
thrown: "Exceeded timeout of 5000 ms for a test.
Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
18 | beforeEach(async () => await colyseus.cleanup());
19 | jest.setTimeout(8000)
> 20 | test("Should connect", async () => {
| ^
21 | try {
22 | // `room` is the server-side Room instance reference.
23 | const room = await colyseus.sdk.joinOrCreate("my_game", {...User_1});
at server/test.js:20:5
at Object.<anonymous> (server/test.js:7:1)
at TestScheduler.scheduleTests (node_modules/#jest/core/build/TestScheduler.js:333:13)
at runJest (node_modules/#jest/core/build/runJest.js:401:19)
at _run10000 (node_modules/#jest/core/build/cli/index.js:320:7)
at runCLI (node_modules/#jest/core/build/cli/index.js:173:3)
I changed the timeouts for Jest but it did not change anything.
These are versions for Colyseus, Jest, and Node.js which I am using:
"#colyseus/schema": "^1.0.28",
"#colyseus/testing": "^0.14.22",
"colyseus": "^0.14.18",
"jest": "^27.3.1"
node: v14.7
Leaving it there for those struggling with timeout problems (which I had while testing). Mostly it's when no patch is sent after waitForNextPatch() is called, in my case it was either because
nothing has changed
problem at patch sending / serialisation: considering your other issue it's probably was why you had a timeout exception
some weird async situation, calling waitForXXX() too late while the patch has already passed. Unlikely when using in testing situation like this and no real network is involved
This issue was due to an undetermined field type of the synced state's schema of colyseus game framework that had been added to the last versions of the framework. so I just defined the type as playerId: [string] and It resolved without any error.

Mocked module function with Jest is never called

I have a really weird situation where my Jest tests are passing in my Windows 10 desktop and Macbook Pro, but they are not passing in 2 of my other friends' Windows 10 desktops.
Code that is being tested
import { addTerminalItem } from '../../store'
...
class LoginUser extends EventHandler {
...
async handle () {
if (this.isFromOauthRedirect) {
try {
await this._handleOauthRedirect()
} catch (e) {
addTerminalItem(new ErrorMessage(e.message))
}
return
}
if (await zaClient.isUserLoggedIn('testUserId')) {
// TODO: user is already logged in, do something
} else {
const loginStartSecret = uuidv4()
localStorage.setItem(LOGIN_START_SECRET, loginStartSecret)
addTerminalItem(new LoginMessage(loginStartSecret))
}
}
...
}
export const loginUser = new LoginUser()
The testing code does the following:
Adds invalid LOGIN_START_SECRET so that actual code throws exception entering the first catch.
Subscribes the event handler to the event WELCOME_MESSAGE_RENDERED.
Mocks the store.addTerminalItem module function.
Publishes the event so the above async handle() function is triggered.
Checks that the mocked function is called.
import * as store from '../../../store'
...
test('different login start secret in localstorage', async () => {
localStorage.setItem(LOGIN_START_SECRET, 'different-secret')
zaClient.login = jest.fn(() => true)
store.addTerminalItem = jest.fn()
await pubsub.publish(WELCOME_MESSAGE_RENDERED)
expect(store.addTerminalItem).toHaveBeenCalledWith(expect.any(ErrorMessage))
const errorMessage = store.addTerminalItem.mock.calls[0][0]
expect(errorMessage.message).toBe(loginSecurityErrorMsg)
})
As I said on my computer it shows correctly that addTerminalItem function is called once with the correct argument on both machines I have at home. However this mocked function is never called and fails on 2 of my friends' machines. The actual error message they get is below:
expect(jest.fn()).toHaveBeenCalledWith(...expected)
Expected: Any<ErrorMessage>
Number of calls: 0
Here are the following things we tried so far:
Fresh git clone, yarn install, and yarn test. I pass and they don't.
With addTerminalItem mocked, we added a console.log inside addTerminalItem and it correctly doesn't log, but still 0 number of calls.
With addTerminalItem spyed, we added a console.log inside addTerminalItem and it correctly logs, but still 0 number of calls (this makes no sense to me)
We matched our yarn version.
We carefully debug stepped through the code to make sure all other things were working as expected.
If anyone could give us any pointers here it would be greatly appreciated.
Hard to be definitive without the code at hand, but try using jest.mock:
import {addTerminalItem} from "../../../store";
jest.mock('../../../store', () => ({
addTerminalItem: jest.fn()
));
//... stuff ...
test('different login start secret in localstorage', async () => {
localStorage.setItem(LOGIN_START_SECRET, 'different-secret')
zaClient.login = jest.fn(() => true)
await pubsub.publish(WELCOME_MESSAGE_RENDERED)
expect(addTerminalItem).toHaveBeenCalledWith(expect.any(ErrorMessage))
const errorMessage = addTerminalItem.mock.calls[0][0]
expect(errorMessage.message).toBe(loginSecurityErrorMsg)
})

Error: Protocol JSON API error running Lighthouse with TestCafe Server

I am trying to write code that will spin up a TestCafe Server, log into an authenticated page, navigate to the page I want, and then execute Lighthouse against that page.
Here is my testcafeServer.js file:
const createTestCafe = require('testcafe');
let testcafe = null;
createTestCafe('localhost', 1337, 1338)
.then((tc) => {
testcafe = tc;
const runner = testcafe.createRunner();
return runner.src(['test_lightHouse.js']).browsers(['chrome']).run();
})
.then((failedCount) => {
console.log('Tests failed: ' + failedCount);
testcafe.close();
});
Here is my test_lighthouse.js file:
import { Selector } from 'testcafe';
var fs = require('fs');
const lighthouse = require('lighthouse');
fixture`LightHouse Test`.page(
'MY-SPECIFIC-URL'
);
test(`Generate Light House Result `, async (t) => {
//Specific code to navigate to a certain page
const auditResult = await lighthouse(
'MY-CURRENT-URL-I-WANT-TO-TEST',
{
logLevel: 'info',
output: 'html',
port: 1337, //I am getting this port # from the TestCafe server I am standing up locally - might be wrong
}
);
// Write data in 'Output.txt' .
fs.writeFile('mynewfile3.html', auditResult, function (err) {
if (err) throw err;
console.log('Saved!');
});
console.log(auditResult);
});
When executing this code, I get the following error:
✖ Generate Light House Result
1) Error: Protocol JSON API error (list), status: 404
Browser: Chrome 80.0.3987.163 / macOS 10.15.4
102 | return resolve({message: data});
103 | }
104 | return reject(e);
105 | }
106 | }
> 107 | reject(new Error(`Protocol JSON API error (${command}), status: ${response.statusCode}`));
108 | });
109 | });
110 |
111 | // This error handler is critical to ensuring Lighthouse exits cleanly even when Chrome crashes.
112 | // See https://github.com/GoogleChrome/lighthouse/pull/8583.
What is going wrong? Why does this constantly happen? Is Lighthouse just not meant to work with TestCafe?
Currently, there is no simple way to integrate lighthouse with TestCafe. Please track the following issue in the TestCafe repository to be notified of our results: https://github.com/DevExpress/testcafe/issues/3493.
Also, you can try the approach shown here: https://stackoverflow.com/a/55447097/10684943, but it may work incorrectly with authentication pages.

Node red crashing when use http request to call a webservice

I'm having a problem developing a node that makes web service calls.
I'm using:
Node-RED version: v0.17.5
Node.js version: v8.4.0
It is throwing that exception
node-red_1 | 30 Aug 21:21:50 - [red] Uncaught Exception:
node-red_1 | 30 Aug 21:21:50 - TypeError: Cannot set property listening of #<Server> which has only a getter
node-red_1 | at _clone (/usr/src/node-red/node_modules/clone/clone.js:156:16)
node-red_1 | at _clone (/usr/src/node-red/node_modules/clone/clone.js:156:18)
node-red_1 | at _clone (/usr/src/node-red/node_modules/clone/clone.js:156:18)
node-red_1 | at _clone (/usr/src/node-red/node_modules/clone/clone.js:156:18)
node-red_1 | at _clone (/usr/src/node-red/node_modules/clone/clone.js:156:18)
node-red_1 | at clone (/usr/src/node-red/node_modules/clone/clone.js:196:10)
node-red_1 | at Object.cloneMessage (/usr/src/node-red/node_modules/node-red/red/runtime/util.js:53:13)
node-red_1 | at /usr/src/node-red/node_modules/node-red/red/runtime/nodes/flows/Flow.js:262:48
node-red_1 | at Array.forEach (<anonymous>)
node-red_1 | at Flow.handleError (/usr/src/node-red/node_modules/node-red/red/runtime/nodes/flows/Flow.js:256:34)
I have a list of data that I need to POST to a webservice.
Everything works fine until I fire my HTTP post.
Basically, I have this snippet of code
const objects = msg.payload || []
const hpptCalls = objects.map(obj => (callback) => {
processObject(obj, callback)
})
async.parallelLimit(hpptCalls, 5, (err, results) => {
node.send(msg)
})
Inside my processObject function, I have almost the same code that exists in core node 21-httprequest.js
const req = http.request(options, res => {
let data = ''
res.on('data', chunk => {
data += chunk
})
res.on('end', () => {
callback(null)
})
})
req.setTimeout(120000, () => {
node.error('Error', msg)
req.abort()
callback('Error')
})
req.on('error', err => {
node.error(err, msg)
callback(err)
})
if (content) {
req.write(JSON.stringify(content))
}
req.end()
But, it seems that when the first HTTP post is called, my node-red crash entirely with that exception. I can figure what is the problem. I put a lot o try catches thinking that my code is breaking something, but it is a straightforward code.
Apparently found the problem, as mentioned in project's github. At a random point in the flow, someone put a function node with the following code
return {
"_msg": msg
[other properties]
}
Thanks! (It was hard to find the problem lol, we have a big flow).

Categories

Resources