<commit_before>// $(function () {
// 	var $window = $(window);
// 	var $document = $(document);
// 	var $pagesSpacer = $('.pagesSpacer');
// 	var $pagesContainer = $('.pagesContainer');
// 	var $pages = $('.pageSingle');
// 	var $header = $('.header');

// 	var html;
// 	var maxPageNumber = $pagesContainer.data('maxPages');
// 	var currentPage;
// 	var pageCount = 0;
// 	var pageHeight;
// 	var screenHeight = $window.height();
// 	var pagePlaceholder = $header.height();
// 	var scrollValue;
// 	var prevScroll = 0;
// 	var firstRun = true;
// 	var pagesViewport;
// 	var pagesObjHeight;
// 	var nextPageTriggerHeight;
// 	var prevPageTriggerHeight;
// 	var pagesCurrentHeight;
// 	var deletedPages = 0;
// 	var startPage = 'startPage';
// 	var urlStartUp = false;

// 	var scrollAmount = {up: 0, down: 0};

// 	function loadPage(position, printPageNumber) {
// 		html = '
' + printPageNumber + '
';
// 		if (position === 'ini') {
// 			$pagesContainer.prepend(html);
// 		} else if (position === 'end') {
// 			$pagesContainer.append(html);
// 		}
// 		$pages = $('.pageSingle');
// 	}

// 	function loadNextPage() {
// 		if (pagesViewport > nextPageTriggerHeight) {
// 			pageCount++;
// 			$('.pageCountValue').text(pageCount);
// 			loadPage('end', pageCount);
// 		}
// 	}

// 	function loadPrevPage() {
// 		if ((pagesViewport < prevPageTriggerHeight) && (deletedPages > 0)) {
// 			loadPage('ini', (currentPage - 1));
// 			deletedPages--;
// 			$('.deletedPageValue').text(deletedPages);
// 			$pagesSpacer.height(deletedPages * pageHeight);
// 		}
// 	}

// 	function removePage(position) {
// 		if (position === 'first') {

// 			$pages.splice(0,1);
// 			$('.pageSingle:first-child').remove();
// 			deletedPages++;
// 			$('.deletedPageValue').text(deletedPages);
// 			$pagesSpacer.height(deletedPages * pageHeight);
// 		} else if (position === 'last') {
// 			$pages.splice($pages.lengths-1,1);
// 			$('.pageSingle:last-child').remove();
// 			pageCount--;
// 			$('.pageCountValue').text(pageCount);
// 		}
// 	}

// 	function currentPageControl(direction) {
// 		if (direction === 'down') {
// 			if (pagesViewport > pagesCurrentHeight) {
// 				currentPage++;
// 			}
// 		} else if (direction === 'up') {
// 			if (urlStartUp) {
// 				// first load when the url is used
// 				if ((pagesViewport < prevPageTriggerHeight) && (currentPage > 1)) {
// 					currentPage--;
// 					urlStartUp = false;
// 				}
// 			} else {
// 				if ((pagesViewport < (pagesCurrentHeight - pageHeight * 0.5)) && (currentPage > 1)) {
// 					currentPage--;
// 				}
// 			}
// 		}

// 		$('.currentPageValue').text(currentPage);
// 	}

// 	function scrollingOptions() {
// 		if (prevScroll > scrollValue) { // scroll up
// 			scrollAmount.up = scrollValue;

// 			pagesViewport = pagesViewport + scrollValue;

// 			currentPageControl('up');
// 			loadPrevPage();

// 			if ($pages.length > maxPageNumber) {
// 				removePage('last');
// 			}
// 		} else if ((prevScroll < scrollValue) && (prevScroll !== 0)){ // scroll down
// 			scrollAmount.down = scrollValue;

// 			pagesViewport = pagesViewport + scrollValue;

// 			currentPageControl('down');
// 			loadNextPage();

// 			if ($pages.length > maxPageNumber) {
// 				removePage('first');
// 			}
// 		}
// 	}

// 	function updateValues() {
// 		if (!pageHeight) {
// 			pageHeight = $pages.height();
// 		}
// 		pagesViewport = screenHeight - pagePlaceholder;
// 		pagesObjHeight = pageHeight * pageCount;
// 		pagesCurrentHeight = pageHeight * currentPage;

// 		// screen half way through last visible page
// 		nextPageTriggerHeight = pagesObjHeight - pageHeight / 2;

// 		// screen half way through first visible page
// 		prevPageTriggerHeight = $pagesSpacer.height() + pageHeight * 1.5;
// 	}

// 	function onScroll() {
// 		scrollValue = $document.scrollTop();

// 		// check if the screen is at half size
// 		if (firstRun) {
// 			pageCount++;
// 			loadPage('end', pageCount);
// 			firstRun = false;
// 			updateValues();

// 			if (pagesViewport > (pageHeight / 2)) {
// 				pageCount++;
// 				$('.pageCountValue').text(pageCount);
// 				loadPage('end', pageCount);
// 			}
// 		} else {
// 			updateValues();
// 			scrollingOptions();
// 		}

// 		// for visual aid (do not include)
// 		$('.scrollDownValue').text(scrollAmount.down);
// 		$('.scrollUpValue').text(scrollAmount.up);

// 		prevScroll = scrollValue;
// 	}

// 	function init() {
// 		var arr = $(location)
// 					.attr('href')
// 					.split('?');

// 		if (arr.length === 1) {
// 			currentPage = $pagesContainer.data('startPage');
// 		} else {
// 			urlStartUp = true;

// 			arr[1]
// 				.split('&')
// 				.forEach(function (arg) {
// 					if (arg.indexOf(startPage) !== -1) {
// 						currentPage = parseInt(arg.split('=')[1], 10);
// 					}
// 				});

// 			// don't load the first page normally
// 			firstRun = false;

// 			if (currentPage > 1) {
// 				loadPage('end', (currentPage - 1));
// 			}
// 			loadPage('end', currentPage);
// 			pageHeight = $pages.height();

// 			if (currentPage > 1) {
// 				$pagesSpacer.height((currentPage - 1) * pageHeight);
// 			}

// 			$('html, body').animate({
// 				scrollTop: ($pagesContainer.offset().top + pageHeight)
// 			}, 0);

// 			pageCount = currentPage;
// 			if (currentPage > 2) {
// 				deletedPages = currentPage - 2;
// 			}

// 			// auxiliarty info
// 			$('.deletedPageValue').text(deletedPages);
// 			$('.pageCountValue').text(pageCount);
// 			$('.currentPageValue').text(currentPage);
// 		}
// 	}

// 	init();
// 	onScroll();
// 	// $(window).on('scroll', _.debounce(onScroll, 50));
// 	$(window).on('scroll', onScroll);
// });

/**
 * jQuery plugin template by https://github.com/publicJorn
 * Features:
 * - dynamic plugin name (only supply once) so it's easy to change later
 * - plugin factory to make it work in the browser, or with AMD / COMMONJS modules
 * - Plugin instance is saved on the selector element
 * - Default options are saved to the instance in case you need to figure out a difference between passed options
 */
(function(global, factory) {
	'use strict';
	if (typeof define === 'function' && define.amd) {
		define(['jquery'], function($) {
			return factory($, global, global.document);
		});
	} else if (typeof exports === "object" && exports) {
		module.exports = factory(require('jquery'), global, global.document);
	} else {
		factory(jQuery, global, global.document);
	}
})(typeof window !== 'undefined' ? window : this, function($, window, document, undefined) {
	'use strict';

	// -- Name is used to keep jQUery plugin template portable
	var pluginName = 'HeavenScroll';

	// -- Globals (shared across all plugin instances)
	var defaultOptions = {
		pageHeight: -1,
		maxPagesNumber: -1,
		startPage: -1,
		loadPageFunction: -1
	};

	var $window = $(window);
	var $document = $(document);
	var $htmlBody = $('html, body');
	var screenHeight = $window.height();

	class HeavenScroll {
		constructor(el, options) {
			this.el = el;
			this.$el = $(el);
			this.options = $.extend({}, defaultOptions, options) ;

			this.init();
			this.initContainerOffset();
			this.urlHasStartPageInfo();

			this.onScroll();
			$window.on('scroll', this.onScroll);

			// delete console.log
			console.log(this.options.maxPagesNumber);
			console.log(this.options.pageHeight);
			console.log(this.options.startPage);
			console.log(this.options.loadPageFunction);
			console.log(this.pagePlaceholder);
			console.log(this.currentPage);
		}

		init() {
			if (this.options.maxPagesNumber === -1) {
				this.options.maxPagesNumber = this.$el.data('maxPages');
			}

			if (this.options.pageHeight === -1) {
				this.options.pageHeight = this.$el.data('pageHeight');
			}

			if (this.options.startPage === -1) {
				this.options.startPage = this.$el.data('startPage');
			}

			if (this.options.loadPageFunction === -1) {
				this.options.loadPageFunction = this.$el.data('infoOnPages');
			}

			this.currentPage = this.options.startPage;
			this.pageCount = 0;
			this.deletedPages = 0;
			this.prevScroll = 0;
			this.firstRun = true;
		}

		initContainerOffset() {
			this.pagePlaceholder = this.$el.position().top;
		}

		loadPage(position, printPageNumber) {
			var html = '
' + printPageNumber + '
';
			if (position === 'ini') {
				this.$el.prepend(html);
			} else if (position === 'end') {
				this.$el.append(html);
			}
		}

		updateContainerPadding() {
			this.$el.css('padding-top', ((this.currentPage - 1) * this.options.pageHeight) + 'px');
		}

		urlHasStartPageInfo() {
			var scrollAmount;
			var urlStartPage = 'startPage';
			var currentPage;
			var arr = $(location)
				.attr('href')
				.split('?');

			if (arr.length > 1) {
				this.urlStartUp = true;

				arr[1]
					.split('&')
					.forEach(function (arg) {
						if (arg.indexOf(urlStartPage) !== -1) {
							currentPage = parseInt(arg.split('=')[1], 10);
							return;
						}
					});

				this.currentPage = currentPage;
				this.firstRun = false;

				if (this.currentPage > 1) {
					this.loadPage('end', (this.currentPage - 1));
				}
				this.loadPage('end', this.currentPage);

				if (currentPage > 1) {
					this.updateContainerPadding(); // needs to be created

					scrollAmount = this.$el.offset().top + this.options.pageHeight * this.currentPage;
					setTimeout(function () {
						$htmlBody.animate({ scrollTop: scrollAmount }, 0);
					}, 0);
				}

				this.pageCount = this.currentPage;
				if (this.currentPage > 2) {
					this.deletedPages = this.currentPage - 2;
				}
			}
		}

		updateValues() {
			this.pagesViewport = this.screenHeight - this.pagePlaceholder;
			this.pagesObjHeight = this.options.pageHeight * this.pageCount;
			this.pagesCurrentHeight = this.options.pageHeight * this.currentPage;

			// screen half way through last visible page
			this.nextPageTriggerHeight = this.pagesObjHeight - this.options.pageHeight / 2;

			// screen half way through first visible page
			this.prevPageTriggerHeight = parseInt(this.$el.css('padding-top'), 10) + this.options.pageHeight * 1.5;
		}

		scrollingOptions() {

		}

		onScroll() {
			console.log('scrolling');

			this.scrollValue = $document.scrollTop();

			// check if the screen is at half size
			if (this.firstRun) {
				this.pageCount++;
				this.loadPage('end', this.pageCount);
				this.firstRun = false;
				this.updateValues();

				if (this.pagesViewport > (this.options.pageHeight / 2)) {
					this.pageCount++;
					this.loadPage('end', this.pageCount);
				}
			} else {
				this.updateValues();
				this.scrollingOptions();
			}

			this.prevScroll = this.scrollValue;
		}
	}

	// -- Prevent multiple instantiations
	$.fn[pluginName] = function(options) {
		return this.each(function () {
			if (!$.data(this, 'plugin_'+ pluginName)) {
				$.data(this, 'plugin_'+ pluginName, new HeavenScroll(this, options));
			}
		});
	};
});
$(document).ready(function () {
	$('.pagesContainer').HeavenScroll({
		maxPagesNumber: 3,
		pageHeight: 1584,
		startPage: 1,
		loadPageFunction: 'productTileFetcher'
	});
});
<commit_msg>Scroll issue fixed<commit_after>// $(function () {
// 	var $window = $(window);
// 	var $document = $(document);
// 	var $pagesSpacer = $('.pagesSpacer');
// 	var $pagesContainer = $('.pagesContainer');
// 	var $pages = $('.pageSingle');
// 	var $header = $('.header');

