Search code examples
mysqlnode.jscypressssh-tunnel

How do I connect mysql with cypress through ssh tunneling?


Currently cypress supports mysql connection without using ssh as seen in the link below

https://docs.cypress.io/api/commands/task#Allows-a-single-argument-only

But I am trying to connect cypress to mysql through an ssh tunneling. I am using the npm package mysql-ssh to establish the connection.

I am able to achieve this directly using node.js but I am facing issues while implementing through cypress. Here's the snippet I tried in node.js.

const mysqlssh = require('mysql-ssh');
const fs = require('fs');

mysqlssh.connect(
    {
        host: 'x.x.x.x',
        user: 'xyz',
        privateKey: fs.readFileSync('filePath')  //this is the ssh filePath
    },
    {
        host: 'HOST_NAME',
        user: 'USER_NAME',
        password: 'xxxx',
        database: 'DB_NAME'
    }
)
.then(client => {
    client.query('select * from TABLE_NAME',  function (err, results, fields) {
        if (err)
        {
            console.log(err)
        }
        console.log(results);
        mysqlssh.close()
    })
})
.catch(err => {
    console.log(err)
})

I want to do this either through the cypress/plugins/index.js file or directly in cypress/integration. Is there a simple way to do this?


Solution

  • I have found the solution. Here is my code for cypress/plugins/index.js file:

    const dotenvPlugin = require('cypress-dotenv');
    const mysqlssh = require('mysql-ssh');
    const fs = require('fs');
    
    module.exports = (on, config) => {
      //  `config` is the resolved Cypress config
        config = dotenvPlugin(config);
    
        on('task', {
            executeSql (sql, ...args) {
                return new Promise(async (resolve, reject) => {
                    try {
                        let connection = await mysqlssh.connect(  {
                                host: process.env.SSH_HOST,
                                user: process.env.SSH_USER,
                                privateKey: fs.readFileSync(process.env.HOME + '/.ssh/id_rsa_old')
                            },
                            {
                                host: process.env.MYSQL_HOST,
                                user: process.env.MYSQL_USER,
                                password: process.env.MYSQL_PASSWORD,
                                database: process.env.MYSQL_DB
                            });
                        let result = await connection.promise().query(sql, args);
                        mysqlssh.close();
                        resolve(result[0][0]); 
                    } catch (err) {
                        reject(err);
                    }
                });
            }
        })
    
        return config
    }
    

    So this connection has to be established in this file b/c cypress does not communicate with node process supplied by the host. So we need to use cypress tasks to run a Node code. see docs here - https://docs.cypress.io/api/commands/task#Examples

    And in a test file example, I used it like so:

    describe('Db Test',  () => {
        it('Query Test', () => {
            cy.task('executeSql', 'SELECT count(id) as cnt FROM table_name').then(result => {
                expect(result.cnt, 'Does not equal to 8').to.equal(2000);
            })
        })
    })
    

    P.S. Additional cypress-dotenv package is just used to load env vars from .env file.