systematic failure when trying to execute a system command with Cypress - cmd

I'm new to Cypress and Javascript
I'm trying to send system commands through Cypress. I've been through several examples but even the simplest does not work.
it always fails with the following message
Information about the failure:
Code: 127
Stderr:
/c/Program: Files\Git\usr\bin\bash.exe: No such file or directory`
I'm trying cy.exec('pwd') or 'ls' to see where it is launched from but it does not work.
Is there a particular include I am missing ? some particular configuration ?
EDIT :
indeed, I'm not clear about the context I'm trying to use the command in. However, I don't set any path explicitely.
I send requests on a linux server but I also would like to send system commands.
My cypress project is in /c/Cypress/test_integration/cypress
I work with a .feature file located in /c/Cypress/test_integration/cypress/features/System and my scenario calls a function in a file system.js located in /c/Cypress/test_integration/cypress/step_definitions/generic.
System_operations.features:
Scenario: [0004] - Restore HBox configuration
Given I am logging with "Administrator" account from API
And I store the actual configuration
...
Then I my .js file, I want to send a system command
system.js:
Given('I store the actual configuration', () => {
let nb_elem = 0
cy.exec('ls -l')
...
})
I did no particular path configuration in VS Code for the use of bash command (I just configured the terminal in bash instead of powershell)

Finally, with some help, I managed to call system functions by using tasks.
In my function I call :
cy.task('send_system_cmd', 'pwd').then((output) => {
console.log("output = ", output)
})
with a task created as follows:
on('task', {
send_system_cmd(cmd) {
console.log("task test command system")
const execSync = require('child_process').execSync;
const output = execSync(cmd, { encoding: 'utf-8' });
return output
}
})
this works at least for simple commands, I haven't tried much further for the moment.
UPDATE for LINUX system commands as the previous method works for WINDOWS
(sorry, I can't remember where I found this method, it's not my credit. though it fulfills my needs)
This case requires node-ssh
Still using tasks, the function call is done like this
cy.task('send_system_cmd', {cmd:"<my_command>", endpoint:<address>,user:<ssh_login>, pwd:<ssh_password>}).then((output) => {
<process output.stdout or output.stderr>
})
with the task being build like this:
// send system command - remote
on('task', {
send_system_cmd({cmd, endpoint, user, pwd}) {
return new Promise((resolve, reject) => {
const { NodeSSH } = require('node-ssh')
const ssh = new NodeSSH()
let ssh_output = {}
ssh.connect({
host: endpoint,
username: user,
password: pwd
})
.then(() => {
if(!ssh.isConnected())
reject("ssh connection not set")
//console.log("ssh connection OK, send command")
ssh.execCommand(cmd).then(function (result) {
ssh_output["stderr"] = result.stderr
ssh_output["stdout"] = result.stdout
resolve(ssh_output)
});
})
.catch((err)=>{
console.log(err)
reject(err)
})
})
}
})

Related

Some modules can be used with NodejsFunction(AWS CDK) and some cannot?

I defined a lambda function using NodejsFunction of AWS CDK.
I installed the modules I want to use in my lambda function in node_modules of CDK.
When I execute sam local invoke, some modules succeed and others fail.
When an error occurs, the error message "File not found in '/var/task/...'" is displayed.
Does this mean that some modules can be used with NodejsFunction and some cannot?
lambda-stack.ts
new lambda.NodejsFunction(this, 'SampleFunction', {
runtime: Runtime.NODEJS_14_X,
entry: 'lambda/sample-function/index.ts'
})
lambda/sample-function/index.ts (use 'date-fns') -> succeeded!
import { format } from 'date-fns'
export const handler = async () => {
try {
console.log(format(new Date(), "'Today is a' eeee"))
} catch (error) {
console.log(error)
}
}
lambda/sample-function/index.ts (use 'chrome-aws-lambda') -> failed
const chromium = require('chrome-aws-lambda')
export const handler = async () => {
try {
const browser = await chromium.puppeteer.launch()
} catch (error) {
// Cannot find module '/var/task/puppeteer/lib/Browser'
console.log(error)
}
}
lambda/sample-function/index.ts (use 'pdfkit') -> failed
const PDFDocument = require('pdfkit')
export const handler = async () => {
try {
const doc = new PDFDocument()
} catch (error) {
// no such file or directory, open '/var/task/data/Helvetica.afm'
console.log(error)
}
}
it seems that the "pdfkit" and "chrome-aws-lambda" are packages that use some binary files and you need to verify that those binary found in lambda.
when you create a lambda using 'new lambda.NodejsFunction()' in background, there is a esbuild process that bundles all files into one so make sure you not see any error related to that build during synth.
in order to verfiy this is the problem you could try upload your lambda with node_modules and chcek if it is work.
alternative you can:
look (or create) "lambda layer" that will contain those binary see example.
build your lambda with all of the dependencies as a docker image and set lambda to run that docker.

Looking for a way to excute a command line from cypress

I need to create a file and copy it somewhere by some code from cypress .
the first step is done by using cy.writeFile and now myfile.txt is created
Now i need to copy it somewhere like c:/lib/Sth
i used this command cy.exec('cp myfile.txt c:/lib/sth')
it shows this error message :
CypressError: cy.exec('cp myfile.txt c:/lib/sth') failed because the command exited with a non-zero code. Pass {failOnNonZeroExit: false}` to ignore exit code failures.
Information about the failure:
Code: 127
I add {failOnNonZeroExit: false} to my code to ignore error , it works , but my file is not copied.
is there any other solution to copy my file from cypress ??
A work-around you could do is set up a custom cypress task to execute a command.
Something like
// cypress/plugins/index.ts
const { exec } = require('child_process');
/**
* #type {Cypress.PluginConfig}
*/
// eslint-disable-next-line no-unused-vars
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
on('task', {
async execute(command: string) {
return new Promise((resolve, reject) => {
try {
resolve(exec(command));
} catch (e) {
reject(e);
}
});
},
});
};
Then execute like so
cy.task('execute', 'cp myfile.txt c:/lib/sth');
This was a potential solution I came up with when cy.exec() didn't work for me either when trying to execute a relatively complex node script.
Another thing you could try is to create a really simple script that copies the file, and try executing that script.
Best of luck!