// 	var html;
// 	var maxPageNumber = $pagesContainer.data('maxPages');
// 	var currentPage;
// 	var pageCount = 0;
// 	var pageHeight;
// 	var screenHeight = $window.height();
// 	var pagePlaceholder = $header.height();
// 	var scrollValue;
// 	var prevScroll = 0;
// 	var firstRun = true;
// 	var pagesViewport;
// 	var pagesObjHeight;
// 	var nextPageTriggerHeight;
// 	var prevPageTriggerHeight;
// 	var pagesCurrentHeight;
// 	var deletedPages = 0;
// 	var startPage = 'startPage';
// 	var urlStartUp = false;

// 	var scrollAmount = {up: 0, down: 0};

// 	function loadPage(position, printPageNumber) {
// 		html = '
' + printPageNumber + '
';
// 		if (position === 'ini') {
// 			$pagesContainer.prepend(html);
// 		} else if (position === 'end') {
// 			$pagesContainer.append(html);
// 		}
// 		$pages = $('.pageSingle');
// 	}

// 	function loadNextPage() {
// 		if (pagesViewport > nextPageTriggerHeight) {
// 			pageCount++;
// 			$('.pageCountValue').text(pageCount);
// 			loadPage('end', pageCount);
// 		}
// 	}

// 	function loadPrevPage() {
// 		if ((pagesViewport < prevPageTriggerHeight) && (deletedPages > 0)) {
// 			loadPage('ini', (currentPage - 1));
// 			deletedPages--;
// 			$('.deletedPageValue').text(deletedPages);
// 			$pagesSpacer.height(deletedPages * pageHeight);
// 		}
// 	}

// 	function removePage(position) {
// 		if (position === 'first') {

// 			$pages.splice(0,1);
// 			$('.pageSingle:first-child').remove();
// 			deletedPages++;
// 			$('.deletedPageValue').text(deletedPages);
// 			$pagesSpacer.height(deletedPages * pageHeight);
// 		} else if (position === 'last') {
// 			$pages.splice($pages.lengths-1,1);
// 			$('.pageSingle:last-child').remove();
// 			pageCount--;
// 			$('.pageCountValue').text(pageCount);
// 		}
// 	}

// 	function currentPageControl(direction) {
// 		if (direction === 'down') {
// 			if (pagesViewport > pagesCurrentHeight) {
// 				currentPage++;
// 			}
// 		} else if (direction === 'up') {
// 			if (urlStartUp) {
// 				// first load when the url is used
// 				if ((pagesViewport < prevPageTriggerHeight) && (currentPage > 1)) {
// 					currentPage--;
// 					urlStartUp = false;
// 				}
// 			} else {
// 				if ((pagesViewport < (pagesCurrentHeight - pageHeight * 0.5)) && (currentPage > 1)) {
// 					currentPage--;
// 				}
// 			}
// 		}

// 		$('.currentPageValue').text(currentPage);
// 	}

// 	function scrollingOptions() {
// 		if (prevScroll > scrollValue) { // scroll up
// 			scrollAmount.up = scrollValue;

// 			pagesViewport = pagesViewport + scrollValue;

// 			currentPageControl('up');
// 			loadPrevPage();

// 			if ($pages.length > maxPageNumber) {
// 				removePage('last');
// 			}
// 		} else if ((prevScroll < scrollValue) && (prevScroll !== 0)){ // scroll down
// 			scrollAmount.down = scrollValue;

// 			pagesViewport = pagesViewport + scrollValue;

// 			currentPageControl('down');
// 			loadNextPage();

// 			if ($pages.length > maxPageNumber) {
// 				removePage('first');
// 			}
// 		}
// 	}

// 	function updateValues() {
// 		if (!pageHeight) {
// 			pageHeight = $pages.height();
// 		}
// 		pagesViewport = screenHeight - pagePlaceholder;
// 		pagesObjHeight = pageHeight * pageCount;
// 		pagesCurrentHeight = pageHeight * currentPage;

// 		// screen half way through last visible page
// 		nextPageTriggerHeight = pagesObjHeight - pageHeight / 2;

// 		// screen half way through first visible page
// 		prevPageTriggerHeight = $pagesSpacer.height() + pageHeight * 1.5;
// 	}

// 	function onScroll() {
// 		scrollValue = $document.scrollTop();

// 		// check if the screen is at half size
// 		if (firstRun) {
// 			pageCount++;
// 			loadPage('end', pageCount);
// 			firstRun = false;
// 			updateValues();

// 			if (pagesViewport > (pageHeight / 2)) {
// 				pageCount++;
// 				$('.pageCountValue').text(pageCount);
// 				loadPage('end', pageCount);
// 			}
// 		} else {
// 			updateValues();
// 			scrollingOptions();
// 		}

// 		// for visual aid (do not include)
// 		$('.scrollDownValue').text(scrollAmount.down);
// 		$('.scrollUpValue').text(scrollAmount.up);

// 		prevScroll = scrollValue;
// 	}

// 	function init() {
// 		var arr = $(location)
// 					.attr('href')
// 					.split('?');

// 		if (arr.length === 1) {
// 			currentPage = $pagesContainer.data('startPage');
// 		} else {
// 			urlStartUp = true;

// 			arr[1]
// 				.split('&')
// 				.forEach(function (arg) {
// 					if (arg.indexOf(startPage) !== -1) {
// 						currentPage = parseInt(arg.split('=')[1], 10);
// 					}
// 				});

// 			// don't load the first page normally
// 			firstRun = false;

// 			if (currentPage > 1) {
// 				loadPage('end', (currentPage - 1));
// 			}
// 			loadPage('end', currentPage);
// 			pageHeight = $pages.height();

// 			if (currentPage > 1) {
// 				$pagesSpacer.height((currentPage - 1) * pageHeight);
// 			}

// 			$('html, body').animate({
// 				scrollTop: ($pagesContainer.offset().top + pageHeight)
// 			}, 0);

// 			pageCount = currentPage;
// 			if (currentPage > 2) {
// 				deletedPages = currentPage - 2;
// 			}

// 			// auxiliarty info
// 			$('.deletedPageValue').text(deletedPages);
// 			$('.pageCountValue').text(pageCount);
// 			$('.currentPageValue').text(currentPage);
// 		}
// 	}

// 	init();
// 	onScroll();
// 	// $(window).on('scroll', _.debounce(onScroll, 50));
// 	$(window).on('scroll', onScroll);
// });

/**
 * jQuery plugin template by https://github.com/publicJorn
 * Features:
 * - dynamic plugin name (only supply once) so it's easy to change later
 * - plugin factory to make it work in the browser, or with AMD / COMMONJS modules
 * - Plugin instance is saved on the selector element
 * - Default options are saved to the instance in case you need to figure out a difference between passed options
 */
(function(global, factory) {
	'use strict';
	if (typeof define === 'function' && define.amd) {
		define(['jquery'], function($) {
			return factory($, global, global.document);
		});
	} else if (typeof exports === "object" && exports) {
		module.exports = factory(require('jquery'), global, global.document);
	} else {
		factory(jQuery, global, global.document);
	}
})(typeof window !== 'undefined' ? window : this, function($, window, document, undefined) {
	'use strict';

	// -- Name is used to keep jQUery plugin template portable
	var pluginName = 'HeavenScroll';

	// -- Globals (shared across all plugin instances)
	var defaultOptions = {
		pageHeight: -1,
		maxPagesNumber: -1,
		startPage: -1,
		loadPageFunction: -1
	};

	var $window = $(window);
	var $document = $(document);
	var $htmlBody = $('html, body');
	var screenHeight = $window.height();

	class HeavenScroll {
		constructor(el, options) {
			this.el = el;
			this.$el = $(el);
			this.options = $.extend({}, defaultOptions, options) ;

			this.init();
			this.initContainerOffset();
			this.urlHasStartPageInfo();

			this.onScroll();
			$window.on('scroll', this.onScroll.bind(this));

			// delete console.log
			console.log(this.options.maxPagesNumber);
			console.log(this.options.pageHeight);
			console.log(this.options.startPage);
			console.log(this.options.loadPageFunction);
			console.log(this.pagePlaceholder);
			console.log(this.currentPage);
		}

		init() {
			if (this.options.maxPagesNumber === -1) {
				this.options.maxPagesNumber = this.$el.data('maxPages');
			}

			if (this.options.pageHeight === -1) {
				this.options.pageHeight = this.$el.data('pageHeight');
			}

			if (this.options.startPage === -1) {
				this.options.startPage = this.$el.data('startPage');
			}

			if (this.options.loadPageFunction === -1) {
				this.options.loadPageFunction = this.$el.data('infoOnPages');
			}

			this.currentPage = this.options.startPage;
			this.pageCount = 0;
			this.deletedPages = 0;
			this.prevScroll = 0;
			this.firstRun = true;
		}

		initContainerOffset() {
			this.pagePlaceholder = this.$el.position().top;
		}

		loadPage(position, printPageNumber) {
			var html = '
' + printPageNumber + '
';
			if (position === 'ini') {
				this.$el.prepend(html);
			} else if (position === 'end') {
				this.$el.append(html);
			}
		}

		updateContainerPadding() {
			this.$el.css('padding-top', ((this.currentPage - 1) * this.options.pageHeight) + 'px');
		}

		urlHasStartPageInfo() {
			var scrollAmount;
			var urlStartPage = 'startPage';
			var currentPage;
			var arr = $(location)
				.attr('href')
				.split('?');

			if (arr.length > 1) {
				this.urlStartUp = true;

				arr[1]
					.split('&')
					.forEach(function (arg) {
						if (arg.indexOf(urlStartPage) !== -1) {
							currentPage = parseInt(arg.split('=')[1], 10);
							return;
						}
					});

				this.currentPage = currentPage;
				this.firstRun = false;

				if (this.currentPage > 1) {
					this.loadPage('end', (this.currentPage - 1));
				}
				this.loadPage('end', this.currentPage);

				if (currentPage > 1) {
					this.updateContainerPadding(); // needs to be created

					scrollAmount = this.$el.offset().top + this.options.pageHeight * this.currentPage;
					setTimeout(function () {
						$htmlBody.animate({ scrollTop: scrollAmount }, 0);
					}, 0);
				}

				this.pageCount = this.currentPage;
				if (this.currentPage > 2) {
					this.deletedPages = this.currentPage - 2;
				}
			}
		}

		updateValues() {
			this.pagesViewport = this.screenHeight - this.pagePlaceholder;
			this.pagesObjHeight = this.options.pageHeight * this.pageCount;
			this.pagesCurrentHeight = this.options.pageHeight * this.currentPage;

			// screen half way through last visible page
			this.nextPageTriggerHeight = this.pagesObjHeight - this.options.pageHeight / 2;

			// screen half way through first visible page
			this.prevPageTriggerHeight = parseInt(this.$el.css('padding-top'), 10) + this.options.pageHeight * 1.5;
		}

		scrollingOptions() {

		}

		onScroll() {
			console.log('scrolling');

			this.scrollValue = $document.scrollTop();

			// check if the screen is at half size
			if (this.firstRun) {
				this.pageCount++;
				this.loadPage('end', this.pageCount);
				this.firstRun = false;
				this.updateValues();

				if (this.pagesViewport > (this.options.pageHeight / 2)) {
					this.pageCount++;
					this.loadPage('end', this.pageCount);
				}
			} else {
				this.updateValues();
				this.scrollingOptions();
			}

			this.prevScroll = this.scrollValue;
		}
	}

	// -- Prevent multiple instantiations
	$.fn[pluginName] = function(options) {
		return this.each(function () {
			if (!$.data(this, 'plugin_'+ pluginName)) {
				$.data(this, 'plugin_'+ pluginName, new HeavenScroll(this, options));
			}
		});
	};
});
$(document).ready(function () {
	$('.pagesContainer').HeavenScroll({
		maxPagesNumber: 3,
		pageHeight: 1584,
		startPage: 1,
		loadPageFunction: 'productTileFetcher'
	});
});
<|endoftext|>


