<commit_before>/**
 * KeyboardNavigation.js
 *
 * Copyright, Moxiecode Systems AB
 * Released under LGPL License.
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

/**
 * This class handles keyboard navigation of controls and elements.
 *
 * @class tinymce.ui.KeyboardNavigation
 */
define("tinymce/ui/KeyboardNavigation", [
], function() {
	"use strict";

	/**
	 * This class handles all keyboard navigation for WAI-ARIA support. Each root container
	 * gets an instance of this class.
	 *
	 * @constructor
	 */
	return function(settings) {
		var root = settings.root, focusedElement, focusedControl;

		focusedElement = document.activeElement;
		focusedControl = root.getParentCtrl(focusedElement);

		/**
		 * Returns the currently focused elements wai aria role of the currently
		 * focused element or specified element.
		 *
		 * @private
		 * @param {Element} elm Optional element to get role from.
		 * @return {String} Role of specified element.
		 */
		function getRole(elm) {
			elm = elm || focusedElement;

			return elm && elm.getAttribute('role');
		}

		/**
		 * Returns the wai role of the parent element of the currently
		 * focused element or specified element.
		 *
		 * @private
		 * @param {Element} elm Optional element to get parent role from.
		 * @return {String} Role of the first parent that has a role.
		 */
		function getParentRole(elm) {
			var role, parent = elm || focusedElement;

			while ((parent = parent.parentNode)) {
				if ((role = getRole(parent))) {
					return role;
				}
			}
		}

		/**
		 * Returns a wai aria property by name for example aria-selected.
		 *
		 * @private
		 * @param {String} name Name of the aria property to get for example "disabled".
		 * @return {String} Aria property value.
		 */
		function getAriaProp(name) {
			var elm = focusedElement;

			if (elm) {
				return elm.getAttribute('aria-' + name);
			}
		}

		/**
		 * Is the element a text input element or not.
		 *
		 * @private
		 * @param {Element} elm Element to check if it's an text input element or not.
		 * @return {Boolean} True/false if the element is a text element or not.
		 */
		function isTextInputElement(elm) {
			// Notice: since type can be "email" etc we don't check the type
			// So all input elements gets treated as text input elements
			return elm.tagName == "INPUT" || elm.tagName == "TEXTAREA";
		}

		/**
		 * Returns true/false if the specified element can be focused or not.
		 *
		 * @private
		 * @param {Element} elm DOM element to check if it can be focused or not.
		 * @return {Boolean} True/false if the element can have focus.
		 */
		function canFocus(elm) {
			if (isTextInputElement(elm) && !elm.hidden) {
				return true;
			}

			if (/^(button|menuitem|checkbox|tab|menuitemcheckbox|option|gridcell)$/.test(getRole(elm))) {
				return true;
			}

			return false;
		}

		/**
		 * Returns an array of focusable visible elements within the specified container element.
		 *
		 * @private
		 * @param {Element} elm DOM element to find focusable elements within.
		 * @return {Array} Array of focusable elements.
		 */
		function getFocusElements(elm) {
			var elements = [];

			function collect(elm) {
				if (elm.nodeType != 1 || elm.style.display == 'none') {
					return;
				}

				if (canFocus(elm)) {
					elements.push(elm);
				}

				for (var i = 0; i < elm.childNodes.length; i++) {
					collect(elm.childNodes[i]);
				}
			}

			collect(elm || root.getEl());

			return elements;
		}

		/**
		 * Returns the navigation root control for the specified control. The navigation root
		 * is the control that the keyboard navigation gets scoped to for example a menubar or toolbar group.
		 * It will look for parents of the specified target control or the currenty focused control if this option is omitted.
		 *
		 * @private
		 * @param {tinymce.ui.Control} targetControl Optional target control to find root of.
		 * @return {tinymce.ui.Control} Navigation root control.
		 */
		function getNavigationRoot(targetControl) {
			var navigationRoot, controls;

			targetControl = targetControl || focusedControl;
			controls = targetControl.parents().toArray();
			controls.unshift(targetControl);

			for (var i = 0; i < controls.length; i++) {
				navigationRoot = controls[i];

				if (navigationRoot.settings.ariaRoot) {
					break;
				}
			}

			return navigationRoot;
		}

		/**
		 * Focuses the first item in the specified targetControl element or the last aria index if the
		 * navigation root has the ariaRemember option enabled.
		 *
		 * @private
		 * @param {tinymce.ui.Control} targetControl Target control to focus the first item in.
		 */
		function focusFirst(targetControl) {
			var navigationRoot = getNavigationRoot(targetControl);
			var focusElements = getFocusElements(navigationRoot.getEl());

			if (navigationRoot.settings.ariaRemember && "lastAriaIndex" in navigationRoot) {
				moveFocusToIndex(navigationRoot.lastAriaIndex, focusElements);
			} else {
				moveFocusToIndex(0, focusElements);
			}
		}

		/**
		 * Moves the focus to the specified index within the elements list.
		 * This will scope the index to the size of the element list if it changed.
		 *
		 * @private
		 * @param {Number} idx Specified index to move to.
		 * @param {Array} elements Array with dom elements to move focus within.
		 * @return {Number} Input index or a changed index if it was out of range.
		 */
		function moveFocusToIndex(idx, elements) {
			if (idx < 0) {
				idx = elements.length - 1;
			} else if (idx >= elements.length) {
				idx = 0;
			}

			if (elements[idx]) {
				elements[idx].focus();
			}

			return idx;
		}

		/**
		 * Moves the focus forwards or backwards.
		 *
		 * @private
		 * @param {Number} dir Direction to move in positive means forward, negative means backwards.
		 * @param {Array} elements Optional array of elements to move within defaults to the current navigation roots elements.
		 */
		function moveFocus(dir, elements) {
			var idx = -1, navigationRoot = getNavigationRoot();

			elements = elements || getFocusElements(navigationRoot.getEl());

			for (var i = 0; i < elements.length; i++) {
				if (elements[i] === focusedElement) {
					idx = i;
				}
			}

			idx += dir;
			navigationRoot.lastAriaIndex = moveFocusToIndex(idx, elements);
		}

		/**
		 * Moves the focus to the left this is called by the left key.
		 *
		 * @private
		 */
		function left() {
			var parentRole = getParentRole();

			if (parentRole == "tablist") {
				moveFocus(-1, getFocusElements(focusedElement.parentNode));
			} else if (focusedControl.parent().submenu) {
				cancel();
			} else {
				moveFocus(-1);
			}
		}

		/**
		 * Moves the focus to the right this is called by the right key.
		 *
		 * @private
		 */
		function right() {
			var role = getRole(), parentRole = getParentRole();

			if (parentRole == "tablist") {
				moveFocus(1, getFocusElements(focusedElement.parentNode));
			} else if (role == "menuitem" && parentRole == "menu" && getAriaProp('haspopup')) {
				enter();
			} else {
				moveFocus(1);
			}
		}

		/**
		 * Moves the focus to the up this is called by the up key.
		 *
		 * @private
		 */
		function up() {
			moveFocus(-1);
		}

		/**
		 * Moves the focus to the up this is called by the down key.
		 *
		 * @private
		 */
		function down() {
			var role = getRole(), parentRole = getParentRole();

			if (role == "menuitem" && parentRole == "menubar") {
				enter();
			} else if (role == "button" && getAriaProp('haspopup')) {
				enter({key: 'down'});
			} else {
				moveFocus(1);
			}
		}

		/**
		 * Moves the focus to the next item or previous item depending on shift key.
		 *
		 * @private
		 * @param {DOMEvent} e DOM event object.
		 */
		function tab(e) {
			var parentRole = getParentRole();

			if (parentRole == "tablist") {
				var elm = getFocusElements(focusedControl.getEl('body'))[0];

				if (elm) {
					elm.focus();
				}
			} else {
				moveFocus(e.shiftKey ? -1 : 1);
			}
		}

		/**
		 * Calls the cancel event on the currently focused control. This is normally done using the Esc key.
		 *
		 * @private
		 */
		function cancel() {
			focusedControl.fire('cancel');
		}

		/**
		 * Calls the click event on the currently focused control. This is normally done using the Enter/Space keys.
		 *
		 * @private
		 * @param {Object} aria Optional aria data to pass along with the enter event.
		 */
		function enter(aria) {
			aria = aria || {};
			focusedControl.fire('click', {target: focusedElement, aria: aria});
		}

		root.on('keydown', function(e) {
			function handleEvent(e, handler, isArrowKey) {
				// Ignore arrow keys for text input elements
				if (isArrowKey && isTextInputElement(focusedElement)) {
					return;
				}

				if (handler(e) !== false) {
					e.preventDefault();
				}
			}

			if (e.isDefaultPrevented()) {
				return;
			}

			switch (e.keyCode) {
				case 37: // DOM_VK_LEFT
					handleEvent(e, left, true);
					break;

				case 39: // DOM_VK_RIGHT
					handleEvent(e, right, true);
					break;

				case 38: // DOM_VK_UP
					handleEvent(e, up, true);
					break;

				case 40: // DOM_VK_DOWN
					handleEvent(e, down, true);
					break;

				case 9: // DOM_VK_TAB
					handleEvent(e, tab);
					break;

				case 27: // DOM_VK_ESCAPE
					handleEvent(e, cancel);
					break;

				case 14: // DOM_VK_ENTER
				case 13: // DOM_VK_RETURN
				case 32: // DOM_VK_SPACE
					handleEvent(e, enter);
					break;
			}
		});

		root.on('focusin', function(e) {
			focusedElement = e.target;
			focusedControl = e.control;
		});

		return {
			focusFirst: focusFirst
		};
	};
});<commit_msg>Fixed issue with KeyboardNavigation blocking space and enter on text controls.<commit_after>/**
 * KeyboardNavigation.js
 *
 * Copyright, Moxiecode Systems AB
 * Released under LGPL License.
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

/**
 * This class handles keyboard navigation of controls and elements.
 *
 * @class tinymce.ui.KeyboardNavigation
 */
