scratch

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 133  →  ?path2? @ 134
/bower_components/bootstrap-tokenfield/test/README.md
@@ -0,0 +1,22 @@
Testing
=======
 
The tests have been set up to run with a simulated DOM created with JSDOM.
Mouse and keyboard events are simulated using jQuery and jquery-simulate-ext plugin.
 
We looked into several other alternatives like Zombie.js and Karma, but
for our use case, they did not seem to offer many advantages over a JSDOM.
The main reason behind this is that neither of those options provide a
built-in or better way to simulate mouse and keyboard events.
 
A step up from the current test solution would be to create Selenium or PtahnomJS
tests so that we do not have to simulate mouse and keyboard, but could actually
control the browser. This will be on the roadmap in the future.
 
For now - simply do `npm test`.
 
### Writing tests
 
Take care to follow the style of existing tests. All tests that require DOM
manipulation and/or involve simulating user interaction, should go under
integration tests. Testing tokenfield methods should go under unit tests.
/bower_components/bootstrap-tokenfield/test/helpers/jsdom-patch.js
@@ -0,0 +1,79 @@
/**
* Patch from zombie.js for jsdom https://github.com/assaf/zombie/blob/master/src/zombie/dom_focus.coffee
*
* Adds focus() and blur() methods and events to dom elements
*/
 
var FOCUS_ELEMENTS, HTML, elementType, setAttribute, setFocus, _i, _j, _len, _len1, _ref, _ref1;
 
HTML = require("jsdom").dom.level3.html;
 
FOCUS_ELEMENTS = ["INPUT", "SELECT", "TEXTAREA", "BUTTON", "ANCHOR"];
 
HTML.HTMLDocument.prototype.__defineGetter__("activeElement", function() {
return this._inFocus || this.body;
});
 
setFocus = function(document, element) {
var inFocus, onblur, onfocus;
inFocus = document._inFocus;
if (element !== inFocus) {
if (inFocus) {
onblur = document.createEvent("HTMLEvents");
onblur.initEvent("blur", false, false);
inFocus.dispatchEvent(onblur);
}
if (element) {
onfocus = document.createEvent("HTMLEvents");
onfocus.initEvent("focus", false, false);
element.dispatchEvent(onfocus);
document._inFocus = element;
}
}
};
 
HTML.HTMLElement.prototype.focus = function() {};
 
HTML.HTMLElement.prototype.blur = function() {};
 
_ref = [HTML.HTMLInputElement, HTML.HTMLSelectElement, HTML.HTMLTextAreaElement, HTML.HTMLButtonElement, HTML.HTMLAnchorElement];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
elementType = _ref[_i];
elementType.prototype.focus = function() {
return setFocus(this.ownerDocument, this);
};
elementType.prototype.blur = function() {
return setFocus(this.ownerDocument, null);
};
setAttribute = elementType.prototype.setAttribute;
elementType.prototype.setAttribute = function(name, value) {
var document;
setAttribute.call(this, name, value);
if (name === "autofocus") {
document = this.ownerDocument;
if (~FOCUS_ELEMENTS.indexOf(this.tagName) && !document._inFocus) {
return this.focus();
}
}
};
}
 
_ref1 = [HTML.HTMLInputElement, HTML.HTMLTextAreaElement, HTML.HTMLSelectElement];
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
elementType = _ref1[_j];
elementType.prototype._eventDefaults.focus = function(event) {
var element;
element = event.target;
return element._focusValue = element.value || '';
};
elementType.prototype._eventDefaults.blur = function(event) {
var change, element, focusValue;
element = event.target;
focusValue = element._focusValue;
if (focusValue !== element.value) {
change = element.ownerDocument.createEvent("HTMLEvents");
change.initEvent("change", false, false);
return element.dispatchEvent(change);
}
};
}
/bower_components/bootstrap-tokenfield/test/setup.js
@@ -0,0 +1,65 @@
var jsdom = require('jsdom');
require('./helpers/jsdom-patch');
 
before(function (done) {
jsdom.env({
html: '<html><body></body></html>',
done: function (err, window) {
// Set clientTop and clientLeft to 0 so that offset() works
window.document.documentElement.clientTop = 0;
window.document.documentElement.clientLeft = 0;
// Expose jQuery and require tokenfield
window.$ = global.$ = global.jQuery = require('jquery')(window);
require('../js/bootstrap-tokenfield')(window);
// Globalize window, document, navigator
global.window = window;
global.document = window.document;
global.navigator = window.navigator;
 
// Provide a focus method on DOM elements if it does not exist.
// Helps to avoid issues with the simulate-ext plugin
window.HTMLDivElement.prototype.focus = window.HTMLDivElement.prototype.focus || function() {};
 
// Global configuration object for our tests
global.TFT = window.TFT = {};
 
done();
}
});
});
 
