How to connect to SFTP server in Cypress test? - cypress

I am trying to connect to an SFTP server using the ssh2-sftp-client
NPM package in my Cypress test.
Here is my test at the moment
describe('example to-do app', () => {
it('displays two todo items by default', () => {
let Client = require('ssh2-sftp-client');
let sftp = new Client();
sftp.connect({
host: 'myHost',
port: 'myPort',
username: 'myUsername',
password: 'myPassword'
}).then(() => {
return sftp.list('/reports');
}).then(data => {
console.log(data, 'the data info');
}).catch(err => {
console.log(err, 'catch error');
});
})
})
Currently, when I run the test I get this error:
Cannot read properties of undefined (reading 'DEFLATE')
node_modules/ssh2/lib/protocol/zlib.js:7:1
5 | createInflate,
6 | constants: {
> 7 | DEFLATE,
| ^
8 | INFLATE,
9 | Z_DEFAULT_CHUNK,
10 | Z_DEFAULT_COMPRESSION,
Can someone please tell me how to resolve this issue?

Establishing such connection in a test will not work. This is because cypress does not communicate with a Node.js process supplied by the host. In cypress if we need to run node code, we need to use their so called cy.task Here is the link to their docs - https://docs.cypress.io/api/commands/task#Examples
That's why you need to establish this connection in your cypress/plugins/index.js file inside a task and then use this task in your test.
Here is an example of connecting to mysql with ssh - How do I connect mysql with cypress through ssh tunneling?

Related

systematic failure when trying to execute a system command with Cypress

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)
})
})
}
})

Suddenly, Heroku credentials to a PostgreSQL server gives FATAL password for user error

Without changing anything in my settings, I can't connect to my PostgreSQL database hosted on Heroku. I can't access it in my application, and is given error
OperationalError: (psycopg2.OperationalError) FATAL: password authentication failed for user "<heroku user>" FATAL: no pg_hba.conf entry for host "<address>", user "<user>", database "<database>", SSL off
It says SSL off, but this is enabled as I have confirmed in PgAdmin. When attempting to access the database through PgAdmin 4 I get the same problem, saying that there is a fatal password authentication for user '' error.
I have checked the credentials for the database on Heroku, but nothing has changed. Am I doing something wrong? Do I have to change something in pg_hba.conf?
Edit: I can see in the notifications on Heroku that the database was updated right around the time the database stopped working for me. I am not sure if I triggered the update, however.
Here's the notification center:
In general, it isn't a good idea to hard-code credentials when connecting to Heroku Postgres:
Do not copy and paste database credentials to a separate environment or into your application’s code. The database URL is managed by Heroku and will change under some circumstances such as:
User-initiated database credential rotations using heroku pg:credentials:rotate.
Catastrophic hardware failures that require Heroku Postgres staff to recover your database on new hardware.
Security issues or threats that require Heroku Postgres staff to rotate database credentials.
Automated failover events on HA-enabled plans.
It is best practice to always fetch the database URL config var from the corresponding Heroku app when your application starts. For example, you may follow 12Factor application configuration principles by using the Heroku CLI and invoke your process like so:
DATABASE_URL=$(heroku config:get DATABASE_URL -a your-app) your_process
This way, you ensure your process or application always has correct database credentials.
Based on the messages in your screenshot, I suspect you were affected by the second bullet. Whatever the cause, one of those messages explicitly says
Once it has completed, your database URL will have changed
I had the same issue. Thx to #Chris I solved it this way.
This file is in config/database.js (Strapi 3.1.3)
var parseDbUrl = require("parse-database-url");
if (process.env.NODE_ENV === 'production') {
module.exports = ({ env }) => {
var dbConfig = parseDbUrl(env('DATABASE_URL', ''));
return {
defaultConnection: 'default',
connections: {
default: {
connector: 'bookshelf',
settings: {
client: dbConfig.driver,
host: dbConfig.host,
port: dbConfig.port,
database: dbConfig.database,
username: dbConfig.user,
password: dbConfig.password,
},
options: {
ssl: false,
},
},
},
}
};
} else {
// to use the default local provider you can return an empty configuration
module.exports = ({ env }) => ({
defaultConnection: 'default',
connections: {
default: {
connector: 'bookshelf',
settings: {
client: 'sqlite',
filename: env('DATABASE_FILENAME', '.tmp/data.db'),
},
options: {
useNullAsDefault: true,
},
},
},
});
}

