I have javascript:
$('#link').on('click', function ()
{
console.log('Click link');
});
And i write dalekjs-test:
module.exports = {
'Clicked link': function (test)
{
test.open('http://localhost/')
.click('#link')
.done();
}
};
And after running $ dalek tests/test.js i wanna see that Click link.
How can i get it?
This is currently not possible & I do not know if it will be possible in the future.
The thing is, you have to overwrite the console object in the browser. That would mean, you have to actively change something in the environment of your user. And I don't think that this is a good idea.
Although, there might be a workaround for your Problem ;)
Lets say, you write a debugging function (as a client side javascript file) like this:
window.myDebugLog = [];
window.myDebug = function () {
var list = Array.prototype.slice.call(arguments, 0);
window.myDebugLog.push(list);
}
Now, lets modify your logging function a bit:
$('#link').on('click', function () {
var msg = 'Click link';
console.log(msg);
window.myDebug(msg);
});
With this you can access & output your logging. Even better, with some ClojureCompiler or Esprima fun, you could parse out that debugging stuff when building your production code, so that you do not need to ship it.
In your Dalek test, just do this:
module.exports = {
'Clicked link': function (test) {
test.open('http://localhost/')
.click('#link')
.execute(function () {
this.data('logs', window.myDebugLog);
})
.log.message(function () {
return JSON.stringify(test.data('logs').pop());
})
.done();
}
};
That will give you your log stuff in the Command Line Output.
If you´re not willing to add this extra function call, you could also overwrite the console.log on your own. But that could cause some trouble, so take this with a grain of salt:
window.myDebugLog = [];
window.oldLog = console.log;
console.log = function () {
var list = Array.prototype.slice.call(arguments, 0);
window.myDebugLog.push(list);
window.oldLog.apply(console, list);
};
Hope that helps you with your problem.
Related
Context : I am using a Collection Params to call method from the Server to a C app. The C app does its stuff and then calls the server by RPC to send me the results. With the result, I get the Params ID to delete the corresponding element.
With the deletion of the Element of Params, the C app gets a removed message. I want to prevent this behavior to avoid overloading the C app of messages.
I've thinked about implementing the removed event into the Publish method on the server to prevent the server from informing the C app. I just want the C app to be inform about added events.
On the Meteor Doc, there is an example of implementation of added and removed but I don't understand it. Can someone help me ?
I've tried this (don't work at all) :
Meteor.publish('expert_mode_parameters', function ()
{
var self = this;
var handle = Expert_Mode_Parameters.find().observeChanges({
added: function ()
{
return Expert_Mode_Parameters.find();
},
removed: function ()
{
return [];
}
});
self.ready();
self.onStop(function () {
handle.stop();
});
}
It looks like your goal is to subscribe to a data set but only receive added messages, not changed or removed.
The below code should do this:
Meteor.publish('expert_mode_parameters', function () {
var self = this;
var handle = Expert_Mode_Parameters.find().observe({
added: function (document) {
self.added("expert_mode_parameters", document._id, document);
}
});
self.ready();
self.onStop(function () {
handle.stop();
});
}
The concept is, you're watching the results of Expert_Mode_Parameters.find() and then calling self.added(document) when there is a new item. The same thing can easily be expanded to include changed.
i'm having issues with wrapAsync + method + sessions.
How do I implement the WrapAsync correctly?
I want, in a template to know if the user has at least one item created by him. And then define whether or not he can create another item.
Now i'm getting this error:
W20141013-15:04:43.237(-3)? (STDERR) Error: Can't wait without a fiber
But, I could not find Fiber at Documentation. And for implementing this, is it really necessary?
On the client side I want something like:
//pagina.js
Template.pagina.helpers{
userHasItem: return Session.get('userHasItem');
}
//pagina.js
Meteor.call('userHasItem', Meteor.userId(), function (error,result) {
Session.set('userHasItem', result);
});
//at server side:
if(Meteor.isServer){
Meteor.startup(function () {
var userHasItemAsync = function (userId) {
setTimeout(function () {
if (Items.findOne({'userId': userId})) {
return true;
} else {
return false;
}
}, 4000);
};
Meteor.methods({
userHasItem: function(userId) {
var userHasItemSync = Meteor.wrapAsync(userHasItemAsync),
result;
try {
userHasItemSync(userId);
console.log(result);
return result;
}catch (e) {
console.log('erreur', e.message);
throw new Meteor.Error(500, e);
}
},
}
});
}
Can't get your error to reproduce based on the existing code.
Still, userHasItemAsync is not available because you've defined it locally in the Meteor.startup function. But the error you should get in this case is userHasItemAsync is undefined.
Also the code you've entered here has multiple errors (i guess you typed it in not copy / pasted from your project): template instead of Template, Template it's defined outside of isClient (probably it's in a file available for the client) etc. Because of that it's hard to reproduce your exact case.
There is no need to call a server method to see if the item exists (assuming you have set up the proper publications/subscriptions), nor any need to call wrapAsync. In fact, what you want to achieve doesn't even require a session. All of the code can be ultimately distilled to this:
Template.pagina.helpers{
userHasItem: return Items.find({ userId: Meteor.userId() }).count() > 0;
}
The cursor returned by Items.find is reactive in itself, so there is no need for using a Session.
i have followed this tutorial from Codelab and yeoman. When implemented right you are using local storage to store the TodoList. I have problems with setting up with my tests, to test if this works. This is what i've got so far:
'use strict';
describe('Controller: MainCtrl', function () {
// load the controller's module
beforeEach(module('yeoTodoApp'), module('LocalStorageModule'));
var MainCtrl,
scope;
// Initialize the controller and a mock scope
beforeEach(inject(function ($controller, $rootScope, $httpBackend) {
scope = $rootScope.$new();
MainCtrl = $controller('MainCtrl', {
$scope: scope
});
}));
it('should add items to the list', function () {
var beforeLength = scope.todos.length;
scope.todo = 'Test 1';
scope.addTodo();
var afterLength = scope.todos.length;
expect(afterLength-beforeLength).toBe(1);
});
it('should add items to the list then remove', function () {
var beforeLength = scope.todos.length;
scope.todo = 'Test 1';
scope.addTodo();
scope.removeTodo(0);
var afterLength = scope.todos.length;
expect(afterLength-beforeLength).toBe(0);
});
});
The error i get is
line 12 col 68 '$httpBackend' is defined but never used.
});
How would i write my unit tests to sit the local storage?
I think at the moment the idea is kind of mocking your local storage:
Write unit tests
For an extra challenge, revisit unit testing in Step 8 and consider
how you might update your tests now that the code is using local
storage.
Tip: It's not a straight forward answer and involves knowing about
mock services. Check out Unit Testing Best Practices in AngularJS,
specifically the Mocking Services and Modules in AngularJS section.
Things may have changed since this question was asked. Anyhow, here is my solution:
'use strict';
describe('Controller: MainCtrl', function () {
// load the controller's module
beforeEach(module('mytodoyoappApp'));
var MainCtrl,
scope,
localStorage, store;
// Initialize the controller and a mock scope
beforeEach(inject(function ($controller, $rootScope) {
scope = $rootScope.$new();
MainCtrl = $controller('MainCtrl', {
$scope:scope
// place here mocked dependencies
});
/*mock the localStorageService*/
store={};
localStorage = {
set: function(key, value) {
store[key] = value;
},
get: function(key) {
return store[key];
}
};
}));
it('should check the list length', function () {
expect(MainCtrl.todos.length).toBe(0);
});
it('should add items to the list', function () {
MainCtrl.todoadded = 'Test 1';
MainCtrl.addTodo();
expect(MainCtrl.todos.length).toBe(1);
});
it('should add then remove an item from the list', function () {
MainCtrl.todoadded = 'Test 2';
MainCtrl.addTodo();
MainCtrl.removeTodo(0);
expect(MainCtrl.todos.length).toBe(0);
});
it('should check that the localstorage is undefined before being set', function() {
var a=localStorage.get('todos');
expect(a).toBeUndefined();
});
it('should set and get the localstorage', function() {
localStorage.set('todos', ['Test 3']);
var a=localStorage.get('todos');
expect(a).toEqual(['Test 3']);
localStorage.set('todos', ['Test 4']);
var b=localStorage.get('todos');
expect(b).toEqual(['Test 4']);
});
});
your setup is correct now (after you removed $httpBackend from the arguments list)
Controller: MainCtrl should add items to the list then remove FAILED
this error is a simple test error, which means that your code somewhere doesnt work as expected (your second test fails)
i for myself would check todos length, and not the result of a mathematical operation.
i would write your tests the test like this:
it('should add items to the list then remove', function () {
scope.todo = 'Test 1';
expect(scope.todos.length).toBe(0);
scope.addTodo();
expect(scope.todos.length).toBe(1);
scope.removeTodo(0);
expect(scope.todos.length).toBe(0);
});
you use jasmine as a test-tool. jasmine logs on errors exactly which expectation fails, so you should get something like
expect '1' to be '0'
go from there!
I'm using balanced-payments and their version 1.1 of balanced.js within Meteor.
I'm trying to create a new customer using
balanced.marketplace.customers.create(formData);
Here is my CheckFormSubmitEvents.js file
Template.CheckFormSubmit.events({
'submit form': function (e, tmpl) {
e.preventDefault();
var recurringStatus = $(e.target).find('[name=is_recurring]').is(':checked');
var checkForm = {
name: $(e.target).find('[name=name]').val(),
account_number: $(e.target).find('[name=account_number]').val(),
routing_number: $(e.target).find('[name=routing_number]').val(),
recurring: { is_recurring: recurringStatus },
created_at: new Date
}
checkForm._id = Donations.insert(checkForm);
Meteor.call("balancedCardCreate", checkForm, function(error, result) {
console.log(result);
// Successful tokenization
if(result.status_code === 201 && result.href) {
// Send to your backend
jQuery.post(responseTarget, {
uri: result.href
}, function(r) {
// Check your backend result
if(r.status === 201) {
// Your successful logic here from backend
} else {
// Your failure logic here from backend
}
});
} else {
// Failed to tokenize, your error logic here
}
// Debuging, just displays the tokenization result in a pretty div
$('#response .panel-body pre').html(JSON.stringify(result, false, 4));
$('#response').slideDown(300);
});
}
});
Here is my Methods.js file
var wrappedDelayedFunction = Async.wrap(balanced.marketplace.customers.create);
Meteor.methods({
balancedCardCreate: function (formData) {
console.log(formData);
var response = wrappedDelayedFunction(formData);
console.log(response);
return response;
}
});
I get nothing back when I submit the form, except that on the server console I do see the log of the form data.
I'm sure I'm not calling some of these async functions correctly. The hard part for me here is that the balanced function are async, but I don't know if they fit into the same mold as some of the examples I've seen.
I've tried to follow this example code.
http://meteorhacks.com/improved-async-utilities-in-meteor-npm.html
Is there a specific change that needs to be done in regard to working with balanced here? Does anyone have any tips for working with Async functions or see something specific about my code that I've done wrong?
Thanks
The NPM utilities Async.wrap does the same thing as the undocumented Meteor function Meteor._wrapAsync, in that it takes an asynchronous function with the last argument function(err, result) {} and turns it into a synchronous function which takes the same arguments, but either returns a result or throws an error instead of using the callback. The function yields in a Fiber until the asynchronous callback returns, so that other code in the event loop can run.
One pitfall with this is that you need to make sure that the function you wrap is called with the correct context. So if balanced.marketplace.customers.create is a prototype method that expects this to be set to something, it will not be set properly unless you bind it yourself, using function.bind or any of the other various library polyfills.
For more information, see https://stackoverflow.com/a/21542356/586086.
What I ended up doing was using a future. This works great, I just need to do better at catching errors. Which will be a question for a pro I think ; - )
Credit should go to user3374348 for answering another similar question of mine, which solved both of these.
https://stackoverflow.com/a/23777507/582309
var Future = Npm.require("fibers/future");
function extractFromPromise(promise) {
var fut = new Future();
promise.then(function (result) {
fut["return"](result);
}, function (error) {
fut["throw"](error);
});
return fut.wait();
}
Meteor.methods({
createCustomer: function (data) {
balanced.configure(Meteor.settings.balancedPaymentsAPI);
var customerData = extractFromPromise(balanced.marketplace.customers.create({
'name': data.fname + " " + data.lname,
"address": {
"city": data.city,
"state": data.region,
"line1": data.address_line1,
"line2": data.address_line2,
"postal_code": data.postal_code,
},
'email': data.email_address,
'phone': data.phone_number
}));
var card = extractFromPromise(balanced.marketplace.cards.create({
'number': data.card_number,
'expiration_year': data.expiry_year,
'expiration_month': data.expiry_month,
'cvv': data.cvv
}));
var associate = extractFromPromise(card.associate_to_customer(customerData.href).debit({
"amount": data.total_amount*100,
"appears_on_statement_as": "Trash Mountain" }));
});
As Andrew mentioned, you need to set the context for the method.
Here's the way you can do that with Async.wrap
Async.wrap(balanced.marketplace.customers, "create");
I'm trying to do some validation prior to loading the main page. To do this I need to find a document that I have confirmed, exist in the Mongo Collection. Unfortunately finding the document in the client.js doesn't seem to work. In my opinion the client and server collection are not in sync. Based on similar articles i have read I made many changes without success. Here is a quick summary of what I have tried.
Option1: Try to find the record in the client side and not using auto-subscribe: record not found.
In app.js
credentialToken = "2KcNCRzpTHzyZ1111";
if (Meteor.isClient) {
Template.hello.greeting = function () {
return "Welcome to ares_sso.";
};
Meteor.startup(function () {
var results = Meteor.findrec(credentialToken);
console.log("results:",results); //results is undefined.
});
Template.hello.events({
'click input': function () {
if (typeof console !== 'undefined')
console.log("You pressed the button");
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
In /client/app.js
crs_collection = new Meteor.Collection("crs");
Meteor.subscribe("crs");
Meteor.findrec = function(credentialToken) {
target = {credentialtoken:credentialToken};
recfound = crs_collection.findOne(target);
//No luck with find either.
//recfound = crs_collection.find({credentialtoken:credentialToken}, {limit:1}).fetch()[0];
console.log("recfound:",recfound); //returns recfound is undefined.
return recfound;
}
In /server/server.js
crs_collection = new Meteor.Collection("crs");
Meteor.publish("crs", function(){
return crs_collection.find();
});
Option2: Next I did the find in the server side, using a method "server_recfind" which worked but I'm not able get the content to the client.
In app.js
credentialToken = "2KcNCRzpTHzyZ1111";
if (Meteor.isClient) {
Template.hello.greeting = function () {
return "Welcome to ares_sso.";
};
Meteor.startup(function () {
var results = Meteor.call('server_findrec',credentialToken);
console.log("results=",results); // also returns undefined
});
Template.hello.events({
'click input': function () {
if (typeof console !== 'undefined')
console.log("You pressed the button");
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
In /client/app.js
crs_collection = new Meteor.Collection("crs");
Meteor.subscribe("crs");
In /server/app.js
crs_collection = new Meteor.Collection("crs");
Meteor.publish("crs", function(){
return crs_collection.find();
});
// Using Sync which finds the record but how do I sent the content to the client?
Meteor.methods ({
'server_findrec': function(credentialToken) {
// tried unblock but didnt work
//this.unblock();
var rec = crs_collection.findOne({'credentialtoken': credentialToken});
console.log("INSIDE server findrec rec=",rec); //shows content found
// tried flush but it didn't do anything
crs_collection.flush;
return rec; //rec not returning to the client
}
})
Option3: Frustrated and since I was able to find the document record with the server method. I tried adding global variables to delivery the content to the client side. Unfortunately it didn't work
In app.js
credentialToken = "2KcNCRzpTHzyZ1111";
//added global variables
c1 = '';
c2 = '';
c3 = ''
if (Meteor.isClient) {
Template.hello.greeting = function () {
return "Welcome to ares_sso.";
};
Meteor.startup(function () {
var results = Meteor.call('server_findrec',credentialToken);
console.log("results=",results); // also returns undefined
console.log("c1=",c1);
console.log("c2=",c2);
console.log("c3=",c3);
});
Template.hello.events({
'click input': function () {
if (typeof console !== 'undefined')
console.log("You pressed the button");
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
In /client/app.js
crs_collection = new Meteor.Collection("crs");
Meteor.subscribe("crs");
In /server/app.js
crs_collection = new Meteor.Collection("crs");
Meteor.publish("crs", function(){
return crs_collection.find();
});
// Using Sync which finds the record but how do I sent the content to the client?
Meteor.methods ({
'server_findrec': function(credentialToken) {
// tried unblock but didnt work
//this.unblock();
var rec = crs_collection.findOne({'credentialtoken': credentialToken});
console.log("INSIDE server findrec rec=",rec); //shows content found
c1 = rec.cont1;
c2 = rec.cont2;
c3 = rec.cont3;
//confirm that c1,c2 and c3 have content
console.log(In server_findrec c1=",c); //shows content
console.log(In server_findrec c2=",c2); //shows content
console.log(In server_findrec c3=",c3); //shows content
// tried flush to sync to client...didn't work
crs_collection.flush;
return rec; //rec not returning to the client
}
})
There is a lot more code, so I have assembled all of the above hoping it gives you a clear picture of what I have tried and what I'm trying to do. I'm sorry if I made a mistake in the process.
Overall it will be great to know what am I doing wrong? I believe the 3 scenarios should work. Any help or recommendation will be appreciated.
I'm using Meteor Release 0.7.1.2, no CoffeeScript.
Thank you all
You're making two mistakes:
Define crs_collection once, and make sure its in a file thats executed on the client AND the server. It should be defined globally.
crs_collection must be defined before your pub/sub code. Meteor executes files in the lib directory first, so its best to put your collection code there.
That's really all there is to it. I'm happy to provide an example if needed.