// Global tokenfield test object
beforeEach(function() {
var template = TFT.template || '<input type="text" class="tokenize" value="" />',
options = TFT.options || null;
 
this.$sandbox = $('<div />').appendTo($('body'));
this.$template = $(template).appendTo(this.$sandbox);
 
this.$field = this.$template.hasClass('tokenize') ? this.$template : this.$template.find('.tokenize');
this.$field.tokenfield( options );
 
// Shortcuts
this.$input = this.$field.data('bs.tokenfield').$input;
this.$wrapper = this.$field.data('bs.tokenfield').$wrapper;
this.$copyHelper = this.$field.data('bs.tokenfield').$copyHelper;
 
// Set an initial empty value for inputs (workaround for bililiteRange `null` value error)
this.$input.val('');
this.$copyHelper.val('');
});
 
afterEach( function() {
this.$field.tokenfield('destroy');
this.$sandbox.remove();
 
delete this.$field;
delete this.$input;
delete this.$wrapper;
delete this.$copyHelper;
delete this.$sandbox;
delete this.$template;
});
/bower_components/bootstrap-tokenfield/test/test.tokenfield.1.unit.js
@@ -0,0 +1,431 @@
describe('1. Unit tests:', function() {
 
describe('initializing tokenfield', function() {
describe('with an empty input', function() {
 
it('must wrap the original input with the wrapper element', function() {
this.$field.parents('.tokenfield').hasClass('form-control').must.be.true();
});
 
it('must create a new input element for token input', function() {
this.$field.parents('.tokenfield').find('.token-input').length.must.equal(1);
});
 
it('must move the original input out of the way', function() {
this.$field.css('position').must.equal('absolute');
this.$field.css('left').must.equal('-10000px');
});
 
it('must not create any tokens', function() {
this.$wrapper.find('.token').length.must.equal(0);
});
 
});
 
describe('with an input with comma-separated values', function() {
 
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green, blue" />';
});
 
after(function() {
TFT.template = null;
});
 
it('must create tokens for each comma-separated value', function() {
this.$wrapper.find('.token').length.must.equal(3);
});
 
});
 
describe('with an input with data-tokens values', function() {
 
before(function() {
TFT.template = '<input type="text" class="tokenize" data-tokens="red, green, blue" />';
});
 
after(function() {
TFT.template = null;
});
 
it('must create tokens for each comma-separated token', function() {
this.$wrapper.find('.token').length.must.equal(3);
});
 
});
 
describe('with RTL', function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" style="direction:rtl" value="red,green, blue" />';
});
 
after(function() {
TFT.template = null;
});
 
it('must set rtl class on tokenfield', function() {
this.$wrapper.hasClass('rtl').must.equal(true);
});
})
 
});
 
describe('destroying tokenfield', function() {
before(function() {
TFT.template = '<div id="destroy-test-container"><label for="destroy-test"></label><input type="text" id="destroy-test" class="tokenize" value="red,green, blue" /></div>';
});
 
after(function() {
TFT.template = null;
});
 
it('must reset the original input to previous state', function() {
var $field = this.$field.tokenfield('destroy');
$field.must.be.an.object();
$field.data().must.not.have.property('bs.tokenfield');
$field.parent().prop('id').must.equal('destroy-test-container');
$field.val().must.equal('red, green, blue');
});
});
 
describe('Tokenfield public methods', function() {
 
describe('.createToken()', function() {
 
describe('using an empty input', function() {
 
beforeEach(function() {
this.$field.tokenfield('createToken', 'awesome');
});
 
it('must create a new token', function() {
this.$wrapper.find('.token').must.have.length(1);
});
 
it('add the new token value to original input', function() {
this.$field.val().must.equal('awesome');
});
 
});
 
describe('using a non-empty input', function() {
 
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green, blue" />';
});
 
beforeEach(function() {
this.$field.tokenfield('createToken', 'awesome');
});
 
after(function() {
TFT.template = null;
});
 
it('must append a new token to the end of existing tokens', function() {
this.$field.val().must.equal('red, green, blue, awesome');
});
 
});
 
describe('given an object', function() {
 
beforeEach(function() {
this.$field.tokenfield('createToken', { value: 'purple', label: 'Violet' });
});
 
it('must create a new token', function() {
this.$wrapper.find('.token').must.have.length(1);
});
 
it('add the new token value to original input', function() {
this.$field.val().must.equal('purple');
});
 
});
 
});
 
describe('.getTokens()', function() {
 
describe('given no arguments', function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green, blue" />';
});
 
after(function() {
TFT.template = null;
});
 
it('must return an array of token key-value pairs', function() {
var tokens = this.$field.tokenfield('getTokens');
tokens.must.be.an.array();
tokens.must.have.length(3);
tokens[0].must.have.keys(['label', 'value']);
tokens[0].label.must.equal('red');
tokens[0].value.must.equal('red');
});
});
 
