Jasmine/velocity synchronous tests and client logon

67 views
Skip to first unread message

David Logan

unread,
Jul 8, 2015, 10:42:46 AM7/8/15
to jasmi...@googlegroups.com
Hi guys. Oh man, am I at my wits end. I have been working on what I originally thought would be a simple problem for more than a week. I have tried every combination of done, before, after, describe, it, waitFor, setTimeout, custom methods, custom classes, Deps.autoruns, nested Deps.autoruns, and more that I can think of. Nothing works. The architecture is basically this:

Parent server (like Tomcat) sends HTTP headers to Meteor, who then uses those headers to identify the user. In production, meteor would just Meteor.call('MySystem.getSelf'), and on the server it gets the headers, identifies the user based on connection id and returns the appropriate database record.

The problem is in TESTING. I have to have a fixture, which is a Meteor.method('/fixtures/client/setheaders'), where in the package I hijack the headers calls on the server. OK, easy enough.

But here's the problem. I have various describes/its, like
describe('Getting info on self',
    describe('no valid headers
         it(should only get basic info from getSelf
    describe("normal user logged on
        it(should get certain useful information about self
    describe("admin user
        it(should get everything available about self

The problem is that I have to logon by invoking both the fixtures call and then the getself call, both with callbacks. Any type of "logon" causes all of the describe functions to step all over each other, no matter what I do. For example, if I use beforeEach(done), what will happen is guest will logon, be marked as done, then normal user will logon, be marked as done, then guest will fail the "it" test because it's got user information for the normal user.

Each of these describe tests must be run, with callbacks available, serially. I need some way to logon, run my tests, then logoff. The callbacks cannot interfere with each other, as there is only one connection and only one connection id.

The only other thing I can think of at this point is to actually integrate testing code into my production code, so that the server-side "getSelf" somehow knows to send the correct data back. Since it currently uses a connection id, and there is only one connection id for the client side tests, there just doesn't seem to be any way to do this, much less a good way.

Help! Does anyone have any good ideas?

Thank you,
David Logan

David Logan

unread,
Jul 8, 2015, 12:26:08 PM7/8/15
to jasmi...@googlegroups.com
Nope, it's just not possible. Two different attempts resulted in completely working serialization, but velocity crashes or hangs because it screws up the describe/it relationship (presumably that's why it crashes/hangs.) The try I wrote just now somehow seems to happily ignore my own functions and starts calling the describes.

I have something like this:
var logonas = function(username, uid, func) {
    console.log('in logonas');
    etc...
};

logonas('admin', 0', describe(){
   console.log('starting admin');
   etc.

The first log message I get in the browser is "starting admin", and the whole set fails. How it does that is beyond me. Simply nothing works.

David Logan

unread,
Jul 11, 2015, 1:02:06 PM7/11/15
to jasmi...@googlegroups.com
I thought I would post an update. I completely rewrote my initial framework yet again, but it seems I finally got it to work. I'm sure I had tried my ideas before, but perhaps it was just the choice of architecture that was biting me, I don't know. Anyway, here's how I got it to work this time, posting the important parts at the top of the test.js source:

var jasmine_client_integration_next = new ReactiveVar(-1);
var nexttest = 0;

Meteor.startup(function(){
Meteor.call('fixtures/client/reset',function(){
jasmine_client_integration_next.set(0);
});
});
var waitformyturn = function (done) {
var x = nexttest++;
Deps.autorun(function () {
var cur = jasmine_client_integration_next.get();
if (cur == x) {
this.stop();
done();
}
});
};

var firenexttest = function () {
var cur = jasmine_client_integration_next.get();
cur++;
jasmine_client_integration_next.set(cur);
};

var sub3;
var subscription3 = function(done) {
if(sub3) sub3.stop();
sub3 = Meteor.subscribe('MySystem.user.field.security', done);
};

var sub2;
var subscription2 = function(done) {
if(sub2) sub2.stop();
sub2 = Meteor.subscribe('MySystem.self', function(){subscription3(done)});
};

var sub1;
var subscription1 = function(done) {
if(sub1) sub1.stop();
sub1 = Meteor.subscribe('MySystem.general', function(){subscription2(done)});
};
var logonas = function (username, uid, done) {
Meteor.call('fixtures/client/setheaders', username, uid, function(){subscription1(done)});
};

describe("TournamentSystem", function () {
beforeEach(waitformyturn);
afterEach(firenexttest);
describe("logged on as guest", function () {
beforeEach(function (done) {
logonas('', '', done)
});
it("should return guest information about themselves", function () {
expect(MySystem._userdb.find({conn: {$exists: true}}).count()).toEqual(0);
});

David Logan

unread,
Jul 13, 2015, 10:59:10 AM7/13/15
to jasmi...@googlegroups.com
Another update. It doesn't seem to quite be working. The "this.stop" in the first autorun is causing a whole boatload of websocket interruption errors in my firefox browser. I think it was causing some test failures I was putting in later in the code because of an endless re-assignment of connection ids. Thus I embarked upon a task to remove the errors. I put debug lines in between virtually every line of code to see where the error was occurring, which is how I arrived at the above conclusion.

The best part is, the first run through this, it doesn't bother to "waitformyturn", it just starts it() #1, even before the database reset is done. So somehow the first run through isn't following the "done" rules. Subsequent tests seem to do fine, but the first one doesn't wait. I think it's just by luck that all of my tests were passing with the previously posted code, as it() #2 did wait, even though it() #1 didn't, and I'm also guessing that it() #1 generally happened to get into the expect() logic after the reset mostly by chance.

It's still curious why this.stop() causes errors, why adding function(comp) and comp.stop() seems to fail, and why the initial run doesn't honor the done logic.

David Logan
Reply all
Reply to author
Forward
0 new messages