<commit_before>import { getSNAPBenefits } from '../../../programs/federal/snap';

// CLIENTS
import { CLIENT_DEFAULTS } from '../../../utils/CLIENT_DEFAULTS';
import { sampleClients } from '../../sampleClients';
import { cloneDeep } from 'lodash';

const defaultClient       = cloneDeep( CLIENT_DEFAULTS );

describe('getSNAPBenefits', () => {
  describe('default client', () => {
    it('Should calculate the correct current benefits', () => {
      expect(getSNAPBenefits(defaultClient, 'current')).toEqual(192);
    });
  });

  describe('row3', () => {
    it('Should calculate the correct current benefits', () => {
      let client = sampleClients.row3;
      // expect(getSNAPBenefits(client, 'current')).toBeCloseTo(client.current.expectedSNAP, 4);
      // Project Hope: 1062, Excel: 1066, Ours: 1066.3
      expect(getSNAPBenefits(client, 'current')).toBeCloseTo(1066.3, 4);
    });
  });

  describe('row4', () => {
    it('Should calculate the correct current benefits', () => {
      let client = sampleClients.row4;
      // expect(getSNAPBenefits(client, 'current')).toBeCloseTo(client.current.expectedSNAP, 4);
      // Project Hope: 117, Excel: 86, Ours: 85.6
      expect(getSNAPBenefits(client, 'current')).toBeCloseTo(85.6, 4);
    });
  });

  describe('row5', () => {
    it('Should calculate the correct current benefits', () => {
      let client = sampleClients.row5;
      // Sample data result didn't match. Missing data?
      // expect(getSNAPBenefits(client, 'current')).toBeCloseTo(client.current.expectedSNAP, 4);
      // Current result
      expect(getSNAPBenefits(client, 'current')).toBeCloseTo(15, 4);
    });
  });

  describe('row6', () => {
    it('Should calculate the correct current benefits', () => {
      let client = sampleClients.row6;
      // Sample data result didn't match. Missing data?
      // expect(getSNAPBenefits(client, 'current')).toBeCloseTo(client.current.expectedSNAP, 4);
      // Current result
      expect(getSNAPBenefits(client, 'current')).toBeCloseTo(352, 4);
    });
  });

  describe('row7', () => {
    it('Should calculate the correct current benefits', () => {
      let client = sampleClients.row7;
      // Sample data result didn't match. Missing data?
      // expect(getSNAPBenefits(client, 'current')).toBeCloseTo(client.current.expectedSNAP, 4);
      // Current result
      expect(getSNAPBenefits(client, 'current')).toBeCloseTo(0, 4);
    });
  });

  describe('row8', () => {
    it('Should calculate the correct current benefits', () => {
      let client = sampleClients.row8;
      // expect(getSNAPBenefits(client, 'current')).toBeCloseTo(client.current.expectedSNAP, 4);
      // TODO: - Current result - returning undefined
      // Project Hope: null, Excel: 0, Ours: 0
      expect(getSNAPBenefits(client, 'current')).toBeCloseTo(0, 4);
    });
  });

  describe('row9', () => {
    it('Should calculate the correct current benefits', () => {
      let client = sampleClients.row9;
      // expect(getSNAPBenefits(client, 'current')).toBeCloseTo(client.current.expectedSNAP, 4);
      // Project Hope: 150, Excel: 54, Ours: 54.4
      expect(getSNAPBenefits(client, 'current')).toBeCloseTo(54.4, 4);
    });
  });

  describe('row10', () => {
    it('Should calculate the correct current benefits', () => {
      let client = sampleClients.row10;
      // Sample data result didn't match. Missing data?
      // expect(getSNAPBenefits(client, 'current')).toBeCloseTo(client.current.expectedSNAP, 4);
      // Current result
      expect(getSNAPBenefits(client, 'current')).toBeCloseTo(0, 4);
    });
  });

});
<commit_msg>updated rows 8<commit_after>import { getSNAPBenefits } from '../../../programs/federal/snap';

// CLIENTS
import { CLIENT_DEFAULTS } from '../../../utils/CLIENT_DEFAULTS';
import { sampleClients } from '../../sampleClients';
import { cloneDeep } from 'lodash';

const defaultClient       = cloneDeep( CLIENT_DEFAULTS );

describe('getSNAPBenefits', () => {
  describe('default client', () => {
    it('Should calculate the correct current benefits', () => {
      expect(getSNAPBenefits(defaultClient, 'current')).toEqual(192);
    });
  });

  describe('row3', () => {
    it('Should calculate the correct current benefits', () => {
      let client = sampleClients.row3;
      // expect(getSNAPBenefits(client, 'current')).toBeCloseTo(client.current.expectedSNAP, 4);
      // Project Hope: 1062, Excel: 1066, Ours: 1066.3
      expect(getSNAPBenefits(client, 'current')).toBeCloseTo(1066.3, 4);
    });
  });

  describe('row4', () => {
    it('Should calculate the correct current benefits', () => {
      let client = sampleClients.row4;
      // expect(getSNAPBenefits(client, 'current')).toBeCloseTo(client.current.expectedSNAP, 4);
      // Project Hope: 117, Excel: 86, Ours: 85.6
      expect(getSNAPBenefits(client, 'current')).toBeCloseTo(85.6, 4);
    });
  });

  describe('row5', () => {
    it('Should calculate the correct current benefits', () => {
      let client = sampleClients.row5;
      // Sample data result didn't match. Missing data?
      // expect(getSNAPBenefits(client, 'current')).toBeCloseTo(client.current.expectedSNAP, 4);
      // Current result
      expect(getSNAPBenefits(client, 'current')).toBeCloseTo(15, 4);
    });
  });

  describe('row6', () => {
    it('Should calculate the correct current benefits', () => {
      let client = sampleClients.row6;
      // Sample data result didn't match. Missing data?
      // expect(getSNAPBenefits(client, 'current')).toBeCloseTo(client.current.expectedSNAP, 4);
      // Current result
      expect(getSNAPBenefits(client, 'current')).toBeCloseTo(352, 4);
    });
  });

  describe('row7', () => {
    it('Should calculate the correct current benefits', () => {
      let client = sampleClients.row7;
      // Sample data result didn't match. Missing data?
      // expect(getSNAPBenefits(client, 'current')).toBeCloseTo(client.current.expectedSNAP, 4);
      // Current result
      expect(getSNAPBenefits(client, 'current')).toBeCloseTo(0, 4);
    });
  });

  describe('row8', () => {
    it('Should calculate the correct current benefits', () => {
      let client = sampleClients.row8;
      // expect(getSNAPBenefits(client, 'current')).toBeCloseTo(client.current.expectedSNAP, 4);
      // TODO: - Current result - returning undefined
      // Project Hope: null, Excel: 211, Ours: 211
      // expect(getSNAPBenefits(client, 'current')).toBeCloseTo(0, 4);
    });
  });

  describe('row9', () => {
    it('Should calculate the correct current benefits', () => {
      let client = sampleClients.row9;
      // expect(getSNAPBenefits(client, 'current')).toBeCloseTo(client.current.expectedSNAP, 4);
      // Project Hope: 150, Excel: 54, Ours: 54.4
      expect(getSNAPBenefits(client, 'current')).toBeCloseTo(54.4, 4);
    });
  });

  describe('row10', () => {
    it('Should calculate the correct current benefits', () => {
      let client = sampleClients.row10;
      // Sample data result didn't match. Missing data?
      // expect(getSNAPBenefits(client, 'current')).toBeCloseTo(client.current.expectedSNAP, 4);
      // Current result
      expect(getSNAPBenefits(client, 'current')).toBeCloseTo(0, 4);
    });
  });

});
<|endoftext|>


<commit_before>import http from 'k6/http'
import {check, group} from 'k6'
import {getTestAuthHeaders} from './auth.js'

const BASE_URL = __ENV.BASE_URL || 'https://localhost:8080'

export const options = {
  vus: 10,
  duration: '1m',
  thresholds: {
    http_req_duration: ['p(95)<50']
  },
  insecureSkipTLSVerify: true
}

function getMetricsByMinute() {
  const res = http.get(
    // TODO: Use valid date
    `${BASE_URL}/metrics/timeseries/minute?startDate=2017-12-01T10:00:00.000Z&endDate=2017-12-01T11:00:00.000Z`,
    {
      headers: Object.assign(getTestAuthHeaders(), {
        Accept: 'application/json'
      }),
      tags: {
        name: 'All metrics by minute'
      }
    }
  )
  check(res, {
    'status code is 200': r => r.status === 200
  })
}

function getMetricsByHour() {
  const res = http.get(
    // TODO: Use valid date
    `${BASE_URL}/metrics/timeseries/hour?startDate=2017-12-01T00:00:00.000Z&endDate=2017-12-02T00:00:00.000Z`,
    {
      headers: Object.assign(getTestAuthHeaders(), {
        Accept: 'application/json'
      }),
      tags: {
        name: 'All metrics by hour'
      }
    }
  )
  check(res, {
    'status code is 200': r => r.status === 200
  })
}

function getMetricsByDay() {
  const res = http.get(
    // TODO: Use valid date
    `${BASE_URL}/metrics/timeseries/day?startDate=2017-12-01&endDate=2017-12-31`,
    {
      headers: Object.assign(getTestAuthHeaders(), {
        Accept: 'application/json'
      }),
      tags: {
        name: 'All metrics by day'
      }
    }
  )
  check(res, {
    'status code is 200': r => r.status === 200
  })
}