describe('given arguments active = true', function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />';
});
 
after(function() {
TFT.template = null;
});
 
it('must return an array of only active token key-value pairs', function() {
// Mark green as active
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(green))').addClass('active');
 
var tokens = this.$field.tokenfield('getTokens', true);
tokens.must.be.an.array();
tokens.must.have.length(1);
tokens[0].must.have.keys(['label', 'value']);
tokens[0].label.must.equal('green');
tokens[0].value.must.equal('green');
});
});
 
 
});
 
describe('getTokensList()', function() {
 
describe('given no arguments', function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green, blue" />';
});
 
after(function() {
TFT.template = null;
});
 
it('must return a string with comma-separated token values', function() {
var tokens = this.$field.tokenfield('getTokensList');
tokens.must.be.a.string();
tokens.must.equal('red, green, blue');
});
});
 
describe('given an alternative delimiter', function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />';
});
 
after(function() {
TFT.template = null;
});
 
it('must return a string with semicolon-separated token values', function() {
var tokens = this.$field.tokenfield('getTokensList', ';', false);
tokens.must.be.a.string();
tokens.must.equal('red;green;blue');
});
});
 
describe('given an alternative delimiter and active = true', function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue,yellow" />';
});
 
after(function() {
TFT.template = null;
});
 
it('must return a string with semicolon-separated token values', function() {
// Mark green and yellow as active
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(green))').addClass('active');
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(yellow))').addClass('active');
 
var tokens = this.$field.tokenfield('getTokensList', ';', false, true);
tokens.must.be.a.string();
tokens.must.equal('green;yellow');
});
});
 
 
});
 
describe('setTokens()', function() {
 
describe('using comma-separated string', function() {
 
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green, blue" />';
});
 
beforeEach(function(){
this.$field.tokenfield('setTokens', 'black,yellow,white');
});
 
after(function() {
TFT.template = null;
});
 
it('must replace any existing tokens with new ones', function() {
var tokens = this.$field.tokenfield('getTokens')
, tokensList = this.$field.tokenfield('getTokensList');
 
tokens.must.have.length(3);
tokens[0].must.have.keys(['label', 'value']);
tokens[0].label.must.equal('black');
tokens[0].value.must.equal('black');
 
tokensList.must.not.contain('red');
 
});
 
it('must set the original input value to comma-separated list of token values', function() {
this.$field.val().must.equal('black, yellow, white');
});
});
 
describe('using an array of string values', function() {
 
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green, blue" />';
});
 
beforeEach(function(){
this.$field.tokenfield('setTokens', 'black,yellow,white');
});
 
after(function() {
TFT.template = null;
});
 
it('must replace any existing tokens with new ones', function() {
var tokens = this.$field.tokenfield('getTokens')
, tokensList = this.$field.tokenfield('getTokensList');
 
tokens.must.have.length(3);
tokens[0].must.have.keys(['label', 'value']);
tokens[0].label.must.equal('black');
tokens[0].value.must.equal('black');
 
tokensList.must.not.contain('red');
 
});
 
it('must set the original input value to comma-separated list of token values', function() {
this.$field.val().must.equal('black, yellow, white');
});
 
});
 
describe('using an array of token objects', function() {
 
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green, blue" />';
});
 
beforeEach(function(){
this.$field.tokenfield('setTokens', [{ value: "black", label: "Schwarz" }, { value: "yellow", label: "Gelb" }]);
});
 
after(function() {
TFT.template = null;
});
 
it('must replace any existing tokens with new ones', function() {
this.$field.tokenfield('setTokens', [{ value: "black", label: "Schwarz" }, { value: "yellow", label: "Gelb" }]);
 
var tokens = this.$field.tokenfield('getTokens')
, tokensList = this.$field.tokenfield('getTokensList');
 
tokens.must.have.length(2);
tokens[0].must.have.keys(['label', 'value']);
tokens[0].label.must.equal('Schwarz');
tokens[0].value.must.equal('black');
 
tokensList.must.not.contain('red');
 
});
 
it('must set the original input value to comma-separated list of token values', function() {
this.$field.val().must.equal('black, yellow');
});
 
});
 
});
 
describe('disable()', function() {
 
beforeEach(function() {
this.$field.tokenfield('disable');
});
 
it('must disable both original and token input', function() {
this.$field.prop('disabled').must.be.true();
this.$input.prop('disabled').must.be.true();
});
 
it('must add "disabled" class to tokenfield', function() {
this.$wrapper.hasClass('disabled').must.be.true();
});
 
});
 
describe('enable()', function() {
 
beforeEach(function() {
this.$field.tokenfield('disable');
this.$field.tokenfield('enable');
});
 
it('must enable both original and token input', function() {
this.$field.prop('disabled').must.be.false();
this.$input.prop('disabled').must.be.false();
});
 
it('must remove "disabled" class from tokenfield', function() {
this.$wrapper.hasClass('disabled').must.be.false();
});
 
});
 