define("tinymce/ui/KeyboardNavigation", [
], function() {
	"use strict";

	/**
	 * This class handles all keyboard navigation for WAI-ARIA support. Each root container
	 * gets an instance of this class.
	 *
	 * @constructor
	 */
	return function(settings) {
		var root = settings.root, focusedElement, focusedControl;

		focusedElement = document.activeElement;
		focusedControl = root.getParentCtrl(focusedElement);

		/**
		 * Returns the currently focused elements wai aria role of the currently
		 * focused element or specified element.
		 *
		 * @private
		 * @param {Element} elm Optional element to get role from.
		 * @return {String} Role of specified element.
		 */
		function getRole(elm) {
			elm = elm || focusedElement;

			return elm && elm.getAttribute('role');
		}

		/**
		 * Returns the wai role of the parent element of the currently
		 * focused element or specified element.
		 *
		 * @private
		 * @param {Element} elm Optional element to get parent role from.
		 * @return {String} Role of the first parent that has a role.
		 */
		function getParentRole(elm) {
			var role, parent = elm || focusedElement;

			while ((parent = parent.parentNode)) {
				if ((role = getRole(parent))) {
					return role;
				}
			}
		}

		/**
		 * Returns a wai aria property by name for example aria-selected.
		 *
		 * @private
		 * @param {String} name Name of the aria property to get for example "disabled".
		 * @return {String} Aria property value.
		 */
		function getAriaProp(name) {
			var elm = focusedElement;

			if (elm) {
				return elm.getAttribute('aria-' + name);
			}
		}

		/**
		 * Is the element a text input element or not.
		 *
		 * @private
		 * @param {Element} elm Element to check if it's an text input element or not.
		 * @return {Boolean} True/false if the element is a text element or not.
		 */
		function isTextInputElement(elm) {
			// Notice: since type can be "email" etc we don't check the type
			// So all input elements gets treated as text input elements
			return elm.tagName == "INPUT" || elm.tagName == "TEXTAREA";
		}

		/**
		 * Returns true/false if the specified element can be focused or not.
		 *
		 * @private
		 * @param {Element} elm DOM element to check if it can be focused or not.
		 * @return {Boolean} True/false if the element can have focus.
		 */
		function canFocus(elm) {
			if (isTextInputElement(elm) && !elm.hidden) {
				return true;
			}

			if (/^(button|menuitem|checkbox|tab|menuitemcheckbox|option|gridcell)$/.test(getRole(elm))) {
				return true;
			}

			return false;
		}

		/**
		 * Returns an array of focusable visible elements within the specified container element.
		 *
		 * @private
		 * @param {Element} elm DOM element to find focusable elements within.
		 * @return {Array} Array of focusable elements.
		 */
		function getFocusElements(elm) {
			var elements = [];

			function collect(elm) {
				if (elm.nodeType != 1 || elm.style.display == 'none') {
					return;
				}

				if (canFocus(elm)) {
					elements.push(elm);
				}

				for (var i = 0; i < elm.childNodes.length; i++) {
					collect(elm.childNodes[i]);
				}
			}

			collect(elm || root.getEl());

			return elements;
		}

		/**
		 * Returns the navigation root control for the specified control. The navigation root
		 * is the control that the keyboard navigation gets scoped to for example a menubar or toolbar group.
		 * It will look for parents of the specified target control or the currenty focused control if this option is omitted.
		 *
		 * @private
		 * @param {tinymce.ui.Control} targetControl Optional target control to find root of.
		 * @return {tinymce.ui.Control} Navigation root control.
		 */
		function getNavigationRoot(targetControl) {
			var navigationRoot, controls;

			targetControl = targetControl || focusedControl;
			controls = targetControl.parents().toArray();
			controls.unshift(targetControl);

			for (var i = 0; i < controls.length; i++) {
				navigationRoot = controls[i];

				if (navigationRoot.settings.ariaRoot) {
					break;
				}
			}

			return navigationRoot;
		}

		/**
		 * Focuses the first item in the specified targetControl element or the last aria index if the
		 * navigation root has the ariaRemember option enabled.
		 *
		 * @private
		 * @param {tinymce.ui.Control} targetControl Target control to focus the first item in.
		 */
		function focusFirst(targetControl) {
			var navigationRoot = getNavigationRoot(targetControl);
			var focusElements = getFocusElements(navigationRoot.getEl());

			if (navigationRoot.settings.ariaRemember && "lastAriaIndex" in navigationRoot) {
				moveFocusToIndex(navigationRoot.lastAriaIndex, focusElements);
			} else {
				moveFocusToIndex(0, focusElements);
			}
		}

		/**
		 * Moves the focus to the specified index within the elements list.
		 * This will scope the index to the size of the element list if it changed.
		 *
		 * @private
		 * @param {Number} idx Specified index to move to.
		 * @param {Array} elements Array with dom elements to move focus within.
		 * @return {Number} Input index or a changed index if it was out of range.
		 */
		function moveFocusToIndex(idx, elements) {
			if (idx < 0) {
				idx = elements.length - 1;
			} else if (idx >= elements.length) {
				idx = 0;
			}

			if (elements[idx]) {
				elements[idx].focus();
			}

			return idx;
		}

		/**
		 * Moves the focus forwards or backwards.
		 *
		 * @private
		 * @param {Number} dir Direction to move in positive means forward, negative means backwards.
		 * @param {Array} elements Optional array of elements to move within defaults to the current navigation roots elements.
		 */
		function moveFocus(dir, elements) {
			var idx = -1, navigationRoot = getNavigationRoot();

			elements = elements || getFocusElements(navigationRoot.getEl());

			for (var i = 0; i < elements.length; i++) {
				if (elements[i] === focusedElement) {
					idx = i;
				}
			}

			idx += dir;
			navigationRoot.lastAriaIndex = moveFocusToIndex(idx, elements);
		}

		/**
		 * Moves the focus to the left this is called by the left key.
		 *
		 * @private
		 */
		function left() {
			var parentRole = getParentRole();

			if (parentRole == "tablist") {
				moveFocus(-1, getFocusElements(focusedElement.parentNode));
			} else if (focusedControl.parent().submenu) {
				cancel();
			} else {
				moveFocus(-1);
			}
		}

		/**
		 * Moves the focus to the right this is called by the right key.
		 *
		 * @private
		 */
		function right() {
			var role = getRole(), parentRole = getParentRole();

			if (parentRole == "tablist") {
				moveFocus(1, getFocusElements(focusedElement.parentNode));
			} else if (role == "menuitem" && parentRole == "menu" && getAriaProp('haspopup')) {
				enter();
			} else {
				moveFocus(1);
			}
		}

		/**
		 * Moves the focus to the up this is called by the up key.
		 *
		 * @private
		 */
		function up() {
			moveFocus(-1);
		}

		/**
		 * Moves the focus to the up this is called by the down key.
		 *
		 * @private
		 */
		function down() {
			var role = getRole(), parentRole = getParentRole();

			if (role == "menuitem" && parentRole == "menubar") {
				enter();
			} else if (role == "button" && getAriaProp('haspopup')) {
				enter({key: 'down'});
			} else {
				moveFocus(1);
			}
		}

		/**
		 * Moves the focus to the next item or previous item depending on shift key.
		 *
		 * @private
		 * @param {DOMEvent} e DOM event object.
		 */
		function tab(e) {
			var parentRole = getParentRole();

			if (parentRole == "tablist") {
				var elm = getFocusElements(focusedControl.getEl('body'))[0];

				if (elm) {
					elm.focus();
				}
			} else {
				moveFocus(e.shiftKey ? -1 : 1);
			}
		}

		/**
		 * Calls the cancel event on the currently focused control. This is normally done using the Esc key.
		 *
		 * @private
		 */
		function cancel() {
			focusedControl.fire('cancel');
		}

		/**
		 * Calls the click event on the currently focused control. This is normally done using the Enter/Space keys.
		 *
		 * @private
		 * @param {Object} aria Optional aria data to pass along with the enter event.
		 */
		function enter(aria) {
			aria = aria || {};
			focusedControl.fire('click', {target: focusedElement, aria: aria});
		}

		root.on('keydown', function(e) {
			function handleNonTabEvent(e, handler) {
				// Ignore non tab keys for text elements
				if (isTextInputElement(focusedElement)) {
					return;
				}

				if (handler(e) !== false) {
					e.preventDefault();
				}
			}

			if (e.isDefaultPrevented()) {
				return;
			}

			switch (e.keyCode) {
				case 37: // DOM_VK_LEFT
					handleNonTabEvent(e, left);
					break;

				case 39: // DOM_VK_RIGHT
					handleNonTabEvent(e, right);
					break;

				case 38: // DOM_VK_UP
					handleNonTabEvent(e, up);
					break;

				case 40: // DOM_VK_DOWN
					handleNonTabEvent(e, down);
					break;

				case 27: // DOM_VK_ESCAPE
					handleNonTabEvent(e, cancel);
					break;

				case 14: // DOM_VK_ENTER
				case 13: // DOM_VK_RETURN
				case 32: // DOM_VK_SPACE
					handleNonTabEvent(e, enter);
					break;

				case 9: // DOM_VK_TAB
					if (tab(e) !== false) {
						e.preventDefault();
					}
					break;
			}
		});

		root.on('focusin', function(e) {
			focusedElement = e.target;
			focusedControl = e.control;
		});

		return {
			focusFirst: focusFirst
		};
	};
});<|endoftext|>


<commit_before>var baseURI = 'http://localhost:9095';

Envjs(baseURI+'/test.html', {
	scriptTypes : {
	"text/javascript"   : true
	},
	logLevel: Envjs.DEBUG
});

REST.loglevel = 1;

function testFunctions() {
	assertNotNull("get function", MyResource.get);
}

function testGet() {
	var data = MyResource.get();
	assertEquals("ok", data);
}

function testGetFoo() {
	var data = MyResource.getFoo();
	assertEquals("foo", data);
}

function testGetParam() {
	var value = "bla";
	var data = MyResource.getParam({param: value});
	assertEquals(value, data);
}
/*
function testGetFooParam() {
	var data = MyResource.getFooParam({param: "paramv", other: "otherv",
		q : "qv", c : "cv", h: "hv", m: "mv"});
	// cookie is null since env.js doesn't support cookies yet :(
	assertEquals("param=paramv;other=otherv;q=qv;c=null;h=hv;m=mv;", data);
}

function testPutFooParam() {
	var data = MyResource.putFooParam({param: "paramv", other: "otherv",
		q : "qv", c : "cv", h: "hv", m: "mv", $entity: "entityv"});
	// cookie is null since env.js doesn't support cookies yet :(
	assertEquals("param=paramv;other=otherv;q=qv;c=null;h=hv;m=mv;entity=entityv;", data);
}
*/
function testGetXML() {
	var data = MyResource.getXML();
	print(data);
	assertTrue(data instanceof Document);
	var root = data.documentElement;
	assertEquals("test", root.nodeName);
	assertEquals(1, root.childNodes.length);
	assertEquals("var", root.childNodes[0].nodeName);
	assertEquals(1, root.childNodes[0].childNodes.length);
	assertEquals("foo", root.childNodes[0].childNodes[0].nodeValue);
}

function testGetJSON() {
	var data = MyResource.getJSON();
	assertEquals(data['var'], "foo");
}

function testGetJSONStarMIME() {
	var data = MyResource.getJSONStarMIME();
	assertEquals(data['var'], "foo");
}

function testPutJSON() {
	var toSend = {'var' : "ok"};
	var data = MyResource.putJSON({$entity: toSend});
	assertEquals("ok", data);
}

function testPutXML() {
	var toSend = document.implementation.createDocument(null, "test", null);
	var v = toSend.createElement("var");
	toSend.documentElement.appendChild(v);
	v.appendChild(toSend.createTextNode("ok"));
	var data = MyResource.putXML({$entity: toSend});
	assertEquals("ok", data);
}

function testGetMultiRepresentationXML(){
	var data = MyResource.getMultiRepresentation({$accepts: "application/xml"});
	assertTrue(data instanceof Document);
	var root = data.documentElement;
	assertEquals(23, root.childNodes.length);
}

function testGetMultiRepresentationJSON(){
	var data = MyResource.getMultiRepresentation({$accepts: "application/json"});
	assertTrue(data instanceof Array);
	assertEquals(23, data.length);
}

function testLookup(){
	var value = "foo";
	var data = MyResource.lookup({id: value});
	assertEquals(baseURI+"/rest/mine/"+value, data);
}