Does Mocha support multiple before hook for creating independent http server?

Here is my project structure:
src/
- demo-1/
- server.ts
- server.spec.ts
- demo-2/
- server.ts
- server.spec.ts
Each server.spec.ts has below setup:
import { start } from './server';
let server: http.Server;
before('start server', (done: Done) => {
server = start(done);
});
after('stop server', (done: Done) => {
server.close(done);
});
describe('test suites', () => {
//...
})
Here is my package.json scripts:
"scripts": {
"test": "NODE_ENV=test mocha --timeout=3000 --require=ts-node/register ./src/**/*.spec.ts"
},
When I run npm test, it gives me an error:
1) "before all" hook: start server:
Uncaught Error: listen EADDRINUSE :::4000
at Object._errnoException (util.js:1022:11)
at _exceptionWithHostPort (util.js:1044:20)
at Server.setupListenHandle [as _listen2] (net.js:1351:14)
at listenInCluster (net.js:1392:12)
at Server.listen (net.js:1476:7)
at Function.listen (node_modules/express/lib/application.js:618:24)
at Object.start (src/constructor-types/server.ts:33:14)
at Context.before (src/constructor-types/server.spec.ts:12:12)
at Server.app.listen (src/aliases/server.ts:42:7)
at emitListeningNT (net.js:1378:10)
at _combinedTickCallback (internal/process/next_tick.js:135:11)
at process._tickCallback (internal/process/next_tick.js:180:9)
2) "after all" hook: stop server:
Error: Not running
at Server.close (net.js:1604:12)
at emitCloseNT (net.js:1655:8)
at _combinedTickCallback (internal/process/next_tick.js:135:11)
at Immediate._tickCallback (internal/process/next_tick.js:180:9)
I expect each server.spec.ts works independently which means start the server and run its test suites one by one in order to avoiding http port conflict. Because these servers have a same http port.
Mocha run test files in parallel. Servers will be created same time into one port.
The workaround is assigning random port for each file (change start function to add dynamic port param)
import { start } from './server';
const PORT = Math.floor((Math.random() * 100000) + 1);
let server: http.Server;
before('start server', (done: Done) => {
// change start function accept port param
server = start(PORT, done);
});
after('stop server', (done: Done) => {
server.close(done);
});
Another solution is serial-mocha that support running test synchronous. However the package is old, and I don't know if it still work

Issues running BrowserStackLocal for website behind firewall

