Removing created records in e2e tests after all tests have run - angularjs

I have been looking around for suitable ways to 'clean up' created records after tests are run using Protractor.
As an example, I have a test suite that currently runs tests on create and update screens, but there is currently no delete feature, however there is a delete end point I can hit against the backend API.
So the approach I have taken is to record the id of the created record so that in an afterAll I can then issue a request to perform a delete operation on the record.
For example:
beforeAll(function() {
loginView.login();
page.customerNav.click();
page.customerAddBtn.click();
page.createCustomer();
});
afterAll(function() {
helper.buildRequestOptions('DELETE', 'customers/'+createdCustomerId).then(function(options){
request(options, function(err, response){
if(response.statusCode === 200) {
console.log('Successfully deleted customer ID: '+ createdCustomerId);
loginView.logout();
} else {
console.log('A problem occurred when attempting to delete customer ID: '+ createdCustomerId);
console.log('status code - ' + response.statusCode);
console.log(err);
}
});
});
});
//it statements below...
Whilst this works, I am unsure whether this is a good or bad approach, and if the latter, what are the alternatives.
I'm doing this in order to prevent a whole load of dummy test records being added over time. I know you could just clear down the database between test runs, e.g. through a script or similar on say a CI server, but it's not something I\we have looked into further. Plus this approach seems on the face of it simpler, but again I am unsure about the practicalities of such an approach directly inside the test spec files.
Can anyone out there provide further comments\solutions?
Thanks

Well, for what it's worth I basically use that exact same approach. We have an endpoint that can reset data for a specific user based on ID, and I hit that in a beforeAll() block as well to reset the data to an expected state before every run (I could have done it afterAll as well, but sometimes people mess with the test accounts so I do beforeAll). So I simply grab the users ID and send the http request.
I can't really speak to the practicality of it, as it was simply a task that I accomplished and it worked perfectly for me so I saw no need for an alternative. Just wanted to let you know you are not alone in that approach :)
I'm curious if other people have alternative solutions.

The more robust solution is to mock your server with $httpBackend so you don't have to do actual calls to your API.
You can then configure server responses from your e2e test specs.
here's a fake server example :
angular.module('myModule')
.config(function($provide,$logProvider) {
$logProvider.debugEnabled(true);
})
.run(function($httpBackend,$log) {
var request = new RegExp('\/api\/route\\?some_query_param=([^&]*)');
$httpBackend.whenGET(request).respond(function(method, url, data) {
$log.debug(url);
// see http://stackoverflow.com/questions/24542465/angularjs-how-uri-components-are-encoded/29728653#29728653
function decode_param(param) {
return decodeURIComponent(param.
replace('#', '%40').
replace(':', '%3A').
replace('$', '%24').
replace(',', '%2C').
replace(';', '%3B').
replace('+', '%20'));
}
var params = url.match(request);
var some_query_param = decodeURIComponent(params[1]);
return [200,
{
someResponse...
}, {}];
});
});
Then load this script in your test environnement and your done.

Related

Meteor with query on publication is not reactive

I have a problem with a meteor publication not being reactive when using a query inside it.
Let's say I have many files, and each file has many projects, so I can go to the route:
http://localhost:3000/file/:file_id/projects
And I would like to both display the projects of the selected file and add new projects to it.
I am currently using angularjs, so the controller would look something like this:
class ProjectsCtrl {
//some setup
constructor($scope, $reactive, $stateParams){
'ngInject'
$reactive(this).attach($scope)
let ctrl = this
//retrieve current file id
ctrl.file_id = Number($stateParams.file)
//get info from DB and save it in a property of the controller
ctrl.subscribe('projects', function(){return [ctrl.file_id]}, function(){
ctrl.projects = Projects.find({file_id: ctrl.file_id}).fetch()
})
//function to add a new project
ctrl.addProject = function(){
if(ctrl.projectName){
Meteor.call('projects.insert', {name: ctrl.projectName, file_id: ctrl.file_id }, function(error, result){
if(error){
console.log(error)
}else{
console.log(result)
}
})
}
}
}
}
The publication looks something like this:
Meteor.publish('projects', function(file_id){
return Projects.find({file_id: file_id})
})
The problem is that, if I insert a new project to the DB the subscription doesn't run again, I mean the array stays the same instead of displaying the new projects I am adding.
I got many problems with this as I thought that meteor would work something like: "Oh there is a new project, let's re run the query and see if the publication change, if it does, let's return the new matching documents"... but no.
I have not found a problem similar to mine as every question regardind querys inside the publication is about how to reactively change the query (the file_id in this case) but that is not the problem here as I don't change the file_id unless I go to another route, and that triggers a new subscription.
My current solution is to expose the complete collection of projects and make the query using minimongo, but I don't know if it is a good workaround (many projects exposed uses too much memory of the browser, minimongo is not as fast as mongo... etc, I don't really know).
Your issue is that the Meteor.subscribe call doesn't know that file_id has changed. There's no reactive relationship between that argument and executing the subscription.
To fix this, whenever you are passing criteria in publish-subscribe, you must write a subscription of Collection inside a tracker.
To know more about trackers, Click here.
While I'm unsure how to do this in Angular, consider this simple Blaze template as an example:
Template.Name.onCreated(function(){
this.autorun(() => {
Meteor.subscribe('projects', file_id);
});
});
Whenever file_id changes, a new subscription is triggered, giving you the desired effect of auto pub-sub utility.
I hope this will give you some insight. It could be easily achieved via Angular JS as well.