function getMetricsByMonth() {
  const res = http.get(
    // TODO: Use valid date
    `${BASE_URL}/metrics/timeseries/month?startDate=2017-01-01&endDate=2017-12-31`,
    {
      headers: Object.assign(getTestAuthHeaders(), {
        Accept: 'application/json'
      }),
      tags: {
        name: 'All metrics by month'
      }
    }
  )
  check(res, {
    'status code is 200': r => r.status === 200
  })
}

function getMetricsByChannel() {
  const res = http.get(
    // TODO: Use valid date and channel id
    `${BASE_URL}/metrics/channels/5a1ff399ab40973d07eec9f9?startDate=2017-01-01&endDate=2017-12-31`,
    {
      headers: Object.assign(getTestAuthHeaders(), {
        Accept: 'application/json'
      }),
      tags: {
        name: 'Metrics by channel'
      }
    }
  )
  check(res, {
    'status code is 200': r => r.status === 200
  })
}

export default function execute() {
  group('Metrics', () => {
    group('By time range', () => {
      group('By minute', getMetricsByMinute)
      group('By hour', getMetricsByHour)
      group('By day', getMetricsByDay)
      group('By month', getMetricsByMonth)
    })
    group('By channel', getMetricsByChannel)
  })
}
<commit_msg>Use a single virtual user for metrics<commit_after>import http from 'k6/http'
import {check, group} from 'k6'
import {getTestAuthHeaders} from './auth.js'

const BASE_URL = __ENV.BASE_URL || 'https://localhost:8080'

export const options = {
  vus: 1,
  iterations: 100,
  thresholds: {
    http_req_duration: ['p(95)<50']
  },
  insecureSkipTLSVerify: true
}

function getMetricsByMinute() {
  const res = http.get(
    // TODO: Use valid date
    `${BASE_URL}/metrics/timeseries/minute?startDate=2017-12-01T10:00:00.000Z&endDate=2017-12-01T11:00:00.000Z`,
    {
      headers: Object.assign(getTestAuthHeaders(), {
        Accept: 'application/json'
      }),
      tags: {
        name: 'All metrics by minute'
      }
    }
  )
  check(res, {
    'status code is 200': r => r.status === 200
  })
}

function getMetricsByHour() {
  const res = http.get(
    // TODO: Use valid date
    `${BASE_URL}/metrics/timeseries/hour?startDate=2017-12-01T00:00:00.000Z&endDate=2017-12-02T00:00:00.000Z`,
    {
      headers: Object.assign(getTestAuthHeaders(), {
        Accept: 'application/json'
      }),
      tags: {
        name: 'All metrics by hour'
      }
    }
  )
  check(res, {
    'status code is 200': r => r.status === 200
  })
}

function getMetricsByDay() {
  const res = http.get(
    // TODO: Use valid date
    `${BASE_URL}/metrics/timeseries/day?startDate=2017-12-01&endDate=2017-12-31`,
    {
      headers: Object.assign(getTestAuthHeaders(), {
        Accept: 'application/json'
      }),
      tags: {
        name: 'All metrics by day'
      }
    }
  )
  check(res, {
    'status code is 200': r => r.status === 200
  })
}

function getMetricsByMonth() {
  const res = http.get(
    // TODO: Use valid date
    `${BASE_URL}/metrics/timeseries/month?startDate=2017-01-01&endDate=2017-12-31`,
    {
      headers: Object.assign(getTestAuthHeaders(), {
        Accept: 'application/json'
      }),
      tags: {
        name: 'All metrics by month'
      }
    }
  )
  check(res, {
    'status code is 200': r => r.status === 200
  })
}

function getMetricsByChannel() {
  const res = http.get(
    // TODO: Use valid date and channel id
    `${BASE_URL}/metrics/channels/5a1ff399ab40973d07eec9f9?startDate=2017-01-01&endDate=2017-12-31`,
    {
      headers: Object.assign(getTestAuthHeaders(), {
        Accept: 'application/json'
      }),
      tags: {
        name: 'Metrics by channel'
      }
    }
  )
  check(res, {
    'status code is 200': r => r.status === 200
  })
}

export default function execute() {
  group('Metrics', () => {
    group('By time range', () => {
      group('By minute', getMetricsByMinute)
      group('By hour', getMetricsByHour)
      group('By day', getMetricsByDay)
      group('By month', getMetricsByMonth)
    })
    group('By channel', getMetricsByChannel)
  })
}
<|endoftext|>


<commit_before>var saved_list;
var _remove = function () {
    var removing_list = saved_list;
    if (removing_list) {
        var target = this;
        setTimeout(function () {
            if (removing_list !== saved_list) return remove(removing_list);
            var { activeElement } = document;
            if (!getTargetIn(removing_list, activeElement)) {
                remove(removing_list);
                if (removing_list === saved_list) saved_list = null;
            } else {
                once('blur')(activeElement, function () {
                    setTimeout(function () {
                        if (document.activeElement === target) return;
                        _remove();
                    })
                });
            }
        });
    }
};
var preventDefault = function (event) {
    event.preventDefault();
};
var lastTimeClick = 0;
function select(target, list) {
    if (!target) {
        target = createElement(div);
    }
    target.tabIndex = 0;
    onblur(target, _remove);
    if (/select/i.test(target.tagName)) {
        onmousedown(target, preventDefault);
    }
    var bindEvent = function () {
        on("change")(list, function (event) {
            if (target.multiple) {
            } else {
                target.value = this.value;
                dispatch(target, "change");
            }
        });
        onclick(list, function (event) {
            if (!event.defaultPrevented) {
                _remove();
            }
        });
        onremove(list, () => {
            if (saved_list === list) {
                saved_list = null;
            }
        });
    };
    if (list) {
        var initList = bindEvent;
    } else {
        var savedOptions;
        var initList = function () {
            var allOptions = [].concat.apply([], target.querySelectorAll("option"));
            if (deepEqual.shallow(allOptions, savedOptions)) return;
            savedOptions = allOptions;
            list = selectList(allOptions, target.multiple);
            if (!target.multiple) {
                onclick(list, _remove);
            }
            bindEvent();
        };
    }
    var mousedown = function () {
        initList();
        if (saved_list !== list) {
            _remove();
            if (document.activeElement !== target) target.focus();
            popup(list, target);
            saved_list = list;
        }
        else _remove();
    };
    onclick(target, mousedown);
    return target;
}<commit_msg>在弹出对象上mousedown加上preventDefault<commit_after>var saved_list;
var _remove = function () {
    var removing_list = saved_list;
    if (removing_list) {
        var target = this;
        setTimeout(function () {
            if (removing_list !== saved_list) return remove(removing_list);
            var { activeElement } = document;
            if (!getTargetIn(removing_list, activeElement)) {
                remove(removing_list);
                if (removing_list === saved_list) saved_list = null;
            } else {
                once('blur')(activeElement, function () {
                    setTimeout(function () {
                        if (document.activeElement === target) return;
                        _remove();
                    })
                });
            }
        });
    }
};
var preventDefault = function (event) {
    event.preventDefault();
};
var lastTimeClick = 0;
function select(target, list) {
    if (!target) {
        target = createElement(div);
    }
    target.tabIndex = 0;
    onblur(target, _remove);
    if (/select/i.test(target.tagName)) {
        onmousedown(target, preventDefault);
    }
    var bindEvent = function () {
        on("change")(list, function (event) {
            if (target.multiple) {
            } else {
                target.value = this.value;
                dispatch(target, "change");
            }
        });
        onclick(list, function (event) {
            if (!event.defaultPrevented) {
                _remove();
            }
        });
        onmousedown(list, preventDefault);
        onremove(list, () => {
            if (saved_list === list) {
                saved_list = null;
            }
        });
    };
    if (list) {
        var initList = bindEvent;
    } else {
        var savedOptions;
        var initList = function () {
            var allOptions = [].concat.apply([], target.querySelectorAll("option"));
            if (deepEqual.shallow(allOptions, savedOptions)) return;
            savedOptions = allOptions;
            list = selectList(allOptions, target.multiple);
            if (!target.multiple) {
                onclick(list, _remove);
            }
            bindEvent();
        };
    }
    var mousedown = function () {
        initList();
        if (saved_list !== list) {
            _remove();
            if (document.activeElement !== target) target.focus();
            popup(list, target);
            saved_list = list;
        }
        else _remove();
    };
    onclick(target, mousedown);
    return target;
}<|endoftext|>


<commit_before>/**
 * @file Unit tests for the competitions background module
 * @author Daniil Filippov <filippovdaniil@gmail.com>
 */

require('../background.js');
var sinon = require('sinon');
var assertStyles = require('../../assert-styles.js');
var expect = assertStyles.expect;
var fixtures = require('../../fixtures.js');