function testSubResource() {
	var data = MyResource.getSubResource.get();
	assertEquals("Hello", data);
}

function testSubResourceWithPath() {
	var data = MyResource.getSubResource.getWithPath();
	assertEquals("Hello withPath", data);
}
/*

function testSubResource2() {
	var data = MyResource.getSubResource2.get({id: "a", foo: "b"});
	assertEquals("Hello a/b", data);
}

function testSubResource2WithPath() {
	var data = MyResource.getSubResource2.getWithPath({id: "a", foo: "b", bar: "c"});
	assertEquals("Hello withPath a/b/c", data);
}
*/
function testDoubleSubResource() {
	var data = MyResource.getSubResource2.getSubResource.get({id: "a"});
	assertEquals("Hello", data);
}

function testDoubleSubResourceWithPath() {
	var data = MyResource.getSubResource2.getSubResource.getWithPath({id: "a"});
	assertEquals("Hello withPath", data);
}

function testForm() {
	var data = MyResource.postForm({a: "aa", b: "bb"});
	assertEquals("aa/bb", data);
}

// Encoding

function testUTF8(){
	assertEquals("%61", REST.Encoding.percentUTF8(0x61));
	assertEquals("%ce%91", REST.Encoding.percentUTF8(0x0391));
	assertEquals("%e2%89%a2", REST.Encoding.percentUTF8(0x2262));
	assertEquals("%f0%a3%8e%b4", REST.Encoding.percentUTF8(0x233B4));
}

function testPercentByte(){
	assertEquals("%05", REST.Encoding.percentByte(5));
	assertEquals("%20", REST.Encoding.percentByte(32));
}

function testEncoder(){
	assertEquals("abc", REST.Encoding.encodeFormNameOrValue("abc"));
	assertEquals("%c3%a9", REST.Encoding.encodeFormNameOrValue("é"));
	assertEquals("%f0%9f%82%84", REST.Encoding.encodeFormNameOrValue("🂄"));
}

function testEncoders(){
	assertEquals("abc%24%2d%5f%2e%2b%21%2a%27%28%29%2c%2f%3f%26%3d%23+%0D%0A", REST.Encoding.encodeFormNameOrValue("abc$-_.+!*'(),/?&=# \n"));
	assertEquals("azAZ09-._~!$&'()*+,%3b=:@%c3%a9%2f%3f%23%5b%5d", REST.Encoding.encodePathParamValue("azAZ09-._~!$&'()*+,;=:@é/?#[]"));
	assertEquals("azAZ09-._~!$&'()*+,%3b=:@%c3%a9%2f%3f%23%5b%5d", REST.Encoding.encodePathSegment("azAZ09-._~!$&'()*+,;=:@é/?#[]"));
	assertEquals("azAZ09-._~!$&'()*+,%3b%3d:@%c3%a9%2f%3f%23%5b%5d", REST.Encoding.encodePathParamName("azAZ09-._~!$&'()*+,;=:@é/?#[]"));
	assertEquals("azAZ09-._~!$%26'()*%2b,;%3d:@%c3%a9/?%23%5b%5d", REST.Encoding.encodeQueryParamNameOrValue("azAZ09-._~!$&'()*+,;=:@é/?#[]"));
}
<commit_msg>Fixing test.js to deal with RESTEasy return xml payload with Content-Type 'application/xml;charset=UTF-8'<commit_after>var baseURI = 'http://localhost:9095';

Envjs(baseURI+'/test.html', {
	scriptTypes : {
	"text/javascript"   : true
	},
	logLevel: Envjs.DEBUG
});

REST.loglevel = 1;

function testFunctions() {
	assertNotNull("get function", MyResource.get);
}

function testGet() {
	var data = MyResource.get();
	assertEquals("ok", data);
}

function testGetFoo() {
	var data = MyResource.getFoo();
	assertEquals("foo", data);
}

function testGetParam() {
	var value = "bla";
	var data = MyResource.getParam({param: value});
	assertEquals(value, data);
}
/*
function testGetFooParam() {
	var data = MyResource.getFooParam({param: "paramv", other: "otherv",
		q : "qv", c : "cv", h: "hv", m: "mv"});
	// cookie is null since env.js doesn't support cookies yet :(
	assertEquals("param=paramv;other=otherv;q=qv;c=null;h=hv;m=mv;", data);
}

function testPutFooParam() {
	var data = MyResource.putFooParam({param: "paramv", other: "otherv",
		q : "qv", c : "cv", h: "hv", m: "mv", $entity: "entityv"});
	// cookie is null since env.js doesn't support cookies yet :(
	assertEquals("param=paramv;other=otherv;q=qv;c=null;h=hv;m=mv;entity=entityv;", data);
}
*/
function testGetXML() {
	var data = MyResource.getXML();
	print(data);
        if (data instanceof Document) {
	  assertTrue(data instanceof Document);
	  var root = data.documentElement;
        } else {
          var parser = new DOMParser()
          var root = parser.parseFromString(data, "application/xml").childNodes[1];
        }
	assertEquals("test", root.nodeName);
	assertEquals(1, root.childNodes.length);
	assertEquals("var", root.childNodes[0].nodeName);
	assertEquals(1, root.childNodes[0].childNodes.length);
	assertEquals("foo", root.childNodes[0].childNodes[0].nodeValue);
}

function testGetJSON() {
	var data = MyResource.getJSON();
	assertEquals(data['var'], "foo");
}

function testGetJSONStarMIME() {
	var data = MyResource.getJSONStarMIME();
	assertEquals(data['var'], "foo");
}

function testPutJSON() {
	var toSend = {'var' : "ok"};
	var data = MyResource.putJSON({$entity: toSend});
	assertEquals("ok", data);
}

function testPutXML() {
	var toSend = document.implementation.createDocument(null, "test", null);
	var v = toSend.createElement("var");
	toSend.documentElement.appendChild(v);
	v.appendChild(toSend.createTextNode("ok"));
	var data = MyResource.putXML({$entity: toSend});
	assertEquals("ok", data);
}

function testGetMultiRepresentationXML(){
	var data = MyResource.getMultiRepresentation({$accepts: "application/xml"});
        if (data instanceof Document) {
	  assertTrue(data instanceof Document);
	  var root = data.documentElement;
        } else {
          var parser = new DOMParser()
          var root = parser.parseFromString(data, "application/xml").childNodes[1];
        }
	assertEquals(23, root.childNodes.length);
}

function testGetMultiRepresentationJSON(){
	var data = MyResource.getMultiRepresentation({$accepts: "application/json"});
	assertTrue(data instanceof Array);
	assertEquals(23, data.length);
}

function testLookup(){
	var value = "foo";
	var data = MyResource.lookup({id: value});
	assertEquals(baseURI+"/rest/mine/"+value, data);
}

function testSubResource() {
	var data = MyResource.getSubResource.get();
	assertEquals("Hello", data);
}

function testSubResourceWithPath() {
	var data = MyResource.getSubResource.getWithPath();
	assertEquals("Hello withPath", data);
}
/*

function testSubResource2() {
	var data = MyResource.getSubResource2.get({id: "a", foo: "b"});
	assertEquals("Hello a/b", data);
}

function testSubResource2WithPath() {
	var data = MyResource.getSubResource2.getWithPath({id: "a", foo: "b", bar: "c"});
	assertEquals("Hello withPath a/b/c", data);
}
*/
function testDoubleSubResource() {
	var data = MyResource.getSubResource2.getSubResource.get({id: "a"});
	assertEquals("Hello", data);
}

function testDoubleSubResourceWithPath() {
	var data = MyResource.getSubResource2.getSubResource.getWithPath({id: "a"});
	assertEquals("Hello withPath", data);
}

function testForm() {
	var data = MyResource.postForm({a: "aa", b: "bb"});
	assertEquals("aa/bb", data);
}

// Encoding

function testUTF8(){
	assertEquals("%61", REST.Encoding.percentUTF8(0x61));
	assertEquals("%ce%91", REST.Encoding.percentUTF8(0x0391));
	assertEquals("%e2%89%a2", REST.Encoding.percentUTF8(0x2262));
	assertEquals("%f0%a3%8e%b4", REST.Encoding.percentUTF8(0x233B4));
}

function testPercentByte(){
	assertEquals("%05", REST.Encoding.percentByte(5));
	assertEquals("%20", REST.Encoding.percentByte(32));
}

function testEncoder(){
	assertEquals("abc", REST.Encoding.encodeFormNameOrValue("abc"));
	assertEquals("%c3%a9", REST.Encoding.encodeFormNameOrValue("é"));
	assertEquals("%f0%9f%82%84", REST.Encoding.encodeFormNameOrValue("🂄"));
}

function testEncoders(){
	assertEquals("abc%24%2d%5f%2e%2b%21%2a%27%28%29%2c%2f%3f%26%3d%23+%0D%0A", REST.Encoding.encodeFormNameOrValue("abc$-_.+!*'(),/?&=# \n"));
	assertEquals("azAZ09-._~!$&'()*+,%3b=:@%c3%a9%2f%3f%23%5b%5d", REST.Encoding.encodePathParamValue("azAZ09-._~!$&'()*+,;=:@é/?#[]"));
	assertEquals("azAZ09-._~!$&'()*+,%3b=:@%c3%a9%2f%3f%23%5b%5d", REST.Encoding.encodePathSegment("azAZ09-._~!$&'()*+,;=:@é/?#[]"));
	assertEquals("azAZ09-._~!$&'()*+,%3b%3d:@%c3%a9%2f%3f%23%5b%5d", REST.Encoding.encodePathParamName("azAZ09-._~!$&'()*+,;=:@é/?#[]"));
	assertEquals("azAZ09-._~!$%26'()*%2b,;%3d:@%c3%a9/?%23%5b%5d", REST.Encoding.encodeQueryParamNameOrValue("azAZ09-._~!$&'()*+,;=:@é/?#[]"));
}
<|endoftext|>


<commit_before>/**
 * Test that the dist works
 */
var assert = require("assert"),
	Browser = require("zombie"),
	connect = require("connect"),
	path = require("path"),
	rmdir = require("rimraf");

var browserify = require('browserify');
var fs = require('fs'), path = require("path");

// Helpers
var find = function(browser, property, callback, done){
	var start = new Date();
	var check = function(){
		if(browser.window && browser.window[property]) {
			callback(browser.window[property]);
		} else if(new Date() - start < 2000){
			setTimeout(check, 20);
		} else {
			done("failed to find "+property+" in "+browser.window.location.href);
		}
	};
	check();
};

var open = function(url, callback, done){
	var server = connect().use(connect.static(path.join(__dirname,"../../.."))).listen(8081);
	var browser = Browser.create();
	browser.visit("http://localhost:8081/"+url)
		.then(function(){
			callback(browser, function(err){
				server.close();
				done(err);
			})
		}).catch(function(e){
			server.close();
			done(e)
		});
};

describe("browserify", function(){
	it("is able to build an app that does not use templates", function(done){
		this.timeout(10000);
		var b = browserify();
		b.add(path.join(__dirname, "main.js"));
		var out = fs.createWriteStream(path.join(__dirname, "out.js"));
		b.bundle().pipe(out);
		out.on('finish', function(){
			open("test/builders/browserify/prod.html", function(browser, close) {
				find(browser, "PAGE_READY", function(m){
					var helloWorld = browser.document.getElementsByTagName("hello-world")[0];
					assert.equal(helloWorld.innerHTML, "Hello World", "right text");
					close();
				}, close);
			}, done);
		});

	});
});