describe('readonly()', function() {
 
beforeEach(function() {
this.$field.tokenfield('readonly');
});
 
it('must make both original and token input readonly', function() {
this.$field.prop('readonly').must.be.true();
this.$input.prop('readonly').must.be.true();
});
 
it('must add "readonly" class to tokenfield', function() {
this.$wrapper.hasClass('readonly').must.be.true();
});
 
});
 
describe('writeable()', function() {
 
beforeEach(function() {
this.$field.tokenfield('readonly');
this.$field.tokenfield('writeable');
});
 
it('must make both original and token input writeable', function() {
this.$field.prop('readonly').must.be.false();
this.$input.prop('readonly').must.be.false();
});
 
it('must remove "readonly" class from tokenfield', function() {
this.$wrapper.hasClass('readonly').must.be.false();
});
 
});
});
 
});
/bower_components/bootstrap-tokenfield/test/test.tokenfield.2.integration.js
@@ -0,0 +1,1028 @@
describe('2. Integration tests:', function() {
 
before(function() {
require('../node_modules/jquery-simulate-ext/libs/bililiteRange');
require('../node_modules/jquery-simulate-ext/libs/jquery.simulate');
// https://github.com/j-ulrich/jquery-simulate-ext/issues/9
// For us, it just saves a littlebit time
global.$.simulate.ext_disableQuirkDetection = true;
require('../node_modules/jquery-simulate-ext/src/jquery.simulate.ext');
require('../node_modules/jquery-simulate-ext/src/jquery.simulate.key-combo');
require('../node_modules/jquery-simulate-ext/src/jquery.simulate.key-sequence');
});
 
describe('Using an alternative delimiter', function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red;green;blue;yellow" />'
TFT.options = {
delimiter: ';'
}
});
 
after(function() {
delete TFT.template;
delete TFT.options;
});
 
it('must create tokens by splitting the original value with delimiters', function() {
this.$field.data('bs.tokenfield').$wrapper.find('.token').length.must.equal(4);
});
 
it('must create a token when the delimiting key is pressed and use the first delimiter for setting original input value', function() {
this.$input.focus().simulate("key-sequence", { sequence: "purple;olive;" })
this.$field.data('bs.tokenfield').$wrapper.find('.token').length.must.equal(6);
this.$field.val().must.equal('red; green; blue; yellow; purple; olive');
});
})
 
describe('with multiple alternative delimiters', function() {
describe("Delimiters: [' ', '.']", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red green blue.yellow" />'
TFT.options = {
delimiter: [' ', '.']
}
});
 
after(function() {
delete TFT.template;
delete TFT.options;
});
 
it('must create tokens by splitting the original value with delimiters', function() {
this.$field.data('bs.tokenfield').$wrapper.find('.token').length.must.equal(4);
});
 
it('must create a token when the delimiting key is pressed and use the first delimiter for setting original input value', function() {
this.$input.focus().simulate("key-sequence", { sequence: "purple olive." });
this.$field.data('bs.tokenfield').$wrapper.find('.token').length.must.equal(6);
this.$field.val().must.equal('red green blue yellow purple olive');
});
});
 
describe("Delimiters: [',', ' ', '-', '_'] (Regression test for #79)", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green blue-yellow_123" />'
TFT.options = {
delimiter: [',', ' ', '-', '_']
}
});
 
after(function() {
delete TFT.template;
delete TFT.options;
});
 
it('must create tokens by splitting the original value with delimiters', function() {
this.$field.data('bs.tokenfield').$wrapper.find('.token').length.must.equal(5);
});
});
 
describe("Using regexp special characters as delimiters", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red\\green$blue[yellow{orange^violet.purple|black?white*gray+silver(lime)navy" />'
TFT.options = {
delimiter: ['\\', '$', '[', '{', '^', '.', '|', '?', '*', '+', '(', ')']
}
});
 
after(function() {
delete TFT.template;
delete TFT.options;
});
 
it('must create tokens by splitting the original value with delimiters', function() {
this.$field.data('bs.tokenfield').$wrapper.find('.token').length.must.equal(13);
});
});
});
 
describe('Keyboard interaction', function() {
 
describe("Pressing Ctrl+A", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must select all tokens", function() {
this.$input.focus().simulate("key-combo", { combo: "ctrl+a" });
this.$field.tokenfield('getTokens', true).length.must.equal(3);
});
});
 
describe("pressing Cmd+A", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must select all tokens", function() {
this.$input.focus().simulate("key-combo", { combo: "meta+a" });
this.$field.tokenfield('getTokens', true).length.must.equal(3);
});
});
 