describe('competitions module', function () {
  describe('Competitions class', function () {
    // Reference to the sinon sandbox:
    var sandbox;
    // Reference to the Competitions class instance:
    var competitions;

    beforeEach(function () {
      sandbox = sinon.sandbox.create();
      sandbox.useFakeTimers();
      // Setting up stubs and spies for the kango mock object:
      sandbox.stub(kango.storage, 'getItem');
      sandbox.stub(kango.xhr, 'send');
      sandbox.spy(kango.storage, 'setItem');
      sandbox.spy(kango.browser.tabs, 'create');
      sandbox.spy(Competitions.prototype, '_updateNotifications');
      sandbox.spy(Competitions.prototype, '_createNotification');
      // Setting up a spy for the DeferredNotification class constructor:
      sandbox.spy(global, 'DeferredNotification');
      sandbox.stub(DeferredNotification.prototype, 'revoke');
      sandbox.stub(DeferredNotification.prototype, 'show');
      competitions = new Competitions;
      // Set the default server time delta to 1000 milliseconds:
      competitions._timeCorrection = 1000;
    });

    afterEach(function () {
      // Unwraping all stubs and spies:
      sandbox.restore();
    });

    /**
     * Tests for the Competitions class constructor
     */
    it('should set the correct default settings', function () {
      expect(competitions.rates).to.be.deep.equal([3, 5]);
      expect(competitions.delay).to.be.equal(60);
      expect(competitions.displayTime).to.be.equal(0);
      expect(competitions.audio).to.be.equal(false);
    });

    /**
     * Test for the Competitions.prototype.getParams method
     */
    it('should return the correct settings with the getParams() method', function () {
      kango.storage.getItem.withArgs('competition_rates').returns([1, 2, 3, 5]);
      kango.storage.getItem.withArgs('competition_delay').returns(15);
      kango.storage.getItem.withArgs('competition_displayTime').returns(5);
      kango.storage.getItem.withArgs('competition_audio').returns(false);
      competitions = new Competitions;
      expect(competitions.getParams()).to.be.deep.equal({
        rates: [1, 2, 3, 5],
        delay: 15,
        displayTime: 5,
        audio: false
      });
    });

    /**
     * Tests for the Competitions.prototype.setParams method
     */
    it('should save the correct settings to storage with the setParams() method', function () {
      // Checking the invalid parameters:
      competitions.setParams({
        delay: null,
        rates: null,
        displayTime: null,
        audio: null
      });
      // sinon-chai doesn't support neverCalledWithMatch :(
      sinon
        .assert
        .neverCalledWithMatch(kango.storage.setItem, sinon.match.string, null);
      // Checking the valid parameters:
      competitions.setParams({
        delay: 15,
        rates: [1, 2, 3, 5],
        displayTime: 5,
        audio: false
      });
      expect(kango.storage.setItem)
        .to.have.been.calledWithExactly('competition_delay', 15)
        .to.have.been.calledWithExactly('competition_rates', [1, 2, 3, 5])
        .to.have.been.calledWithExactly('competition_displayTime', 5);
        .to.have.been.calledWithExactly('competition_audio', false);
    });

    it('should call the _updateNotifications() method within ' +
        'the setParams() method', function () {
      var competitions = new Competitions;
      competitions.setParams({ delay: 15 });
      competitions.setParams({ displayTime: 5 });
      expect(Competitions.prototype._updateNotifications).to.have.been.calledTwice;
    });

    it('should recreate deferred notifications instances with the for ' +
        'active competitions', function () {
      var spy1 = new DeferredNotification('test1');
      var spy2 = new DeferredNotification('test2');
      sandbox.stub(Competitions.prototype, 'getRemainingTime').returns(1000);
      competitions._hash = {
        1337: {
          id: 1337,
          beginTime: null,
          ratingValue: 1,
        },
        1338: {
          id: 1338,
          // For this test doesn't matter:
          beginTime: 0,
          ratingValue: 3,
          notification: spy1,
        },
        1339: {
          id: 1339,
          beginTime: 0,
          ratingValue: 5,
          notification: spy2,
        },
      }
      competitions._updateNotifications();
      expect(spy1.revoke).to.have.been.called;
      expect(spy2.revoke).to.have.been.called;
      expect(Competitions.prototype._createNotification).to.have.been.calledTwice;
      expect(competitions._hash[1338].notification)
        .to.be.an.instanceOf(DeferredNotification)
        .to.be.not.deep.equal(spy1);
      expect(competitions._hash[1339].notification)
        .to.be.an.instanceOf(DeferredNotification)
        .to.be.not.deep.equal(spy2);
    });

    it('should create the "deferred" notification with correct parameters', function () {
      var competitionData = {
        id: 1337,
        ratingValue: 5,
        // For this test doesn't matter:
        beginTime: 0,
      };
      var notification = competitions._createNotification(competitionData, 400);
      expect(DeferredNotification)
        .to.have.been.calledWithExactly('Соревнование', {
          body: 'Соревнование x5 начинается',
          // TODO: set the stub for the kango.io.getResourceUrl
          icon: undefined,
          displayTime: undefined,
        });
      // Default delay is set to 1 minute:
      expect(DeferredNotification.prototype.show)
        .to.have.been.calledWithExactly(340);
      // Check the notification's click handler:
      notification.onclick();
      expect(kango.browser.tabs.create)
        .to.have.been.calledWithExactly({
          url: 'http://klavogonki.ru/g/?gmid=1337',
          focused: true,
        });
      // Check the case with a huge displayTime:
      kango.storage.getItem.withArgs('competition_displayTime').returns(500);
      competitions = new Competitions;
      var notification = competitions._createNotification(competitionData, 400);
      expect(DeferredNotification)
        .to.have.been.calledWithExactly('Соревнование', {
          body: 'Соревнование x5 начинается',
          icon: undefined,
          // displayTime == delay:
          displayTime: 60,
        });
      // Check the case with a huge delay:
      kango.storage.getItem.withArgs('competition_delay').returns(500);
      competitions = new Competitions;
      var notification = competitions._createNotification(competitionData, 400);
      expect(DeferredNotification.prototype.show)
        .to.have.been.calledWithExactly(0);
    });

    it('should revoke the notification with the click on it', function () {
      var competitionData = {
        id: 1337,
        ratingValue: 5,
        // For this test doesn't matter:
        beginTime: 0,
      };
      var notification = competitions._createNotification(competitionData, 400);
      notification.onclick();
      expect(DeferredNotification.prototype.revoke).to.have.been.called;
    });

    it('should correctly calculate the remaining time before the ' +
        'competition start', function () {
      sandbox.clock.tick(1470230514177);
      // The default server time delta is set to 1000 milliseconds:
      expect(competitions.getRemainingTime(1470230614)).to.be.equal(99);
      expect(competitions.getRemainingTime('2016-08-03T13:23:34.000Z')).to.be.equal(99);
    });

    it('should throw an error for invalid competition begin time or ' +
        'server time delta', function () {
      sandbox.clock.tick(1470230514177);
      expect(competitions.getRemainingTime.bind(competitions, null)).to.throw(TypeError);
      competitions._timeCorrection = null;
      expect(competitions.getRemainingTime.bind(competitions, 1470230614))
        .to.throw(Error);
    });

    it('should delete already started competitions with _clearStarted() ' +
        'method', function () {
      sandbox.clock.tick(2 * 1e3);
      competitions._hash = {
        1337: {
          id: 1337,
          beginTime: null,
          ratingValue: 1,
        },
        1338: {
          id: 1338,
          beginTime: 0,
          ratingValue: 3,
        },
        1339: {
          id: 1339,
          beginTime: 5,
          ratingValue: 5,
        },
      };
      competitions._clearStarted();
      expect(competitions._hash[1337]).to.be.an('object');
      expect(competitions._hash[1338]).to.be.undefined;
      expect(competitions._hash[1339]).to.be.an('object');
    });

    it('should show the notifications only for selected rates', function () {
      sandbox.stub(Competitions.prototype, 'getRemainingTime').returns(1000);
      kango.storage.getItem.withArgs('competition_rates').returns([2, 3, 5]);
      competitions = new Competitions;
      competitions._hash = {
        1337: {
          id: 1337,
          beginTime: 0,
          ratingValue: 1,
        },
        1338: {
          id: 1338,
          beginTime: 0,
          ratingValue: 2,
        },
        1339: {
          id: 1339,
          beginTime: 0,
          ratingValue: 3,
        },
        1340: {
          id: 1340,
          beginTime: 0,
          ratingValue: 5,
        },
      };
      competitions._notify(1337);
      competitions._notify(1338);
      competitions._notify(1339);
      competitions._notify(1340);
      expect(Competitions.prototype._createNotification).to.have.been.calledThrice;
    });

    it('should not show notifications if the delay is set to zero', function () {
      sandbox.stub(Competitions.prototype, 'getRemainingTime').returns(1000);
      kango.storage.getItem.withArgs('competition_delay').returns(0);
      competitions = new Competitions;
      competitions._hash = {
        1337: {
          id: 1338,
          beginTime: 0,
          ratingValue: 3,
        },
        1338: {
          id: 1339,
          beginTime: 5,
          ratingValue: 5,
        },
      };
      competitions._notify(1337);
      competitions._notify(1338);
      expect(Competitions.prototype._createNotification).to.not.been.called;
    });

    it('should revoke all notifications on teardown');
  });
});
<commit_msg>fixtypo<commit_after>/**
 * @file Unit tests for the competitions background module
 * @author Daniil Filippov <filippovdaniil@gmail.com>
 */

require('../background.js');
var sinon = require('sinon');
var assertStyles = require('../../assert-styles.js');
var expect = assertStyles.expect;
var fixtures = require('../../fixtures.js');