In my Cypress.io tests why do I need to treat a cy.task like it is asyncronous when its not

I have Cypress.io tests that use a simple Cypress task to log some table information to the terminal. For example I have a test like so:
it("Writes some console logs and checks a val", () => {
cy.task("rowLog", { id: 1, name: "foo", type: "bar" });
let one = 1;
expect(one).to.equal(2);
});
And the task, "rowLog" like so:
module.exports = (on, config) => {
on("task", {
rowLog(data) {
// use node.js console.table to pretty print table data:
console.table(data);
return null;
},
}
But the result of rowLog will not display in my terminal if I run Cypress headlessly via Cypress run. This is because the test will fail. If we switch the test so that it passes, then it will show.
However I just realized that if I treat rowLog like it's async like below. It will print the results to the terminal:
it("Writes some console logs and checks a val", () => {
// add a .then to task:
cy.task("rowLog", { id: 1, name: "foo", type: "bar" }).then(() => {
let one = 1;
expect(one).to.equal(2);
});
});
This is not what I would expect from the docs. They say that:
cy.task() yields the value returned or resolved by the task event in the pluginsFile.
(source)
And that a task can yield either a promise or a value.
I'm new to Cypress here-- is there something I'm missing or doing wrong? I'd like to be able to not have to chain my tasks with .then statements if it is just synchronous stuff like writing output to ensure everything is emitted to my terminal.
If you look into the type definition of cy.task command, you will see that it returns a Chainable (that is a promise-like entity). So it behaves like any other cy command (ansynchrounously).
As for the yield either a promise or a **value** - this statement refers to the handler of the task, not the task itself. As for the other command, Cypress will wrap a returned value into a promise if it was not done by the handler.

How can I run a shell script as a setup file in Jest?

Something like this. The goal is to start and stop my test server as part of the jest setup so I can do end to end testing with a single command.
"jest": {
"setupFiles": ["<rootDir>/TestScript.sh"]
}
I will answer this myself for anyone in the future who is trying to solve the same problem as me.
Jest config has globalSetup and globalTeardown options. This script will be run once at the beginning of all tests.
"jest": {
"globalSetup": "<rootDir>/jestGlobalSetup.js"
}
In node, you can use the child_process API to run shell scripts from a js file.
I ran mine like this in my setup file.
import { spawn } from 'child_process';
import cwd from 'cwd';
export default async function setup() {
process.stdout.write('Starting Server');
// Run this command in shell.
// Every argument needs to be a separate string in an an array.
const command = 'foreman';
const arguments = [
'start',
'-p',
'3000',
'-f',
'Procfile.test',
];
const options = {
shell: true,
cwd: cwd()
};
const server = spawn(
command,
arguments,
options,
);
// Then I run a custom script that pings the server until it returns a 200.
await serverReady();
}
you have to configure the globalSetup option in your jest.config.js file
module.exports = {
...
globalSetup: "<rootDir>/jestGlobalSetup.js",
...
};
then create the jestGlobalSetup.js file as following:
const exec = require('child_process').exec;
module.exports = async function() {
const myShellScript = exec('./TestScript.sh');//or run any other shell command
myShellScript.stdout.on('data', (data)=>{
console.log(data);
// do whatever you want here with data
});
myShellScript.stderr.on('data', (data)=>{
console.error(data);
})
}

Directory path is incorrect when running from cypress test runner

When I login from normal browser the login is successful with the URL : http://neelesh.zapto.org:8084/EnrolMe/indHome.html
But when I run the script from Cypress the directory location is not appended and the new URL after login is formed as : http://neelesh.zapto.org:8084/__/indHome.html
I have tried setting cypress.json with
{
"chromeWebSecurity": false,
"modifyObstructiveCode" : false
}
I have tried on chrome/electron(head and headless).
Below is my code snippet:
describe('My First Test Suite', function() {
it('My First test case', function() {
cy.visit("http://neelesh.zapto.org:8084/EnrolMe")
cy.get("#login").click()
cy.get("input[value='Individual']").click()
cy.get("#username").type('1234567890')
cy.get("#pwd").type('0646')
Cypress.Cookies.debug(true)
cy.clearCookies()
cy.get("#login").click()
cy.wait(6000)
})
})
When I run the script from Cypress the directory location is not appended and the new URL after login is formed as : http://neelesh.zapto.org:8084/__/indHome.html
It should be redirected as : http://neelesh.zapto.org:8084/EnrolMe/indHome.html
Can anyone help me on this?
This sounds like an issue with "Frame Busting". There's a related discussion for Cypress GitHub Issue #992 which may lend some help.
Your application code may contain problematic frame busting code like the following:
if (window.top !== window.self) {
window.top.location.href = window.self.location.href;
}
You can get around this by changing your application code's reference to window.self from the Application Window to the Cypress Test Runner window (window.top).
Cypress emits a series of events as it runs in your browser. You can use the emitted window:before:load application event to ensure it's done before you attempt to login.
// cypress/support/index.js
Cypress.on('window:before:load', (win) => {
Object.defineProperty(win, 'self', {
get: () => {
return window.top
}
})
})

Resources