I'm trying to run browserstack behind the firewall.
I tried to run this command on terminal:
RK$ ./BrowserStackLocal --key <key> --force-local
BrowserStackLocal v7.0
You can now access your local server(s) in our remote browser.
Press Ctrl-C to exit
I opened another terminal and I ran the command
npm run test:functional:cr:mobile
I get the following error:
1) Run sample test flow page:
Uncaught WebDriverError: [browserstack.local] is set to true but local testing through BrowserStack is not connected.
This is my config.js
'use strict'
import webdriver from 'selenium-webdriver'
let driver
module.exports = {
getDriverConfiguration: function (testTitle, browserName) {
var capabilities = {
'browserName': process.env.BROWSER || 'Chrome',
'realMobile': 'true',
'os': 'android',
'deviceName': process.env.DEVICE || 'Samsung Galaxy S8',
'browserstack.user': 'USER',
'browserstack.key': 'KEY',
'browserstack.debug': 'true',
'build': 'Build for mobile testing',
'browserstack.local' : 'true',
'browserstack.localIdentifier' : 'Test123'
}
driver = new webdriver.Builder().withCapabilities(capabilities).usingServer('http://hub-cloud.browserstack.com/wd/hub').build()
driver.manage().deleteAllCookies()
return driver
}
}
I enabled browserstack.local to true but I still get this error.
Not sure where I'm going wrong.
Please kindly help.
The error [browserstack.local] is set to true but local testing through BrowserStack is not connected. is returned if your BrowserStackLocal connection (the one you established using ./BrowserStackLocal --key --force-local) is disconnected.
I would suggest you use the following approach instead, to avoid the additional step and easily manage your local testing connection:
npm install browserstack-local
Once you have installed the browserstack-local module, use the following code snippet as reference to modify your code and start browserstack-local from your code itself(before the line driver = new webdriver.Builder().withCapabilities(capabilities).usingServer('http://hub-cloud.browserstack.com/wd/hub').build()), instead of starting it from a separate terminal window:
var browserstack = require('browserstack-local');
//creates an instance of Local
var bs_local = new browserstack.Local();
// replace <browserstack-accesskey> with your key. You can also set an environment variable - "BROWSERSTACK_ACCESS_KEY".
var bs_local_args = { 'key': '<browserstack-accesskey>', 'forceLocal': 'true' };
// starts the Local instance with the required arguments
bs_local.start(bs_local_args, function() {
console.log("Started BrowserStackLocal");
});
// check if BrowserStack local instance is running
console.log(bs_local.isRunning());
// stop the Local instance
bs_local.stop(function() {
console.log("Stopped BrowserStackLocal");
});

Sailsjs 0.10.3 - Heroku - RedisToGo - req.session undefined

When using sailsjs v0.10.3 with Redis To Go for session storage, req.session is always undefined.
It is undefined when I deploy both locally and to Heroku. req.session is correctly defined when I use the default memory adapter.
I created a sailsjs app:
sails new testapp
sails generate api test testSet testGet
Installed connect-redis v1.4.7:
npm install connect-redis#~1.4.7
Set the configuration in config/session.js:
adapter: 'redis',
host: 'hoki.redistogo.com',
port: 10015,
db: 'redistogo',
pass: '88819aa089d3dd86235f9fad4cb92e48'
Set the configuration in config/socket.js:
adapter: 'redis',
host: 'hoki.redistogo.com',
port: 10015,
db: 'redistogo',
pass: '88819aa089d3dd86235f9fad4cb92e48'
Created some controller actions which get and set a session value:
UserController.js
testSet: function (req, res) {
req.session.testVar = "I am the test var!";
return res.ok();
},
testGet: function (req, res) {
return res.json({
testVar: req.session.testVar
});
}
And finally deployed to Heroku:
git init
git add .
git commit -m "Initial commit"
heroku create
heroku addons:add redistogo
git push heroku master
git
This is the error:
error: Sending 500 ("Server Error") response:
TypeError: Cannot set property 'testVar' of undefined
at module.exports.testSet (/app/api/controllers/TestController.js:46:25)
It seems like this simple example should work.
Here is a repo of the example above:
https://github.com/derekbasch/sailsjs-redistogo-testapp
Does anyone know what I am doing wrong?
UPDATE:
I tried using the MemoryStore adapter on Heroku to get/set a session variable. That failed with undefined also. It works locally. Now I am even more confused.
We are using rediscloud (sails app on heroku) and the db property is set to 0. Could this be the problem?
Also, you should parse the URL provided by heroku via en env variables. This is what we use (coffeescript):
parseRedisUrl = ( url ) ->
parsed = require( 'url' ).parse( url )
password = (parsed.auth || '').split( ':' )[1]
hostname: parsed.hostname
port: parsed.port
password: password
redis = parseRedisUrl( process.env.REDISCLOUD_URL || "redis://localhost:6379" )
module.exports.session =
secret: '...'
adapter: 'redis'
host: redis.hostname
port: redis.port
pass: redis.password
db: 0
ttl: 60 * 60 * 24

Resources