describe('competitions module', function () {
  describe('Competitions class', function () {
    // Reference to the sinon sandbox:
    var sandbox;
    // Reference to the Competitions class instance:
    var competitions;

    beforeEach(function () {
      sandbox = sinon.sandbox.create();
      sandbox.useFakeTimers();
      // Setting up stubs and spies for the kango mock object:
      sandbox.stub(kango.storage, 'getItem');
      sandbox.stub(kango.xhr, 'send');
      sandbox.spy(kango.storage, 'setItem');
      sandbox.spy(kango.browser.tabs, 'create');
      sandbox.spy(Competitions.prototype, '_updateNotifications');
      sandbox.spy(Competitions.prototype, '_createNotification');
      // Setting up a spy for the DeferredNotification class constructor:
      sandbox.spy(global, 'DeferredNotification');
      sandbox.stub(DeferredNotification.prototype, 'revoke');
      sandbox.stub(DeferredNotification.prototype, 'show');
      competitions = new Competitions;
      // Set the default server time delta to 1000 milliseconds:
      competitions._timeCorrection = 1000;
    });

    afterEach(function () {
      // Unwraping all stubs and spies:
      sandbox.restore();
    });

    /**
     * Tests for the Competitions class constructor
     */
    it('should set the correct default settings', function () {
      expect(competitions.rates).to.be.deep.equal([3, 5]);
      expect(competitions.delay).to.be.equal(60);
      expect(competitions.displayTime).to.be.equal(0);
      expect(competitions.audio).to.be.equal(false);
    });

    /**
     * Test for the Competitions.prototype.getParams method
     */
    it('should return the correct settings with the getParams() method', function () {
      kango.storage.getItem.withArgs('competition_rates').returns([1, 2, 3, 5]);
      kango.storage.getItem.withArgs('competition_delay').returns(15);
      kango.storage.getItem.withArgs('competition_displayTime').returns(5);
      kango.storage.getItem.withArgs('competition_audio').returns(false);
      competitions = new Competitions;
      expect(competitions.getParams()).to.be.deep.equal({
        rates: [1, 2, 3, 5],
        delay: 15,
        displayTime: 5,
        audio: false
      });
    });

    /**
     * Tests for the Competitions.prototype.setParams method
     */
    it('should save the correct settings to storage with the setParams() method', function () {
      // Checking the invalid parameters:
      competitions.setParams({
        delay: null,
        rates: null,
        displayTime: null,
        audio: null
      });
      // sinon-chai doesn't support neverCalledWithMatch :(
      sinon
        .assert
        .neverCalledWithMatch(kango.storage.setItem, sinon.match.string, null);
      // Checking the valid parameters:
      competitions.setParams({
        delay: 15,
        rates: [1, 2, 3, 5],
        displayTime: 5,
        audio: false
      });
      expect(kango.storage.setItem)
        .to.have.been.calledWithExactly('competition_delay', 15)
        .to.have.been.calledWithExactly('competition_rates', [1, 2, 3, 5])
        .to.have.been.calledWithExactly('competition_displayTime', 5)
        .to.have.been.calledWithExactly('competition_audio', false);
    });

    it('should call the _updateNotifications() method within ' +
        'the setParams() method', function () {
      var competitions = new Competitions;
      competitions.setParams({ delay: 15 });
      competitions.setParams({ displayTime: 5 });
      expect(Competitions.prototype._updateNotifications).to.have.been.calledTwice;
    });

    it('should recreate deferred notifications instances with the for ' +
        'active competitions', function () {
      var spy1 = new DeferredNotification('test1');
      var spy2 = new DeferredNotification('test2');
      sandbox.stub(Competitions.prototype, 'getRemainingTime').returns(1000);
      competitions._hash = {
        1337: {
          id: 1337,
          beginTime: null,
          ratingValue: 1,
        },
        1338: {
          id: 1338,
          // For this test doesn't matter:
          beginTime: 0,
          ratingValue: 3,
          notification: spy1,
        },
        1339: {
          id: 1339,
          beginTime: 0,
          ratingValue: 5,
          notification: spy2,
        },
      }
      competitions._updateNotifications();
      expect(spy1.revoke).to.have.been.called;
      expect(spy2.revoke).to.have.been.called;
      expect(Competitions.prototype._createNotification).to.have.been.calledTwice;
      expect(competitions._hash[1338].notification)
        .to.be.an.instanceOf(DeferredNotification)
        .to.be.not.deep.equal(spy1);
      expect(competitions._hash[1339].notification)
        .to.be.an.instanceOf(DeferredNotification)
        .to.be.not.deep.equal(spy2);
    });

    it('should create the "deferred" notification with correct parameters', function () {
      var competitionData = {
        id: 1337,
        ratingValue: 5,
        // For this test doesn't matter:
        beginTime: 0,
      };
      var notification = competitions._createNotification(competitionData, 400);
      expect(DeferredNotification)
        .to.have.been.calledWithExactly('Соревнование', {
          body: 'Соревнование x5 начинается',
          // TODO: set the stub for the kango.io.getResourceUrl
          icon: undefined,
          displayTime: undefined,
        });
      // Default delay is set to 1 minute:
      expect(DeferredNotification.prototype.show)
        .to.have.been.calledWithExactly(340);
      // Check the notification's click handler:
      notification.onclick();
      expect(kango.browser.tabs.create)
        .to.have.been.calledWithExactly({
          url: 'http://klavogonki.ru/g/?gmid=1337',
          focused: true,
        });
      // Check the case with a huge displayTime:
      kango.storage.getItem.withArgs('competition_displayTime').returns(500);
      competitions = new Competitions;
      var notification = competitions._createNotification(competitionData, 400);
      expect(DeferredNotification)
        .to.have.been.calledWithExactly('Соревнование', {
          body: 'Соревнование x5 начинается',
          icon: undefined,
          // displayTime == delay:
          displayTime: 60,
        });
      // Check the case with a huge delay:
      kango.storage.getItem.withArgs('competition_delay').returns(500);
      competitions = new Competitions;
      var notification = competitions._createNotification(competitionData, 400);
      expect(DeferredNotification.prototype.show)
        .to.have.been.calledWithExactly(0);
    });

    it('should revoke the notification with the click on it', function () {
      var competitionData = {
        id: 1337,
        ratingValue: 5,
        // For this test doesn't matter:
        beginTime: 0,
      };
      var notification = competitions._createNotification(competitionData, 400);
      notification.onclick();
      expect(DeferredNotification.prototype.revoke).to.have.been.called;
    });

    it('should correctly calculate the remaining time before the ' +
        'competition start', function () {
      sandbox.clock.tick(1470230514177);
      // The default server time delta is set to 1000 milliseconds:
      expect(competitions.getRemainingTime(1470230614)).to.be.equal(99);
      expect(competitions.getRemainingTime('2016-08-03T13:23:34.000Z')).to.be.equal(99);
    });

    it('should throw an error for invalid competition begin time or ' +
        'server time delta', function () {
      sandbox.clock.tick(1470230514177);
      expect(competitions.getRemainingTime.bind(competitions, null)).to.throw(TypeError);
      competitions._timeCorrection = null;
      expect(competitions.getRemainingTime.bind(competitions, 1470230614))
        .to.throw(Error);
    });

    it('should delete already started competitions with _clearStarted() ' +
        'method', function () {
      sandbox.clock.tick(2 * 1e3);
      competitions._hash = {
        1337: {
          id: 1337,
          beginTime: null,
          ratingValue: 1,
        },
        1338: {
          id: 1338,
          beginTime: 0,
          ratingValue: 3,
        },
        1339: {
          id: 1339,
          beginTime: 5,
          ratingValue: 5,
        },
      };
      competitions._clearStarted();
      expect(competitions._hash[1337]).to.be.an('object');
      expect(competitions._hash[1338]).to.be.undefined;
      expect(competitions._hash[1339]).to.be.an('object');
    });

    it('should show the notifications only for selected rates', function () {
      sandbox.stub(Competitions.prototype, 'getRemainingTime').returns(1000);
      kango.storage.getItem.withArgs('competition_rates').returns([2, 3, 5]);
      competitions = new Competitions;
      competitions._hash = {
        1337: {
          id: 1337,
          beginTime: 0,
          ratingValue: 1,
        },
        1338: {
          id: 1338,
          beginTime: 0,
          ratingValue: 2,
        },
        1339: {
          id: 1339,
          beginTime: 0,
          ratingValue: 3,
        },
        1340: {
          id: 1340,
          beginTime: 0,
          ratingValue: 5,
        },
      };
      competitions._notify(1337);
      competitions._notify(1338);
      competitions._notify(1339);
      competitions._notify(1340);
      expect(Competitions.prototype._createNotification).to.have.been.calledThrice;
    });

    it('should not show notifications if the delay is set to zero', function () {
      sandbox.stub(Competitions.prototype, 'getRemainingTime').returns(1000);
      kango.storage.getItem.withArgs('competition_delay').returns(0);
      competitions = new Competitions;
      competitions._hash = {
        1337: {
          id: 1338,
          beginTime: 0,
          ratingValue: 3,
        },
        1338: {
          id: 1339,
          beginTime: 5,
          ratingValue: 5,
        },
      };
      competitions._notify(1337);
      competitions._notify(1338);
      expect(Competitions.prototype._createNotification).to.not.been.called;
    });

    it('should revoke all notifications on teardown');
  });
});
<|endoftext|>


<commit_before>import riot       from 'riot'
import {expect}   from 'chai'
import {Form}     from 'riot-form'
import {mountTag} from './helpers'

describe('rf-form', () => {
  const form = new Form.Builder('hello')
          .addInput({name: 'username', type: 'text'})
          .addInput({name: 'other', type: 'text'})
          .setModel({username: 'world'})
          .build()

  before(() => {
    mountTag('rf-form', {
      model: form,
      className: 'custom-class'
    })
  })

  it('should display form', () => {
    const form = document.querySelector('form[name="hello"]')
    expect(form).not.to.be.null
    expect(form.className).to.eq('custom-class')
  })

  it('should render the inputs', () => {
    const label = document.querySelector('label[for="hello_username"]')
    expect(label).not.to.be.null
    expect(label.innerText).to.eq('Username')
  })

  it('should render the inputs', () => {
    const input = document.querySelector('input[name="hello_username"]')
    expect(input).not.to.be.null
    if (input.placeholder) {
      expect(input.placeholder).to.eq('Username')
    }
    expect(input.value).to.eq('world')
  })

  it('should not set undefined initial values', () => {
    const input = document.querySelector('input[name="hello_other"]')
    expect(input).not.to.be.null
    expect(input.value).to.eq('')
  })
})
<commit_msg>Fix tests on firefox.<commit_after>import riot       from 'riot'
import {expect}   from 'chai'
import {Form}     from 'riot-form'
import {mountTag} from './helpers'

describe('rf-form', () => {
  const form = new Form.Builder('hello')
          .addInput({name: 'username', type: 'text'})
          .addInput({name: 'other', type: 'text'})
          .setModel({username: 'world'})
          .build()

  before(() => {
    mountTag('rf-form', {
      model: form,
      className: 'custom-class'
    })
  })

  it('should display form', () => {
    const form = document.querySelector('form[name="hello"]')
    expect(form).not.to.be.null
    expect(form.className).to.eq('custom-class')
  })

  it('should render the label', () => {
    const label = document.querySelector('label[for="hello_username"]')
    expect(label).not.to.be.null
    expect(label.innerText || label.textContent).to.eq('Username')
  })

  it('should render the input', () => {
    const input = document.querySelector('input[name="hello_username"]')
    expect(input).not.to.be.null
    expect(input.placeholder).to.eq('Username')
    expect(input.value).to.eq('world')
  })

  it('should not set undefined initial values', () => {
    const input = document.querySelector('input[name="hello_other"]')
    expect(input).not.to.be.null
    expect(input.value).to.eq('')
  })
})
<|endoftext|>


<commit_before>const should = require('chai').should();
const expect = require('chai').expect;
const assert = require('chai').assert;

const Payload = require('../../lib/preprocess/payload/payload');
const deconstructPayload = Payload.prototype.deconstructPayload;
const ctx = new Payload();

describe('Payload:', () => {

  describe('deconstructPayload():', () => {
    it('should deconstruct an item in array update payload', () => {
      var parsedPayload, payload, result;
      payload = {
        'account.friends.0': {
          name: 1
        }
      };
      parsedPayload = {
        'account.friends': {
          value: {
            name: 1
          },
          payloadPath: ['account.friends.0'],
        }
      };
      result = deconstructPayload.call(ctx, payload);
      result.should.eql(parsedPayload);
    });

    it('should deconstruct an insert payload', () => {
      var parsedPayload, payload, result;
      payload = {
        account: {
          name: 'jay',
          email: 'j@j.com',
          friends: [
            {name: 'lrn'},
            {name: 'lou'}
          ]
        },
        notifications: [1, 2, 3]
      };
      parsedPayload = {
        'account.name': {
          value: 'jay',
          payloadPath: ['account', 'name'],
        },
        'account.email': {
          value: 'j@j.com',
          payloadPath: ['account', 'email'],
        },
        'account.friends': {
          value: [
            {name: 'lrn'},
            {name: 'lou'}
          ],
          payloadPath: ['account', 'friends'],
        },
        'notifications': {
          value: [1, 2, 3],
          payloadPath: ['notifications'],
        }
      };
      result = deconstructPayload.call(ctx, payload);
      result.should.eql(parsedPayload);
    });

    it('should deconstruct a $set payload', () => {
      var parsedPayload, payload, result;
      payload = {
        "tags.1": "rain gear",
        "ratings.0.rating": 2,
        "account": {
          name: 'jay',
          location: {
            name: 'home'
          }
        }
      };
      parsedPayload = {
        'tags': {
          payloadPath: ['tags.1'],
          value: 'rain gear',
        },
        'ratings.rating': {
          value: 2,
          payloadPath: ['ratings.0.rating'],
        },
        'account.name': {
          value: 'jay',
          payloadPath: ['account', 'name'],
        },
        'account.location.name': {
          value: 'home',
          payloadPath: ['account', 'location', 'name'],
        }
      };
      result = deconstructPayload.call(ctx, payload);
      result.should.eql(parsedPayload);
    });
  });

});
<commit_msg>refactored test for deconstructPayload<commit_after>const should = require('chai').should();
const expect = require('chai').expect;
const assert = require('chai').assert;

const Payload = require('../../lib/preprocess/payload/payload');
const deconstructPayload = Payload.prototype.deconstructPayload;
const ctx = new Payload();