<commit_msg>fixes zombie with browserify<commit_after>/**
 * Test that the dist works
 */
var assert = require("assert"),
	Browser = require("zombie"),
	connect = require("connect"),
	path = require("path"),
	rmdir = require("rimraf");

var browserify = require('browserify');
var fs = require('fs'), path = require("path");

// Helpers
var find = function(browser, property, callback, done){
	var start = new Date();
	var check = function(){
		if(browser.window && browser.window[property]) {
			callback(browser.window[property]);
		} else if(new Date() - start < 2000){
			setTimeout(check, 20);
		} else {
			done("failed to find "+property+" in "+browser.window.location.href);
		}
	};
	check();
};

var open = function(url, callback, done){
	var server = connect().use(connect.static(path.join(__dirname,"../../.."))).listen(8081);
	var browser = new Browser();
	browser.visit("http://localhost:8081/"+url)
		.then(function(){
			callback(browser, function(err){
				server.close();
				done(err);
			})
		}).catch(function(e){
			server.close();
			done(e)
		});
};

describe("browserify", function(){
	it("is able to build an app that does not use templates", function(done){
		this.timeout(10000);
		var b = browserify();
		b.add(path.join(__dirname, "main.js"));
		var out = fs.createWriteStream(path.join(__dirname, "out.js"));
		b.bundle().pipe(out);
		out.on('finish', function(){
			open("test/builders/browserify/prod.html", function(browser, close) {
				find(browser, "PAGE_READY", function(m){
					var helloWorld = browser.document.getElementsByTagName("hello-world")[0];
					assert.equal(helloWorld.innerHTML, "Hello World", "right text");
					close();
				}, close);
			}, done);
		});

	});
});

<|endoftext|>


<commit_before>const testWithServer = require('./helpers/test-with-server');

testWithServer('Request for HTML Content', {}, (t, ctx) => {
  t.plan(2);

  const htmlRequest = {
    method: 'GET',
    url: '/',
    headers: {'Accept': 'text/html'}
  };

  ctx.server.inject(htmlRequest, (res) => {
    t.ok(res.payload.toLowerCase().indexOf('<!doctype html>') > -1, 'HTML request should respond with HTML');
    t.ok(res.headers['content-type'].indexOf('text/html') > -1, 'Response header should be text/html');
    t.end();
  });
});

testWithServer('Request for JSONAPI Content', {}, (t, ctx) => {
  // http://jsonapi.org/format/#content-negotiation-servers
  //
  // Servers MUST send all JSON API data in response documents with the header
  // `Content-Type: application/vnd.api+json` without any media type parameters.
  t.plan(1);

  const jsonRequest = {
    method: 'GET',
    url: '/search?q=test',
    headers: {'Accept': 'application/vnd.api+json'}
  };

  ctx.server.inject(jsonRequest, (res) => {
    t.ok(res.headers['content-type'].indexOf('application/vnd.api+json') > -1, 'JSONAPI response header should be application/vnd.api+json');
    t.end();
  });
});

testWithServer('Request with multiple instances of JSONAPI media type, one without parameters', {}, (t, ctx) => {
  t.plan(1);

  const acceptableJSONRequest = {
    method: 'GET',
    url: '/search?q=test',
    headers: {'Accept': 'application/vnd.api+json; charset=utf-8, application/vnd.api+json'}
  };

  ctx.server.inject(acceptableJSONRequest, (res) => {
    t.equal(res.statusCode, 200, 'At least one JSONAPI without parameters should work');
    t.end();
  });
});
<commit_msg>add test for content negociation, #373<commit_after>const testWithServer = require('./helpers/test-with-server');

testWithServer('Request for HTML Content', {}, (t, ctx) => {
  t.plan(2);

  const htmlRequest = {
    method: 'GET',
    url: '/',
    headers: {'Accept': 'text/html'}
  };

  ctx.server.inject(htmlRequest, (res) => {
    t.ok(res.payload.toLowerCase().indexOf('<!doctype html>') > -1, 'HTML request should respond with HTML');
    t.ok(res.headers['content-type'].indexOf('text/html') > -1, 'Response header should be text/html');
    t.end();
  });
});

testWithServer('Request for JSONAPI Content', {}, (t, ctx) => {
  // http://jsonapi.org/format/#content-negotiation-servers
  //
  // Servers MUST send all JSON API data in response documents with the header
  // `Content-Type: application/vnd.api+json` without any media type parameters.
  t.plan(1);

  const jsonRequest = {
    method: 'GET',
    url: '/search?q=test',
    headers: {'Accept': 'application/vnd.api+json'}
  };

  ctx.server.inject(jsonRequest, (res) => {
    t.ok(res.headers['content-type'].indexOf('application/vnd.api+json') > -1, 'JSONAPI response header should be application/vnd.api+json');
    t.end();
  });
});

testWithServer('Request with multiple instances of JSONAPI media type, one without parameters', {}, (t, ctx) => {
  t.plan(1);

  const acceptableJSONRequest = {
    method: 'GET',
    url: '/search?q=test',
    headers: {'Accept': 'application/vnd.api+json; charset=utf-8, application/vnd.api+json'}
  };

  ctx.server.inject(acceptableJSONRequest, (res) => {
    t.equal(res.statusCode, 200, 'At least one JSONAPI without parameters should work');
    t.end();
  });
});

testWithServer('Not acceptable request when to accept header', {}, (t, ctx) => {
  t.plan(1);

  const acceptableJSONRequest = {
    method: 'GET',
    url: '/'
  };

  ctx.server.inject(acceptableJSONRequest, (res) => {
    t.equal(res.statusCode, 416, 'Not acceptable request when no accept header is defined');
    t.end();
  });
});

testWithServer('Not acceptable if json and html header are defined at the same time', {}, (t, ctx) => {
  t.plan(1);

  const acceptableJSONRequest = {
    method: 'GET',
    url: '/',
    headers: {'Accept': 'text/html, application/json'}
  };

  ctx.server.inject(acceptableJSONRequest, (res) => {
    t.equal(res.statusCode, 416, 'Not acceptable request when a json and html header are defined at the same time');
    t.end();
  });
});

testWithServer('Return html if user agent is twitter bot', {}, (t, ctx) => {
  t.plan(1);

  const acceptableJSONRequest = {
    method: 'GET',
    url: '/',
    headers: {'user-agent': 'Twitterbot'}
  };

  ctx.server.inject(acceptableJSONRequest, (res) => {
    t.equal(res.statusCode, 200, 'return some html for twitter');
    t.end();
  });
});

testWithServer('Not acceptable if no accept header and no user-agent twitter', {}, (t, ctx) => {
  t.plan(1);

  const acceptableJSONRequest = {
    method: 'GET',
    url: '/',
    headers: {'user-agent': 'bot'}
  };

  ctx.server.inject(acceptableJSONRequest, (res) => {
    t.equal(res.statusCode, 416, 'not acceptage if user-agent is not twitter');
    t.end();
  });
});
<|endoftext|>


<commit_before>"use strict";

describe("define/definition/member", function () {

    if (gpf.internals) {

        var _GpfClassDefinition = gpf.internals._GpfClassDefinition,
            _GpfClassDefMember = gpf.internals._GpfClassDefMember;

        describe("class definition", function () {

            it("gives access to class definition", function () {
                var classA = new _GpfClassDefinition("test.A"),
                    member = new _GpfClassDefMember("member1", 12);
                assert(!member.getClassDefinition());
                classA.addMember(member);
                assert(member.getClassDefinition() === classA);
            });

        });

        describe("typing", function () {

            it("handles default type", function () {
                var member = new _GpfClassDefMember("member1");
                assert(member.getType() === "undefined");
            });

            it("validates provided type (correct)", function () {
                var member = new _GpfClassDefMember("member1", 12, "number");
                assert(member);
            });

            it("validates provided type (incorrect)", function () {
                var caught = false;
                try {
                    var member = new _GpfClassDefMember("member1", 12, "invalid");
                    assert(member);
                } catch (e) {
                    assert(e instanceof gpf.Error);
                    assert(e.code === gpf.Error.CODE_INVALIDCLASSMEMBERTYPE);
                    assert(e.code === gpf.Error.invalidClassMemberType.CODE);
                    assert(e.name === "invalidClassMemberType");
                    caught = true;
                }
                assert(true === caught);
            });

            it("deduces type from default value", function () {
                var member = new _GpfClassDefMember("member1", 12);
                assert(member.getType() === "number");
            });

        });

    }

});
<commit_msg>No type checking<commit_after>"use strict";

describe("define/definition/member", function () {

    if (gpf.internals) {

        var _GpfClassDefinition = gpf.internals._GpfClassDefinition,
            _GpfClassDefMember = gpf.internals._GpfClassDefMember;

        describe("class definition", function () {

            it("gives access to class definition", function () {
                var classA = new _GpfClassDefinition("test.A"),
                    member = new _GpfClassDefMember("member1", 12);
                assert(!member.getClassDefinition());
                classA.addMember(member);
                assert(member.getClassDefinition() === classA);
            });

        });

        describe("typing", function () {

            it("handles default type", function () {
                var member = new _GpfClassDefMember("member1");
                assert(member.getType() === "undefined");
            });

            it("accepts any member type", function () {
                var member = new _GpfClassDefMember("member1", 12, "real");
                assert(member.getType() === "real");
            });

            it("deduces type from default value", function () {
                var member = new _GpfClassDefMember("member1", 12);
                assert(member.getType() === "number");
            });

        });

    }

});
<|endoftext|>


<commit_before>// Load in dependencies
var path = require('path');
var expect = require('chai').expect;
var wrench = require('wrench');
var gitRelease = require('../');
var fixtureUtils = require('./utils/fixtures');

describe('Committing', function () {
  describe('in a git folder', function () {
    fixtureUtils.mkdir('git_test');
    fixtureUtils.exec('git init');
    fixtureUtils.exec('touch a');
    fixtureUtils.exec('git add -A');
    fixtureUtils.exec('git commit -m "Initial commit =D"');

    before(function publish (done) {
      this.inFixtureDir(function () {
        console.log('hai');
        gitRelease.publish({
          version: '0.1.0',
          message: 'Release 0.1.0',
          description: null
        }, done);
      });
    });

    it('adds a git tag', function (done) {
      this.inFixtureDir(function () {
        exec('git tag', function (err, stdout, stderr) {
          if (err) {
            return done(err);
          }
          expect(stdout).to.equal('0.1.0\n');
          done();
        });
      });
    });

    it('adds a git commit', function (done) {
      this.inFixtureDir(function () {
        exec('git log --format=oneline -n 1', function (err, stdout, stderr) {
          if (err) {
            return done(err);
          }
          expect(stdout).to.match(/\w{32} Release 0.1.0\n/);
          done();
        });
      });
    });
  });
});
<commit_msg>Moving back to publishing comment<commit_after>// Load in dependencies
var path = require('path');
var expect = require('chai').expect;
var wrench = require('wrench');
var gitRelease = require('../');
var fixtureUtils = require('./utils/fixtures');

