Protractor + CucumberJS MySQL Query - asynchronous

Currently my automation framework uses protractor from cucumberJS. We use chai as promised as a assertion library, and I have recently come across a need to do direct mysql queries against a database.
How would I structure a step-definition to be able to get a query, and use the query results within the same step? My current struggles are the asynchronous way protractor is being run, causing me to perform the query after the step requiring the query results happens, and also the scope of which to pass the JSON Object that is created as a result of the query.
this.loginWithMysqlUser = function(uname) {
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : '*******',
password : '*******',
database : '*******'
});
connection.connect();
connection.query('SELECT * FROM prot_users WHERE username = ?', [uname], function(err, rows) {
if(err) throw err;
mysqlUser = {
username: rows[0].username,
password: rows[0].password
};
});
connection.end();
loginpage.login(mysqlUser);
};
This function resides on loginpage declaration.

So typically your cucumber test script would like:
Feature: As an admin I would like to check if a customer has an
account
Scenario: Check that customer name is registered in DB
Given that I am logged in as admin
And I wish to check that customer (foo) is registered
Then I expect following details from DB query:
| username | password | database |
| foo | bar | mysql |
with step definitions for:
Given(/^that I am logged in as admin$/, function(callback){
..
logic goes here
..
});
And(/^I wish to check that customer (foo) is registered$/,
function(username, callback){
// create connection with db as described
// with supplied username
// Use a promise to create mySQL connection
// and queries DB based on username as described
// on successful resolution set DBResult to results
// for username, password and database
// on error set DBResult to undefined
});
Then(/^I expect following details from DB query$/, function(data,
callback)
{
var rows = data.raw;
// extract values of input table cells into DBExpect using
// rows[0].username
// rows[0].password
// rows[0].database
// Check equality of DBResult and DBExpect objects
..
expect.isFulfilled(DBResult).toEqual(DBExpect).notify(callback);
});

I ended up containing all of the logic for the login and functions that needed to work with the data within the connection.query function.
Seemed to work ok, and protractor was able to be called from within that query function.

Related

Google App Maker how to apply custom data validation

App Maker has default validations and regular expression validation which will highlight the fields once the error occurs.
We have requirement to do custom validations to check duplicate records in models. Is there any function to check the validation or do we need to do any script?
The best way to avoid data duplication will be enforcing 'unique' constraint for your tables using Cloud SQL.
In case you don't want to use Cloud SQL and want to go with Drive Tables you can emulate unique constraint manually using locks, queries and model events:
// onCreate model event (actually it is onBeforeCreate)
// this events accepts about-to-create record as parameter
var lock = LockService.getScriptLock();
lock.waitLock(5000);
var query = app.models.MyModel.newQuery();
query.filters.SomeField._equals = record.SomeField;
var records = query.run();
if (records.length > 0) {
throw new Error('Record with SomeField value equal to ' + record.SomeField +
' already exists.');
}
lock.releaseLock();
You need lock here to prevent other threads concurrently creating records that will violate your unique constraint.
Then you can handle the error on UI in createItem function callback:
// create button onClick handler
widget.datasource.createItem({
success: function(record) {
// TODO
},
failure: function(error) {
// TODO
}
});

Angularfire 2.1 - How to access auto-generated ID for users (or how to make my UID the first node for each user)