describe('Payload:', () => {

  describe('deconstructPayload():', () => {
    it('should deconstruct an item in array update payload', () => {
      var parsedPayload, payload, result;
      payload = {
        'account.friends.0': {
          name: 1
        }
      };
      parsedPayload = {
        'account.friends.name': {
          payloadPath: ['account.friends.0', 'name'],
          value: 1,
          isArrayItemUpdate: true,
        }
      };
      result = deconstructPayload.call(ctx, payload);
      result.should.eql(parsedPayload);
    });

    it('should deconstruct an insert payload', () => {
      var parsedPayload, payload, result;
      payload = {
        account: {
          name: 'jay',
          email: 'j@j.com',
          friends: [
            {name: 'lrn'},
            {name: 'lou'}
          ]
        },
        notifications: [1, 2, 3]
      };
      parsedPayload = {
        'account.name': {
          value: 'jay',
          payloadPath: ['account', 'name'],
          isArrayItemUpdate: false,
        },
        'account.email': {
          value: 'j@j.com',
          payloadPath: ['account', 'email'],
          isArrayItemUpdate: false,
        },
        'account.friends': {
          value: [
            {name: 'lrn'},
            {name: 'lou'}
          ],
          payloadPath: ['account', 'friends'],
          isArrayItemUpdate: false,
        },
        'notifications': {
          value: [1, 2, 3],
          payloadPath: ['notifications'],
          isArrayItemUpdate: false,
        }
      };
      result = deconstructPayload.call(ctx, payload);
      result.should.eql(parsedPayload);
    });

    it('should deconstruct a $set payload', () => {
      var parsedPayload, payload, result;
      payload = {
        "tags.1": "rain gear",
        "ratings.0.rating": 2,
        "account": {
          name: 'jay',
          location: {
            name: 'home'
          }
        }
      };
      parsedPayload = {
        'tags': {
          payloadPath: ['tags.1'],
          value: 'rain gear',
          isArrayItemUpdate: true,
        },
        'ratings.rating': {
          value: 2,
          payloadPath: ['ratings.0.rating'],
          isArrayItemUpdate: true,
        },
        'account.name': {
          value: 'jay',
          payloadPath: ['account', 'name'],
          isArrayItemUpdate: false,
        },
        'account.location.name': {
          value: 'home',
          payloadPath: ['account', 'location', 'name'],
          isArrayItemUpdate: false,
        }
      };
      result = deconstructPayload.call(ctx, payload);
      result.should.eql(parsedPayload);
    });
  });

});
<|endoftext|>


<commit_before>/*---------------------------------------------------------
 * OpenERP web_gantt
 *---------------------------------------------------------*/
openerp.web_gantt = function (openerp) {
var _t = openerp.web._t;
var QWeb = openerp.web.qweb;

QWeb.add_template('/web_gantt/static/src/xml/web_gantt.xml');
openerp.web.views.add('gantt', 'openerp.web_gantt.GanttView');
openerp.web_gantt.GanttView = openerp.web.View.extend({

init: function(parent, dataset, view_id) {
        this._super(parent);
        this.view_manager = parent || new openerp.web.NullViewManager();
        this.dataset = dataset;
        this.model = dataset.model;
        this.view_id = view_id;
        this.domain = this.dataset.domain || [];
        this.context = this.dataset.context || {};
        this.has_been_loaded = $.Deferred();
    },

    start: function() {
        this._super();
        return this.rpc("/web/view/load", {"model": this.model, "view_id": this.view_id, "view_type": "gantt"}, this.on_loaded);
    },

    on_loaded: function(data) {
        this.fields_view = data,
        this.name =  this.fields_view.arch.attrs.string,
        this.view_id = this.fields_view.view_id,
        this.fields = this.fields_view.fields;

        this.date_start = this.fields_view.arch.attrs.date_start,
        this.date_delay = this.fields_view.arch.attrs.date_delay,
        this.date_stop = this.fields_view.arch.attrs.date_stop,
        this.day_length = this.fields_view.arch.attrs.day_length || 8;

        this.color_field = this.fields_view.arch.attrs.color,
        this.colors = this.fields_view.arch.attrs.colors;

        var level = this.fields_view.arch.children[0];
        this.parent = level.attrs.link,
        this.text = level.children.length ? level.children[0].attrs.name : level.attrs.name;

        if (!this.date_start) {
            return self.do_warn(_t("date_start is not defined "))
        }

        this.$element.html(QWeb.render("GanttView", {'height': $('.oe-application-container').height(), 'width': $('.oe-application-container').width()}));
        this.has_been_loaded.resolve();
    },

    on_project_loaded: function(projects) {

        if(!projects.length) return;
        var self = this,
            started_projects = _.filter(projects, function(res) {
            return res[self.date_start];
        });

        this.database_projects = started_projects;

        if(!self.name) {
            var name = started_projects[0][self.parent];
            self.name = name instanceof Array? name[name.length - 1] : name;
        }

        $.when(this.project_starting_date(), this.get_project_duration(), this.calculate_difference())
            .then(function() {
                if(self.ganttChartControl) {
                    self.ganttChartControl.clearAll();
                    self.$element.find('#GanttView').empty();
                }
            })
            .then(this.group_projects())
            .then(this.generate_projects())
            .then(this.add_tasks())
            .done(this.init_gantt_view());
    },

    generate_projects : function() {
        var projects = this.database_projects,
            self = this;

        this.GanttProjects = [],
        this.GanttTasks = [];
        if(this.GroupProject) {
            _.each(this.GroupProject, function(grp, index) {
                self.GanttProjects.push(new GanttProjectInfo(index, grp, self.project_start_date));
                self.GanttTasks.push(new GanttTaskInfo(index, grp, self.project_start_date, self.total_duration, 100, ""));
            });
        } else {
            this.GanttProjects.push(new GanttProjectInfo(0, self.name, self.project_start_date));
            this.GanttTasks.push(new GanttTaskInfo(0, self.name, self.project_start_date, self.total_duration, 100, ""));
        }

        return $.Deferred().resolve().promise();
    },

    group_projects: function() {
        var def = $.Deferred(),
            self = this,
            projects = this.database_projects;

        if (!this.group_by.length) return def.resolve().promise();

        var groups = _.pluck(projects, this.group_by[0]);
        this.GroupProject = [];
        _.each(groups, function(grp) {
            if(grp instanceof Array) {
                grp = grp[grp.length - 1];
            }
            if(!_.include(self.GroupProject,grp))
                self.GroupProject.push(grp);
        });

        return def.resolve().promise();
    },

    get_project_duration: function() {

        var self = this,
            projects = this.database_projects;

        this.project_duration = [];

        _.each(projects, function(project, index) {
            if (self.date_stop && project[self.date_stop]) {
                //ToDO
                console.log('TODO for date_stop');
                self.project_duration.push(0);
            } else if(self.date_delay && project[self.date_delay]) {
                self.project_duration.push(project[self.date_delay]);
            } else {
                self.project_duration.push(0);
            }
        });

        this.max_project_duration = _.max(this.project_duration);
        return $.Deferred().resolve().promise();
    },

    calculate_difference: function() {
        var extend_end_date_day = Math.floor(this.max_project_duration / this.day_length),
            extend_end_date_hours = this.max_project_duration % this.day_length;

        this.project_end_date = this.project_end_date.add({days: extend_end_date_day, hours: extend_end_date_hours})

        var DAY = 1000 * 60 * 60 * 24,
            difference = Math.abs(this.project_start_date.getTime() - this.project_end_date.getTime()),
            day = Math.ceil(difference / DAY),
            hour = (difference % DAY)/(1000 * 60 * 60),
            DiffHour = (day * this.day_length) + hour;

        this.total_duration = parseFloat(DiffHour.toFixed(2));
        return $.Deferred().resolve().promise();
    },

    add_tasks: function() {
        var self = this,
            tasks = this.database_projects;

        _.each(tasks, function(task, index) {
            var name = task[self.text];
            if(task[self.text] instanceof Array) {
                name = task[self.text][1];
            }
            self.GanttTasks[0].addChildTask(
                new GanttTaskInfo(task.id, name, self.format_date(task[self.date_start]), self.project_duration[index], 100, "")
            );
        });

        return $.Deferred().resolve().promise();
    },

    project_starting_date : function() {
        var self = this,
            projects = this.database_projects,
            min_date = _.min(projects, function(prj) {
                return new Date(prj[self.date_start]);
            }),
            max_date = _.max(projects, function(prj) {
                return self.format_date(prj[self.date_start]);
            });

        this.project_end_date =  this.format_date(max_date[self.date_start]);
        if (min_date) this.project_start_date = this.format_date(min_date[self.date_start]);
        else
            this.project_start_date = Date.today();
        return $.Deferred().resolve().promise();
    },

    init_gantt_view: function() {

        this.GanttProjects[0].addTask(this.GanttTasks[0]);
        var self = this;

        var ganttChartControl = this.ganttChartControl = new GanttChart();

        // Setup paths and behavior
        ganttChartControl.setImagePath("/web_gantt/static/lib/dhtmlxGantt/codebase/imgs/");
        ganttChartControl.setEditable(true);
        ganttChartControl.showTreePanel(true);
        ganttChartControl.showContextMenu(false);
        ganttChartControl.showDescTask(true,'d,s-f');
        ganttChartControl.showDescProject(true,'n,d');

        // Load data structure
        ganttChartControl.addProject(this.GanttProjects[0]);
        // Create Gantt control
        ganttChartControl.create('GanttView');

        // Setup Events
        ganttChartControl.attachEvent("onTaskStartDrag", function(task) {
            var task_date = task.getEST();
            if(task_date.getHours()) {
                task_date.set({hour: task_date.getHours(), minute : task_date.getMinutes(), second:0});
            }
        });
        ganttChartControl.attachEvent("onTaskEndResize", function(task) {return self.ResizeTask(task);});
        ganttChartControl.attachEvent("onTaskEndDrag", function(task) {return self.ResizeTask(task);});
        ganttChartControl.attachEvent("onTaskDblClick", function(task) { return self.editTask(task);});
    },

    format_date : function(date) {
        var datetime_regex = /^(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)(?:\.\d+)?$/,
            date_regex = /^\d\d\d\d-\d\d-\d\d$/,
            time_regex = /^(\d\d:\d\d:\d\d)(?:\.\d+)?$/,
            def = $.Deferred();
        if(date_regex.exec(date)) {
            this.date_format = "yyyy-MM-dd";
        } else if(time_regex.exec(date)) {
            this.date_format = "HH:mm:ss";
        } else {
            this.date_format = "yyyy-MM-dd HH:mm:ss";
        }
        return openerp.web.auto_str_to_date(date);
    },

    ResizeTask: function(task) {

        var event_id = task.getId();

        if(!event_id)
            return this.do_warn(_t("Project can not be resized"));

        var data = {};
        data[this.date_start] = task.getEST().toString(this.date_format);

        if(this.date_stop) {
            var diff = task.getDuration() % this.day_length,
                finished_date = task.getFinishDate().add({hours: diff});
            data[this.date_stop] = finished_date.toString(this.date_format);
        } else {
            data[this.date_delay] = task.getDuration();
        }
        this.dataset
            .write(event_id, data, {})
            .done(function() {
                self.reloadView();
            });
    },

    editTask: function(task) {
        var self = this;
        var event_id = task.getId();
        if(!event_id)
            return false;

        if(event_id) event_id = parseInt(event_id, 10);

        var action_manager = new openerp.web.ActionManager(this);

        var dialog = new openerp.web.Dialog(this, {
            width: 800,
            height: 600,
            buttons : {
                Cancel : function() {
                    $(this).dialog('destroy');
                },
                Save : function() {
                    var form_view = action_manager.inner_viewmanager.views.form.controller;

                    form_view.do_save(function() {
                        self.reloadView();
                    });
                    $(this).dialog('destroy');
                }
            }
        }).start().open();
        action_manager.appendTo(dialog.$element);
        action_manager.do_action({
            res_model : this.dataset.model,
            res_id: event_id,
            views : [[false, 'form']],
            type : 'ir.actions.act_window',
            auto_search : false,
            flags : {
                search_view: false,
                sidebar : false,
                views_switcher : false,
                action_buttons : false,
                pager: false
            }
        });
    },

    reloadView: function() {
       self.on_project_loaded(self.database_projects);
    },

    do_show: function () {
        this.$element.show();
    },

    do_hide: function () {
        this.$element.hide();
    },

    do_search: function (domains, contexts, groupbys) {
        var self = this;
        this.group_by = groupbys;
        $.when(this.has_been_loaded).then(function() {
            self.dataset
                .read_slice([], {
                    domain: domains,
                    context: contexts,
                    group_by: groupbys
                })
                .done(function(projects) {
                    self.on_project_loaded(projects);
                });
        })

    }

});

// here you may tweak globals object, if any, and play with on_* or do_* callbacks on them

};
// vim:et fdc=0 fdl=0:
<commit_msg>[FIX] First level group_by.<commit_after>/*---------------------------------------------------------
 * OpenERP web_gantt
 *---------------------------------------------------------*/