describe('Publishing', function () {
  describe('in a git folder', function () {
    fixtureUtils.mkdir('git_test');
    fixtureUtils.exec('git init');
    fixtureUtils.exec('touch a');
    fixtureUtils.exec('git add -A');
    fixtureUtils.exec('git commit -m "Initial commit =D"');

    before(function publish (done) {
      this.inFixtureDir(function () {
        console.log('hai');
        gitRelease.publish({
          version: '0.1.0',
          message: 'Release 0.1.0',
          description: null
        }, done);
      });
    });

    it('adds a git tag', function (done) {
      this.inFixtureDir(function () {
        exec('git tag', function (err, stdout, stderr) {
          if (err) {
            return done(err);
          }
          expect(stdout).to.equal('0.1.0\n');
          done();
        });
      });
    });

    it('adds a git commit', function (done) {
      this.inFixtureDir(function () {
        exec('git log --format=oneline -n 1', function (err, stdout, stderr) {
          if (err) {
            return done(err);
          }
          expect(stdout).to.match(/\w{32} Release 0.1.0\n/);
          done();
        });
      });
    });
  });
});
<|endoftext|>


<commit_before>import { expect } from 'chai';

import helpers from '../../server/config/helpers';
import computer from '../../server/config/computerPlayer';
import gameController from '../../server/controllers/gameController';
import roomController from '../../server/controllers/roomController';
import big2Rooms from '../../server/models/big2Rooms';

for (let i = 0; i < 4; i +=1) {
  roomController.joinRoom(`testUser${i}`, 'testRoom', `testSocket${i}`);
}
gameController.createGame('testRoom');
const testRoom = big2Rooms.rooms['testRoom'];
// console.log('test room: ', testRoom);
const testHand1 = ['3♦'];
const testHand2 = ['3♣'];
const testHand3 = ['4♦'];

describe('Validator Checks', () => {
  describe('getValue', () => {
    const cardValue = computer.getValue(testHand1[0]);
    const diffCardValue = computer.getValue('13♠');
    it('should find suit value for card', () => {
      expect(cardValue).to.be.an('object');
      expect(cardValue.value).to.equal(1);
      expect(diffCardValue.value).to.equal(13);
    });
    it('should find A - K value for card', () => {
      expect(cardValue).to.be.an('object');
      expect(cardValue.suitValue).to.equal(1);
      expect(diffCardValue.suitValue).to.equal(4);
    });
  });
  describe('cardIsLarger', () => {
    const notLarger = computer.cardIsLarger(testHand1[0], testHand3[0]);
    const isLarger = computer.cardIsLarger(testHand2[0], testHand1[0]);
    it('should return false if first param is smaller', () => {
      expect(notLarger).to.be.a('boolean');
      expect(notLarger).to.equal(false);
    });
    it('should return true if first param is larger', () => {
      expect(isLarger).to.be.a('boolean');
      expect(isLarger).to.equal(true);
    });
    it('should return true if card value is same and suit value is higher', () => {
      expect(isLarger).to.equal(true);
    });
    it('should return true if card value is higher and suit value is same', () => {
      expect(computer.cardIsLarger('1♦', '13♦')).to.equal(true);
    });
    it('should correctly identify Ace as higher than King', () => {
      expect(computer.cardIsLarger('1♦', '13♦')).to.equal(true);
    });
    it('should correctly identify 2 as higher than Ace', () => {
      expect(computer.cardIsLarger('2♦', '1♦')).to.equal(true);
    });
  });
  describe('suitIsMatch', () => {
    const matchedSuit = computer.suitIsMatch(testHand1[0], testHand3[0]);
    const notMatched = computer.suitIsMatch(testHand2[0], testHand1[0]);
    it('should return true if cards have same suit', () => {
      expect(matchedSuit).to.be.a('boolean');
      expect(matchedSuit).to.equal(true);
    });
    it('should return false if cards have different suit', () => {
      expect(notMatched).to.be.a('boolean');
      expect(notMatched).to.equal(false);
    });
  });
  xdescribe('handPatternCheck', () => {
    it('should return true if hand is a single card', () => {
      expect().to.be.a('boolean');
      expect().to.equal(true);
    });
    it('should return true if hand is two cards with same number value', () => {
      expect().to.be.a('boolean');
      expect().to.equal(true);
    });
    it('should return false if hand is two cards with different number value', () => {
      expect().to.be.a('boolean');
      expect().to.equal(false);
    });
    it('should return true if hand is three cards with same number value', () => {
      expect().to.be.a('boolean');
      expect().to.equal(true);
    });
    it('should return false if hand is three cards with different number value', () => {
      expect().to.be.a('boolean');
      expect().to.equal(false);
    });
    it('should return false if hand is four cards', () => {
      expect().to.be.a('boolean');
      expect().to.equal(false);
    });
    it('should return true if hand is a straight', () => {
      expect().to.be.a('boolean');
      expect().to.equal(true);
    });
    it('should return true if hand is a flush', () => {
      expect().to.be.a('boolean');
      expect().to.equal(true);
    });
    it('should return true if hand is a full house', () => {
      expect().to.be.a('boolean');
      expect().to.equal(true);
    });
    it('should return true if hand is a four of a kind', () => {
      expect().to.be.a('boolean');
      expect().to.equal(true);
    });
  });
});

xdescribe('Computer Behavior', () => {

});
<commit_msg>(test)Test handPatternCheck function for singles and pairs<commit_after>import { expect } from 'chai';

import helpers from '../../server/config/helpers';
import computer from '../../server/config/computerPlayer';
import gameController from '../../server/controllers/gameController';
import roomController from '../../server/controllers/roomController';
import big2Rooms from '../../server/models/big2Rooms';

for (let i = 0; i < 4; i +=1) {
  roomController.joinRoom(`testUser${i}`, 'testRoom', `testSocket${i}`);
}
gameController.createGame('testRoom');
const testRoom = big2Rooms.rooms['testRoom'];
// console.log('test room: ', testRoom);
const testHand1 = ['3♦'];
const testHand2 = ['3♣'];
const testHand3 = ['4♦'];
const testPair = ['4♦', '4♣'];
const invalidPair = ['4♦', '2♣'];

describe('Validator Checks', () => {
  describe('getValue', () => {
    const cardValue = computer.getValue(testHand1[0]);
    const diffCardValue = computer.getValue('13♠');
    it('should find number value for card', () => {
      expect(cardValue).to.be.an('object');
      expect(cardValue.value).to.equal(3);
      expect(diffCardValue.value).to.equal(13);
    });
    it('should find suit value for card', () => {
      expect(cardValue).to.be.an('object');
      expect(cardValue.suitValue).to.equal(1);
      expect(diffCardValue.suitValue).to.equal(4);
    });
  });
  describe('cardIsLarger', () => {
    const notLarger = computer.cardIsLarger(testHand1[0], testHand3[0]);
    const isLarger = computer.cardIsLarger(testHand2[0], testHand1[0]);
    it('should return false if first param is smaller', () => {
      expect(notLarger).to.be.a('boolean');
      expect(notLarger).to.equal(false);
    });
    it('should return true if first param is larger', () => {
      expect(isLarger).to.be.a('boolean');
      expect(isLarger).to.equal(true);
    });
    it('should return true if card value is same and suit value is higher', () => {
      expect(isLarger).to.equal(true);
    });
    it('should return true if card value is higher and suit value is same', () => {
      expect(computer.cardIsLarger('1♦', '13♦')).to.equal(true);
    });
    it('should correctly identify Ace as higher than King', () => {
      expect(computer.cardIsLarger('1♦', '13♦')).to.equal(true);
    });
    it('should correctly identify 2 as higher than Ace', () => {
      expect(computer.cardIsLarger('2♦', '1♦')).to.equal(true);
    });
  });
  describe('suitIsMatch', () => {
    const matchedSuit = computer.suitIsMatch(testHand1[0], testHand3[0]);
    const notMatched = computer.suitIsMatch(testHand2[0], testHand1[0]);
    it('should return true if cards have same suit', () => {
      expect(matchedSuit).to.be.a('boolean');
      expect(matchedSuit).to.equal(true);
    });
    it('should return false if cards have different suit', () => {
      expect(notMatched).to.be.a('boolean');
      expect(notMatched).to.equal(false);
    });
  });
  describe('handPatternCheck', () => {
    it('should return true if hand is a single card', () => {
      const checkSingle = computer.handPatternCheck(testHand1);
      expect(checkSingle).to.be.a('boolean');
      expect(checkSingle).to.equal(true);
    });
    it('should return true if hand is two cards with same number value', () => {
      const checkDouble = computer.handPatternCheck(testPair)
      expect(checkDouble).to.be.a('boolean');
      expect(checkDouble).to.equal(true);
    });
    it('should return false if hand is two cards with different number value', () => {
      const checkDouble = computer.handPatternCheck(invalidPair)
      expect(checkDouble).to.be.a('boolean');
      expect(checkDouble).to.equal(false);
    });
    it('should return true if hand is three cards with same number value', () => {
      expect().to.be.a('boolean');
      expect().to.equal(true);
    });
    it('should return false if hand is three cards with different number value', () => {
      expect().to.be.a('boolean');
      expect().to.equal(false);
    });
    it('should return false if hand is four cards', () => {
      expect().to.be.a('boolean');
      expect().to.equal(false);
    });
    it('should return true if hand is a straight', () => {
      expect().to.be.a('boolean');
      expect().to.equal(true);
    });
    it('should return true if hand is a flush', () => {
      expect().to.be.a('boolean');
      expect().to.equal(true);
    });
    it('should return true if hand is a full house', () => {
      expect().to.be.a('boolean');
      expect().to.equal(true);
    });
    it('should return true if hand is a four of a kind', () => {
      expect().to.be.a('boolean');
      expect().to.equal(true);
    });
  });
});

xdescribe('Computer Behavior', () => {

});
<|endoftext|>


<commit_before>'use strict';

const assert = require('assert');
const Request = require('../../lib/Request');
const fs = require('fs');
const requestModule = require('request');