describe("Pressing delete", function() {
describe("when a token is selected", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue,yellow" />'
});
 
after(function() {
delete TFT.template;
});
 
describe('and there are more tokens to the right of selected token', function() {
it("must delete the selected token and move focus to the next token", function() {
// Mark green as active
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(green))').addClass('active');
 
this.$copyHelper.simulate("key-sequence", { sequence: "{del}" });
this.$field.tokenfield('getTokens').length.must.equal(3);
this.$field.tokenfield('getTokensList', null, null, true).must.equal('blue');
});
})
 
describe('and there are no more tokens to the right of the selected token', function() {
it("must delete the selected token and move focus to input", function() {
// Mark green as active
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(yellow))').addClass('active');
 
this.$copyHelper.simulate("key-sequence", { sequence: "{del}" });
this.$field.tokenfield('getTokens').length.must.equal(3);
this.$field.tokenfield('getTokensList', null, null, true).must.equal('');
this.$input.is(document.activeElement).must.be.true();
});
})
});
 
describe("when multiple tokens are selected", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue,yellow,purple" />'
});
 
after(function() {
delete TFT.template;
});
 
describe('and there are more tokens to the right of selected tokens', function() {
it("must delete the selected tokens and move focus to the next token of the rightmost selected token", function() {
// Mark green and yellow as active
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(green))').addClass('active');
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(yellow))').addClass('active');
 
this.$copyHelper.simulate("key-sequence", { sequence: "{del}" });
this.$field.tokenfield('getTokens').length.must.equal(3);
this.$field.tokenfield('getTokensList', null, null, true).must.equal('purple');
});
});
 
describe('and there are no more tokens to the right of selected tokens', function() {
it("must delete the selected tokens and move focus input", function() {
// Mark green and yellow as active
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(green))').addClass('active');
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(purple))').addClass('active');
 
this.$copyHelper.simulate("key-sequence", { sequence: "{del}" });
this.$field.tokenfield('getTokens').length.must.equal(3);
this.$field.tokenfield('getTokensList').must.equal('red, blue, yellow');
this.$input.is(document.activeElement).must.be.true();
 
});
});
});
});
 
describe("Pressing backspace", function() {
describe("when a token is selected", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue,yellow" />'
});
 
after(function() {
delete TFT.template;
});
 
describe('and there are more tokens to the left of selected token', function() {
it("must delete the selected token and move focus to the previous token", function() {
// Mark green as active
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(blue))').addClass('active');
 
this.$copyHelper.simulate("key-sequence", { sequence: "{backspace}" });
this.$field.tokenfield('getTokens').length.must.equal(3);
this.$field.tokenfield('getTokensList', null, null, true).must.equal('green');
});
})
 
describe('and there are no more tokens to the left of the selected token', function() {
it("must delete the selected token and move focus to input", function() {
// Mark green as active
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(red))').addClass('active');
 
this.$copyHelper.simulate("key-sequence", { sequence: "{backspace}" });
this.$field.tokenfield('getTokens').length.must.equal(3);
this.$field.tokenfield('getTokensList', null, null, true).must.equal('');
this.$input.is(document.activeElement).must.be.true();
});
})
});
 
describe("when multiple tokens are selected", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue,yellow,purple" />'
});
 
after(function() {
delete TFT.template;
});
 
describe('and there are more tokens to the left of selected tokens', function() {
it("must delete the selected tokens and move focus to the previous token of the leftmost selected token", function() {
// Mark green and yellow as active
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(green))').addClass('active');
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(yellow))').addClass('active');
 
this.$copyHelper.simulate("key-sequence", { sequence: "{backspace}" });
this.$field.tokenfield('getTokens').length.must.equal(3);
this.$field.tokenfield('getTokensList', null, null, true).must.equal('red');
});
});
 
describe('and there are no more tokens to the left of selected tokens', function() {
it("must delete the selected tokens and move focus input", function() {
// Mark green and yellow as active
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(red))').addClass('active');
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(purple))').addClass('active');
 
this.$copyHelper.simulate("key-sequence", { sequence: "{backspace}" });
this.$field.tokenfield('getTokens').length.must.equal(3);
this.$field.tokenfield('getTokensList').must.equal('green, blue, yellow');
this.$input.is(document.activeElement).must.be.true();
});
});
});
 
describe("when focus is on input", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must move focus to the last token", function() {
this.$input.simulate("key-sequence", { sequence: "{backspace}" });
this.$field.tokenfield('getTokensList', null, null, true ).must.equal('blue');
});
});
});
 
describe("Pressing left arrow key", function() {
describe("when no tokens are selected", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must move focus to the last token", function() {
this.$input.simulate("key-sequence", { sequence: "{leftarrow}" });
this.$field.tokenfield('getTokensList', null, null, true ).must.equal('blue');
});
});
 
describe("when a token is selected", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must move focus to the previous token", function() {
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(blue))').addClass('active');
 
