~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/app/javascript/lazr/choiceedit/tests/choiceedit.js

[r=deryck][bug=803954] Bring lazr-js source into lp tree and package
        yui as a dependency

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2008, Canonical Ltd. All rights reserved. */
 
2
 
 
3
YUI().use('lazr.choiceedit', 'lazr.testing.runner', 'node',
 
4
          'event', 'event-simulate', 'widget-stack', 'console', function(Y) {
 
5
 
 
6
// Local aliases
 
7
var Assert = Y.Assert,
 
8
    ArrayAssert = Y.ArrayAssert;
 
9
 
 
10
/*
 
11
 * A wrapper for the Y.Event.simulate() function.  The wrapper accepts
 
12
 * CSS selectors and Node instances instead of raw nodes.
 
13
 */
 
14
function simulate(widget, selector, evtype, options) {
 
15
    var rawnode = Y.Node.getDOMNode(widget.one(selector));
 
16
    Y.Event.simulate(rawnode, evtype, options);
 
17
}
 
18
 
 
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);
 
27
            }
 
28
        }
 
29
    }
 
30
    // Kill the widget itself.
 
31
    widget.destroy();
 
32
}
 
33
 
 
34
var suite = new Y.Test.Suite("LAZR Choice Edit Tests");
 
35
 
 
36
function setUp() {
 
37
    // add the in-page HTML
 
38
    var inpage = Y.Node.create([
 
39
        '<p id="thestatus">',
 
40
        'Status: <span class="value">Unset</span> ',
 
41
        '<img class="editicon" src="https://bugs.edge.launchpad.net/@@/edit">',
 
42
        '</p>'].join(''));
 
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();
 
47
}
 
48
 
 
49
function tearDown() {
 
50
    if (this.choice_edit._choice_list) {
 
51
        cleanup_widget(this.choice_edit._choice_list);
 
52
    }
 
53
    var status = Y.one("document").one("#thestatus");
 
54
    if (status) {
 
55
        status.get("parentNode").removeChild(status);
 
56
    }
 
57
}
 
58
 
 
59
suite.add(new Y.Test.Case({
 
60
 
 
61
    name: 'choice_edit_basics',
 
62
 
 
63
    setUp: setUp,
 
64
 
 
65
    tearDown: tearDown,
 
66
 
 
67
    make_config: function() {
 
68
        return {
 
69
            contentBox:  '#thestatus',
 
70
            value:       'incomplete',
 
71
            title:       'Change status to',
 
72
            items: [
 
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' }
 
87
            ]
 
88
        };
 
89
    },
 
90
 
 
91
    test_can_be_instantiated: function() {
 
92
        Assert.isInstanceOf(
 
93
            Y.ChoiceSource, this.choice_edit, "ChoiceSource not instantiated.");
 
94
    },
 
95
 
 
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
 
99
        // config.value
 
100
        Assert.areEqual("Incomplete", st.one(".value").get("innerHTML"),
 
101
                        "ChoiceSource is not overriding displayed value in HTML");
 
102
    },
 
103
 
 
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");
 
110
    },
 
111
 
 
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");
 
117
    },
 
118
 
 
119
    test_choicelist_has_correct_values: function() {
 
120
        simulate(this.choice_edit.get('boundingBox'), '.value', 'click');
 
121
        var that = this;
 
122
        Y.each(this.config.items, function(configitem) {
 
123
            var found = false;
 
124
            Y.each(that.choice_edit._choice_list.get("items"), function(choiceitem) {
 
125
                if (choiceitem.name == configitem.name) {
 
126
                    found = true;
 
127
                }
 
128
            });
 
129
            Assert.isTrue(found,
 
130
              "Item " + configitem.name + " is passed to ChoiceSource but is " +
 
131
              "not in ChoiceList.items");
 
132
        });
 
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 + ")");
 
138
    },
 
139
 
 
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
 
148
        var that = this;
 
149
        choicelist_lis.each(function(li) {
 
150
            var text = li.get("text");
 
151
            var found = false;
 
152
            for (var i=0; i<that.config.items.length; i++) {
 
153
                if (that.config.items[i].name == text) {
 
154
                    found = true;
 
155
                    break;
 
156
                }
 
157
            }
 
158
            Assert.isTrue(found, "Page LI '" + text +
 
159
               "' did not come from a config item");
 
160
        });
 