describe('Request', function () {
  const postBody = { id: 3, name: 'FooBar', age: 35 };

  it('should post new user', function () {
    const request = new Request('http://localhost:3000');

    request.upon(requestModule);

    return request
      .post('/user')
      .body(postBody)
      .json()
      .then((response) => {
        assert.ok(response.headers['content-type']);
        assert.ok(response.headers['content-type'].search(/json/));
        assert.deepEqual(response.body, postBody);

        return response;
      });
  });

  it('should get user by name', function () {
    const request = new Request('http://localhost:3000');

    request.upon(requestModule);

    return request
      .get('/user')
      .json()
      .query({ name: 'FooBar' })
      .then((response) => {
        assert.deepEqual(postBody, response.body[0]);

        return response;
      });
  });

  it('should update user info', function () {
    const request = new Request('http://localhost:3000');

    request.upon(requestModule);

    return request
      .put('/user/:id', { id: 1 })
      .json()
      .body({ age: 20 })
      .then((response) => {
        assert.equal(response.body.age, 20);

        return response;
      });
  });

  it('should get user by id without path parser', function () {
    const request = new Request('http://localhost:3000');

    request.upon(requestModule);

    return request
      .get('/user/3')
      .json()
      .then((response) => {
        assert.ifError(response.error);
        assert.equal(response.statusCode, 200);
        assert.equal(response.type, 2);
        assert.equal(response.ok, true);
        assert.equal(response.status.ok, true);

        assert.equal(response.body.id, 3);

        return response;
      });
  });

  it('should delete user by id', function () {
    const request = new Request('http://localhost:3000');

    request.upon(requestModule);

    return request
      .delete('/user/:id', { id: 1 })
      .json()
      .then((response) => {
        assert.ifError(response.error);
        assert.ok(response.ok);

        return response;
      });
  });

  it('should return error 404 for user', function () {
    const request = new Request('http://localhost:3000');

    request.upon(requestModule);

    return request
      .get('/user/-1')
      .json()
      .then((response) => {
        assert.equal(response.statusCode, 404);
        assert.equal(response.type, 4);
        assert.equal(response.status.notFound, true);
        assert.equal(response.clientError, true);

        return response;
      });
  });

  it('should get image using request.toOptions() with request', function (done) {
    const options = new Request('http://localhost:3000').get('/image').toOptions();
    const request = require('request'); // eslint-disable-line

    request(options)
      .on('response', (response) => {
        assert.equal(response.statusCode, 200);
        assert.equal(response.headers['content-type'], 'image/png');
      })
      .on('end', done)
      .on('error', done)
      .pipe(fs.createWriteStream('test/fixtures/image_downloaded.png'));
  });

  it('should get image as buffer using request.encoding(null)', function () {
    const request = new Request('http://localhost:3000');

    request.upon(requestModule);

    return request
      .get('/image')
      .encoding(null)
      .then((response) => {
        assert.equal(response.body instanceof Buffer, true);

        return response;
      });
  });

  it('should get image as non-buffer using request.encoding("utf-8")', function () {
    const request = new Request('http://localhost:3000');

    request.upon(requestModule);

    return request
      .get('/image')
      .encoding('utf-8')
      .then((response) => {
        assert.equal(response.body instanceof Buffer, false);

        return response;
      });
  });

  describe('#timeout()', function () {
    it('should timeout request', function () {
      this.timeout(3000);
      const request = new Request('http://localhost:3000');

      request.upon(requestModule);

      return request
        .get('/timeout')
        .timeout(1000)
        .catch((error) => {
          assert.equal(error.code, 'ESOCKETTIMEDOUT');

          return error;
        });
    });

    it('should NOT timeout request', function () {
      this.timeout(3000);
      const request = new Request('http://localhost:3000');

      request.upon(requestModule);

      return request
        .get('/timeout')
        .timeout(2500)
        .then((response) => {
          assert.equal(response.body, 'NO_TIMEOUT');

          return response;
        });
    });
  });

  describe('#jar()', function () {
    it('should send and get cookies', function () {
      const request = new Request('http://localhost:3000');

      request.upon(requestModule);

      const j = request.request.jar();
      const cookie = request.request.cookie('key1=value1');
      const url = 'http://localhost:3000';
      j.setCookie(cookie, url);

      return request
        .get('/cookie')
        .jar(j)
        .then((response) => {
          assert.equal(response.body, 'key1=value1');
          assert.ok(j.getCookieString(url).includes('key2=value2'));

          return response;
        });
    });
  });

  describe('#exec()', function () {
    it('should request stream image with exec and callback', function (done) {
      const request = new Request('http://localhost:3000').get('/image');

      request.upon(requestModule);

      request.exec(() => done())
        .on('response', (response) => {
          assert.equal(response.headers['content-type'], 'image/png');
        })
        .on('error', done);
    });

    it('should request stream image with exec', function (done) {
      const request = new Request('http://localhost:3000').get('/image');

      request.upon(requestModule);

      request.exec()
        .on('response', (response) => {
          assert.equal(response.headers['content-type'], 'image/png');
        })
        .on('end', done)
        .on('error', done);
    });
  });
});
<commit_msg>Request#upon() test added<commit_after>'use strict';

const assert = require('assert');
const Request = require('../../lib/Request');
const fs = require('fs');
const requestModule = require('request');

describe('Request', function () {
  const postBody = { id: 3, name: 'FooBar', age: 35 };

  it('should post new user', function () {
    const request = new Request('http://localhost:3000');

    request.upon(requestModule);

    return request
      .post('/user')
      .body(postBody)
      .json()
      .then((response) => {
        assert.ok(response.headers['content-type']);
        assert.ok(response.headers['content-type'].search(/json/));
        assert.deepEqual(response.body, postBody);

        return response;
      });
  });

  it('should get user by name', function () {
    const request = new Request('http://localhost:3000');

    request.upon(requestModule);

    return request
      .get('/user')
      .json()
      .query({ name: 'FooBar' })
      .then((response) => {
        assert.deepEqual(postBody, response.body[0]);

        return response;
      });
  });

  it('should update user info', function () {
    const request = new Request('http://localhost:3000');

    request.upon(requestModule);

    return request
      .put('/user/:id', { id: 1 })
      .json()
      .body({ age: 20 })
      .then((response) => {
        assert.equal(response.body.age, 20);

        return response;
      });
  });

  it('should get user by id without path parser', function () {
    const request = new Request('http://localhost:3000');

    request.upon(requestModule);

    return request
      .get('/user/3')
      .json()
      .then((response) => {
        assert.ifError(response.error);
        assert.equal(response.statusCode, 200);
        assert.equal(response.type, 2);
        assert.equal(response.ok, true);
        assert.equal(response.status.ok, true);

        assert.equal(response.body.id, 3);

        return response;
      });
  });

  it('should delete user by id', function () {
    const request = new Request('http://localhost:3000');

    request.upon(requestModule);

    return request
      .delete('/user/:id', { id: 1 })
      .json()
      .then((response) => {
        assert.ifError(response.error);
        assert.ok(response.ok);

        return response;
      });
  });

  it('should return error 404 for user', function () {
    const request = new Request('http://localhost:3000');

    request.upon(requestModule);

    return request
      .get('/user/-1')
      .json()
      .then((response) => {
        assert.equal(response.statusCode, 404);
        assert.equal(response.type, 4);
        assert.equal(response.status.notFound, true);
        assert.equal(response.clientError, true);

        return response;
      });
  });

  it('should get image using request.toOptions() with request', function (done) {
    const options = new Request('http://localhost:3000').get('/image').toOptions();
    const request = require('request'); // eslint-disable-line

    request(options)
      .on('response', (response) => {
        assert.equal(response.statusCode, 200);
        assert.equal(response.headers['content-type'], 'image/png');
      })
      .on('end', done)
      .on('error', done)
      .pipe(fs.createWriteStream('test/fixtures/image_downloaded.png'));
  });

  it('should get image as buffer using request.encoding(null)', function () {
    const request = new Request('http://localhost:3000');

    request.upon(requestModule);

    return request
      .get('/image')
      .encoding(null)
      .then((response) => {
        assert.equal(response.body instanceof Buffer, true);

        return response;
      });
  });

  it('should get image as non-buffer using request.encoding("utf-8")', function () {
    const request = new Request('http://localhost:3000');

    request.upon(requestModule);

    return request
      .get('/image')
      .encoding('utf-8')
      .then((response) => {
        assert.equal(response.body instanceof Buffer, false);

        return response;
      });
  });

  describe('#timeout()', function () {
    it('should timeout request', function () {
      this.timeout(3000);
      const request = new Request('http://localhost:3000');

      request.upon(requestModule);

      return request
        .get('/timeout')
        .timeout(1000)
        .catch((error) => {
          assert.equal(error.code, 'ESOCKETTIMEDOUT');

          return error;
        });
    });

    it('should NOT timeout request', function () {
      this.timeout(3000);
      const request = new Request('http://localhost:3000');

      request.upon(requestModule);

      return request
        .get('/timeout')
        .timeout(2500)
        .then((response) => {
          assert.equal(response.body, 'NO_TIMEOUT');

          return response;
        });
    });
  });

  describe('#jar()', function () {
    it('should send and get cookies', function () {
      const request = new Request('http://localhost:3000');

      request.upon(requestModule);

      const j = request.request.jar();
      const cookie = request.request.cookie('key1=value1');
      const url = 'http://localhost:3000';
      j.setCookie(cookie, url);

      return request
        .get('/cookie')
        .jar(j)
        .then((response) => {
          assert.equal(response.body, 'key1=value1');
          assert.ok(j.getCookieString(url).includes('key2=value2'));

          return response;
        });
    });
  });

  describe('#exec()', function () {
    it('should request stream image with exec and callback', function (done) {
      const request = new Request('http://localhost:3000').get('/image');

      request.upon(requestModule);

      request.exec(() => done())
        .on('response', (response) => {
          assert.equal(response.headers['content-type'], 'image/png');
        })
        .on('error', done);
    });

    it('should fail due to missng request.upon() call', function () {
      const request = new Request('http://localhost:3000');
      assert.throws(() => request.exec(), /must be called first with request module/);
    });

    it('should request stream image with exec', function (done) {
      const request = new Request('http://localhost:3000').get('/image');

      request.upon(requestModule);

      request.exec()
        .on('response', (response) => {
          assert.equal(response.headers['content-type'], 'image/png');
        })
        .on('end', done)
        .on('error', done);
    });
  });
});
<|endoftext|>


<commit_before>var Plotly = require('@lib/index');
var Lib = require('@src/lib');
var Table = require('@src/traces/table');
var attributes = require('@src/traces/table/attributes');
var cn = require('@src/traces/table/constants').cn;

var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var supplyAllDefaults = require('../assets/supply_defaults');

var mockMulti = require('@mocks/table_latex_multitrace.json');

// mock with two columns; lowest column count of general case
var mock2 = Lib.extendDeep({}, mockMulti);
mock2.data = [mock2.data[2]]; // keep the subplot with two columns

// mock with one column as special case
var mock1 = Lib.extendDeep({}, mock2);
mock1.data[0].header.values = mock1.data[0].header.values.slice(0, 1);
mock1.data[0].cells.values = mock1.data[0].cells.values.slice(0, 1);

// mock with zero columns; special case, as no column can be rendered
var mock0 = Lib.extendDeep({}, mock1);
mock0.data[0].header.values = [];
mock0.data[0].cells.values = [];

var mock = require('@mocks/table_plain_birds.json');