this.$copyHelper.simulate("key-sequence", { sequence: "{leftarrow}" });
this.$field.tokenfield('getTokensList', null, null, true ).must.equal('green');
});
});
 
describe("when multiple tokens are selected", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue,yellow" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must move focus to the previous token of the leftmost selected token", function() {
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(green))').addClass('active');
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(yellow))').addClass('active');
this.$copyHelper.simulate("key-sequence", { sequence: "{leftarrow}" });
this.$field.tokenfield('getTokensList', null, null, true ).must.equal('red');
});
});
 
describe("when the first token is selected", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must keep the focus on the first token", function() {
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(red))').addClass('active');
 
this.$copyHelper.simulate("key-sequence", { sequence: "{leftarrow}" });
this.$field.tokenfield('getTokensList', null, null, true ).must.equal('red');
});
});
 
describe("when no tokens are selected and direction is RTL", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" style="direction:rtl" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must keep the focus on the input", function() {
this.$input.simulate("key-sequence", { sequence: "{leftarrow}" });
this.$field.tokenfield('getTokensList', null, null, true ).must.equal('');
this.$input.is(document.activeElement).must.be.true();
});
});
});
 
describe("Pressing right arrow key", function() {
describe("when no tokens are selected", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must keep the focus on the input", function() {
this.$input.simulate("key-sequence", { sequence: "{rightarrow}" });
this.$field.tokenfield('getTokensList', null, null, true ).must.equal('');
this.$input.is(document.activeElement).must.be.true();
});
});
 
describe("when a token is selected", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must move focus to the next token", function() {
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(red))').addClass('active');
this.$copyHelper.simulate("key-sequence", { sequence: "{rightarrow}" });
this.$field.tokenfield('getTokensList', null, null, true ).must.equal('green');
});
});
 
describe("when multiple tokens are selected", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue,yellow" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must move focus to the next token of the rightmost selected token", function() {
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(red))').addClass('active');
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(blue))').addClass('active');
this.$copyHelper.simulate("key-sequence", { sequence: "{rightarrow}" });
this.$field.tokenfield('getTokensList', null, null, true ).must.equal('yellow');
});
});
 
describe("when the last token is selected", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must move the focus to the input", function() {
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(blue))').addClass('active');
this.$copyHelper.simulate("key-sequence", { sequence: "{rightarrow}" });
this.$field.tokenfield('getTokensList', null, null, true ).must.equal('');
this.$input.is(document.activeElement).must.be.true();
});
});
 
describe("when no tokens are selected and direction is RTL", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" style="direction:rtl" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must move focus to the last token", function() {
this.$input.simulate("key-sequence", { sequence: "{rightarrow}" });
this.$field.tokenfield('getTokensList', null, null, true ).must.equal('blue');
});
});
});
 
describe("Pressing Shift + left arrow key", function() {
describe("when no tokens are selected", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must move focus to the last token", function() {
this.$input.focus().simulate("keydown", { keyCode: 37, charCode: 37, shiftKey: true });
this.$field.tokenfield('getTokensList', null, null, true ).must.equal('blue');
});
});
 
describe("when a token is selected", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must activate the previous token in addition to the already active token", function() {
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(blue))').addClass('active');
 
this.$copyHelper.focus()
.simulate("keydown", { keyCode: 37, shiftKey: true })
.simulate("keydown", { keyCode: 37, shiftKey: true });
this.$field.tokenfield('getTokensList', null, null, true ).must.equal('red, green, blue');
});
});
 
describe("when multiple, non-adjacent tokens are selected", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue,yellow,purple" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must move select the previous token of the leftmost selected token in addition to the already selected tokens", function() {
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(green))').addClass('active');
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(yellow))').addClass('active');
 
this.$copyHelper.focus().simulate("keydown", { keyCode: 37, shiftKey: true });
this.$field.tokenfield('getTokensList', null, null, true ).must.equal('red, green, yellow');
});
});
});
 
describe("Pressing Shift + right arrow key", function() {
describe("when a token is selected", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must activate the next token in addition to the already active token", function() {
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(red))').addClass('active');
 
this.$copyHelper.focus()
.simulate("keydown", { keyCode: 39, shiftKey: true })
.simulate("keydown", { keyCode: 39, shiftKey: true });
this.$field.tokenfield('getTokensList', null, null, true ).must.equal('red, green, blue');
});
});
 
describe("when multiple, non-adjacent tokens are selected", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue,yellow,purple" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must move select the next token of the rightmost selected token in addition to the already selected tokens", function() {
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(green))').addClass('active');
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(yellow))').addClass('active');
 
this.$copyHelper.focus().simulate("keydown", { keyCode: 39, shiftKey: true });
this.$field.tokenfield('getTokensList', null, null, true ).must.equal('green, yellow, purple');
});
});
});
 
