Error: Protocol JSON API error running Lighthouse with TestCafe Server - javascript

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.

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.

How To Configure Cypress To Wait Longer (or Indefinitely) for BaseUrl?

I am using this Cypress image in a docker-compose.yml to run end to end tests: cypress/included:6.1.0
When the test runner starts it will verify that a server can be reached at baseUrl. If not, it retries 3 times.
My services and web server need a little more time to start.
How can I increase the timeout and/or number of retries for this check.
Preferably, in my case I'd like a retry-until-success policy, i.e. indefinite retries/wait.
I have checked the Timeouts section and the cypress.json documentation more generally. However none of those timeouts or retries seem to relate to this behavior.
Is there a setting for this?
TO CLARIFY: This is not a check I implemented (or want to) as part of my specs. This is, as far as I can tell so far, a feature of cyprus run, the default command in the image. If possible I would like to configure this without adding to or revising the tests themselves.
Here is the docker-compose console output when cypress starts in the container:
cypress_1 | Cypress could not verify that this server is running:
cypress_1 |
cypress_1 | > http://localhost:5000
cypress_1 |
cypress_1 | We are verifying this server because it has been configured as your `baseUrl`.
cypress_1 |
cypress_1 | Cypress automatically waits until your server is accessible before running tests.
cypress_1 |
cypress_1 | We will try connecting to it 3 more times...
cypress_1 | We will try connecting to it 2 more times...
cypress_1 | We will try connecting to it 1 more time...
cypress_1 |
cypress_1 | Cypress failed to verify that your server is running.
cypress_1 |
cypress_1 | Please start this server and then run Cypress again.
cypress_1 exited with code 1
You should ensure your server is running before calling cypress run using a utility like wait-on or start-server-and-test.
Cypress's check on the baseUrl is a final courtesy check just so you don't run through your whole test suite on a server that is not running.
For tips on ensuring your server is running before running Cypress, check out the Cypress docs here: https://on.cypress.io/continuous-integration#Boot-your-server
Disclaimer
#jennifer-shehane is correct; in most cases you should ensure that the server is running before starting cypress.
However
We're using Cypress primarily for API testing (for now), and one of the workflows we need to support includes a server restart. Of course, we could just drop in an arbitrarily long cy.wait(30000); before moving on to the next step, but that's inelegant and can waste a lot of time, especially if you're like me and end up running the tests over and over.
Since Cypress doesn't really work in the same asynchronous way we're usually accustomed to, the solution we came up with is to use a task.
Add this to plugins/index.js:
const https = require("https");
const { URL } = require("url");
/**
* #type {Cypress.PluginConfig}
*/
module.exports = (on, config) => {
require('#cypress/code-coverage/task')(on, config)
on("task", {
async waitForServerResponse({ server_url }) {
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function makeRequest({ hostname, port, path }) {
return new Promise((resolve, reject) => {
const options = {
hostname,
port,
path,
body: {},
method: 'POST'
}
const req = https.request(options, response => {
response.on('data', d => {
resolve(d.toString());
});
});
req.on('error', error => {
reject(error);
});
req.end();
});
}
async function recursiveGet(retry = 1) {
try {
const res = await makeRequest({ hostname, port, path });
if (res?.code?.includes("ECONNREFUSED") || res?.code?.includes("ECONNRESET")) {
await sleep(1000);
await recursiveGet(retry + 1);
}
}
catch(error) {
if (error?.code?.includes("ECONNREFUSED") || error?.code?.includes("ECONNRESET")) {
await sleep(1000);
await recursiveGet(retry + 1);
}
}
}
if (!server_url) {
server_url = config.baseUrl;
}
const parsedUrl = new URL(server_url);
const hostname = parsedUrl?.hostname ?? "localhost";
const port = parsedUrl?.port ?? 443;
const path = parsedUrl?.pathname ?? "/";
return new Promise(async (resolve, reject) => {
// tasks should not resolve with undefined
setTimeout(() => reject(new Error("Timeout")), 60000);
await recursiveGet();
resolve(true);
});
}
});
return config;
};
and call it in your test:
it("Restarts the server", () => {
// Restart the server
cy.systemRestart().then(({ body, status }) => { // server returns success before actually restarting
expect(status).to.equal(200);
expect(body).property("success").to.eq(true);
cy.wait(1000); // initial wait
cy.task("waitForServerResponse", { server_url: server_url + "/auth/token" });
cy.login();
cy.adminIndex().then(({ body, status }) => {
if (body?.properties) {
expect(status).to.equal(200);
expect(body).property("properties").to.be.a("object");
const bootedAt = new Date(body.properties.system.bootedAt).getTime();
const now = new Date().getTime();
const diff = Math.ceil(Math.abs(now - bootedAt) / 1000); // ms -> s
expect(diff).to.be.lessThan(20); // seconds
}
});
});
});
This will poll the server (any given endpoint, I chose /auth/token) and if the connection is refused or reset, it will wait for 1 second and try again. The task will only return once it receives a response from the server.

SyntaxError: Unexpected token { in JSON at position 101033 at JSON.parse (<anonymous>) fix?

So I am trying to complete the open source mission in TwilioQuest but I can't becuase the terminal gives me an error when I run this command:
git commit -m "feat(pixels): add my new pixel"
It tells me there is an error in one of the scripts which is this one and its written in Javascript:
const fs = require('fs');
const path = require('path');
const { promisify } = require('util');
const { sortPixels, pixelsToString } = require('../utils/pixels-helper');
const readFile = promisify(fs.readFile);
const writeFile = promisify(fs.writeFile);
const pixelFilePath = path.join('_data', 'pixels.json');
readFile(pixelFilePath, { encoding: 'utf8' })
.then(pixelFileData => {
const pixels = JSON.parse(pixelFileData);
const sortedPixelString = pixelsToString(sortPixels(pixels));
writeFile(pixelFilePath, sortedPixelString);
})
.catch(console.log);
The error it gives me for this script is this:
SyntaxError: Unexpected token { in JSON at position 101033
at JSON.parse (<anonymous>)
8 | const filePath = path.resolve(__dirname, '../_data/', dataJsonFile);
9 | const pixelJsonString = await readFile(filePath, 'utf8');
> 10 | return JSON.parse(pixelJsonString);
| ^
11 | }
12 |
13 | describe('pixels', () => {
What is this error about and how can I fix it?
Regarding git features in this matter : this error is triggered by a custom script, most probably .git/hooks/pre-commit.
You may open .git/hooks/pre-commit in an editor to view how your code is tested, and execute in your terminal .git/hooks/pre-commit to see if the test passes or fails.
Regarding javascript debugging : use your regular tools and methods to debug.
For example :
you may add console.log(filePath) before calling JSON.parse, to see which file was opened, or console.log(pixelJsonString) to see what is returned from your function,
you may use a node debugger to follow you program's execution
...

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