Tinytest meteor mocking - meteor

I tried to mock Template.__create__ with the code below but I still get the error.
In package.js
Package.describe({
name: 'robwatkin:mypackage',
});
Package.onUse(function(api) {
api.versionsFrom('1.1.0.2');
api.use('meteor-platform');
api.use('iron:router');
api.use('reactive-var');
api.use('templating');
});
Package.onTest(function(api) {
api.use('tinytest');
api.addFiles('mocks.js');
api.use('robwatkin:mypackage');
api.addFiles('tests.js');
});
in mocks.js
Template = {
__create__: function() {console.log('STUB Template.__create__')}
};
in tests.js
Tinytest.add('example', function (test) {
test.equal(true, true);
});
Gives
Uncaught TypeError: Template.__create__ is not a function(anonymous function) # layout.js:286(anonymous function) # iron_layout.js?d62e492972d7f97328c54d2ba052d5adf0cf0d9a:534(anonymous function) # iron_layout.js? d62e492972d7f97328c54d2ba052d5adf0cf0d9a:541
It works fine if I comment out
api.use('robwatkin:mypackage');
Thanks

Related

meteorhacks:aggregate error

I'm trying to publish some data using meteorhacks:aggregate:
Meteor.publish('alleNascholingen',function() {
var self = this;
var nascholingenOverzicht = nascholingenCollectie.aggregate([
//{$match: {creatorId: this.userId}},
//{$project: {naam: 1, familienaam:1, nascholingen:1}},
{ $unwind : "$nascholingen" },
{ $sort: {
"nascholingen.inschrijfMoment": -1
}}
]);
_.each(nascholingenOverzicht, function(parent){
_.each(parent, function(child){
self.added('selectie', child._id, child);
});
});
self.ready()
});
I have two collections, one to store the aggregated data:
nascholingenCollectie = new Mongo.Collection('nascholingen');
nascholingenSelectie = new Mongo.Collection('selectie');
On my template I subscribe to the data:
Template.nascholingBeheer.onCreated(function() {
let self = Template.instance();
self.subscribe('alleNascholingen', function () {
setTimeout(function () {
}, 300)
})
})
});
I'm getting the following error in my chrome console:
collection.js:173 Uncaught Error: Expected to find a document to change
at Object.update (http://localhost:3000/packages/mongo.js?hash=c4281c0ff989ebee020f59f5a7b0735053cea5f7:246:29)
at Object.store.(anonymous function) [as update] (http://localhost:3000/packages/ddp-client.js?hash=bc32a166cd269e06a394f9418e0024d805bab379:3613:48)
at http://localhost:3000/packages/ddp-client.js?hash=bc32a166cd269e06a394f9418e0024d805bab379:4441:19
at Array.forEach (native)
at Function._.each._.forEach (http://localhost:3000/packages/underscore.js?hash=cde485f60699ff9aced3305f70189e39c665183c:149:11)
at http://localhost:3000/packages/ddp-client.js?hash=bc32a166cd269e06a394f9418e0024d805bab379:4440:13
at Function._.each._.forEach (http://localhost:3000/packages/underscore.js?hash=cde485f60699ff9aced3305f70189e39c665183c:157:22)
at Connection._performWrites (http://localhost:3000/packages/ddp-client.js?hash=bc32a166cd269e06a394f9418e0024d805bab379:4437:9)
at Connection._flushBufferedWrites (http://localhost:3000/packages/ddp-client.js?hash=bc32a166cd269e06a394f9418e0024d805bab379:4423:10)
at Connection._livedata_data (http://localhost:3000/packages/ddp-client.js?hash=bc32a166cd269e06a394f9418e0024d805bab379:4391:12)
What am I doing wrong here?
You can not use aggregation in Meteor publication, only in Meteor method. To work around that you could consider using this package (disclaimer: I am the author).
My bad...I found my error:
_.each(nascholingenOverzicht, function(parent){
_.each(parent, function(child){
self.added('selectie', child._id, child);
});
});
should be:
_.each(nascholingenOverzicht, function(parent){
self.added('selectie', parent._id, parent);
});

Session object inside global template helpers

Session.set('coursesReady', false); on startup.
UPDATE:
I made it into a simpler problem. Consider the following code.
Inside router.js
Router.route('/', function () {
Meteor.subscribe("courses", function() {
console.log("data ready")
Session.set("coursesReady", true);
});
}
and inside main template Main.js
Template.Main.rendered = function() {
if (Session.get('coursesReady')) {
console.log("inject success");
Meteor.typeahead.inject();
}
The message "inject success" is not printed after "data ready" is printed. How come reactivity does not work here?
Reactivity "didn't work" because rendered only executes once (it isn't reactive). You'd need to wrap your session checks inside of a template autorun in order for them to get reevaluated:
Template.Main.rendered = function() {
this.autorun(function() {
if (Session.get('coursesReady')) {
console.log("inject success");
Meteor.typeahead.inject();
}
});
};
Probably a better solution is to wait on the subscription if you want to ensure your data is loaded prior to rendering the template.
Router.route('/', {
// this template will be rendered until the subscriptions are ready
loadingTemplate: 'loading',
waitOn: function () {
// return one handle, a function, or an array
return Meteor.subscribe('courses');
},
action: function () {
this.render('Main');
}
});
And now your rendered can just do this:
Template.Main.rendered = function() {
Meteor.typeahead.inject();
};
Don't forget to add a loading template.
To Solve Your Problem
Template.registerHelper("course_data", function() {
console.log("course_data helper is called");
if (Session.get('coursesReady')) {
var courses = Courses.find().fetch();
var result = [ { **Changed**
name: 'course-info1',
valueKey: 'titleLong',
local: function() {
return Courses.find().fetch();
},
template: 'Course'
}];
Session.set('courseResult', result); **New line**
return Session.get('courseResult'); **New line**
,
Explanation
The answer is at the return of the helper function needs to have be associated with reactivity in order for Blaze, template renderer, to know when to rerender.
Non-reactive (Doesn't change in the DOM as values changes)
Template.Main.helpers({
course_data: UI._globalHelpers.course_data ** Not reactive
});
Essentially: UI._globalHelpers.course_data returns an array of objects which is not reactive:
return [
{
name: 'course-info1',
valueKey: 'titleLong',
local: function() {
return Courses.find().fetch();
},
template: 'Course'
},
Reactive
From Meteor Documentation:
http://docs.meteor.com/#/full/template_helpers
Template.myTemplate.helpers({
foo: function () {
return Session.get("foo"); ** Reactive
}
});
Returning Session.get function to Blaze is reactive; thus, the template will change as the values changes.

Meteor publishes even when autopublish is removed

I am using Meteor 1.0
I have the following code :
/lib/collections.js
Members = new Mongo.Collection('members');
/lib/router.js
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
notFoundTemplate: 'notFound',
waitOn: function() { return Meteor.subscribe('members'); }
});
Router.route('/', {name: 'menu'});
Router.route('/member/new/', {name: 'memberNew'});
Router.route('/member/renew/', {name: 'memberRenewal'});
/server/publications.js
Meteor.publish('members', function() {
console.log("Publishing....");
return Members.find();
});
/client/templates/memberList.js
Template.membersList.helpers({
listMembers: function() {
return members.find().fetch(); >>>>>> Error line
}
});
I get the following error:
Exception in template helper: ReferenceError: members is not defined
at Object.Template.membersList.helpers.listMembers
(http://meteorvb.dhcp.meraka.csir.co.za:3000/client/templates/membersList.js?
I have removed autopublish bit if I change /client/templates/memberList.js to read
Template.membersList.helpers({
listMembers: function() {
return Members.find().fetch();
}
});
Everything works.
Can anyone please help me?
I think it's just a typo where you have used lowercase m instead of upper case M for Members.
Template.membersList.helpers({
listMembers: function() {
return Members.find().fetch(); >>>>>> Error line
}
});
Variables are case sensitive and since the members collection was assigned to "Members" you need to refer it as "Members" elsewhere.
Members = new Mongo.Collection('members');

Iron router Meteor.user() isn't ready

The problem I'm facing is that my userId function is running before Meteor.user() is ready, therefore there is no Meteor.user()._id present and thus I get Exception in defer callback: TypeError: Cannot read property '_id' of undefined when I run the code. If I use the command Meteor.userId(), it fixes it for that part, but it doesn't solve the big issue being that Meteor.user() isn't ready.
Here's my code:
userId : function(){
console.log('userId called and here is the Meteor.user(): ', Meteor.user());
return (this.params._id || Meteor.user()._id);
},
waitOn: function () {
console.log('waitOn called');
return Meteor.subscribe('userProfile', this.userId())
},
addedData : function(){
........
},
data: function(){
...........
},
onBeforeAction : function(){
............
},
onStop : function(){
_.each(this.subscriptions, function(sub){
sub.stop();
});
}
How do I fix this?

How to load Google Maps API with RequireJS?

I am struggling to load gmaps api with requireJS . This is what I've tried:
requirejs.config({
urlArgs: "noCache=" + (new Date).getTime(),
paths : {
"jquery": "vendor/jquery-1.8.2.min",
"bootstrap": "vendor/bootstrap.min",
"underscore": "libs/underscore-min",
"backbone": "libs/backbone-min",
"template": "libs/template",
"gmaps": "http://maps.google.com/maps/api/js?v=3&sensor=false"
},
shim: {
'backbone': {
deps: ['jquery', 'underscore'],
exports: 'Backbone'
},
'underscore': {
exports: '_'
},
'bootstrap': {
deps: ['jquery']
},
'gmaps': {
deps: ['jquery']
},
'main':{
deps: ['jquery','gmaps']
}
}
});
require(["main"], function (main) {})
But inside main.js when I try to instantiate the geocoder i got ,,undefined is not a function" error.
var geocoder = new google.maps.Geocoder();
Any ideas what could I be doing wrong?
I've managed to sort it out with the async plugin.
A quick example is:
require.config({
paths: {
'async': 'lib/requirejs-plugins/src/async'
}
});
define(['async!http://maps.google.com/maps/api/js?sensor=false'], function() {
// Google Maps API and all its dependencies will be loaded here.
});
Thanks to user1706254 cause official documentation : https://github.com/millermedeiros/requirejs-plugins/ was using the keyword 'define' that wasn't working for me but 'require' is working fine.
I couldn't load directly :
require(["goog!maps,3,other_params:sensor=false"], function(){});
But using the asynchronous way did the trick :
require(['async!http://maps.google.com/maps/api/js?sensor=false'], function(){});
You don't need the async plugin to use Google Maps with require.js. The goal can be achieved using only a simple shim config:
require.config({
paths: {
gmaps: '//maps.googleapis.com/maps/api/js?' // question mark is appended to prevent require.js from adding a .js suffix
},
shim: {
gmaps: {
exports: 'google.maps'
}
}
});
require(['gmaps'], function (gmaps) {
var center = {lat: -34.397, lng: 150.644};
var map = new gmaps.Map(document.getElementById('map'), {
center: center,
zoom: 8
});
new gmaps.Marker({
map: map,
position: center
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.5/require.js"></script>
<div id="map" style="width: 100%; height: 200px"></div>
Following on from hjuster here's a quick example of how to use the async plugin
https://gist.github.com/millermedeiros/882682
There is also goog plugin (requires async and propertyParser), available on github
Usage example for google maps:
require(["goog!maps,3,other_params:sensor=false"], function(){});
#hjuster's answer led me the way and I've solved by a callback function.
define(['async!http://maps.google.com/maps/api/js?key=YOURKEY!callback'],
function (_ExpectedMap) {
callback();
});
Notice the !callback at the end of the url starts with async!, callback method is being called when load operation is done.
function callback()
{
//Now load google maps API dependant libraries
require(['gmapsLib'], function (googlemaps) {
window.GMaps = googlemaps;
}
}
There is another question I lately noticed, another function (onLoad) is in use instead of callback to prevent from timeout error. Interesting.
Couldn't make the plugins work for some reason, but this workaround saved my day:
require(['https://apis.google.com/js/client.js?onload=doNothing'], function() {
// Poll until gapi is ready
function checkGAPI() {
if (gapi && gapi.client) {
self.init();
} else {
setTimeout(checkGAPI, 100);
}
}
checkGAPI();
});
});
Just check if gapi is ready every 100 millisec, until it finally loads.
Found the code in this article http://dailyjs.com/2012/12/06/backbone-tutorial-2/
I guess you can also try it with
if (google && google.maps && google.maps.Geocoder) {
// now google.maps.Geocoder is gonna be defined for sure :)
}

Resources