1
/* Copyright (c) 2008, Canonical Ltd. All rights reserved. */
3
YUI().use('lazr.choiceedit', 'lazr.testing.runner', 'node',
4
'event', 'event-simulate', 'widget-stack', 'console', function(Y) {
8
ArrayAssert = Y.ArrayAssert;
11
* A wrapper for the Y.Event.simulate() function. The wrapper accepts
12
* CSS selectors and Node instances instead of raw nodes.
14
function simulate(widget, selector, evtype, options) {
15
var rawnode = Y.Node.getDOMNode(widget.one(selector));
16
Y.Event.simulate(rawnode, evtype, options);
19
/* Helper function to clean up a dynamically added widget instance. */
20
function cleanup_widget(widget) {
21
// Nuke the boundingBox, but only if we've touched the DOM.
22
if (widget.get('rendered')) {
23
var bb = widget.get('boundingBox');
24
if (Y.Node.getDOMNode(bb)) {
25
if (bb.get('parentNode')) {
26
bb.get('parentNode').removeChild(bb);
30
// Kill the widget itself.
34
var suite = new Y.Test.Suite("LAZR Choice Edit Tests");
37
// add the in-page HTML
38
var inpage = Y.Node.create([
40
'Status: <span class="value">Unset</span> ',
41
'<img class="editicon" src="https://bugs.edge.launchpad.net/@@/edit">',
43
Y.one("body").appendChild(inpage);
44
this.config = this.make_config();
45
this.choice_edit = new Y.ChoiceSource(this.config);
46
this.choice_edit.render();
50
if (this.choice_edit._choice_list) {
51
cleanup_widget(this.choice_edit._choice_list);
53
var status = Y.one("document").one("#thestatus");
55
status.get("parentNode").removeChild(status);
59
suite.add(new Y.Test.Case({
61
name: 'choice_edit_basics',
67
make_config: function() {
69
contentBox: '#thestatus',
71
title: 'Change status to',
73
{ name: 'New', value: 'new', style: '',
74
help: '', disabled: false },
75
{ name: 'Invalid', value: 'invalid', style: '',
76
help: '', disabled: true },
77
{ name: 'Incomplete', value: 'incomplete', style: '',
78
help: '', disabled: false },
79
{ name: 'Fix Released', value: 'fixreleased', style: '',
80
help: '', disabled: false },
81
{ name: 'Fix Committed', value: 'fixcommitted', style: '',
82
help: '', disabled: true },
83
{ name: 'In Progress', value: 'inprogress', style: '',
84
help: '', disabled: false },
85
{ name: 'Stalled', value: 'stalled', style: '',
86
help: '', disabled: false, source_name: 'STALLED' }
91
test_can_be_instantiated: function() {
93
Y.ChoiceSource, this.choice_edit, "ChoiceSource not instantiated.");
96
test_choicesource_overrides_value_in_page: function() {
97
var st = Y.one(document).one("#thestatus");
98
// value in page should be set to the config.items.name corresponding to
100
Assert.areEqual("Incomplete", st.one(".value").get("innerHTML"),
101
"ChoiceSource is not overriding displayed value in HTML");
104
test_clicking_creates_choicelist: function() {
105
simulate(this.choice_edit.get('boundingBox'), '.value', 'click');
106
Assert.isNotNull(this.choice_edit._choice_list,
107
"ChoiceList object is not created");
108
Assert.isNotNull(Y.one(document).one(".yui3-ichoicelist"),
109
"ChoiceList HTML is not being added to the page");
112
test_right_clicking_doesnt_create_choicelist: function() {
113
simulate(this.choice_edit.get('boundingBox'),
114
'.value', 'click', { button: 2 });
115
Assert.isNull(Y.one(document).one(".yui3-ichoicelist"),
116
"ChoiceList created when the right mouse button was clicked");
119
test_choicelist_has_correct_values: function() {
120
simulate(this.choice_edit.get('boundingBox'), '.value', 'click');
122
Y.each(this.config.items, function(configitem) {
124
Y.each(that.choice_edit._choice_list.get("items"), function(choiceitem) {
125
if (choiceitem.name == configitem.name) {
130
"Item " + configitem.name + " is passed to ChoiceSource but is " +
131
"not in ChoiceList.items");
133
var choicelistcount = this.choice_edit._choice_list.get("items").length;
134
var configcount = this.config.items.length;
135
Assert.areEqual(choicelistcount, configcount,
136
"ChoiceList HTML list is a different length (" + choicelistcount +
137
") than config items list (" + configcount + ")");
140
test_choicelist_html_has_correct_values: function() {
141
simulate(this.choice_edit.get('boundingBox'), '.value', 'click');
142
var configcount = this.config.items.length;
143
var choicelist_lis = Y.one(document).all(".yui3-ichoicelist li");
144
Assert.areEqual(choicelist_lis.size(), configcount,
145
"ChoiceList HTML list is a different length (" + choicelist_lis.size() +
146
") than config items list (" + configcount + ")");
147
// confirm that each LI matches with an item
149
choicelist_lis.each(function(li) {
150
var text = li.get("text");
152
for (var i=0; i<that.config.items.length; i++) {
153
if (that.config.items[i].name == text) {
158
Assert.isTrue(found, "Page LI '" + text +
159
"' did not come from a config item");
163
test_choicelist_html_has_disabled: function() {
164
simulate(this.choice_edit.get('boundingBox'), '.value', 'click');
165
var configcount = this.config.items.length;
166
var choicelist_lis = Y.one(document).all(".yui3-ichoicelist li");
167
// confirm that disabled LIs are disabled
169
choicelist_lis.each(function(li) {
170
var text = li.get("text");
171
for (var i=0; i<that.config.items.length; i++) {
172
if (that.config.items[i].name == text) {
173
if (that.config.items[i].disabled) {
174
Assert.isNotNull(li.one("span.disabled"),
175
"Page LI '" + text + "' was not disabled");
183
test_choicelist_html_has_current: function() {
184
simulate(this.choice_edit.get('boundingBox'), '.value', 'click');
185
var configcount = this.config.items.length;
186
var choicelist_lis = Y.one(document).all(".yui3-ichoicelist li");
187
// confirm that current value has an LI with current style
189
var asserted = false;
190
choicelist_lis.each(function(li) {
191
var text = li.get("text");
192
for (var i=0; i<that.config.items.length; i++) {
193
if (that.config.items[i].name == text) {
194
if (that.config.items[i].value == that.config.value) {
195
Assert.isNotNull(li.one("span.current"),
196
"Page LI '" + text + "' was not marked as current");
203
Assert.isTrue(asserted, "There was no current LI item");
206
test_clicking_choicelist_item_fires_signal: function() {
207
simulate(this.choice_edit.get('boundingBox'), '.value', 'click');
210
this.choice_edit._choice_list.on("valueChosen", function() {
213
// simulate a click on the "fix released" option, which is
215
// (b) not the current option
216
simulate(this.choice_edit._choice_list.get('boundingBox'),
217
'li a[href$=fixreleased]', 'click');
218
Assert.isTrue(fired, "valueChosen signal was not fired");
221
test_clicking_choicelist_item_does_green_flash: function() {
222
simulate(this.choice_edit.get('boundingBox'), '.value', 'click');
224
var green_flash = Y.lazr.anim.green_flash;
226
Y.lazr.anim.green_flash = function() {
233
simulate(this.choice_edit._choice_list.get('boundingBox'),
234
'li a[href$=fixreleased]', 'click');
235
Assert.isTrue(flashed, "green_flash animation was not fired");
236
Y.lazr.anim.green_flash = green_flash;
239
test_clicking_choicelist_item_sets_page_value: function() {
240
var st = Y.one(document).one("#thestatus");
241
// The page value is set to item.name of the selected item.
242
simulate(this.choice_edit.get('boundingBox'), '.value', 'click');
243
simulate(this.choice_edit._choice_list.get('boundingBox'),
244
'li a[href$=fixreleased]', 'click');
245
Assert.areEqual("Fix Released", st.one(".value").get("innerHTML"),
246
"Chosen choicelist item is not displayed in HTML (value is '" +
247
st.one(".value").get("innerHTML") + "')");
250
test_clicking_choicelist_item_sets_page_source_name: function() {
251
var st = Y.one(document).one("#thestatus");
252
// By default, the page value is set to item.name of the
253
// selected item, but this can be overridden by specifying
255
simulate(this.choice_edit.get('boundingBox'), '.value', 'click');
256
var choice_list_bb = this.choice_edit._choice_list.get('boundingBox');
257
var stalled_in_list = choice_list_bb.one('li a[href$=stalled]');
259
"Stalled", stalled_in_list.get('innerHTML'),
260
"ChoiceList item not displayed correctly: " +
261
stalled_in_list.get('innerHTML'));
262
simulate(choice_list_bb, 'li a[href$=stalled]', 'click');
263
Assert.areEqual("STALLED", st.one(".value").get("innerHTML"),
264
"Chosen choicelist item is not displayed in HTML (value is '" +
265
st.one(".value").get("innerHTML") + "')");
270
suite.add(new Y.Test.Case({
272
name: 'choice_edit_non_clickable_content',
278
make_config: function() {
280
contentBox: '#thestatus',
282
title: 'Change status to',
284
{ name: 'New', value: 'new', style: '',
285
help: '', disabled: false },
286
{ name: 'Invalid', value: 'invalid', style: '',
287
help: '', disabled: true },
288
{ name: 'Incomplete', value: 'incomplete', style: '',
289
help: '', disabled: false },
290
{ name: 'Fix Released', value: 'fixreleased', style: '',
291
help: '', disabled: false },
292
{ name: 'Fix Committed', value: 'fixcommitted', style: '',
293
help: '', disabled: true },
294
{ name: 'In Progress', value: 'inprogress', style: '',
295
help: '', disabled: false },
296
{ name: 'Stalled', value: 'stalled', style: '',
297
help: '', disabled: false, source_name: 'STALLED' }
299
clickable_content: false
303
test_clicking_content_doesnt_create_choicelist: function() {
304
simulate(this.choice_edit.get('boundingBox'), '.value', 'click');
305
Assert.isUndefined(this.choice_edit._choice_list,
306
"ChoiceList object is created");
307
Assert.isNull(Y.one(document).one(".yui3-ichoicelist"),
308
"ChoiceList HTML is being added to the page");
311
test_clicking_icon_creates_choicelist: function() {
312
simulate(this.choice_edit.get('boundingBox'), '.editicon', 'click');
313
Assert.isNotUndefined(this.choice_edit._choice_list,
314
"ChoiceList object is not being created");
315
Assert.isNotNull(Y.one(document).one(".yui3-ichoicelist"),
316
"ChoiceList HTML is not being added to the page");
323
* Tests what happens when config.value does not correspond to any of
324
* the items in config.items.
326
suite.add(new Y.Test.Case({
328
name: 'choice_edit_value_item_mismatch',
334
make_config: function() {
336
contentBox: '#thestatus',
338
title: 'Change status to',
340
{ name: 'New', value: 'new', style: '',
341
help: '', disabled: false },
342
{ name: 'Invalid', value: 'invalid', style: '',
343
help: '', disabled: true }
349
* The value displayed in the page should be left alone if
350
* config.value does not correspond to any item in config.items.
352
test_choicesource_leaves_value_in_page: function() {
353
var st = Y.one(document).one("#thestatus");
355
"Unset", st.one(".value").get("innerHTML"),
356
"ChoiceSource is overriding displayed value in HTML");
359
test_choicelist_html_has_current: function() {
360
simulate(this.choice_edit.get('boundingBox'), '.value', 'click');
361
var configcount = this.config.items.length;
362
var choicelist_lis = Y.one(document).all(".yui3-ichoicelist li");
366
var test_li = function(li) {
367
var text = li.get("text");
368
for (var i=0; i < that.config.items.length; i++) {
369
if (that.config.items[i].name == text) {
370
if (that.config.items[i].value == that.choice_edit.get("value")) {
371
Assert.isNotNull(li.one("span.current"),
372
"Page LI '" + text + "' was not marked as current");
379
// When config.value does not correspond to any item in
380
// config.items, no LI in the choice list will be marked with
381
// the "current" style.
383
choicelist_lis.each(test_li);
384
Assert.isFalse(asserted, "There was a current LI item");
385
// Once a choice is made, the current value is marked with the
386
// "current" class in the choice list.
387
simulate(this.choice_edit._choice_list.get('boundingBox'),
388
'li a[href$=new]', 'click');
389
simulate(this.choice_edit.get('boundingBox'), '.value', 'click');
391
choicelist_lis.refresh();
392
choicelist_lis.each(test_li);
393
Assert.isTrue(asserted, "There was no current LI item");
398
suite.add(new Y.Test.Case({
400
name: 'nullable_choice_edit',
403
// add the in-page HTML
404
var inpage = Y.Node.create([
405
'<p id="nullchoiceedit" style="margin-top: 25px">',
406
' <img class="addicon" src="https://bugs.edge.launchpad.net/@@/add">',
407
' <span class="nulltext">Choose something</span>',
408
' <span class="value" style="display:none" />',
409
' <img class="editicon" style="display:none" src="https://bugs.edge.launchpad.net/@@/edit">',
411
Y.one("body").appendChild(inpage);
412
this.null_choice_edit = new Y.NullChoiceSource({
413
contentBox: '#nullchoiceedit',
415
title: 'Choose something',
417
{ name: 'Chico', value: 'chico', style: '',
418
help: '', disabled: false },
419
{ name: 'Harpo', value: 'harpo', style: '',
420
help: '', disabled: false },
421
{ name: 'Groucho', value: 'groucho', style: '',
422
help: '', disabled: false },
423
{ name: 'Gummo', value: 'gummo', style: '',
424
help: '', disabled: false },
425
{ name: 'Zeppo', value: 'zeppo', style: '',
426
help: '', disabled: false },
427
{ name: 'Not funny!', value: null, style: '',
428
help: '', disabled: false }
432
this.null_choice_edit.render();
435
tearDown: function() {
436
if (this.null_choice_edit._choice_list) {
437
cleanup_widget(this.null_choice_edit._choice_list);
439
var nullchoiceedit = Y.one("document").one("#nullchoiceedit");
440
if (nullchoiceedit) {
441
nullchoiceedit.get("parentNode").removeChild(nullchoiceedit);
445
test_can_be_instantiated: function() {
447
Y.NullChoiceSource, this.null_choice_edit,
448
"NullChoiceSource not instantiated.");
451
test_action_icon: function() {
455
this.null_choice_edit.get('actionicon'),
456
this.null_choice_edit.get('addicon'),
457
'Action icon is not the add icon like expected.');
460
this.null_choice_edit.get('addicon').getStyle('display'),
462
'Add icon is not visible when it should be');
464
this.null_choice_edit.get('editicon').getStyle('display'),
466
"Edit icon is visible when it shouldn't be");
468
simulate(this.null_choice_edit.get('boundingBox'),
470
simulate(this.null_choice_edit._choice_list.get('boundingBox'),
471
'li a[href$=groucho]', 'click');
472
this.null_choice_edit._uiClearWaiting();
475
this.null_choice_edit.get('actionicon'),
476
this.null_choice_edit.get('editicon'),
477
'Action icon is not the add icon like expected.');
479
this.null_choice_edit.get('addicon').getStyle('display'),
481
"Add icon is visible when it shouldn't be");
483
this.null_choice_edit.get('editicon').getStyle('display'),
485
"Edit icon is not visible when it shouldn be");
488
test_null_item_absent: function() {
490
this.null_choice_edit.get('value'),
492
"Selected value isn't null");
494
simulate(this.null_choice_edit.get('boundingBox'),
496
var remove_action_present = false;
497
this.null_choice_edit._choice_list.get(
498
'boundingBox').all('li a').each(function(item) {
499
if (item._value == null) {
500
remove_action_present = true;
504
remove_action_present,
505
'Remove item is present even when the current value is null.');
508
test_get_input_for_null: function() {
509
this.null_choice_edit.set('value', 'groucho');
512
this.null_choice_edit.getInput(),
513
"getInput() did not return the current value");
514
// Simulate choosing a null value and check that getInput()
515
// returns the new value.
516
this.null_choice_edit.onClick({button: 1, halt: function(){}});
517
this.null_choice_edit._choice_list.fire('valueChosen', null);
520
this.null_choice_edit.getInput(),
521
"getInput() did not return the current (null) value");
525
Y.lazr.testing.Runner.add(suite);
526
Y.lazr.testing.Runner.run();