Backlog Aggregator: Roadmap preview (part one)

A Roadmap is a concept a little bit harder than a backlog to be managed using external tools. Pivotaltracker or software like that are very handy to manage a lot of things, but sometimes a roadmap’s content doesn’t fit perfectly with the approach that other software impose to you.

So while my teammates were thinking of how to aggregate the data and where to save them, I made the frontend as a Single Page Application using AngularJs and Jasmine and using Chutzpah as test runner.

One of the things I most appreciate using angular are the Directives.

The goal was to have a preview of a roadmap to use it in a dashboard able to summarize all the projects and their statuses.
What I wanted was to create a roadmap easily, something like

<roadmap-preview roadmap="roadmapContract"></roadmap-preview>

and I expected to have a result like
roadmap-preview

Having this idea in my mind, I started with some test.
I usually prefer to describe my expectations in a readable way and so I started describing a “When” situation and declaring all my expectations:

describe('', function () {
	describe('When the roadmap is compiled', function () {
		it('it should have the position of the viewer in the timeline');
		it('it should have a release-detail directive');
		it('it should have the timeline divided in quarter per year');
		it('it should have a street');
	});
});

This approach makes very easy to read all the test in Visual Studio

tests-roadmap-preview

Because I work with templateUrl in my Directives, I have to load the template before to compile it. I tried many solutions in the past, right now I use this:

describe('', function () {
	var compile;
	var rootScope;

	beforeEach(module('backlogsReader.directives'));
	beforeEach(inject(function ($compile, $rootScope, $templateCache) {
		compile = $compile;
		rootScope = $rootScope;

		var roadmapPreviewTemplate = null;

		$.ajax({
			type: 'GET',
			async: false,
			url: 'relativeToTestUrl/roadmapPreview.html',
			success: function (html) {
				roadmapPreviewTemplate = html;
			}
		});

		$templateCache.put("relativeToTheApplicationRootUrl/roadmapPreview.html"
		, roadmapPreviewTemplate);
	}));
	...
});

I preload the template at the beginning of all the suite, so I’m sure to load it only once.
Then I compile the directive passing a mock of the data.

describe('', function () {
 ...
 describe('When the roadmap is compiled', function () {

	var scope;
	var el;

   beforeEach(function() {
      scope = rootScope.$new();
      scope.stub = {
         whereAreYou: {
           month: '2',
	   weekOfTheMonth: '4'
	 },
	 releases: [{}]
      };

      el = compile('<roadmap-preview roadmap="stub"></roadmap-preview>')(scope);
      scope.$digest();
    });
  ...
});
});

I don’t follow this approach every time, it depends on the situation I want to test. In this specific case I didn’t need to test the behaviour with different kind of data, but if that was the case I couldn’t compile at once, I had to compile directly in the it() or had other beforeEach.

Speaking about the data I mocked, at that time I didn’t have a specific contract to use or an exact idea of the data we would have had, so I decided my minimum requirement to achieve my goal and I shaped it into that mock.

I try to keep things simple and avoid to make upfront design.
These tests were about roadmap visualization so I avoided to think about release details, I just assumed that I would have had a release detail and so I wrote my expectations

describe('', function () {
	...

	describe('When the roadmap is compiled', function () {

		...
		it('it should have the position of the viewer in the timeline'
		, function () {
			var whereAreYou = el.find('.where-are-you');
			expect(whereAreYou.length).toBe(1);
			expect(whereAreYou.hasClass('pos-2-4')).toBeTruthy();
		});

		it('it should have a release-detail directive'
		, function() {
			expect(el.find('release-detail').size()).toBe(1);
		});

		it('it should have the timeline divided in quarter per year'
		, function () {
			expect(el.find('.roadmap-q.q-1').length).toBe(1);
			expect(el.find('.roadmap-q.q-2').length).toBe(1);
			expect(el.find('.roadmap-q.q-3').length).toBe(1);
			expect(el.find('.roadmap-q.q-4').length).toBe(1);
		});

		it('it should have a street'
		, function () {
			expect(el.find('.street').length).toBe(1);
		});
	});
});

Here the complete version of my test file.

describe('', function () {
	var compile;
	var rootScope;

	beforeEach(module('backlogsReader.directives'));
	beforeEach(inject(function ($compile, $rootScope, $templateCache) {
		compile = $compile;
		rootScope = $rootScope;

		var roadmapPreviewTemplate = null;

		$.ajax({
			type: 'GET',
			async: false,
			url: 'relativeToTestUrl/roadmapPreview.html',
			success: function (html) {
				roadmapPreviewTemplate = html;
			}
		});

		$templateCache.put("relativeToTheApplicationRootUrl/roadmapPreview.html"
		, roadmapPreviewTemplate);
	}));

	describe('When the roadmap is compiled', function () {

		var scope;
		var el;

		beforeEach(function() {
			scope = rootScope.$new();
			scope.stub = {
				whereAreYou: {
					month: '2',
					weekOfTheMonth: '4'
				},
				releases: [{}]
			};

			el = compile('<roadmap-preview roadmap="stub"></roadmap-preview>')(scope);
			scope.$digest();
		});

		it('it should have the position of the viewer in the timeline'
		, function () {
			var whereAreYou = el.find('.where-are-you');
			expect(whereAreYou.length).toBe(1);
			expect(whereAreYou.hasClass('pos-2-4')).toBeTruthy();
		});

		it('it should have a release-detail directive'
		, function() {
			expect(el.find('release-detail').size()).toBe(1);
		});

		it('it should have the timeline divided in quarter per year'
		, function () {
			expect(el.find('.roadmap-q.q-1').length).toBe(1);
			expect(el.find('.roadmap-q.q-2').length).toBe(1);
			expect(el.find('.roadmap-q.q-3').length).toBe(1);
			expect(el.find('.roadmap-q.q-4').length).toBe(1);
		});

		it('it should have a street'
		, function () {
			expect(el.find('.street').length).toBe(1);
		});
	});
});

Obviously all my tests failed at the first run and I had to solve them.

One thought on “Backlog Aggregator: Roadmap preview (part one)

  1. Pingback: Backlog Aggregator: Roadmap Feedback (part one) | Agile. Angular/Js. Asp.NET & TDD

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s