Running code only for tests using Jasmine package - meteor

I am using the sanjo:jasmine and velocity:html-reporter packages in my app to try and implement some unit and integration testing. Using this tutorial as a guide, I have a few unit tests and a couple integration tests done. What I am not able to figure out is how to get code to run in the "test" environment that is not part of a unit test or integration test, but needs to run prior to the tests and only for the tests.
What I am trying to solve is that I need some dummy users created for testing, but I do not want them in my production app. Sort of like an "init" phase where you can build the mockups and insert any data you need. Is there a way to accomplish this?

I would recommend that you create some seed or fake data for your tests using factories.
I would recommend that you try the following packages:
anti:fake - Fake text and data generator for Meteor.js
dburles:factory - A package for creating test data or for generating fixtures.
You can install these packages using this command:
meteor add anti:fake dburles:factory
Create your factory data for the test environment only.
I'd create a file called server/seeds.js with the following content:
Meteor.startup(function() {
Factory.define('user', Users, {
username: "test-user",
name: "Test user",
email: "test#example.com"
// add any other fields you need
});
var numberOfUsers = 10;
// Ensure this is the test environment
if (process.env.NODE_ENV === 'test') {
// Create the users from the factory definition
_(numberOfUsers).times(function(n) {
Factory.create('user');
});
}
});
You can follow this Factory approach for any data, not just Users.
If your Users need to login, such as when you're using accounts:base, then I would consider an alternative approach to using Factory data:
var email = "test#example.com";
var password = "secret";
var name = "Test user";
Accounts.createUser({email: email, password: password, profile: {name: name}});
Please see Accounts.createUser in the Meteor docs for more details.

If you're using sanjo:jasmine you can insert data into the mirrored db before writing your specs (after describe and before it clauses) and this data would be available for all specs.
Also, you may use beforeEach() in order to provide data for each specs, and then you can delete it using afterEach().
Here you can find more info.

I've been using mike:mocha and as long as your specs are written inside a folder called tests (and then client / server, respectively) then Velocity puts data in velocity specific collections. I run the same Meteor method I use to insert a document in my main app, but velocity knows to put it in the mirrored version.

Related

How to access meteor collection through the database

I want to have my application's admin code hosted on a completely different app that shares the same database. However, that means that my collections are defined, at least in the code, in the global namespace of my main application and not my admin application. How can I access my collections, that are in the database, without having the global variables defined in a file shared between the meteor server/client? For reference, I am using this article as the idea to set up my admin tools this way. admin article
To simplify the problem, let's say you have:
two applications: A and B
one shared collection: Posts
one shared database via MONGO_URL
Quick and Dirty
There's nothing complex about this solution - just copy the collection definition from one app to the next:
A/lib/collections.js
Posts = new Mongo.Collection('posts');
B/lib/collections.js
Posts = new Mongo.Collection('posts');
This works well in cases where you just need the collection name.
More Work but Maintainable
Create a shared local package for your Posts collection. In each app: meteor add posts.
This is a little more complex because you'll need to create a pacakge, but it's better for cases where your collection has a model or other extra code that needs to be shared between the applications. Additionally, you'll get the benefits of creating a package, like testing dependency management, etc.
Each application will have its own code but will share the same mongo db. You'll need to define the same collections (or a subset or even a superset) for the admin app. You can rsync certain directories between the two apps if that makes that process either but there isn't anything in Meteor that will do this for you afaik.
Or you could share data between the two servers using DDP:
var conn = DDP.connect('http://admin-server');
Tracker.autorun(function() {
var status = conn.status();
if(status.connection) {
var messages = new Mongo.Collection('messages', {connection: conn});
conn.subscribe('messages', function() { console.log('I haz messages'); });
}
});
This creates a local collection named messages that pulls data from the "admin server" over DDP. This collection only exists in memory - nothing is created in mongo. You can do this on the server or client. Definitely not the best choice for large datasets. Limit the data transfer with publications.

How to check velocity is using mirrored data in meteor with mocha