Disclaimer, I am trying to self-teach myself development. I am building a hybrid mobile app using Ionic 1 and now Firebase 3 for my database and authentication.
For my scenario, in short, I'm trying to display a list of 'friends' for the user that is currently logged in. Here is the current data structure I have (the relevant part anyway):
Data Structure
I have a line of code that does return me what I want:
var friends = $firebaseArray(ref.child('users').child('-KXcxMXkKs46Xv4-JUgW').child('friends'));
Of course, that can't work because there is a nice little hard coded value in there.
So, I looked into how to retrieve the current UID so I could replace the hard coded value. But after running the following bit of code through, the first node under user is not the UID (it is some other auto generated value that I don't really know how it got there). The UID is actually within the id field.
var ref = firebase.database().ref();
authObj = $firebaseAuth();
var firebaseUser = authObj.$getAuth();
console.log(firebaseUser.uid);
So, ultimately what I would love is to be able to change the data structure so that the UID is the first node under Users, but I can't seem to find documentation to do that. I looked at this other stack thread, but it is for an outdated version and I can't seem to connect the dots. Other thread
Though, if I can't change the structure, I still need to figure out how to access that friends node for the current user, one way or another.
Thank you in advance. This is my first stackoverflow post, so be gentle.
Update:
Per Frank's comment, this is the code that I execute to create users - $add is what is creating the push id (-KXcxM...).
createProfile: function(uid, user) {
var profile = {
id: uid,
email: user.email,
registered_in: Date()
// a number of other things
};
var messagesRef = $firebaseArray(firebase.database().ref().child("users"));
messagesRef.$add(profile);
},
register: function(user) {
return auth.$createUserWithEmailAndPassword(user.email, user.password)
.then(function(firebaseUser) {
console.log("User created with uid: " + firebaseUser.uid);
Auth.createProfile(firebaseUser.uid, user);
Utils.alertshow("Success!","Your user has been registered.");
})
.catch(function(error) {
Utils.alertshow("Error.","Some helpful error message.");
console.log("Error: " + error);
});
}
Instead of creating a $firebaseArray and calling $add on it, you can just store the user using the regular Firebase JavaScript SDK:
createProfile: function(uid, user) {
var profile = {
id: uid,
email: user.email
};
firebase.database().ref().child("users").child(uid).set(profile);
}
Since AngularFire is built on top of the Firebase JavaScript SDK, the two interact nicely with each other. So if you have any existing $firebaseArray on users it will pick up the new profile too.

Firebase & IOS - cannot query immediately after adding user

I'm adding a new Auth user but then seem unable to query the database in the completion block for additional data. the same query works fine however in a different view controller.
FIRAuth.auth()?.createUserWithEmail(emailAddress.lowercaseString,
password: password, completion: { user, error in
if let validUser = user {
let newUsersRef = FIRDatabase.database().reference().child("users")
newUsersRef.queryOrderedByChild("body/email")
.queryEqualToValue(emailAddress.lowercaseString)
.observeSingleEventOfType(.Value, withBlock: { snapshot in ...
will return a null snapshot. I understood from the docs that users are immediately logged in when creating via createUserWithEmail.
what am I missing ?
thanks

Fetch data for record edit page

I have a page that lets you edit user data. I'm using FlowRouter for the routing and it can be found on the route /employees/:id.
I need to update the detail form when data changes on the server and leave the route if it was deleted by other client.
I decided to use Tracker.autorun which informs me whenever the data changes. The previous user info is stored on the template so it's easy to tell if the record was deleted.
Template.UpdateEmployee.onCreated(function () {
const self = this;
self.subscribe('user', FlowRouter.getParam('id'));
self.autorun(function () {
const _id = FlowRouter.getParam('id');
const user = Meteor.users.findOne({_id});
if(!user && self.user)
FlowRouter.go('/employees');
self.user = user;
if(!user)
return;
user.email = user.emails[0].address;
$('.ui.form').form('set values',user);
});
});
And lastly in the onRendered callback I'm checking if the data was set on template as I believe not doing so could lead to data being available before the template is rendered and hence values wouldn't get set properly. Is this correct?
Template.UpdateEmployee.onRendered(function () {
if(this.user){
user.email = user.emails[0].address;
$('.ui.form').form('set values',user);
}
});
Are there any pitfalls to this solution?
I can see a couple drawbacks inherently. The first one is doing a find query on the client. Typically you would want to return data from the server using Meteor publish and subscribe.
The second is you are passing the key to find the data over the URL. This can be spoofed by other users for them to find that users data.
Lastly if you are doing a find on the user object, I assume you might be storing data there. This is generally bad practice. If you need to store user data with their profile, it's best to create a new collection and publish/subscribe what you need.

Meteor user name based on userId

I am saving logged in userId with each record saved in my Meteor app collection as shown in the example below, yet I was wondering if there was any way in Meteor where I can retrieve user name based on the user saved id without have to make another query on the users collection? In Node.js / mongoose there was this Populate function, but I can't seem to find similar package / function in Meteor. So I was wondering if someone can help me by suggesting a resolution to this problem (if any). thanks
var newInvoice = {
customerid: $(e.target).find('[name=customer]').val(),
userid: Meteor.userId(),
//....more fields here
}
Meteor.call('saveInvoice', newInvoice, function(error, id){
if(error)
return alert(error.reason);
});

Resources