describe("Pressing Enter key", function() {
describe("when a token is selected", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must enter edit mode for the active token", function() {
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(green))').addClass('active');
 
this.$copyHelper.simulate("key-sequence", { sequence: "{enter}" });
this.$input.data('edit').must.be.true();
this.$input.prev(':contains(red)').must.have.length(1);
this.$input.next(':contains(blue)').must.have.length(1);
});
});
 
describe("when a token is selected and allowEditing is false", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />';
TFT.options = { allowEditing: false }
});
 
after(function() {
delete TFT.template;
delete TFT.options;
});
 
it("must not enter edit mode for the active token [no data('edit') property]", function() {
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(green))').addClass('active');
 
this.$copyHelper.simulate("key-sequence", { sequence: "{enter}" });
this.$input.data().must.not.have.property('edit');
});
});
 
describe("when input has text", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must create a new token from the input", function() {
 
this.$input.simulate("key-sequence", { sequence: "purple{enter}" });
this.$field.tokenfield('getTokens').must.have.length(4);
});
});
});
 
describe("Pressing Tab key", function() {
describe("when input has text", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must create a new token from the input", function() {
 
this.$input.focus().simulate("key-sequence", { sequence: "purple" });
this.$input.simulate("keydown", { keyCode: 9 });
this.$field.tokenfield('getTokens').must.have.length(4);
});
});
});
});
 
describe("Mouse interaction", function() {
 
describe("Clicking on a token", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must select the token and deactivate any other active tokens", function() {
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(green))').addClass('active');
 
this.$wrapper.find('.token:contains(red)').click();
this.$field.tokenfield('getTokensList', null, null, true ).must.equal('red');
});
});
 
describe("Clicking on a token's remove icon", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must remove the token", function() {
this.$wrapper.find('.token:contains(red)').find('.close').click();
this.$field.tokenfield('getTokensList' ).must.equal('green, blue');
});
});
 
describe("Double-clicking on a token", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must enter the edit mode of the token", function() {
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(green))').addClass('active');
this.$wrapper.find('.token:contains(red)').dblclick();
this.$input.data('edit').must.be.true();
this.$input.next(':contains(green)').must.have.length(1);
});
});
 
describe("must not enter the edit mode of the token when allowEditing false", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />';
TFT.options = { allowEditing: false }
});
 
after(function() {
delete TFT.template;
delete TFT.options;
});
 
it("must not enter the edit mode of the token", function() {
this.$wrapper.find('.token:contains(red)').dblclick();
this.$input.data().must.not.have.property('edit');
});
});
 
describe("Ctrl-clicking on a token when another token is selected", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must activate the token in addition to the already active token", function() {
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(green))').addClass('active');
this.$wrapper.find('.token:contains(red)').simulate('click', { ctrlKey: true });
this.$field.tokenfield('getTokensList', null, null, true ).must.equal('red, green');
});
});
 
describe("Shift-clicking on a token when another token is selected", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must activate the token and all the tokens between the already active token", function() {
this.$wrapper.find('.token:contains(blue)').simulate('click');
this.$wrapper.find('.token:contains(red)').simulate('click', { shiftKey: true });
this.$field.tokenfield('getTokensList', null, null, true ).must.equal('red, green, blue');
});
});
 
describe("Pressing enter when there is no input", function() {
var submitted = false;
 
before(function() {
TFT.template = '<form method="post" action=""><input type="text" class="tokenize" value="red,green,blue" /><input type="submit"></form>';
});
 
after(function() {
delete TFT.template;
});
 
beforeEach(function() {
this.$sandbox.find('form').on('submit', function(e) {
submitted = true;
e.preventDefault();
return false;
});
// key-sequence does not trigger submit event on the form when pressing enter
// so we need to trigger it manually. Not really a solid test-case, but oh well
// https://github.com/j-ulrich/jquery-simulate-ext/pull/14
this.$input.focus().simulate("key-sequence", { sequence: "{enter}" }).trigger('submit');
});
 
it("must submit the underlying form", function() {
submitted.must.equal(true);
});
});
});
 
