I want to return the result of query to DB, which I think would be a promise and then consume that promise in another file.Here is my model code (User.js) :
User.prototype.login = function () {
return new Promise((resolve, reject) => {
pool.execute('SELECT * FROM `users` WHERE `username` = ? AND `password` = ?', [this.data.username, this.data.password], (err, attemptedUser) => {
if (err) {
pool.release();
return reject(err);
} else {
pool.release();
return resolve(attemptedUser);
}
});
});
}
and the code in my controller file (userController.js):
const User = require('../models/User');
exports.login = (req, res) => {
let user = new User(req.body);
user.login()
.then((result) => {
res.send(result);
})
.catch((err) => {
res.send(err);
});
};
But when I click on the login button the page doesn't go to the specified URL and keeps working until crash.
Where is the problem?
UPDATE-1
This is my db.js :
const mysql = require('mysql2/promise');
const dotenv = require('dotenv');
dotenv.config();
const pool = mysql.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
connectionLimit: 100
});
module.exports = pool;
Related
I get an error when running the integration tests:
0 passing (17s)
1 failure
1) Registration page
register new users allowed and update status in the database:
TypeError: Net.connect is not a function
at new Connection (webpack:///./node_modules/mysql2/lib/connection.js:50:0)
at ./node_modules/mysql2/index.js.exports.createConnection (webpack:///./node_modules/mysql2/index.js:10:0)
at Context.eval (webpack:///./cypress/integration/registration.spec.js:23:34)
Here is my environment:
MySQL Workbench
MySQL Server 8.0.29
I raised local backendless, I have access to the database. Here is my code:
const mysql2 = require('mysql2');
describe('Registration page', () => {
beforeEach(() => {
// visit the registration page
cy.visit('http://localhost:3000/registration');
});
it('register new users allowed and update status in the database', () => {
// fill out the registration form
cy.get('input[name="fullName"]').type("Nazar Dmytryshyn")
cy.get('input[type="email"]').type('testuser#example.com');
cy.get('input[name="pwd"]').type('testpassword');
cy.get('input[name="confirmPassword"]').type('testpassword');
// submit the form
cy.get('button[class="btn btn-success"]').click();
// check that the user is redirected to the login page
cy.url().should('include', '/login');
// create a connection to the test database
const connection = mysql2.createConnection({
host: '127.0.0.1:3306',
user: 'root',
password: 'rootpassword',
database: 'local1'
});
// open the connection
connection.connect();
// update the developer status in the database
connection.query(
'UPDATE `main_backendless`.`Developer` SET `developerStatusId` = "1" WHERE (`email` = "testuser#example.com")',
(error, results) => {
if (error) throw error;
expect(results.affectedRows).to.equal(1);
}
);
// close the connection
connection.end();
});
});
I checked this data 10 times, it is correct and I can connect to the database through MySQL WorkBench
host: '127.0.0.1:3306',
user: 'root',
password: 'rootpassword',
database: 'main_backendless'
I will be grateful for any ideas that can be achieved!
I recommend using the cypress-mysql, which hides a lot of the implementation details for you.
If you try to roll your own task, you may end up with an undefined return value.
Install
npm install cypress-mysql
//or
yarn add cypress-mysql
Configure
The release notes are out of date, here is the configuration for Cypress 10+
// cypress.config.js
const { defineConfig } = require("cypress");
const mysql = require('cypress-mysql');
module.exports = defineConfig({
// ...
e2e: {
setupNodeEvents(on, config) {
mysql.configurePlugin(on);
},
"env": {
"db": {
"host": "localhost",
"user": "user",
"password": "password",
"database": "database"
}
}
})
// cypress/support/e2e.js
const mysql = require('cypress-mysql');
mysql.addCommands();
Test
const sql = 'UPDATE "main_backendless.Developer" SET "developerStatusId" = "1" WHERE ("email" = "testuser#example.com")'
cy.query(sql).then(res => {
expect(res.affectedRows).to.equal(1)
});
If you want to use a task to call the mySql library, you must return a Promise from the task.
This is because the mysql calls are asynchronous, and the only way Cypress knows to wait for them is to get a promise returned from your code.
cypress.config.js
const { defineConfig } = require("cypress")
const mysql2 = require('mysql2')
const connection = mysql2.createConnection({
host: '127.0.0.1:3306',
user: 'root',
password: 'rootpassword',
database: 'local1'
})
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
on('task', {
mySql: (sql) => {
return new Promise((resolve, reject) => {
connection.query(sql, (error, results) => {
if (error) {
reject(error)
} else {
resolve(results.affectedRows)
})
})
})
}
})
},
})
it('tests with mysql', () => {
cy.task('mySql', 'sql staement here')
.then(result => {
expect(result).to.equal(1);
})
})
With Promise-wrapper
Alternatively, mysql2 provides a promise-wrapper that can simplify your code:
const { defineConfig } = require("cypress")
const mysql = require('mysql2/promise') // different import here
const connection = mysql2.createConnection({
host: '127.0.0.1:3306',
user: 'root',
password: 'rootpassword',
database: 'local1'
})
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
on('task', {
mySql: async (sql) => { // async here
const result = await connection.execute(sql) // await here
return result;
}
})
},
})
The issue is that you're using a nodejs library with Cypress. Cypress tests execute inside a browser and cannot directly utilize nodejs libraries within a test.
To do what you want to need to create a cy.task() to be able to execute code in nodejs.
Assuming you're using js, create a file with a function to use the sql connector
// runSql.js
const mysql2 = require('mysql2');
function runSql(sql) {
const connection = mysql2.createConnection({
host: '127.0.0.1:3306',
user: 'root',
password: 'rootpassword',
database: 'local1'
});
connection.connect();
let rows;
connection.query(sql, (error, results) => {
if (error) throw error;
rows = results.affectedRows
});
connection.end();
return rows;
}
module.exports = runSql;
Then in the cypress.config.js file
const runSql = require('./runSql.js');
module.exports = defineConfig({
// ...
e2e: {
setupNodeEvents(on, config) {
on('task', {
runSql
});
},
});
Now to call the task in a test
describe('Registration page', () => {
it('test', () => {
const sql = 'UPDATE `main_backendless`.`Developer` SET `developerStatusId` = "1" WHERE (`email` = "testuser#example.com")';
cy.task('runSql', sql).then((rows) => {
expect(rows).to.equal(1);
});
});
});
I get an error when running the integration tests:
0 passing (17s)
1 failure
1) Registration page
register new users allowed and update status in the database:
TypeError: Net.connect is not a function
at new Connection (webpack:///./node_modules/mysql2/lib/connection.js:50:0)
at ./node_modules/mysql2/index.js.exports.createConnection (webpack:///./node_modules/mysql2/index.js:10:0)
at Context.eval (webpack:///./cypress/integration/registration.spec.js:23:34)
Here is my environment:
MySQL Workbench
MySQL Server 8.0.29
I raised local backendless, I have access to the database. Here is my code:
const mysql2 = require('mysql2');
describe('Registration page', () => {
beforeEach(() => {
// visit the registration page
cy.visit('http://localhost:3000/registration');
});
it('register new users allowed and update status in the database', () => {
// fill out the registration form
cy.get('input[name="fullName"]').type("Nazar Dmytryshyn")
cy.get('input[type="email"]').type('testuser#example.com');
cy.get('input[name="pwd"]').type('testpassword');
cy.get('input[name="confirmPassword"]').type('testpassword');
// submit the form
cy.get('button[class="btn btn-success"]').click();
// check that the user is redirected to the login page
cy.url().should('include', '/login');
// create a connection to the test database
const connection = mysql2.createConnection({
host: '127.0.0.1:3306',
user: 'root',
password: 'rootpassword',
database: 'local1'
});
// open the connection
connection.connect();
// update the developer status in the database
connection.query(
'UPDATE `main_backendless`.`Developer` SET `developerStatusId` = "1" WHERE (`email` = "testuser#example.com")',
(error, results) => {
if (error) throw error;
expect(results.affectedRows).to.equal(1);
}
);
// close the connection
connection.end();
});
});
I checked this data 10 times, it is correct and I can connect to the database through MySQL WorkBench
host: '127.0.0.1:3306',
user: 'root',
password: 'rootpassword',
database: 'main_backendless'
I will be grateful for any ideas that can be achieved!
I recommend using the cypress-mysql, which hides a lot of the implementation details for you.
If you try to roll your own task, you may end up with an undefined return value.
Install
npm install cypress-mysql
//or
yarn add cypress-mysql
Configure
The release notes are out of date, here is the configuration for Cypress 10+
// cypress.config.js
const { defineConfig } = require("cypress");
const mysql = require('cypress-mysql');
module.exports = defineConfig({
// ...
e2e: {
setupNodeEvents(on, config) {
mysql.configurePlugin(on);
},
"env": {
"db": {
"host": "localhost",
"user": "user",
"password": "password",
"database": "database"
}
}
})
// cypress/support/e2e.js
const mysql = require('cypress-mysql');
mysql.addCommands();
Test
const sql = 'UPDATE "main_backendless.Developer" SET "developerStatusId" = "1" WHERE ("email" = "testuser#example.com")'
cy.query(sql).then(res => {
expect(res.affectedRows).to.equal(1)
});
If you want to use a task to call the mySql library, you must return a Promise from the task.
This is because the mysql calls are asynchronous, and the only way Cypress knows to wait for them is to get a promise returned from your code.
cypress.config.js
const { defineConfig } = require("cypress")
const mysql2 = require('mysql2')
const connection = mysql2.createConnection({
host: '127.0.0.1:3306',
user: 'root',
password: 'rootpassword',
database: 'local1'
})
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
on('task', {
mySql: (sql) => {
return new Promise((resolve, reject) => {
connection.query(sql, (error, results) => {
if (error) {
reject(error)
} else {
resolve(results.affectedRows)
})
})
})
}
})
},
})
it('tests with mysql', () => {
cy.task('mySql', 'sql staement here')
.then(result => {
expect(result).to.equal(1);
})
})
With Promise-wrapper
Alternatively, mysql2 provides a promise-wrapper that can simplify your code:
const { defineConfig } = require("cypress")
const mysql = require('mysql2/promise') // different import here
const connection = mysql2.createConnection({
host: '127.0.0.1:3306',
user: 'root',
password: 'rootpassword',
database: 'local1'
})
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
on('task', {
mySql: async (sql) => { // async here
const result = await connection.execute(sql) // await here
return result;
}
})
},
})
The issue is that you're using a nodejs library with Cypress. Cypress tests execute inside a browser and cannot directly utilize nodejs libraries within a test.
To do what you want to need to create a cy.task() to be able to execute code in nodejs.
Assuming you're using js, create a file with a function to use the sql connector
// runSql.js
const mysql2 = require('mysql2');
function runSql(sql) {
const connection = mysql2.createConnection({
host: '127.0.0.1:3306',
user: 'root',
password: 'rootpassword',
database: 'local1'
});
connection.connect();
let rows;
connection.query(sql, (error, results) => {
if (error) throw error;
rows = results.affectedRows
});
connection.end();
return rows;
}
module.exports = runSql;
Then in the cypress.config.js file
const runSql = require('./runSql.js');
module.exports = defineConfig({
// ...
e2e: {
setupNodeEvents(on, config) {
on('task', {
runSql
});
},
});
Now to call the task in a test
describe('Registration page', () => {
it('test', () => {
const sql = 'UPDATE `main_backendless`.`Developer` SET `developerStatusId` = "1" WHERE (`email` = "testuser#example.com")';
cy.task('runSql', sql).then((rows) => {
expect(rows).to.equal(1);
});
});
});
I have just started to work with node.js and my js knowledge is a bit rusty.
I started with callbacks and then I found out about promises. This syntax was more like my brain works, so I rewrote my code with promises.
But now my MySql connection does not work. It can't even get reached (I think...)
I have logged the word "test" in the file userDB, that worked. But then in the mySql file the console.log "test2" didn't work.
Thanks to you all!
Chris
Here is my server.js (the file that node starts):
/* REQUIRE */
const oAuth2Server = require('node-oauth2-server');
const express = require('express');
const bodyParser = require('body-parser');
const oAuthModel = require('./endpoints/auth/authModel');
const util = require('util');
const dbCon = require('./subsystem/mySql')
/* CONST */
const port = 3000;
const debug = true;
const app = express();
/* INIT */
app.oauth = oAuth2Server({
model: oAuthModel,
grants: ['password'],
debug: debug
})
/* ROUTER */
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(app.oauth.errorHandler());
const authRoutes = require('./router/auth')(express.Router(), app, dbCon)
app.use('/auth', authRoutes);
app.all('*', (req, res) => {
res.status(404).send({message: "This service was not found"});
});
/* Start Server */
app.listen(port, () => {
console.log(`listening on port ${port}`)
})
Here is my router file auth.js:
module.exports = (router, expressApp, dbCon) => {
const userDB = require('../endpoints/user/userDB')(dbCon)
const authMiddleware = require('../endpoints/auth/authMiddleware')
const userMiddleware = require('../endpoints/user/userMiddleware')(userDB)
router.post('/registerUser', userMiddleware.registerUser)
//router.post('/login', expressApp.oauth.grant(), authMiddleware.login)
router.post('/login', expressApp.oauth.grant())
return router
}
Here is my userDB file:
let mySqlConnection;
module.exports = injectedMySqlConnection => {
mySqlConnection = injectedMySqlConnection
return {
registerUserInDB: registerUserInDB,
getUserFromCrentials: getUserFromCrentials,
doesUserExist: doesUserExist,
getUserByUsername: getUserByUsername
}
}
const registerUserInDB = (username, password) => {
return new Promise((resolve,reject) => {
//execute the query to register the user
mySqlConnection.query(`INSERT INTO users (username, user_password) VALUES ('${username}', SHA('${password}'))`)
.then(data => {resolve(true)})
.catch(error => {reject(error)})
})
}
const getUserFromCrentials = (username, password) => {
return new Promise((resolve,reject) => {
//create query using the data in the req.body to register the user in the db
const getUserQuery = `SELECT * FROM users WHERE username = '${username}' AND user_password = SHA('${password}')`
console.log('getUserFromCrentials query is: ', getUserQuery);
//execute the query to get the user
mySqlConnection.query(getUserQuery)
.then(data => {resolve(data)})
.catch(error => {reject(error)})
})
}
const doesUserExist = username => {
return new Promise((resolve,reject) => {
console.log('test');
//execute the query to check if the user exists
mySqlConnection.query(`SELECT * FROM users WHERE username = '${username}'`)
.then(data => {resolve(data.results !== null ? data.results.length == 1 ? true : false : false)})
.catch(error => {reject(error)})
})
}
const getUserByUsername = username => {
return new Promise((resolve,reject) => {
//execute the query to check if the user exists
mySqlConnection.query(`SELECT id, username FROM users WHERE username = '${username}'`)
.then(data => {resolve(data)})
.catch(error => {reject(error)})
})
}
Here is my userMiddleware (is this middleware?):
let userDb;
module.exports = injectedUserDb => {
userDb = injectedUserDb
return {
registerUser: registerUser
}
}
function registerUser(req, res){
console.log(`authRoutesMethods: registerUser: req.body is:`, req.body);
//query db to see if the user exists already
userDb.doesUserExist(req.body.username)
.then(data => {
if(data)
{
sendResponse(res, "User already exists", 200)
return
}
else
{
//register the user in the db
userDb.registerUserInDB(req.body.username, req.body.password)
.then(data => {
userDb.getUserByUsername(req.body.username)
.then(data => {sendResponse(res, data.results, "")})
.catch(error => {sendResponse(res, "Failed to register user", error)})
})
.catch(error => {sendResponse(res, "Failed to register user", error)})
}
})
.catch(err => {
sendResponse(res, "User already exists", 200)
return
})
}
function sendResponse(res, message, error) {
res
.status(error !== null ? error !== null ? 400 : 200 : 400)
.json({
'message': message,
'error': error,
})
}
And last but not least my mySql.js file:
var mySql = require('mysql');
const query = sql => {
return new Promise( ( resolve, reject ) => {
let connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'oauth2test'
});
console.log('test2');
connection.query( sql, ( err, rows ) => {
if ( err )
{
connection.end();
reject( err );
}
else
{
connection.end();
resolve( rows );
}
});
});
}
module.exports.query = query;
You have a simple typo in your mySql.js file:
The line
var mySql = require('mysql');
should be replaced with
var mysql = require('mysql');
Other than that the query code works ok on my machine:
var mysql = require('mysql');
const query = sql => {
return new Promise( ( resolve, reject ) => {
let connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'oauth2test'
});
console.log('test2');
connection.query( sql, ( err, rows ) => {
if ( err )
{
connection.end();
reject( err );
}
else
{
connection.end();
resolve( rows );
}
});
});
}
module.exports.query = query;
This is simple testing code to get callbacks. I just want to ask how to release connection in case of error and because code goes to catch block.
Here is my code:
const express = require('express');
const mysql = require('mysql2');
const app = express();
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
database: 'mydb',
connectionLimit: 10
}).promise();
pool.getConnection()
.then(() => console.log('DB connected'))
.catch((err) => console.log(err));
app.get('/api/v1', async (req, res) => {
try {
const connection = await pool.getConnection();
const [rows, fields] = await connection.query('SELECT * FROM users WHERE is_active = ?', 'Y');
connection.release();
res.status(200).json({
message: 'success',
data: rows
});
} catch(error) {
res.status(404).json({
message: 'error',
error: error
});
}
});
app.listen(3000, console.log('Listening to 3000'));
I've a table in mysql that i need to be populated by calling a webservice.
The catch is, I would like to pass the data to be inserted into the database as parameters to the webservice.
How would I do this?
Using the MySQL module
http://npmjs.com/mysql
const mysql = require('mysql');
const express = require('express');
const app = express();
const connection = mysql.createConnection({
host: 'localhost',
user: 'me',
password: 'secret',
database: 'my_db'
});
connection.connect();
app.get('/', (req, res) => {
connection.query(`SELECT * FROM table`, (error, data) => {
if(error) {
console.log(error)
}else{
res.json(data)
}
});
});
app.post('/update/user/:id?', (req, res) => {
const id = req.params.id;
const username = req.body.username;
connection.query(`UPDATE MyGuests SET username='${username}' WHERE id=${id}`, (error, data) => {
if(error) {
console.log(error)
}else{
res.json(data)
}
});
});