Function that yields to a Fiber hanging on testing with Jasmine


#1

I have a function that contains a node Fiber which is yielded at the start, then returned when it is ready. What I am trying to do is run the Fiber only when the data has been fetched and added to the collections. The function is below:

/**
	 *	Function to fetch data from Contentful
	 *	@param {String} which - can be contentTypes, entries or assets
	 *	@return {Object} - the result when the data has been fetched - timed by a Fiber yield
	 */
	fetch: function(which) {
		var current = this.Fiber.current,
				now,
				selector, 
				modifier,
				action,
				result;

		if(!this.client) {
			throw new Meteor.Error(500, 'Contentful client not started. Did you forget to call MeteorContentful.start() ?');
		}
		else if(typeof this.client[which] !== 'function') {
			throw new Meteor.Error(500, 'Contentful does not support this function: ' + which);
		}
		else {
			this.client[which]().then(function(data, err) {
				if(err) {
					throw new Meteor.Error(500, 'Cannot fetch this data from Contentful: ' + which);
				}
				this.Fiber(function() {
					data.forEach(function(record) {
						now = new Date().getTime(),
						selector = {'sys\uff0eid': record.sys.id},
						modifier = {$setOnInsert: {fetchedAt: now}, $set: {refreshedAt: now, fields: record.fields, sys: record.sys}},
						Collections.updateToCollection(which, selector, modifier);
					});
					current.run(this);
				}.bind(this)).run();
			}.bind(this));
		}

		result = this.Fiber.yield();

		return result;
	},

I am trying to test this function using Velocity and Jasmine, and it seems to be hanging and not finishing. Here is my test:

it('should call Collections.updateToCollection with the correct parameters', function(done) {
		/**
		 *	Stubs
		 */
		MeteorContentful.client = {
			collected: function() {
				return {
					then: function(cb) {
						cb([
							{sys: {id: 1}, fields: {x: 1, y: 2}}
						]);
					}
				}
			}
		};

		/**
		 *	Spies
		 */
		spyOn(Collections, 'updateToCollection');

		/**
		 *	Run the function and test
		 */
		console.log('X: ', MeteorContentful.fetch('collected'));
		expect(Collections.updateToCollection).toThrow(new Meteor.Error);
		
		/**
		 *	Cleanup and done
		 */
		MeteorContentful.client = false;
		done();
	});

So what I want to do is make sure that the Collections.updateToCollection function is being run with the correct parameters. I have checked around for examples and documentation and cannot find a solid and working example of how to test a function that returns a Fiber. Has anyone tried and succeeded in this before and if so, do you have any pointers?

Thanks


#2

I should also point out that the error message I am getting on the command line is as follows:

W20150804-13:31:09.187(2)? (STDERR) [Error: Couldn't parse stack frame: '']
=> Meteor server restarted

I have four tests for this function, and under the velocity UI on localhost:3000, the fourth test - the troublesome one, doesn’t even show up, and only will when I remove the call to the function MeteorContentful.fetch(‘collected’)


#3

I have just release 0.16.3. You should now get the error with this version. Let me know what error you get now.


#4

Btw. in an Meteor app you are already in a Fiber. You can just use Meteor.wrapAsync to wrap functions with a callback. Or use a Future (see Fibers package documentation).


#5

Hi @sanjo - I will try the latter now. The test looks as follows and the error comes up like this:

Error: This Fiber is already running

This is the test

it('should call Collections.updateToCollection with the correct parameters', function(done) {
		/**
		 *	Stubs
		 */
		MeteorContentful.client = {
			collected: function() {
				return {
					then: function(cb) {
						cb([
							{sys: {id: 1}, fields: {x: 1, y: 2}}
						]);
					}
				}
			}
		};
		/**
		 *	Spies
		 */
		spyOn(Collections, 'updateToCollection');

		/**
		 *	Run the function and test
		 */
		console.log(MeteorContentful.fetch('collected'));
		//expect(Collections.updateToCollection).toHaveBeenCalled();
		
		/**
		 *	Cleanup and done
		 */
		MeteorContentful.client = false;
		done();
	});

The test no longer hangs and its name appears in the list under the Velocity UI.


#6

I think the error is triggered by current.run(this);. Anyway, just use a Future. It is easier.


#7

In the end I stopped using Fibers and started using Futures instead - much easier to work with jasmine and testing. Will post my tests as soon as the package is ready for reference.