describe("Events", function() {
describe("tokenfield:initialize", function() {
it("must must be triggered when tokenfield is created", function (done) {
$('<input type="text" />')
.on('tokenfield:initialize', function() {
done();
})
.tokenfield();
});
});
 
describe("tokenfield:createtoken", function() {
it("must allow changing token label and value", function() {
this.$field.on('tokenfield:createtoken', function (e) {
e.attrs.value = 'one';
e.attrs.label = 'two';
});
this.$field.tokenfield('createToken', 'zero');
 
var results = this.$field.tokenfield('getTokens');
results[0].label.must.equal('two');
results[0].value.must.equal('one');
});
 
it("must allow setting token value to an empty string", function() {
this.$field.on('tokenfield:createtoken', function (e) {
e.attrs.value = '';
});
this.$field.tokenfield('createToken', 'zero');
 
var results = this.$field.tokenfield('getTokens');
results[0].label.must.equal('zero');
results[0].value.must.equal('');
});
 
it("must allow canceling createtoken by setting token to a falsy value", function() {
this.$field.on('tokenfield:createtoken', function (e) {
e.attrs = false;
});
this.$field.tokenfield('createToken', 'yellow');
 
var results = this.$field.tokenfield('getTokens');
results.must.have.length(0);
});
 
it("must allow canceling createtoken by calling event.preventDefault()", function() {
this.$field.on('tokenfield:createtoken', function (e) {
e.preventDefault();
});
this.$field.tokenfield('createToken', 'yellow');
 
var results = this.$field.tokenfield('getTokens');
results.must.have.length(0);
});
 
it("must allow canceling createtoken by returning false in the event handler", function() {
this.$field.on('tokenfield:createtoken', function (e) {
return false;
});
this.$field.tokenfield('createToken', 'yellow');
 
var results = this.$field.tokenfield('getTokens');
results.must.have.length(0);
});
});
 
describe("tokenfield:createdtoken", function() {
it("must be triggered when a token is created and in the DOM", function (done) {
var self = this;
 
this.$field.on('tokenfield:createdtoken', function (e) {
e.attrs.must.be.an.object();
e.attrs.label.must.eql('red');
e.attrs.value.must.eql('red');
e.relatedTarget.must.be.an.object();
 
self.$wrapper.find(e.relatedTarget).must.have.length(1);
 
done();
});
this.$field.tokenfield('createToken', 'red');
});
});
 
describe("tokenfield:edittoken", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must be triggered when a token is edited", function (done) {
this.$field.on('tokenfield:edittoken', function (e) {
e.attrs.must.be.an.object();
e.attrs.label.must.eql('red');
e.attrs.value.must.eql('red');
e.relatedTarget.must.be.an.object();
done();
});
 
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(red))').addClass('active');
 
this.$copyHelper.simulate("key-sequence", { sequence: "{enter}" });
});
 
it("must allow canceling the default event handler by calling event.preventDefault()", function() {
this.$field.on('tokenfield:edittoken', function (e) {
e.preventDefault();
});
 
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(red))').addClass('active');
this.$copyHelper.simulate("key-sequence", { sequence: "{enter}" });
 
this.$input.data().must.not.have.property('edit');
});
 
it("must allow canceling the default event handler by returning false in the event handler", function() {
this.$field.on('tokenfield:edittoken', function (e) {
return false;
});
 
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(red))').addClass('active');
this.$copyHelper.simulate("key-sequence", { sequence: "{enter}" });
 
this.$input.data().must.not.have.property('edit');
});
});
 
describe("tokenfield:editedtoken", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must be triggered when a token is now being edited (replaced with an input in the DOM)", function (done) {
var self = this;
 
this.$field.on('tokenfield:editedtoken', function (e) {
e.attrs.must.be.an.object();
e.attrs.label.must.eql('red');
e.attrs.value.must.eql('red');
e.relatedTarget.must.be.an.object();
 
self.$wrapper.find(e.relatedTarget).must.have.length(0);
 
done();
});
 
this.$wrapper.find('.token')
.filter(':has(.token-label:contains(red))').addClass('active');
 
this.$copyHelper.simulate("key-sequence", { sequence: "{enter}" });
});
});
 
describe("tokenfield:removetoken", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must be triggered when a token is about to be removed", function (done) {
this.$field.on('tokenfield:removetoken', function (e) {
e.attrs.must.be.an.object();
e.attrs.label.must.eql('red');
e.attrs.value.must.eql('red');
done();
});
 
this.$wrapper.find('.token:first').find('.close').click();
});
 
it("must allow canceling the default event handler by calling event.preventDefault()", function() {
this.$field.on('tokenfield:removetoken', function (e) {
e.preventDefault();
});
 
this.$wrapper.find('.token:first').find('.close').click();
 
this.$field.tokenfield('getTokens').must.have.length(3);
});
 
it("must allow canceling the default event handler by returning false in the event handler", function() {
this.$field.on('tokenfield:removetoken', function (e) {
return false;
});
 
this.$wrapper.find('.token:first').find('.close').click();
 
this.$field.tokenfield('getTokens').must.have.length(3);
});
});
 
describe("tokenfield:removedtoken", function() {
before(function() {
TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
});
 
after(function() {
delete TFT.template;
});
 
it("must be triggered when a token is removed from the DOM", function (done) {
var self = this;
 
this.$field.on('tokenfield:removedtoken', function (e) {
e.attrs.must.be.an.object();
e.attrs.label.must.eql('red');
e.attrs.value.must.eql('red');
 
self.$wrapper.find(e.relatedTarget).length.must.equal(0);
 
done();
});
 
this.$wrapper.find('.token:first').find('.close').click();
});
});
 
});
 
});