In nodejs script, I am using execAsync to run cypress tests. Obviously, some tests would fail but that returns error status code 1 and it would fail the script and stop next steps to merge test reports and html report creation.
Solution is to use try catch as follows
import { execSync } from "child_process";
let stdout = "";
try {
stdout = execSync("npx cypress run", { stdio: "inherit" });
} catch (err) {
console.log("stdout=[" + stdout + "]");
const regex = /\d+ of \d+ failed/;
if (!regex.test(stdout)) {
console.log(err);
}
}
Since throw is happening, stdout comes as empty string and console.log(err) gets executed and shows below
Spec Tests Passing Failing Pending Skipped
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
│ ✖ todo.cy.js 351ms 6 - 1 - 5 │
└────────────────────────────────────────────────────────────────────────────────────────────────┘
✖ 1 of 1 failed (100%) 351ms 6 - 1 - 5
stdout=[]
Error: Command failed: npx cypress run
at checkExecSyncError (node:child_process:841:11)
at execSync (node:child_process:912:15)
at file:///home/atulk/workspace/cypress-all/cypress-reports/test.mjs:5:12
at ModuleJob.run (node:internal/modules/esm/module_job:193:25)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:533:24)
at async loadESM (node:internal/process/esm_loader:91:5)
at async handleMainPromise (node:internal/modules/run_main:65:12) {
status: 1,
signal: null,
output: [ null, null, null ],
pid: 35512,
stdout: null,
stderr: null
}
I do not want to show the error when the tests have failed. What could be the way to catch the stdout so that I can look for the string like "1 of 1 failed"?
You may find it is easier to use the Cypress Module API which is designed for running Cypress from Node.
For example,
// e2e-run-tests.js
const cypress = require('cypress')
cypress
.run({
// the path is relative to the current working directory
spec: './cypress/e2e/examples/actions.cy.js',
})
.then((results) => {
console.log(results)
})
.catch((err) => {
console.error(err)
})
Related
I am using rollup (version 2.56.3) hook closeBundle() in a plugin I wrote to postprocess my build using spawn. When I run, rollup hangs after the postprocess. It does print "make done....", which indicates the postprocess went fine, but then sits there without returning to the shell prompt. I have to press ^c to get back to shell prompt. Here is the hook function,
function make() {
return {
closeBundle() {
let elMake = require('child_process').spawn('npm', ['run', 'make'], {
stdio: ['ignore', 'inherit', 'inherit'],
shell: true
});
return new Promise((resolve, reject) => {
elMake.on('error', reject)
elMake.on('exit', code => {
if (code === 0) {
console.log("make done....");
resolve()
} else {
const err = new Error(`make exited with code ${code}`)
reject(err)
}
})
})
}
};
}
What am I doing wrong? Any idea why is this happening?
It was happening due to MS typescript compiler bug. After some digging with google search finally found the answer. Read this thread for the details https://giters.com/rollup/rollup/issues/4213. On some platforms this was hanging up rollup.
It has been fixed with TypeScript 4.4.3
In my Jest unit test file that uses pgPromise library I am getting this error:
Jest did not exit one second after the test run has completed.
I guess this should be because of the code below that I have in my app.ts
import {db} from './shared/db';
...
let sco: any;
db.connect().then(function (obj: any) {
sco = obj;
obj.client.query('LISTEN "table_update"');
obj.client.on('notification', function (data: any) {
var result = JSON.parse(data.payload);
log.info(result);
globalEmitter.emit(
eventTypes.Entity_Data_Changed,
result
}
catch(error) {
log.error({ error }, 'Error happened');
})
.finally(() => {
// release the connection, if it was successful:
if (sco) {
sco.done();
}
});;
I use the same import in my unit test file.
db is coming from
const db = pgp(options);
In my unit test file I have this code at the end
afterAll(async done => {
setImmediate(done); // jest address open handle with --detectOpenHandles
db.$pool.end();
pgp.end();});
I tried pgp.end() to kill all connections as I suspect the db expression in app.ts file does not belong to a connection pool as I read somewhere about it before. But still no luck. any help would be appreciated here.
For some reason I'm not understanding why I'm having an issue in my exec command and I believe I followed the documentation and examples I've referenced correctly. When I run this command in the terminal I do not have an issue:
gitleaks --repo=https://github.com/user/repo -v --username=foo --password=bar
but when I try to code it as a module so I can call upon it in package.json:
const { exec } = require("child_process")
const test = `gitleaks --repo=https://github.com/user/repo -v --username=foo --password=bar`
const execRun = (cmd) => {
return new Promise((resolve, reject) => {
exec(cmd, (error, stdout, stderr) => {
if (error) reject(error)
resolve(stdout ? stdout : stderr)
})
})
}
(async () => {
try {
const testing = await execRun(test)
console.log(testing)
} catch (e) {
console.log(e)
}
})()
but I continue to get the error:
{ Error: Command failed: gitleaks --repo=https://github.com/user/repo -v --username=foo --password=bar
at ChildProcess.exithandler (child_process.js:294:12)
at ChildProcess.emit (events.js:198:13)
at maybeClose (internal/child_process.js:982:16)
at Socket.stream.socket.on (internal/child_process.js:389:11)
at Socket.emit (events.js:198:13)
at Pipe._handle.close (net.js:606:12)
killed: false,
code: 1,
signal: null,
cmd:
'gitleaks --repo=https://github.com/user/repo -v --username=foo --password=bar' }
I've tried to research my issue to see if I'm missing something and read:
nodejs exec command failing with no useful error message
Node Child Process Exec Command Failed with error code 1
nodejs exec command fails for some windows commands with no clear error message
NodeJS Child Process EXEC Command Failed with NVM Permission denied OSX
Why does my exec command fail but I can pass the same command in the terminal and it works?
When the exec function runs a command it examines the exit code from that command. It assumes that an exit code other than 0 is an error and thus passes the error in the callback. If gitleaks finds secrets in a repo then it exits with code 1.
Something along these lines should work:
const { exec } = require("child_process")
const test = `gitleaks --repo=https://github.com/user/repo -v --username=foo --password=bar`
const execRun = (cmd) => {
return new Promise((resolve, reject) => {
exec(cmd, (error, stdout, stderr) => {
if (error) {
if (error.code === 1) {
// leaks present
resolve(stdout);
} else {
// gitleaks error
reject(error);
}
} else {
// no leaks
resolve(stdout);
}
})
})
}
(async () => {
try {
const testing = await execRun(test)
console.log(testing)
} catch (e) {
console.log(e)
}
})()
What I test: An express server endpoints
My goal: automate API tests in a single script
What I do: I launch the express server in a NodeJS child process and would like to wait for it to be launched before the test suite is run (frisby.js endpoints testing)
What isn't working as expected: Test suite is launched before Promise resolution
I rely on the wait-on package which server polls and resolves once the resource(s) is/are available.
const awaitServer = async () => {
await waitOn({
resources: [`http://localhost:${PORT}`],
interval: 1000,
}).then(() => {
console.log('Server is running, launching test suite now!');
});
};
This function is used in the startServer function:
const startServer = async () => {
console.log(`Launching server http://localhost:${PORT} ...`);
// npmRunScripts is a thin wrapper around child_process.exec to easily access node_modules/.bin like in package.json scripts
await npmRunScripts(
`cross-env PORT=${PORT} node -r ts-node/register -r dotenv/config src/index.ts dotenv_config_path=.env-tests`
);
await awaitServer();
}
And finally, I use this in something like
describe('Endpoints' () => {
beforeAll(startTestServer);
// describes and tests here ...
});
Anyway, when I launch jest the 'Server is running, launching test suite now!' console.log never shows up and the test suite fails (as the server isn't running already). Why does jest starts testing as awaitServer obviously hasn't resolved yet?
The npmRunScripts function works fine as the test server is up and running a short while after the tests have failed. For this question's sake, here's how npmRunScripts resolves:
// From https://humanwhocodes.com/blog/2016/03/mimicking-npm-script-in-node-js/
const { exec } = require('child_process');
const { delimiter, join } = require('path');
const env = { ...process.env };
const binPath = join(__dirname, '../..', 'node_modules', '.bin');
env.PATH = `${binPath}${delimiter}${env.PATH}`;
/**
* Executes a CLI command with `./node_modules/.bin` in the scope like you
* would use in the `scripts` sections of a `package.json`
* #param cmd The actual command
*/
const npmRunScripts = (cmd, resolveProcess = false) =>
new Promise((resolve, reject) => {
if (typeof cmd !== 'string') {
reject(
new TypeError(
`npmRunScripts Error: cmd is a "${typeof cmd}", "string" expected.`
)
);
return;
}
if (cmd === '') {
reject(
new Error(`npmRunScripts Error: No command provided (cmd is empty).`)
);
return;
}
const subProcess = exec(
cmd,
{ cwd: process.cwd(), env }
);
if (resolveProcess) {
resolve(subProcess);
} else {
const cleanUp = () => {
subProcess.stdout.removeAllListeners();
subProcess.stderr.removeAllListeners();
};
subProcess.stdout.on('data', (data) => {
resolve(data);
cleanUp();
});
subProcess.stderr.on('data', (data) => {
reject(data);
cleanUp();
});
}
});
module.exports = npmRunScripts;
I found the solution. After trying almost anything, I didn't realize jest had a timeout setup which defaults at 5 seconds. So I increased this timeout and the tests now wait for the server promise to resolve.
I simply added jest.setTimeout(3 * 60 * 1000); before the test suite.
In my case, it caused by the flaw of the beforeAll part. Make sure the beforeAll doesn't contain any uncaught exceptions, otherwise it will behaves that the testing started without waiting for beforeAll resolves.
After much digging I found a reason for why my beforeAll didn't seem to be running before my tests. This might be obvious to some, but it wasn't to me.
If you have code in your describe outside an it or other beforeX or afterY, and that code is dependent on any beforeX, you'll run into this problem.
The problem is that code in your describe is run before any beforeX. Therefore, that code won't have access to the dependencies that are resolved in any beforeX.
For example:
describe('Outer describe', () => {
let server;
beforeAll(async () => {
// Set up the server before all tests...
server = await setupServer();
});
describe('Inner describe', () => {
// The below line is run before the above beforeAll, so server doesn't exist here yet!
const queue = server.getQueue(); // Error! server.getQueue is not a function
it('Should use the queue', () => {
queue.getMessage(); // Test fails due to error above
});
});
});
To me this seems unexpected, considering that code is run in the describe callback, so my impression was that that callback would be run after all beforeX outside the current describe.
It also seems this behavior won't be changed any time soon: https://github.com/facebook/jest/issues/4097
In newer versions of jest (at least >1.3.1) you can pass a done function to your beforeAll function and call it after everything is done:
beforeAll(async (done) => {
await myAsyncFunc();
done();
})
it("Some test", async () => {
// Runs after beforeAll
})
More discussions here: https://github.com/facebook/jest/issues/1256
I'm writing a metalsmith plugin and its associated test suite with mocha.
The plugin should throw an exception if it lacks configuration:
function plugin(config) {
...
return function(files, metalsmith, done) {
...
done(new Error("config error"));
}
}
and I try to test it with mocha this way:
describe('my plugin', function() {
it('should throw an exception', function(done) {
var metalsmith = Metalsmith('test/fixtures/basic');
metalsmith
.use(myplugin({
someconfig: {
}))
.build(function(err,files) {
assert(err);
done();
});
});
});
When I run the test I have this result:
my plugin
✓ should throw an exception
1) should throw an exception
1 passing (31ms)
1 failing
1) my plugin should throw an exception:
Error: done() called multiple times
So it seems the test is ok but somehow is run another time, failing this time...
The problem was that the error was throwed inside a foreach loop, causing done() to be called multiple times:
Object.keys(files).forEach(function (file) {
...
done(new Error("config error"));
...
}
Adding a simple return does not work because you can't return from a foreach loop.
So using a simple for loop instead of the foreach, returning on the first error:
for (var file in files) {
...
return done(new Error("config error"));
...
}