arunoda / laika

testing framework for meteor
http://arunoda.github.io/laika/
MIT License
242 stars 38 forks source link

Client-side test fails after two server-side tests #77

Closed blazer82 closed 10 years ago

blazer82 commented 10 years ago

I have a really strange behavior with my test suite: After two server-side tests the next client-side test fails because of a timeout, always and even if the timeout is set to really high values. I tried to track it down but wasn't able to find anything. It seems to be completely independent of any meteor app, since it's easily reproducible in another app. All you need to do is to run the following tests:

var assert = require('assert');

suite('foo', function() {
    test('should pass', function(done, server) {
        server.eval(function() {
            emit('value', true);
        }).once('value', function(value) {
            assert.ok(value);
            done();
        });
    });
});
suite('bar', function() {
    test('should not break the following test', function(done, server) {
        server.eval(function() {
            emit('value', true);
        }).once('value', function(value) {
            assert.ok(value);
            done();
        });
    });
});
suite('foobar', function() {
    test('should not be broken', function(done, server, client) {
        client.eval(function() {
            emit('value', true);
        }).once('value', function(value) {
            assert.ok(value);
            done();
        });
    });
});

Nothing special here, just some asserting that true equals true. And if you remove the first or the second test, everything works fine again. I noticed something strange during the execution of the third test. It seems as if the app is getting launched three times:

[laika log] start running test
[laika log] using nodejs bin(from meteor): /Users/foo/.meteor/tools/09b63f1ed5/bin/node
[laika log] running test
[server log] laika code injected and listening on: 24210
[server log] laika code injected and listening on: 17026
[server log] laika code injected and listening on: 26365
[server log] LISTENING
[server log] LISTENING
[server log] LISTENING
not ok 3 foobar should not be broken
  Error: timeout of 10000ms exceeded
      at null.<anonymous> (/usr/local/lib/node_modules/laika/node_modules/mocha/lib/runnable.js:175:14)
      at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)

You can place all those tests within the same suite and you'll get the same results. So far, I found no way to avoid this problem. Any ideas what might be causing this?

blazer82 commented 10 years ago

I just found that when you place an additional server.eval(...).once(...) within the last test everything works fine again. The problem seems to be with the nature of the test being client-side only.

blazer82 commented 10 years ago

Might actually be related to #48

blazer82 commented 10 years ago

I found that when you set your initial apps in the AppPool to a number high enough to execute every test on one of those initially started apps (in this case here size: 3) then everything runs fine again. Although this cannot be a solution it suggests that something isn't quite ready while executing the last test. The same conclusion can be reached by applying the following patch to lib/app.js:56

-        self.emit('ready', laikaInjectPort);
+        setTimeout(function() {
+          self.emit('ready', laikaInjectPort);
+        }, 1000);

Delaying the emission of ready also leads to a working and therefore passing third test. Once again, something didn't seem to be ready even though it should have been. But this wouldn't be a very nice solution either. I'm going to investigate further, just wanted to share my results here.

blazer82 commented 10 years ago

I got it. I'm going to make a pull request for the fix...

Linskeyd commented 10 years ago

Hey Blazer82. It seems this issue exits again as of meteor 8.1.1. Yesterday I was running test and when I swapped the order around, it consistently failed every third test. Adding a server side eval like you said a few comments ago does fix the problem. Laika -v is 0.3.9 and node -v is 0.10.28 Code is below. Please see issue #117

// Login.js
var assert = require('assert');

suite('Home Page', function() {
    test('should display a login link instead of username when not logged in', function(done, server, client) {
    client.eval(function() {
      Router.go('/');
      waitForDOM('li', function() {
        emit('login-link-text', $('#sign-in-button').text());
      });
      emit('return');
    }).once('login-link-text', function(text) {
      assert.equal(text, 'Sign In');
    }).once('return', function() {
      done();
    });

    // allows 3rd test to pass
    server.eval(function() {
      emit('return');
    }).once('return', function() {
      done();
    });
  });
});
// promotions.js
var assert = require('assert');

suite('Promotions', function() {
  test('in the server', function(done, server) {
    server.eval(function() {
      Promotions.insert({
        promoName: 'testName',
        blurb: 'test',
        latitude: '43.011338',
        longitude: '-83.713344',
        startDate: 'Jul 9th, 2009',
        endDate: 'Dec 23rd, 2012',
        daysBetween: '1264',
        author: 'admin'
      });
      var docs = Promotions.find({promoName: 'testName'}).fetch();
      emit('docs', docs);
    }).once('docs', function(docs) {
      assert.equal(docs.length, 1);
      done();
    });
  });

  test('access denied when not logged in', function(done, server, client) {
    client.eval(function() {
      Promotions.find().observe({
        removed: onRemoved
      });

      function onRemoved(promotion) {
        emit('remove', promotion);
        emit('return');
      }

      Promotions.insert({promoName: 'testRemove'});
    }).once('remove', function(promotion) {
      assert.equal(promotion.promoName, 'testRemove');
    }).once('return', function() {
      done();
    });

    // allows 3rd test to pass
    server.eval(function() {
      emit('return');
    }).once('return', function() {
      done();
    });
  });
});