Angularjs 1: delete an item, but item still exist until refresh

Here is my simple angular 1 app.
Source code here.
Basically it is a copy of this.
I am able to do CRUD operations. The issue is that, when I delete a record. It redirects back to the home page. The record I deleted is still here. If I refresh the page, it is gone.
Is it a way to delete a record and then after redirect, I should see the latest list?
Update 1:
Unfortunately, it is still unresolved. Something strange that it seems the promise in resolve is cached. I added a few console.log inside the code. You can see the code flow. Open chrome developer tool to see it.
i review you code , the problem is here:
this.deleteContact = function(contactId) {
var url = backend_server + "/contacts/" + contactId;
// actually http delete
return $http.delete(url)
.then(function(response) {
return response;
}, function(response) {
alert("Error deleting this contact.");
console.log(response);
});
}
if you have service to manage your contact use there to call your server to delete the contact.
the reason you cannot delete without refresh is:
your delete from DB but not from angular array.
must review (update the scope (array))
your code is hard to read , i have suggestion for you, using:
broserfy , watchify
lodash
and backen use mvc
You delete it remotely but not locally. So you can see result only after refreshing (only after you requesting updated data from server). You need to update your local contacts after you succeed on server side.
$scope.deleteContact = function(contactId) {
Contacts.deleteContact(contactId).then(function(data){
...
//DELETE YOU LOCAL CONTACT HERE
...
$location.path("/");
});
}
I didn't look deeply into your code, so I can't say how exactly you should do it, but as I see you keep your local contacts in $scope.contacts in your ListController.

GET call failing in AngularJS resource - Strange data result