describe('table initialization tests', function() {

    'use strict';

    describe('table global defaults', function() {

        it('should not coerce trace opacity', function() {
            var gd = Lib.extendDeep({}, mock1);

            supplyAllDefaults(gd);

            expect(gd._fullData[0].opacity).toBeUndefined();
        });

        it('should use global font as label, tick and range font defaults', function() {
            var gd = Lib.extendDeep({}, mock1);
            delete gd.data[0].header.font;
            delete gd.data[0].cells.font;
            gd.layout.font = {
                family: 'Gravitas',
                size: 20,
                color: 'blue'
            };

            supplyAllDefaults(gd);

            var expected = {
                family: 'Gravitas',
                size: 20,
                color: 'blue'
            };

            expect(gd._fullData[0].header.font).toEqual(expected);
            expect(gd._fullData[0].cells.font).toEqual(expected);
        });
    });

    describe('table defaults', function() {

        function _supply(traceIn) {
            var traceOut = { visible: true },
                defaultColor = '#777',
                layout = { font: {family: '"Open Sans", verdana, arial, sans-serif', size: 12, color: '#444'} };

            Table.supplyDefaults(traceIn, traceOut, defaultColor, layout);

            return traceOut;
        }

        it('\'line\' specification should yield a default color', function() {
            var fullTrace = _supply({});
            expect(fullTrace.header.fill.color).toEqual(attributes.header.fill.color.dflt);
            expect(fullTrace.cells.fill.color).toEqual(attributes.cells.fill.color.dflt);
        });

        it('\'domain\' specification should have a default', function() {
            var fullTrace = _supply({});
            expect(fullTrace.domain).toEqual({x: [0, 1], y: [0, 1]});
        });

        it('\'*.values\' specification should have a default of an empty array', function() {
            var fullTrace = _supply({});
            expect(fullTrace.header.values).toEqual([]);
            expect(fullTrace.cells.values).toEqual([]);
        });

        it('\'columnwidth\' specification should accept a numerical array', function() {
            var fullTrace = _supply({
                columnwidth: [1, 2, 3]
            });
            expect(fullTrace.columnwidth).toEqual([1, 2, 3]);
        });

        it('\'columnwidth\' specification should accept a string array (converted downstream)', function() {
            var fullTrace = _supply({
                columnwidth: ['1', '2', '3']
            });
            expect(fullTrace.columnwidth).toEqual(['1', '2', '3']);
        });

        it('\'header\' should be used with default values where attributes are not provided', function() {
            var fullTrace = _supply({
                header: {
                    values: ['A'],
                    alienProperty: 'Alpha Centauri'
                },
                cells: {
                    values: [1, 2], // otherwise header.values will become []
                    alienProperty: 'Betelgeuse'
                }
            });
            expect(fullTrace.header).toEqual({
                values: ['A'], // only one column remains
                format: [],
                align: 'center',
                height: 28,
                line: { width: 1, color: 'grey' },
                fill: { color: attributes.header.fill.color.dflt },
                font: {family: '"Open Sans", verdana, arial, sans-serif', size: 12, color: '#444'}
            });

            expect(fullTrace.cells).toEqual({
                values: [1, 2],
                format: [],
                align: 'center',
                height: 20,
                line: { width: 1, color: 'grey' },
                fill: { color: attributes.cells.fill.color.dflt },
                font: {family: '"Open Sans", verdana, arial, sans-serif', size: 12, color: '#444'}
            });
        });
    });
});

describe('table', function() {

    afterEach(destroyGraphDiv);

    describe('edge cases', function() {

        it('Works with more than one column', function(done) {

            var mockCopy = Lib.extendDeep({}, mock2);
            var gd = createGraphDiv();
            Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(function() {
                expect(gd.data.length).toEqual(1);
                expect(gd.data[0].header.values.length).toEqual(2);
                expect(gd.data[0].cells.values.length).toEqual(2);
                expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(2);
                done();
            });
        });

        it('Works with one column', function(done) {

            var mockCopy = Lib.extendDeep({}, mock1);
            var gd = createGraphDiv();
            Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(function() {
                expect(gd.data.length).toEqual(1);
                expect(gd.data[0].header.values.length).toEqual(1);
                expect(gd.data[0].cells.values.length).toEqual(1);
                expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(1);
                done();
            });
        });

        it('Does not error with zero columns', function(done) {

            var mockCopy = Lib.extendDeep({}, mock0);
            var gd = createGraphDiv();

            Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(function() {
                expect(gd.data.length).toEqual(1);
                expect(gd.data[0].header.values.length).toEqual(0);
                expect(gd.data[0].cells.values.length).toEqual(0);
                expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(0);
                done();
            });
        });

        it('Does not raise an error with zero lines', function(done) {

            var mockCopy = Lib.extendDeep({}, mock2);

            mockCopy.layout.width = 320;
            mockCopy.data[0].header.values = [[], []];
            mockCopy.data[0].cells.values = [[], []];

            var gd = createGraphDiv();
            Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(function() {

                expect(gd.data.length).toEqual(1);
                expect(gd.data[0].header.values.length).toEqual(2);
                expect(gd.data[0].cells.values.length).toEqual(2);
                expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(2);
                done();
            });
        });
    });

    describe('basic use and basic data restyling', function() {
        var mockCopy,
            gd;

        beforeEach(function(done) {
            mockCopy = Lib.extendDeep({}, mock);
            mockCopy.data[0].domain = {
                x: [0.1, 0.9],
                y: [0.05, 0.85]
            };
            gd = createGraphDiv();
            Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(done);
        });

        it('`Plotly.plot` should have proper fields on `gd.data` on initial rendering', function() {

            expect(gd.data.length).toEqual(1);
            expect(gd.data[0].header.values.length).toEqual(7);
            expect(gd.data[0].cells.values.length).toEqual(7);
            expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(7);
        });

        it('Calling `Plotly.plot` again should add the new table trace', function(done) {

            var reversedMockCopy = Lib.extendDeep({}, mockCopy);
            reversedMockCopy.data[0].header.values = reversedMockCopy.data[0].header.values.slice().reverse();
            reversedMockCopy.data[0].cells.values = reversedMockCopy.data[0].cells.values.slice().reverse();
            reversedMockCopy.data[0].domain.y = [0, 0.3];

            Plotly.plot(gd, reversedMockCopy.data, reversedMockCopy.layout).then(function() {
                expect(gd.data.length).toEqual(2);
                expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(7 * 2);
                done();
            });

        });

        it('Calling `Plotly.restyle` with a string path should amend the preexisting table', function(done) {

            expect(gd.data.length).toEqual(1);

            Plotly.restyle(gd, 'header.fill.color', 'magenta').then(function() {

                expect(gd.data.length).toEqual(1);

                expect(gd.data[0].header.fill.color).toEqual('magenta');
                expect(gd.data[0].header.values.length).toEqual(7);
                expect(gd.data[0].cells.values.length).toEqual(7);
                expect(gd.data[0].header.line.color).toEqual('lightgray'); // no change relative to original mock value
                expect(gd.data[0].cells.line.color).toEqual(['grey']); // no change relative to original mock value

                done();
            });

        });

        it('Calling `Plotly.restyle` for a `header.values` change should amend the preexisting one', function(done) {

            function restyleValues(what, key, setterValue) {

                // array values need to be wrapped in an array; unwrapping here for value comparison
                var value = Lib.isArray(setterValue) ? setterValue[0] : setterValue;

                return function() {
                    return Plotly.restyle(gd, what + '.values[' + key + ']', setterValue).then(function() {
                        expect(gd.data[0][what].values[key]).toEqual(value, 'for column \'' + key + '\'');
                        expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(7);
                    });
                };
            }

            restyleValues('cells', 0, [['new cell content 1', 'new cell content 2']])()
                .then(restyleValues('cells', 2, [[0, 0.1]]))
                .then(restyleValues('header', 1, [['Species top', 'Species bottom']]))
                .then(done);
        });

        it('Calling `Plotly.relayout` with string should amend the preexisting table', function(done) {
            expect(gd.layout.width).toEqual(1000);
            Plotly.relayout(gd, 'width', 500).then(function() {
                expect(gd.data.length).toEqual(1);
                expect(gd.layout.width).toEqual(500);
                done();
            });
        });

        it('Calling `Plotly.relayout` with object should amend the preexisting table', function(done) {
            expect(gd.layout.width).toEqual(1000);
            Plotly.relayout(gd, {width: 500}).then(function() {
                expect(gd.data.length).toEqual(1);
                expect(gd.layout.width).toEqual(500);
                done();
            });
        });
    });

    describe('more restyling tests with scenegraph queries', function() {
        var mockCopy,
            gd;

        beforeEach(function(done) {
            mockCopy = Lib.extendDeep({}, mock2);
            gd = createGraphDiv();
            Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(done);
        });

        it('Calling `Plotly.restyle` for a `header.values` change should amend the preexisting one', function(done) {

            function restyleValues(what, fun, setterValue) {

                var value = Lib.isArray(setterValue) ? setterValue[0] : setterValue;

                return function() {
                    return Plotly.restyle(gd, what, setterValue).then(function() {
                        expect(fun(gd)).toEqual(value, what + ':::' + value);
                        expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(2);
                        expect(document.querySelectorAll('.' + cn.columnBlock).length).toEqual(6);
                        expect(document.querySelectorAll('.' + cn.columnCell).length).toEqual(6);
                        expect(document.querySelectorAll('.' + cn.cellRect).length).toEqual(6);
                        expect(document.querySelectorAll('.' + cn.cellTextHolder).length).toEqual(6);
                    });
                };
            }

            restyleValues('cells.fill.color', function(gd) {return gd.data[0].cells.fill.color;}, [['green', 'red']])()
                .then(restyleValues('cells.line.color', function(gd) {return gd.data[0].cells.line.color;}, [['magenta', 'blue']]))
                .then(restyleValues('cells.line.width', function(gd) {return gd.data[0].cells.line.width;}, [[5, 3]]))
                .then(restyleValues('cells.format', function(gd) {return gd.data[0].cells.format;}, [['', '']]))
                .then(restyleValues('cells.prefix', function(gd) {return gd.data[0].cells.prefix;}, [['p1']]))
                .then(restyleValues('cells.suffix', function(gd) {return gd.data[0].cells.suffix;}, [['s1']]))
                .then(restyleValues('header.fill.color', function(gd) {return gd.data[0].header.fill.color;}, [['yellow', 'purple']]))
                .then(restyleValues('header.line.color', function(gd) {return gd.data[0].header.line.color;}, [['green', 'red']]))
                .then(restyleValues('header.line.width', function(gd) {return gd.data[0].header.line.width;}, [[2, 6]]))
                .then(restyleValues('header.format', function(gd) {return gd.data[0].header.format;}, [['', '']]))
                .then(done);
        });
    });
});
<commit_msg>table `values` may be left unspecified - test case<commit_after>var Plotly = require('@lib/index');
var Lib = require('@src/lib');
var Table = require('@src/traces/table');
var attributes = require('@src/traces/table/attributes');
var cn = require('@src/traces/table/constants').cn;

var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var supplyAllDefaults = require('../assets/supply_defaults');

var mockMulti = require('@mocks/table_latex_multitrace.json');

// mock with two columns; lowest column count of general case
var mock2 = Lib.extendDeep({}, mockMulti);
mock2.data = [mock2.data[2]]; // keep the subplot with two columns

// mock with one column as special case
var mock1 = Lib.extendDeep({}, mock2);
mock1.data[0].header.values = mock1.data[0].header.values.slice(0, 1);
mock1.data[0].cells.values = mock1.data[0].cells.values.slice(0, 1);

// mock with zero columns; special case, as no column can be rendered
var mock0 = Lib.extendDeep({}, mock1);
mock0.data[0].header.values = [];
mock0.data[0].cells.values = [];

var mock = require('@mocks/table_plain_birds.json');