openerp.web_gantt = function (openerp) {
var _t = openerp.web._t;
var QWeb = openerp.web.qweb;

QWeb.add_template('/web_gantt/static/src/xml/web_gantt.xml');
openerp.web.views.add('gantt', 'openerp.web_gantt.GanttView');
openerp.web_gantt.GanttView = openerp.web.View.extend({

init: function(parent, dataset, view_id) {
        this._super(parent);
        this.view_manager = parent || new openerp.web.NullViewManager();
        this.dataset = dataset;
        this.model = dataset.model;
        this.view_id = view_id;
        this.domain = this.dataset.domain || [];
        this.context = this.dataset.context || {};
        this.has_been_loaded = $.Deferred();
    },

    start: function() {
        this._super();
        return this.rpc("/web/view/load", {"model": this.model, "view_id": this.view_id, "view_type": "gantt"}, this.on_loaded);
    },

    on_loaded: function(data) {
        this.fields_view = data,
        this.name =  this.fields_view.arch.attrs.string,
        this.view_id = this.fields_view.view_id,
        this.fields = this.fields_view.fields;

        this.date_start = this.fields_view.arch.attrs.date_start,
        this.date_delay = this.fields_view.arch.attrs.date_delay,
        this.date_stop = this.fields_view.arch.attrs.date_stop,
        this.day_length = this.fields_view.arch.attrs.day_length || 8;

        this.color_field = this.fields_view.arch.attrs.color,
        this.colors = this.fields_view.arch.attrs.colors;

        var level = this.fields_view.arch.children[0];
        this.parent = level.attrs.link,
        this.text = level.children.length ? level.children[0].attrs.name : level.attrs.name;

        if (!this.date_start) {
            return self.do_warn(_t("date_start is not defined "))
        }

        this.$element.html(QWeb.render("GanttView", {'height': $('.oe-application-container').height(), 'width': $('.oe-application-container').width()}));
        this.has_been_loaded.resolve();
    },

    on_project_loaded: function(projects) {

        if(!projects.length) return;
        var self = this,
            started_projects = _.filter(projects, function(res) {
            return res[self.date_start];
        });

        this.database_projects = started_projects;

        if(!self.name) {
            var name = started_projects[0][self.parent];
            self.name = name instanceof Array? name[name.length - 1] : name;
        }

        $.when(this.project_starting_date(), this.get_project_duration(), this.calculate_difference())
            .then(function() {
                if(self.ganttChartControl) {
                    self.ganttChartControl.clearAll();
                    self.$element.find('#GanttView').empty();
                }
            })
            .then(this.group_projects())
            .then(this.generate_projects())
            .then(this.add_tasks())
            .done(this.init_gantt_view());
    },

    generate_projects : function() {
        var projects = this.database_projects,
            self = this;

        this.GanttTasks = [];
        if(this.group_by.length) {
            _.each(this.GroupProject, function(grp, index) {
                self.GanttTasks.push([]);
                _.each(grp, function(g, g_index) {
                    self.GanttTasks[index].push(new GanttTaskInfo(index + '_'+ g_index, g, self.project_start_date, self.total_duration, 100, ""));
                });
//                self.GanttTasks.push(new GanttTaskInfo(index, grp, self.project_start_date, self.total_duration, 100, ""));
            });
        } else {
            this.GanttTasks.push(new GanttTaskInfo(0, self.name, self.project_start_date, self.total_duration, 100, ""));
        }
        this.GanttProjects = new GanttProjectInfo(0, self.name, self.project_start_date);
        return $.Deferred().resolve().promise();
    },

    group_projects: function() {
        var def = $.Deferred(),
            self = this,
            projects = this.database_projects;

        if (!this.group_by.length) return def.resolve().promise();

        this.GroupProject = [];

        _.each(this.group_by, function(group) {
            self.GroupProject.push(
                _.uniq(
                    _.map(_.pluck(projects, group), function(prj) {
                        return prj instanceof Array ? prj[1] : prj;
                    })
                ));
        });
        return def.resolve().promise();
    },

    get_project_duration: function() {

        var self = this,
            projects = this.database_projects;

        this.project_duration = [];

        _.each(projects, function(project, index) {
            if (self.date_stop && project[self.date_stop]) {
                //ToDO
                console.log('TODO for date_stop');
                self.project_duration.push(0);
            } else if(self.date_delay && project[self.date_delay]) {
                self.project_duration.push(project[self.date_delay]);
            } else {
                self.project_duration.push(0);
            }
        });

        this.max_project_duration = _.max(this.project_duration);
        return $.Deferred().resolve().promise();
    },

    calculate_difference: function() {
        var extend_end_date_day = Math.floor(this.max_project_duration / this.day_length),
            extend_end_date_hours = this.max_project_duration % this.day_length;

        this.project_end_date = this.project_end_date.add({days: extend_end_date_day, hours: extend_end_date_hours})

        var DAY = 1000 * 60 * 60 * 24,
            difference = Math.abs(this.project_start_date.getTime() - this.project_end_date.getTime()),
            day = Math.ceil(difference / DAY),
            hour = (difference % DAY)/(1000 * 60 * 60),
            DiffHour = (day * this.day_length) + hour;

        this.total_duration = parseFloat(DiffHour.toFixed(2));
        return $.Deferred().resolve().promise();
    },

    add_tasks: function() {
        var self = this,
            tasks = this.database_projects;
        if (this.group_by.length) {
        }
        else {
            _.each(tasks, function(task, index){
                var name = task[self.text];
                if (task[self.text] instanceof Array) {
                    name = task[self.text][1];
                }
                self.GanttTasks[0].addChildTask(new GanttTaskInfo(task.id, name, self.format_date(task[self.date_start]), self.project_duration[index], 100, ""));
            });
        }
        return $.Deferred().resolve().promise();
    },

    project_starting_date : function() {
        var self = this,
            projects = this.database_projects,
            min_date = _.min(projects, function(prj) {
                return new Date(prj[self.date_start]);
            }),
            max_date = _.max(projects, function(prj) {
                return self.format_date(prj[self.date_start]);
            });

        this.project_end_date =  this.format_date(max_date[self.date_start]);
        if (min_date) this.project_start_date = this.format_date(min_date[self.date_start]);
        else
            this.project_start_date = Date.today();
        return $.Deferred().resolve().promise();
    },

    init_gantt_view: function() {
        var self = this;

        if (this.group_by.length) {
            _.each(this.GanttTasks, function(tasks) {
                _.each(tasks, function(task, index) {
                    self.GanttProjects.addTask(task);
                })
            });
        }
        else {
            _.each(this.GanttTasks, function(tsk, index){
                self.GanttProjects.addTask(tsk);
            });
        }

        var ganttChartControl = this.ganttChartControl = new GanttChart();

        // Setup paths and behavior
        ganttChartControl.setImagePath("/web_gantt/static/lib/dhtmlxGantt/codebase/imgs/");
        ganttChartControl.setEditable(true);
        ganttChartControl.showTreePanel(true);
        ganttChartControl.showContextMenu(false);
        ganttChartControl.showDescTask(true,'d,s-f');
        ganttChartControl.showDescProject(true,'n,d');

        // Load data structure
        ganttChartControl.addProject(this.GanttProjects);

        // Create Gantt control
        ganttChartControl.create('GanttView');

        // Setup Events
        ganttChartControl.attachEvent("onTaskStartDrag", function(task) {
            var task_date = task.getEST();
            if(task_date.getHours()) {
                task_date.set({hour: task_date.getHours(), minute : task_date.getMinutes(), second:0});
            }
        });
        ganttChartControl.attachEvent("onTaskEndResize", function(task) {return self.ResizeTask(task);});
        ganttChartControl.attachEvent("onTaskEndDrag", function(task) {return self.ResizeTask(task);});
        ganttChartControl.attachEvent("onTaskDblClick", function(task) { return self.editTask(task);});
    },

    format_date : function(date) {
        var datetime_regex = /^(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)(?:\.\d+)?$/,
            date_regex = /^\d\d\d\d-\d\d-\d\d$/,
            time_regex = /^(\d\d:\d\d:\d\d)(?:\.\d+)?$/,
            def = $.Deferred();
        if(date_regex.exec(date)) {
            this.date_format = "yyyy-MM-dd";
        } else if(time_regex.exec(date)) {
            this.date_format = "HH:mm:ss";
        } else {
            this.date_format = "yyyy-MM-dd HH:mm:ss";
        }
        return openerp.web.auto_str_to_date(date);
    },

    ResizeTask: function(task) {

        var event_id = task.getId();

        if(!event_id)
            return this.do_warn(_t("Project can not be resized"));

        var data = {};
        data[this.date_start] = task.getEST().toString(this.date_format);

        if(this.date_stop) {
            var diff = task.getDuration() % this.day_length,
                finished_date = task.getFinishDate().add({hours: diff});
            data[this.date_stop] = finished_date.toString(this.date_format);
        } else {
            data[this.date_delay] = task.getDuration();
        }
        this.dataset
            .write(event_id, data, {})
            .done(function() {
                self.reloadView();
            });
    },

    editTask: function(task) {
        var self = this;
        var event_id = task.getId();
        if(!event_id)
            return false;

        if(event_id) event_id = parseInt(event_id, 10);

        var action_manager = new openerp.web.ActionManager(this);

        var dialog = new openerp.web.Dialog(this, {
            width: 800,
            height: 600,
            buttons : {
                Cancel : function() {
                    $(this).dialog('destroy');
                },
                Save : function() {
                    var form_view = action_manager.inner_viewmanager.views.form.controller;

                    form_view.do_save(function() {
                        self.reloadView();
                    });
                    $(this).dialog('destroy');
                }
            }
        }).start().open();
        action_manager.appendTo(dialog.$element);
        action_manager.do_action({
            res_model : this.dataset.model,
            res_id: event_id,
            views : [[false, 'form']],
            type : 'ir.actions.act_window',
            auto_search : false,
            flags : {
                search_view: false,
                sidebar : false,
                views_switcher : false,
                action_buttons : false,
                pager: false
            }
        });
    },

    reloadView: function() {
       self.on_project_loaded(self.database_projects);
    },

    do_show: function () {
        this.$element.show();
    },

    do_hide: function () {
        this.$element.hide();
    },

    do_search: function (domains, contexts, groupbys) {
        var self = this;
        this.group_by = groupbys;
        $.when(this.has_been_loaded).then(function() {
            self.dataset
                .read_slice([], {
                    domain: domains,
                    context: contexts,
                    group_by: groupbys
                })
                .done(function(projects) {
                    self.on_project_loaded(projects);
                });
        })

    }

});

// here you may tweak globals object, if any, and play with on_* or do_* callbacks on them

};
// vim:et fdc=0 fdl=0:
<|endoftext|>