161
    },
 
162
 
 
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
 
168
        var that = this;
 
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");
 
176
                    }
 
177
                    break;
 
178
                }
 
179
            }
 
180
        });
 
181
    },
 
182
 
 
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
 
188
        var that = this;
 
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");
 
197
                        asserted = true;
 
198
                    }
 
199
                    break;
 
200
                }
 
201
            }
 
202
        });
 
203
        Assert.isTrue(asserted, "There was no current LI item");
 
204
    },
 
205
 
 
206
    test_clicking_choicelist_item_fires_signal: function() {
 
207
        simulate(this.choice_edit.get('boundingBox'), '.value', 'click');
 
208
        var that = this;
 
209
        var fired = false;
 
210
        this.choice_edit._choice_list.on("valueChosen", function() {
 
211
            fired = true;
 
212
        });
 
213
        // simulate a click on the "fix released" option, which is
 
214
        // (a) enabled
 
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");
 
219
    },
 
220
 
 
221
    test_clicking_choicelist_item_does_green_flash: function() {
 
222
        simulate(this.choice_edit.get('boundingBox'), '.value', 'click');
 
223
        var that = this;
 
224
        var green_flash = Y.lazr.anim.green_flash;
 
225
        var flashed = false;
 
226
        Y.lazr.anim.green_flash = function() {
 
227
          return {
 
228
              run: function() {
 
229
                  flashed = true;
 
230
              }
 
231
          };
 
232
        };
 
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;
 
237
    },
 
238
 
 
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") + "')");
 
248
    },
 
249
 
 
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
 
254
        // item.source_name.
 
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]');
 
258
        Assert.areEqual(
 
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") + "')");
 
266
    }
 
267
 
 
268
}));
 
269
 
 
270
suite.add(new Y.Test.Case({
 
271
 
 
272
    name: 'choice_edit_non_clickable_content',
 
273
 
 
274
    setUp: setUp,
 
275
 
 
276
    tearDown: tearDown,
 
277
 
 
278
    make_config: function() {
 
279
        return {
 
280
            contentBox:  '#thestatus',
 
281
            value:       'incomplete',
 
282
            title:       'Change status to',
 
283
            items: [
 
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' }
 
298
            ],
 
299
            clickable_content: false
 
300
        };
 
301
    },
 
302
 
 
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");
 
309
    },
 
310
 
 
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");
 
317
    },
 
318
 
 
319
}));
 
320
 
 
321
 
 
322
/**
 
323
 * Tests what happens when config.value does not correspond to any of
 
324
 * the items in config.items.
 
325
 */
 
326
suite.add(new Y.Test.Case({
 
327
 
 
328
    name: 'choice_edit_value_item_mismatch',
 
329
 
 
330
    setUp: setUp,
 
331
 
 
332
    tearDown: tearDown,
 
333
 
 
334
    make_config: function() {
 
335
        return {
 
336
            contentBox:  '#thestatus',
 
337
            value:       null,
 
338
            title:       'Change status to',
 
339
            items: [
 
340
                { name: 'New', value: 'new', style: '',
 
341
                  help: '', disabled: false },
 
342
                { name: 'Invalid', value: 'invalid', style: '',
 
343
                  help: '', disabled: true }
 
344
            ]
 
345
        };
 
346
    },
 
347
 
 
348
    /**
 
349
     * The value displayed in the page should be left alone if
 
350
     * config.value does not correspond to any item in config.items.
 
351
     */
 
352
    test_choicesource_leaves_value_in_page: function() {
 
353
        var st = Y.one(document).one("#thestatus");
 
354
        Assert.areEqual(
 
355
            "Unset", st.one(".value").get("innerHTML"),
 
356
            "ChoiceSource is overriding displayed value in HTML");
 
357
    },
 
358
 
 
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");
 
363
 
 
364
        var that = this;
 
365
        var asserted;
 
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");
 
373
                        asserted = true;
 
374
                    }
 
375
                    break;
 
376
                }
 
377
            }
 
378
        };
 
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.
 
382
        asserted = false;
 
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');
 
390
        asserted = false;
 
391
        choicelist_lis.refresh();
 