describe('table initialization tests', function() {

    'use strict';

    describe('table global defaults', function() {

        it('should not coerce trace opacity', function() {
            var gd = Lib.extendDeep({}, mock1);

            supplyAllDefaults(gd);

            expect(gd._fullData[0].opacity).toBeUndefined();
        });

        it('should use global font as label, tick and range font defaults', function() {
            var gd = Lib.extendDeep({}, mock1);
            delete gd.data[0].header.font;
            delete gd.data[0].cells.font;
            gd.layout.font = {
                family: 'Gravitas',
                size: 20,
                color: 'blue'
            };

            supplyAllDefaults(gd);

            var expected = {
                family: 'Gravitas',
                size: 20,
                color: 'blue'
            };

            expect(gd._fullData[0].header.font).toEqual(expected);
            expect(gd._fullData[0].cells.font).toEqual(expected);
        });
    });

    describe('table defaults', function() {

        function _supply(traceIn) {
            var traceOut = { visible: true },
                defaultColor = '#777',
                layout = { font: {family: '"Open Sans", verdana, arial, sans-serif', size: 12, color: '#444'} };

            Table.supplyDefaults(traceIn, traceOut, defaultColor, layout);

            return traceOut;
        }

        it('\'line\' specification should yield a default color', function() {
            var fullTrace = _supply({});
            expect(fullTrace.header.fill.color).toEqual(attributes.header.fill.color.dflt);
            expect(fullTrace.cells.fill.color).toEqual(attributes.cells.fill.color.dflt);
        });

        it('\'domain\' specification should have a default', function() {
            var fullTrace = _supply({});
            expect(fullTrace.domain).toEqual({x: [0, 1], y: [0, 1]});
        });

        it('\'*.values\' specification should have a default of an empty array', function() {
            var fullTrace = _supply({});
            expect(fullTrace.header.values).toEqual([]);
            expect(fullTrace.cells.values).toEqual([]);
        });

        it('\'columnwidth\' specification should accept a numerical array', function() {
            var fullTrace = _supply({
                columnwidth: [1, 2, 3]
            });
            expect(fullTrace.columnwidth).toEqual([1, 2, 3]);
        });

        it('\'columnwidth\' specification should accept a string array (converted downstream)', function() {
            var fullTrace = _supply({
                columnwidth: ['1', '2', '3']
            });
            expect(fullTrace.columnwidth).toEqual(['1', '2', '3']);
        });

        it('\'header\' should be used with default values where attributes are not provided', function() {
            var fullTrace = _supply({
                header: {
                    values: ['A'],
                    alienProperty: 'Alpha Centauri'
                },
                cells: {
                    values: [1, 2], // otherwise header.values will become []
                    alienProperty: 'Betelgeuse'
                }
            });
            expect(fullTrace.header).toEqual({
                values: ['A'], // only one column remains
                format: [],
                align: 'center',
                height: 28,
                line: { width: 1, color: 'grey' },
                fill: { color: attributes.header.fill.color.dflt },
                font: {family: '"Open Sans", verdana, arial, sans-serif', size: 12, color: '#444'}
            });

            expect(fullTrace.cells).toEqual({
                values: [1, 2],
                format: [],
                align: 'center',
                height: 20,
                line: { width: 1, color: 'grey' },
                fill: { color: attributes.cells.fill.color.dflt },
                font: {family: '"Open Sans", verdana, arial, sans-serif', size: 12, color: '#444'}
            });
        });
    });
});

describe('table', function() {

    afterEach(destroyGraphDiv);

    describe('edge cases', function() {

        it('Works with more than one column', function(done) {

            var mockCopy = Lib.extendDeep({}, mock2);
            var gd = createGraphDiv();
            Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(function() {
                expect(gd.data.length).toEqual(1);
                expect(gd.data[0].header.values.length).toEqual(2);
                expect(gd.data[0].cells.values.length).toEqual(2);
                expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(2);
                done();
            });
        });

        it('Works with one column', function(done) {

            var mockCopy = Lib.extendDeep({}, mock1);
            var gd = createGraphDiv();
            Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(function() {
                expect(gd.data.length).toEqual(1);
                expect(gd.data[0].header.values.length).toEqual(1);
                expect(gd.data[0].cells.values.length).toEqual(1);
                expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(1);
                done();
            });
        });

        it('Does not error with zero columns', function(done) {

            var mockCopy = Lib.extendDeep({}, mock0);
            var gd = createGraphDiv();

            Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(function() {
                expect(gd.data.length).toEqual(1);
                expect(gd.data[0].header.values.length).toEqual(0);
                expect(gd.data[0].cells.values.length).toEqual(0);
                expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(0);
                done();
            });
        });

        it('Does not raise an error with zero lines', function(done) {

            var mockCopy = Lib.extendDeep({}, mock2);

            mockCopy.layout.width = 320;
            mockCopy.data[0].header.values = [[], []];
            mockCopy.data[0].cells.values = [[], []];

            var gd = createGraphDiv();
            Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(function() {

                expect(gd.data.length).toEqual(1);
                expect(gd.data[0].header.values.length).toEqual(2);
                expect(gd.data[0].cells.values.length).toEqual(2);
                expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(2);
                done();
            });
        });
    });

    describe('Rendering with partial attribute support', function() {
        var mockCopy,
            gd;

        beforeEach(function(done) {
            mockCopy = Lib.extendDeep({}, mock);
            mockCopy.data[0].domain = {
                x: [0.1, 0.9],
                y: [0.05, 0.85]
            };
            delete mockCopy.data[0].cells;
            gd = createGraphDiv();
            Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(done);
        });

        it('`Plotly.plot` should render all the columns even if no cell contents were supplied yet', function() {
            expect(gd.data.length).toEqual(1);
            expect(gd.data[0].header.values.length).toEqual(7);
            expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(7);
            expect(document.querySelectorAll('.' + cn.columnCell).length).toEqual(7 * 2); // both column rows to render
        });
    });

    describe('basic use and basic data restyling', function() {
        var mockCopy,
            gd;

        beforeEach(function(done) {
            mockCopy = Lib.extendDeep({}, mock);
            mockCopy.data[0].domain = {
                x: [0.1, 0.9],
                y: [0.05, 0.85]
            };
            gd = createGraphDiv();
            Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(done);
        });

        it('`Plotly.plot` should have proper fields on `gd.data` on initial rendering', function() {

            expect(gd.data.length).toEqual(1);
            expect(gd.data[0].header.values.length).toEqual(7);
            expect(gd.data[0].cells.values.length).toEqual(7);
            expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(7);
        });

        it('Calling `Plotly.plot` again should add the new table trace', function(done) {

            var reversedMockCopy = Lib.extendDeep({}, mockCopy);
            reversedMockCopy.data[0].header.values = reversedMockCopy.data[0].header.values.slice().reverse();
            reversedMockCopy.data[0].cells.values = reversedMockCopy.data[0].cells.values.slice().reverse();
            reversedMockCopy.data[0].domain.y = [0, 0.3];

            Plotly.plot(gd, reversedMockCopy.data, reversedMockCopy.layout).then(function() {
                expect(gd.data.length).toEqual(2);
                expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(7 * 2);
                done();
            });

        });

        it('Calling `Plotly.restyle` with a string path should amend the preexisting table', function(done) {

            expect(gd.data.length).toEqual(1);

            Plotly.restyle(gd, 'header.fill.color', 'magenta').then(function() {

                expect(gd.data.length).toEqual(1);

                expect(gd.data[0].header.fill.color).toEqual('magenta');
                expect(gd.data[0].header.values.length).toEqual(7);
                expect(gd.data[0].cells.values.length).toEqual(7);
                expect(gd.data[0].header.line.color).toEqual('lightgray'); // no change relative to original mock value
                expect(gd.data[0].cells.line.color).toEqual(['grey']); // no change relative to original mock value

                done();
            });

        });

        it('Calling `Plotly.restyle` for a `header.values` change should amend the preexisting one', function(done) {

            function restyleValues(what, key, setterValue) {

                // array values need to be wrapped in an array; unwrapping here for value comparison
                var value = Lib.isArray(setterValue) ? setterValue[0] : setterValue;

                return function() {
                    return Plotly.restyle(gd, what + '.values[' + key + ']', setterValue).then(function() {
                        expect(gd.data[0][what].values[key]).toEqual(value, 'for column \'' + key + '\'');
                        expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(7);
                    });
                };
            }

            restyleValues('cells', 0, [['new cell content 1', 'new cell content 2']])()
                .then(restyleValues('cells', 2, [[0, 0.1]]))
                .then(restyleValues('header', 1, [['Species top', 'Species bottom']]))
                .then(done);
        });

        it('Calling `Plotly.relayout` with string should amend the preexisting table', function(done) {
            expect(gd.layout.width).toEqual(1000);
            Plotly.relayout(gd, 'width', 500).then(function() {
                expect(gd.data.length).toEqual(1);
                expect(gd.layout.width).toEqual(500);
                done();
            });
        });

        it('Calling `Plotly.relayout` with object should amend the preexisting table', function(done) {
            expect(gd.layout.width).toEqual(1000);
            Plotly.relayout(gd, {width: 500}).then(function() {
                expect(gd.data.length).toEqual(1);
                expect(gd.layout.width).toEqual(500);
                done();
            });
        });
    });

    describe('more restyling tests with scenegraph queries', function() {
        var mockCopy,
            gd;

        beforeEach(function(done) {
            mockCopy = Lib.extendDeep({}, mock2);
            gd = createGraphDiv();
            Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(done);
        });

        it('Calling `Plotly.restyle` for a `header.values` change should amend the preexisting one', function(done) {

            function restyleValues(what, fun, setterValue) {

                var value = Lib.isArray(setterValue) ? setterValue[0] : setterValue;

                return function() {
                    return Plotly.restyle(gd, what, setterValue).then(function() {
                        expect(fun(gd)).toEqual(value, what + ':::' + value);
                        expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(2);
                        expect(document.querySelectorAll('.' + cn.columnBlock).length).toEqual(6);
                        expect(document.querySelectorAll('.' + cn.columnCell).length).toEqual(6);
                        expect(document.querySelectorAll('.' + cn.cellRect).length).toEqual(6);
                        expect(document.querySelectorAll('.' + cn.cellTextHolder).length).toEqual(6);
                    });
                };
            }

            restyleValues('cells.fill.color', function(gd) {return gd.data[0].cells.fill.color;}, [['green', 'red']])()
                .then(restyleValues('cells.line.color', function(gd) {return gd.data[0].cells.line.color;}, [['magenta', 'blue']]))
                .then(restyleValues('cells.line.width', function(gd) {return gd.data[0].cells.line.width;}, [[5, 3]]))
                .then(restyleValues('cells.format', function(gd) {return gd.data[0].cells.format;}, [['', '']]))
                .then(restyleValues('cells.prefix', function(gd) {return gd.data[0].cells.prefix;}, [['p1']]))
                .then(restyleValues('cells.suffix', function(gd) {return gd.data[0].cells.suffix;}, [['s1']]))
                .then(restyleValues('header.fill.color', function(gd) {return gd.data[0].header.fill.color;}, [['yellow', 'purple']]))
                .then(restyleValues('header.line.color', function(gd) {return gd.data[0].header.line.color;}, [['green', 'red']]))
                .then(restyleValues('header.line.width', function(gd) {return gd.data[0].header.line.width;}, [[2, 6]]))
                .then(restyleValues('header.format', function(gd) {return gd.data[0].header.format;}, [['', '']]))
                .then(done);
        });
    });
});
<|endoftext|>