I have a simple angular resource that I've defined as below:
CompanyService.factory('CompanyService',
function ($resource) {
return $resource('https://baseurl.com/api/values/');
}
);
I then have a controller that calls that resource passing in a success and fail function:
.controller('companyList', function($scope, CompanyService) {
$scope.companies = CompanyService.query(
function(data) {
console.log(data);
return data;
},
function(error){
console.log("Error:");
console.log(error);
}
);
The rest API is a .NET MVC Web API that is extremely basic. I've configured it to return JSON and it simply returns an array of two objects like below. I've also enabled CORS so my angular app, which is hosted in a different domain, can call the api.
[{ID:1, Name:"TEST1"}, {ID:2, Name:"TEST2"}]
I've tested the REST call using jquery and just straight call through browser. All was functional (including the cross site scripting when calling from my angular app just using a straight JavaScript HTTP call).
When I try to call the api from my controller however, it always ends up in the error function. The error object contains a data property that is always populated with the string "resource is required|resource is required|undefined"
When I check the network I see no call to the values end point. It's as if the call is failing before ever being made.
If I change out the url to point to some sample REST api like https://jsonplaceholder.typicode.com/users/ it works fine and I'm able to see the call to "users" in the network traffic, which makes me think there is something wrong with my C# REST endpoint, however all my tests to call the REST endpoint outside of angular work successfully.
Can anyone help? I can't find anyone reporting this issues before anywhere on the net.
should the code be the one below? i didn't test it, just guess.
myModule.factory('CompanyService',
function ($resource) {
return $resource('https://baseurl.com/api/values/');
}
)
.controller('companyList', function($scope, CompanyService) {
CompanyService.query(
function(data) {
$scope.companies = data;
console.log(data);
return data;
},
function(error){
console.log("Error:");
console.log(error);
}
);
I ended up rebuilding my angular app from scratch. My first app was from the angular-seed github and had a handful of libraries already added in for testing and other things. One of those things is was was leading to this error as once I started a new project completely from scratch and added in angular and my REST call things worked perfectly. I've already spent too much time working through this so not going to spend any more time identifying exactly what it is but in case anyone else runs into the problem I did want to answer this one and close the book on it.

Braintree Dropin UI does not work with Ionic Framework unless force refresh

I encounter a very strange behavior with Braintree dropin UI inside Ionic framework.
So I use the solution: Can't create Braintree client token with customer ID
to create the logic for the first time and the return customer.
$http({
method: 'POST',
url: 'http://localhost:3000/api/v1/token',
data: {
customerId: braintreeReturnCustomerId
}
})
As I passed in the customerId in my client view. In my nodejs server, I has a logic to check to see if customerId is undefined. If it is undefined, it is first time customer. If customerId has value, it is return customer. Very straight forward like so:
app.post('/api/v1/token', jsonParser, function (request, response) {
var customerId = request.body.customerId;
if (customerId == undefined) {
gateway.clientToken.generate({}, function (err, res) {
if (err) throw err;
response.json({
"client_token": res.clientToken
});
});
} else {
console.log ("using exsiting customer!");
gateway.clientToken.generate({
customerId: customerId
}, function (err, res) {
if (err) throw err;
response.json({
"client_token": res.clientToken
});
});
}
});
My client is in an Ionic View. So when I pay it the first time, it knows it is frist time user, then generate customerId for me and I store it in my database. All good. Then WITHOUT refreshing (as Ionic app do not refresh when state change), I go to a different state and go back to the payment state, it does not show the store credit card. Even my server log the customerId and I know FOR SURE the server code is running the "else" part with gateway.clientToken.generate({customerId: customerId} ...
If I force refresh in the view like using
$window.location.reload(true);
right after the first time payment successfully or I just manually refresh the page in my chrome browser (as I am in Ionic Serve), the payment Dropin UI page will show store credit card from the first time payment.
I try disable view caching like "cache: false". But it does not help. I have to force refresh to make the Dropin UI works for the second time. I think it is the javascript code in dropin UI causing this issue but I do not know how to fix it...
Full disclosure: I work at Braintree. If you have any further questions, feel free to contact support.
The approach you've posted is extremely unsafe as it is vulnerable to Insecure Direct Object Reference (OWASP Top 10) and can easily result in cross-user charging by a nefarious user. You've essentially allowed any user to use your server to generate client tokens for any customer.
Instead, you should only generate tokens on the server to avoid user agents from choosing the id of another user. Then serve up customer ids based on a user's credentialed login and not allow them to pass in parameters to be used during clientToken generation. There are many guides online on how to build authentication. But once you have the user created on the server you can:
if (userSession == undefined) {
//or force login if you want them to sign up for your site before buying things
gateway.clientToken.generate({}, function (err, res) {
if (err) throw err;
response.json({
"client_token": res.clientToken
});
});
} else {
console.log ("using exsiting customer!");
gateway.clientToken.generate({
customerId: userSession.user.BraintreeId
}, function (err, res) {
if (err) throw err;
response.json({
"client_token": res.clientToken
});
});
}
Whatever you do don't use this code, as-is, in production. I wouldn't advise debugging the front-end until you've rebuilt to fix this vulnerability as the approach will be quite different. However, if you do come back to this problem again it looks like there might be an open issue related this behavior.

Redis: Wrong data in wrong tables

I am trying to solve a problem that has been blocking me for a month
I am bulding the backend of an application using Node.js & Redis and due to our structure we have to transfer data from one redis table to another (What I mean by table is the one's that we use "select" i.e. "select 2")
We receive a lot of request and push a lot of response in a sec, and no matter how much I tried I could not stop data getting mixed. Assume we have a "teacherID" that has to be stored inside Redis table #2. And a "studentID" that has to be stored in Redis table #4. How matter what I tried (I've checked my code multiple times) I could not stop teacherID getting into studentID. The last trick I've tried was actually placing callback at each select.;
redisClient.select(4, function(err) {
if(err)
console.log("You could not select the table. Function will be aborted");
else {
// Proceed with the logic
}
});
What could be the reason that I cannot simply stop this mess ? One detail that drivers me crazy is that it works really well on local and also online however whenever multiple request reach to server it gets mixed. Any suggestions to prevent this error? (Even though I cannot share the code to NDA I can make sure that logic has been coded correctly)
I'm not sure about your statement about having to "transfer data from one redis table to another". Reading through your example it seems like you could simply have two redis clients that write to different databases (what you called "tables").
It would look similar to this:
var redis = require("redis");
var client1 = redis.createClient(6379, '127.0.0.1');
var client2 = redis.createClient(6379, '127.0.0.1');
client1.select(2, function(err){
console.log('client 1 is using database 2');
});
client2.select(4, function(err){
console.log('client 2 is using database 4');
});
Then, wherever your read/write logic is, you just use the appropriate client:
client1.set("someKey", "teacherID", function(err){
// ...
});
client2.set("someKey", "studentID", function(err){
// ...
});
You can obviously encapsulate the above into functions with callbacks, nest the operations, use some async library, etc. to make it do whatever you need it to do. If you need to transfer values from database 2 to database 4 you could do a simple client1.get() and client2.set().

Resources