392
        choicelist_lis.each(test_li);
 
393
        Assert.isTrue(asserted, "There was no current LI item");
 
394
    }
 
395
 
 
396
}));
 
397
 
 
398
suite.add(new Y.Test.Case({
 
399
 
 
400
    name: 'nullable_choice_edit',
 
401
 
 
402
    setUp: function() {
 
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">',
 
410
        '</p>'].join(''));
 
411
      Y.one("body").appendChild(inpage);
 
412
      this.null_choice_edit = new Y.NullChoiceSource({
 
413
        contentBox:  '#nullchoiceedit',
 
414
        value:       null,
 
415
        title:       'Choose something',
 
416
        items: [
 
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 }
 
429
        ]
 
430
      });
 
431
 
 
432
      this.null_choice_edit.render();
 
433
    },
 
434
 
 
435
    tearDown: function() {
 
436
        if (this.null_choice_edit._choice_list) {
 
437
            cleanup_widget(this.null_choice_edit._choice_list);
 
438
        }
 
439
        var nullchoiceedit = Y.one("document").one("#nullchoiceedit");
 
440
        if (nullchoiceedit) {
 
441
            nullchoiceedit.get("parentNode").removeChild(nullchoiceedit);
 
442
        }
 
443
    },
 
444
 
 
445
    test_can_be_instantiated: function() {
 
446
        Assert.isInstanceOf(
 
447
            Y.NullChoiceSource, this.null_choice_edit,
 
448
            "NullChoiceSource not instantiated.");
 
449
    },
 
450
 
 
451
    test_action_icon: function() {
 
452
        var that = this;
 
453
 
 
454
        Assert.areEqual(
 
455
            this.null_choice_edit.get('actionicon'),
 
456
            this.null_choice_edit.get('addicon'),
 
457
            'Action icon is not the add icon like expected.');
 
458
 
 
459
        Assert.areEqual(
 
460
            this.null_choice_edit.get('addicon').getStyle('display'),
 
461
            'inline',
 
462
            'Add icon is not visible when it should be');
 
463
        Assert.areEqual(
 
464
            this.null_choice_edit.get('editicon').getStyle('display'),
 
465
            'none',
 
466
            "Edit icon is visible when it shouldn't be");
 
467
 
 
468
        simulate(this.null_choice_edit.get('boundingBox'),
 
469
                 '.value', 'click');
 
470
        simulate(this.null_choice_edit._choice_list.get('boundingBox'),
 
471
          'li a[href$=groucho]', 'click');
 
472
        this.null_choice_edit._uiClearWaiting();
 
473
 
 
474
        Assert.areEqual(
 
475
            this.null_choice_edit.get('actionicon'),
 
476
            this.null_choice_edit.get('editicon'),
 
477
            'Action icon is not the add icon like expected.');
 
478
        Assert.areEqual(
 
479
            this.null_choice_edit.get('addicon').getStyle('display'),
 
480
            'none',
 
481
            "Add icon is visible when it shouldn't be");
 
482
        Assert.areEqual(
 
483
            this.null_choice_edit.get('editicon').getStyle('display'),
 
484
            'inline',
 
485
            "Edit icon is not visible when it shouldn be");
 
486
    },
 
487
 
 
488
    test_null_item_absent: function() {
 
489
        Assert.areEqual(
 
490
            this.null_choice_edit.get('value'),
 
491
            null,
 
492
            "Selected value isn't null");
 
493
 
 
494
        simulate(this.null_choice_edit.get('boundingBox'),
 
495
                 '.value', 'click');
 
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;
 
501
            }
 
502
        });
 
503
        Assert.isFalse(
 
504
            remove_action_present,
 
505
            'Remove item is present even when the current value is null.');
 
506
    },
 
507
 
 
508
    test_get_input_for_null: function() {
 
509
        this.null_choice_edit.set('value', 'groucho');
 
510
        Assert.areEqual(
 
511
            '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);
 
518
        Assert.areEqual(
 
519
            null,
 
520
            this.null_choice_edit.getInput(),
 
521
            "getInput() did not return the current (null) value");
 
522
    }
 
523
}));
 
524
 
 
525
Y.lazr.testing.Runner.add(suite);
 
526
Y.lazr.testing.Runner.run();
 
527
 
 
528
});