I am using velocity + mocha for testing my meteor app. On client side when I run test case like below, it is passing.
describe("categories server", function(){
it("should return categories", function(done){
setTimeout(done,1500);
chai.assert(Cats.find({}).count() > 0);
this.timeout(1500);
});
But on Client side I'm getting blank collection for the similar test.And in mocha iframe all fields dependent on db are empty. Please any help is much appriciated. I'm new in testing.
Execute meteor mongo to get into the MongoDB shell of your app.
Execute use mocha in the MongoDB shell to switch to the database that the Mocha mirror uses.
Validate the contents of your database with something like: db.cats.find().pretty().

Updating attributes from external authentication source in Meteor

This screencast shows how to retrieve additional user profile attributes from external authentication. But I don't understand how can I update the user account every time user logs in with possibly updated profile attributes? Is onCreateUser called every time user authenticates or just the first time? From what I understand it is just the first time. So how can I hook into login process to update attributes?
You need to hook into when someone logs in and then update the attributes manually.
Firstly you need something that tells when the user is logged in. At the moment you could use a client based solution (where a call is made to the server a second time on a successful login) using something like meteor-prescence or by editing the core packages and placing them in your /packages directory.
Alter the accounts-base package with the file accounts-server.js to create a 'hook' when the user logs in at
Meteor.methods({
login: function(options) {
.....
if (result !== null)
//Run here
this.setUserId(result.id);
return result;
},
});
Then at the //Run Here add a function that connects to facebook and gets the data you need. Or in the Meteor.call method that you would call from the client if you decide to use meteor-prescence or a similar library or method. It would be something similar to this:
if(Meteor.user().services.facebook.accessToken) {
var graph = Npm.require('fbgraph');
graph.setAccessToken(Meteor.user().services.facebook.accessToken);
graph.get('/me',{},function(err,result) {
//Update your user (you could also alter services.facebook instead
Meteor.users.update(Meteor.userId, {$set: {profile:result}});
}
}
In the above the example is for facebook using the fbgraph node module (which you would need to install) - or use the method described here to use Npm modules without a seperate package. You could to the same in principle for other providers too. Note you don't have to use a synchronous type call here to your provider as it is ok the data could be updated shortly after they log in.
Another place you could hook into is also in the _setUserId method in the livedata package.

How do you secure the client side MongoDB API?

I don't want just all of my users being able to insert/destroy data.
While there is no documented way to do this yet, here's some code that should do what you want:
Foo = new Meteor.Collection("foo");
...
if (Meteor.is_server) {
Meteor.startup(function () {
Meteor.default_server.method_handlers['/foo/insert'] = function () {};
Meteor.default_server.method_handlers['/foo/update'] = function () {};
Meteor.default_server.method_handlers['/foo/remove'] = function () {};
});
}
This will disable the default insert/update/remove methods. Clients can try to insert into the database, but the server will do nothing, and the client will notice and remove the locally created item when the server responds.
insert/update/remove will still work on the server. You'll need to make methods with Meteor.methods that run on the server to accomplish any database writes.
All of this will change when the authentication branch lands. Once that happens, you'll be able to provide validators to inspect and authorize database writes on the server. Here's a little more detail: http://news.ycombinator.com/item?id=3825063
[UPDATE] There is now an official and documented Auth Package which provides different solutions to secure a collection.
On a CRUD level :
[Server] collection.allow(options) and collection.deny(options). Restricts default write methods on this collection. Once either of these are called on a collection, all write methods on that collection are restricted regardless of the insecure package.
And there is also insecureto remove full write access from the client.
source : Getting Started with Auth (thanks to #dan-dascalescu)
[OLD ANSWER]
Apparently there are working on Auth Package(?) that should avoid any users taking full control on the db as it is now. There is also someone suggesting that there is an existing solution (workaround) by defining your own mutations (methods) and make them failed if they attempts to perform an unauthorized action. I didn't get it much better but I think this will often be necessary since I doubt the Auth Package will let you implement the usual auth logic on a row level but probably only on the CRUD methods. Will have to see what the devs have to say.
[EDIT]
Found something that seems to confirm my thoughts :
Currently the client is given full write access to the collection. They can execute arbitrary Mongo update commands. Once we build authentication, you will be able to limit the client's direct access to insert, update, and remove. We are also considering validators and other ORM-like functionality.
Sources of this answer :
Accessing to DB at client side as in server side with meteor
https://stackoverflow.com/questions/10100813/data-validation-and-security-in-meteor/10101516#10101516
A more succinct way:
_.each(['collection1', 'collection2'], function(collection){
_.each(['insert','update', 'remove'], function(method){
Meteor.default_server.method_handlers['/' + collection + '/' + method] = function(){}
});
});
or to make it more idiomatic:
extend meteor:
_.extend(Meteor.Collection.prototype, {
remove_client_access: function(methods){
var self = this;
if(!methods) methods = ['insert','update','remove'];
if(typeof methods === 'String') methods = [methods];
_.each(methods, function(method){
Meteor.default_server.method_handlers[self._prefix + method] = function(){}
});
}
});
Calls are simpler:
List.remove_client_access() // restrict all
List.remove_client_access('remove') //restrict one
List.remove_client_access(['remove','update']) //restrict more than one
I am new to Meteor, but what I have come across so far are these two points
You can limit what a client can access in the database by adding parameters to the find command in the server-side publish command. Then when the client calls Collection.find({}), the results that are returned correspond to what on the server side would be, for example, Collection.find({user: this.userId}) (see also Publish certain information for Meteor.users and more information for Meteor.user and http://docs.meteor.com/#meteor_publish)
One thing that is built in (I have meteor 0.5.9) is that the client can only update items by id, not using selectors. An error is logged to console on the client if there is an attempt that doesn't comply. 403: "Not permitted. Untrusted code may only update documents by ID." (see Understanding "Not permitted. Untrusted code may only update documents by ID." Meteor error).
In view of number 2, you need to use Meteor.methods on the server side to make remote procedure calls available to the client with Meteor.call.

asp.net mvc integration test

Hi Im doing TDD for an asp.net mvc project, I need to be able to do end to end testing for sending a request to the controller action all the way to the repository. I have tried using the code here but unfortunately I can't get this to run and I'm running out of time, does anyone know any other way to fake an http request and populate request post parameters in a test scenario?
My controller action is as follows:
[HttpPost]
public ActionResult CreateUser(User user)
{
}
So I need to basically do an http request to populate this User object and hopefully save it to a test repository.
As you posted the link I'll take an extract from Steve Sanderson's blog:
Integration tests test your entire software stack working together. These tests don’t mock or fake anything (they use the real database, and real network connections) and are good at spotting if your unit-tested components aren’t working together as you expected. In general, it’s best to put most of your effort into building a solid suite of unit tests, and then adding a few integration tests for each major feature so you can detect any catastrophic incompatibilities or configuration errors before your customers do.
You shouldn't be faking HTTP requests at this stage as an integration test inherantly tests every component together.
Try some type of browser automation framework:
http://blog.stevensanderson.com/2010/03/30/using-htmlunit-on-net-for-headless-browser-automation/
http://www.codeproject.com/KB/cs/mshtml_automation.aspx
If you want to do full integration testing, then test your application from user prospective. Create test cases like:
Log in as admin
Go to Users page
Add User with name "User1"
Check that user with name "User1" listed in the Users grid.
And automate such tests using Selenium or Watin. See example here
You may also want to take a look at the Verde framework. Semantically the tests look similar to Steve Sanderson's MvcIntegrationTestFramework with the key difference being that Verde executes tests in the context of your actual IIS AppDomain (via a browser-based test runner) rather than a programmatically created one. This provides a couple of advantages: First it is a more realistic emulation of your actual application's configuration, network topology, security settings, etc. Secondly you can automate running of the tests as a post-deployment step or could even run the tests automatically as part of application monitoring in production. Here is an example Verde test taken from the MvcMusicStore sample that is included in the source code on GitHub:
[IntegrationTest]
public void Index_Load_ExpectedHtml()
{
// Get a product to load the details page for.
var album = storeDB.Albums
.Take(1)
.First();
using (var scope = new MvcExecutorScope("Store/Details/" + album.AlbumId))
{
Assert.AreEqual(200, scope.HttpContext.Response.StatusCode);
Assert.IsTrue(scope.Controller is StoreController);
Assert.AreEqual("Details", scope.Action);
var model = scope.Controller.ViewData.Model as Album;
Assert.IsNotNull(model);
Assert.AreEqual(album.AlbumId, model.AlbumId);
Assert.IsFalse(String.IsNullOrEmpty(scope.ResponseText));
// Load the ResponseText into an HtmlDocument
var html = new HtmlDocument();
html.LoadHtml(scope.ResponseText);
// Use ScrappySharp CSS selector to make assertions about the rendered HTML
Assert.AreEqual(album.Title, html.DocumentNode.CssSelect("#main h2").First().InnerText);
}
}
There is a NuGet package which makes it very easy to add to your MVC project.
http://dvonlehman.github.com/Verde/
https://nuget.org/packages/Verde/0.5.1

Resources