Merge lp:~rharding/launchpad/listingnav_yui35 into lp:launchpad
- listingnav_yui35
- Merge into devel
| Status: | Merged |
|---|---|
| Approved by: | Richard Harding on 2012-06-27 |
| Approved revision: | no longer in the source branch. |
| Merged at revision: | 15507 |
| Proposed branch: | lp:~rharding/launchpad/listingnav_yui35 |
| Merge into: | lp:launchpad |
| Diff against target: |
2143 lines (+1050/-1040) 3 files modified
lib/lp/app/javascript/listing_navigator.js (+16/-16) lib/lp/app/javascript/tests/test_listing_navigator.html (+5/-2) lib/lp/app/javascript/tests/test_listing_navigator.js (+1029/-1022) |
| To merge this branch: | bzr merge lp:~rharding/launchpad/listingnav_yui35 |
| Related bugs: |
| Reviewer | Review Type | Date Requested | Status |
|---|---|---|---|
| Raphaël Badin (community) | 2012-06-27 | Approve on 2012-06-27 | |
| Francesco Banconi (community) | code* | 2012-06-27 | Approve on 2012-06-27 |
|
Review via email:
|
|||
Commit Message
Update the test_listing_
Description of the Change
= Summary =
This updates the test_listing_
== Implementation Notes ==
This module was running on its own test runner setup which required duplicated effort to clean up. This reformats the tests to use the standard setup from the testrunner module.
This also updates for YUI 3.5 by fixing some cleanup of the browser history state in the teardown methods of the various test suites. This is required because of the updated History module pulling from a global history state which polluted test runs afterwards.
== Tests ==
./bin/test -x -cvv --layer=
== Lint ==
Linting changed files:
lib/lp/
lib/lp/
== LoC Qualification ==
There are two qualifications:
1. Fixing these tests reduces tech debt and eases maintenance.
2. Getting to YUI 3.5 will allow us to use the build in calendar widget and
will remove all of the YUI2 code from the code base which is aroud 12K LoC
(non-minified) and over 27K lines of total files.
| Raphaël Badin (rvb) wrote : | # |
Looks good.
[0]
1436 + setUp: function() {
1437 + this.target = Y.Node.
1438 + 'id', 'client-listing');
1439 + Y.one('
1440 + },
1441 +
1442 + tearDown: function() {
1443 + this.target.
1444 + delete this.target;
1445 + reset_history();
1446 + },
I see a lot of identical setUp/tearDown methods. Maybe you could put them in a test case class and use that class instead of having that code duplicated.
[1]
pocketlint thinks some of the lines are too long: http://
[2]
285 + * gets pulled into the next text automatically.
s/text/test/ ?
[3]
>This also updates for YUI 3.5 by fixing some cleanup of the browser history state in the teardown methods of the
> various test suites
> 1191 + tests.suite.add(new Y.Test.Case({
Too bad we're not deriving our tests from a custom test case as this seems like the kind of cleanup that should always be done… don't you think?
| Richard Harding (rharding) wrote : | # |
> Looks good.
>
> [0]
>
> 1436 + setUp: function() {
> 1437 + this.target = Y.Node.
> 1438 + 'id', 'client-listing');
> 1439 + Y.one('
> 1440 + },
> 1441 +
> 1442 + tearDown: function() {
> 1443 + this.target.
> 1444 + delete this.target;
> 1445 + reset_history();
> 1446 + },
>
> I see a lot of identical setUp/tearDown methods. Maybe you could put them in
> a test case class and use that class instead of having that code duplicated.
Yes, it's a debate on how far to touch things in the process of just trying to get tests passing under YUI3.5. I'll probably hold off on this at the moment.
>
> [1]
>
> pocketlint thinks some of the lines are too long:
> http://
Sorry, forgot to repush after I ran lint. The branch should be updated. It was mainly comment blocks that were too long.
> [2]
>
> 285 + * gets pulled into the next text automatically.
>
> s/text/test/ ?
ty
> [3]
>
> >This also updates for YUI 3.5 by fixing some cleanup of the browser history
> state in the teardown methods of the
> > various test suites
>
> > 1191 + tests.suite.add(new Y.Test.Case({
>
> Too bad we're not deriving our tests from a custom test case as this seems
> like the kind of cleanup that should always be done… don't you think?
I had the thought, but here's the interesting thing. If I were to reload the page, the previous state was causing the pollution from the browser itself. Now, if a user were to load the page, and do something, and reload the page, it would do the same. So I don't know that I'd want to blindly clear this in all tests. I'd want to make sure people were aware of how this works.
I'm blindly adding here to these tests because I'm documenting the issues as they come up and I've got a list of issues to look into going forward. If there is still an issue in production code, it'll be part of the tests coming out of this. If every test blanked it then tests would always pass, but we'd have a strange history state bug in production.
I guess I lean a bit toward explicit in the case of test setup/teardowns so that I can see expected changes and cleanup that my code does. I hate when people just do things like Y.one('
Preview Diff
| 1 | === modified file 'lib/lp/app/javascript/listing_navigator.js' |
| 2 | --- lib/lp/app/javascript/listing_navigator.js 2012-03-20 12:11:48 +0000 |
| 3 | +++ lib/lp/app/javascript/listing_navigator.js 2012-06-27 14:13:23 +0000 |
| 4 | @@ -40,20 +40,8 @@ |
| 5 | * - batch_key: A string representing the position and ordering of the |
| 6 | * current batch, as returned by listing_navigator.get_batch_key |
| 7 | */ |
| 8 | -module.SimpleListingModel = function () { |
| 9 | - module.SimpleListingModel.superclass.constructor.apply(this, arguments); |
| 10 | -}; |
| 11 | - |
| 12 | - |
| 13 | -module.SimpleListingModel.NAME = 'simple-listing-model'; |
| 14 | - |
| 15 | -module.SimpleListingModel.ATTRS = { |
| 16 | - total: { |
| 17 | - value: null |
| 18 | - } |
| 19 | -}; |
| 20 | - |
| 21 | -Y.extend(module.SimpleListingModel, Y.Base, { |
| 22 | +module.SimpleListingModel = Y.Base.create('simple-listing-model', Y.Base, [], { |
| 23 | + |
| 24 | /** |
| 25 | * Initializer sets up the History object that stores most of the |
| 26 | * model data. |
| 27 | @@ -81,6 +69,18 @@ |
| 28 | var url = '?' + Y.QueryString.stringify(query); |
| 29 | this.get('history').addValue('batch_key', batch_key, {url: url}); |
| 30 | } |
| 31 | +}, { |
| 32 | + ATTRS: { |
| 33 | + batch_key: { |
| 34 | + value: null |
| 35 | + }, |
| 36 | + history: { |
| 37 | + value: null |
| 38 | + }, |
| 39 | + total: { |
| 40 | + value: null |
| 41 | + } |
| 42 | + } |
| 43 | }); |
| 44 | |
| 45 | |
| 46 | @@ -640,7 +640,7 @@ |
| 47 | |
| 48 | }, "0.1", { |
| 49 | "requires": [ |
| 50 | - "node", 'history', 'lp.client', 'lp.app.errors', 'lp.app.indicator', |
| 51 | - 'lp.mustache' |
| 52 | + "base", "node", 'history', 'lp.client', 'lp.app.errors', |
| 53 | + 'lp.app.indicator', 'lp.mustache' |
| 54 | ] |
| 55 | }); |
| 56 | |
| 57 | === modified file 'lib/lp/app/javascript/tests/test_listing_navigator.html' |
| 58 | --- lib/lp/app/javascript/tests/test_listing_navigator.html 2012-03-14 04:41:36 +0000 |
| 59 | +++ lib/lp/app/javascript/tests/test_listing_navigator.html 2012-06-27 14:13:23 +0000 |
| 60 | @@ -30,6 +30,10 @@ |
| 61 | <script type="text/javascript" |
| 62 | src="../../../../../build/js/lp/app/testing/mockio.js"></script> |
| 63 | <script type="text/javascript" |
| 64 | + src="../../../../../build/js/lp/app/extras/extras.js"></script> |
| 65 | + <script type="text/javascript" |
| 66 | + src="../../../../../build/js/lp/app/anim/anim.js"></script> |
| 67 | + <script type="text/javascript" |
| 68 | src="../../../../../build/js/lp/app/client.js"></script> |
| 69 | <script type="text/javascript" |
| 70 | src="../../../../../build/js/lp/app/effects/effects.js"></script> |
| 71 | @@ -65,8 +69,7 @@ |
| 72 | </head> |
| 73 | <body class="yui3-skin-sam"> |
| 74 | <ul id="suites"> |
| 75 | - <!-- <li>lp.large_indicator.test</li> --> |
| 76 | - <li>lp.listing_navigator.test</li> |
| 77 | + <li>lp.app.listing_navigator.test</li> |
| 78 | </ul> |
| 79 | |
| 80 | <div id="fixture"></div> |
| 81 | |
| 82 | === modified file 'lib/lp/app/javascript/tests/test_listing_navigator.js' |
| 83 | --- lib/lp/app/javascript/tests/test_listing_navigator.js 2012-03-20 06:11:07 +0000 |
| 84 | +++ lib/lp/app/javascript/tests/test_listing_navigator.js 2012-06-27 14:13:23 +0000 |
| 85 | @@ -1,1029 +1,1036 @@ |
| 86 | -YUI({ |
| 87 | - base: '../../../../canonical/launchpad/icing/yui/', |
| 88 | - filter: 'raw', combine: false, fetchCSS: false |
| 89 | - }).use('test', 'console', 'lp.app.listing_navigator', 'lp.testing.mockio', |
| 90 | - 'lp.testing.assert', 'history', |
| 91 | - function(Y) { |
| 92 | - |
| 93 | -var suite = new Y.Test.Suite("lp.app.listing_navigator Tests"); |
| 94 | -var module = Y.lp.app.listing_navigator; |
| 95 | - |
| 96 | -var TestModel = function() { |
| 97 | - this.constructor.superclass.constructor.apply(this, arguments); |
| 98 | -}; |
| 99 | - |
| 100 | -TestModel.ATTRS = { |
| 101 | - batch_key: {value: null} |
| 102 | -}; |
| 103 | - |
| 104 | -var TestListingNavigator = function() { |
| 105 | - this.constructor.superclass.constructor.apply(this, arguments); |
| 106 | -}; |
| 107 | - |
| 108 | -Y.extend(TestListingNavigator, Y.lp.app.listing_navigator.ListingNavigator, { |
| 109 | - update_from_cache: function() { |
| 110 | - this.constructor.superclass.update_from_cache.apply(this, arguments); |
| 111 | - this.pre_fetch_batches(); |
| 112 | - this.render(); |
| 113 | - }, |
| 114 | - get_search_params: function(config) { |
| 115 | - return config.search_params; |
| 116 | - } |
| 117 | -}); |
| 118 | - |
| 119 | - |
| 120 | -suite.add(new Y.Test.Case({ |
| 121 | - name: 'render', |
| 122 | - |
| 123 | - setUp: function() { |
| 124 | - this.target = Y.Node.create('<div></div>').set( |
| 125 | - 'id', 'client-listing'); |
| 126 | - Y.one('body').appendChild(this.target); |
| 127 | - }, |
| 128 | - |
| 129 | - tearDown: function() { |
| 130 | - Y.one('#fixture').setContent(''); |
| 131 | - this.target.remove(); |
| 132 | - delete this.target; |
| 133 | - }, |
| 134 | - |
| 135 | - get_render_navigator: function() { |
| 136 | - var lp_cache = { |
| 137 | - mustache_model: { |
| 138 | - items: [{foo: 'bar', show_foo: true}] |
| 139 | - }, |
| 140 | - next: null, |
| 141 | - prev: null, |
| 142 | - start: 5, |
| 143 | - total: 256, |
| 144 | - field_visibility: {show_foo: true}, |
| 145 | - field_visibility_defaults: {show_foo: false} |
| 146 | - }; |
| 147 | - var template = "{{#items}}{{#show_foo}}{{foo}}{{/show_foo}}" + |
| 148 | - "{{/items}}"; |
| 149 | - var navigator = new TestListingNavigator({ |
| 150 | - cache: lp_cache, |
| 151 | - template: template, |
| 152 | - target: this.target |
| 153 | - }); |
| 154 | - var index = Y.Node.create( |
| 155 | - '<div><strong>3</strong> → <strong>4</strong>' + |
| 156 | - ' of 512 results</div>'); |
| 157 | - navigator.get('navigation_indices').push(index); |
| 158 | - navigator.get('backwards_navigation').push( |
| 159 | - Y.Node.create('<div></div>')); |
| 160 | - navigator.get('forwards_navigation').push( |
| 161 | - Y.Node.create('<div></div>')); |
| 162 | - return navigator; |
| 163 | - }, |
| 164 | - test_render: function() { |
| 165 | - // Rendering should work with #client-listing supplied. |
| 166 | - var navigator = this.get_render_navigator(); |
| 167 | - navigator.render(); |
| 168 | - Y.Assert.areEqual('bar', navigator.get('target').getContent()); |
| 169 | - }, |
| 170 | - /** |
| 171 | - * update_navigation_links should disable "previous" and "first" if there |
| 172 | - * is no previous batch (i.e. we're at the beginning.) |
| 173 | - */ |
| 174 | - test_update_navigation_links_disables_backwards_navigation_if_no_prev: |
| 175 | - function() { |
| 176 | - var navigator = this.get_render_navigator(); |
| 177 | - var action = navigator.get('backwards_navigation').item(0); |
| 178 | - navigator.update_navigation_links(); |
| 179 | - Y.Assert.isTrue(action.hasClass('inactive')); |
| 180 | - }, |
| 181 | - /** |
| 182 | - * update_navigation_links should enable "previous" and "first" if there is |
| 183 | - * a previous batch (i.e. we're not at the beginning.) |
| 184 | - */ |
| 185 | - test_update_navigation_links_enables_backwards_navigation_if_prev: |
| 186 | - function() { |
| 187 | - var navigator = this.get_render_navigator(); |
| 188 | - var action = navigator.get('backwards_navigation').item(0); |
| 189 | - action.addClass('inactive'); |
| 190 | - navigator.get_current_batch().prev = { |
| 191 | - start: 1, memo: 'pi' |
| 192 | - }; |
| 193 | - navigator.update_navigation_links(); |
| 194 | - Y.Assert.isFalse(action.hasClass('inactive')); |
| 195 | - }, |
| 196 | - /** |
| 197 | - * update_navigation_links should disable "next" and "last" if there is |
| 198 | - * no next batch (i.e. we're at the end.) |
| 199 | - */ |
| 200 | - test_update_navigation_links_disables_forwards_navigation_if_no_next: |
| 201 | - function() { |
| 202 | - var navigator = this.get_render_navigator(); |
| 203 | - var action = navigator.get('forwards_navigation').item(0); |
| 204 | - navigator.update_navigation_links(); |
| 205 | - Y.Assert.isTrue(action.hasClass('inactive')); |
| 206 | - }, |
| 207 | - /** |
| 208 | - * update_navigation_links should enable "next" and "last" if there is a |
| 209 | - * next batch (i.e. we're not at the end.) |
| 210 | - */ |
| 211 | - test_update_navigation_links_enables_forwards_navigation_if_next: |
| 212 | - function() { |
| 213 | - var navigator = this.get_render_navigator(); |
| 214 | - var action = navigator.get('forwards_navigation').item(0); |
| 215 | - action.addClass('inactive'); |
| 216 | - navigator.get_current_batch().next = { |
| 217 | - start: 1, memo: 'pi' |
| 218 | - }; |
| 219 | - navigator.update_navigation_links(); |
| 220 | - Y.Assert.isFalse(action.hasClass('inactive')); |
| 221 | - }, |
| 222 | - /** |
| 223 | - * linkify_navigation should convert previous, next, first last into |
| 224 | - * hyperlinks, while retaining the original content. |
| 225 | - */ |
| 226 | - test_linkify_navigation: function() { |
| 227 | - Y.one('#fixture').setContent( |
| 228 | - '<span class="previous">PreVious</span>' + |
| 229 | - '<span class="next">NeXt</span>' + |
| 230 | - '<span class="first">FiRST</span>' + |
| 231 | - '<span class="last">lAst</span>'); |
| 232 | - module.linkify_navigation(); |
| 233 | - function checkNav(selector, content) { |
| 234 | - var node = Y.one(selector); |
| 235 | - Y.Assert.areEqual('a', node.get('tagName').toLowerCase()); |
| 236 | - Y.Assert.areEqual(content, node.getContent()); |
| 237 | - Y.Assert.areEqual('#', node.get('href').substr(-1, 1)); |
| 238 | - } |
| 239 | - checkNav('.previous', 'PreVious'); |
| 240 | - checkNav('.next', 'NeXt'); |
| 241 | - checkNav('.first', 'FiRST'); |
| 242 | - checkNav('.last', 'lAst'); |
| 243 | - }, |
| 244 | - /** |
| 245 | - * Render should update the navigation_indices with the result info. |
| 246 | - */ |
| 247 | - test_update_navigation_links_indices: function() { |
| 248 | - var navigator = this.get_render_navigator(); |
| 249 | - var index = navigator.get('navigation_indices').item(0); |
| 250 | - Y.Assert.areEqual( |
| 251 | - '<strong>3</strong> \u2192 <strong>4</strong> of 512 results', |
| 252 | - index.getContent()); |
| 253 | - navigator.render(); |
| 254 | - Y.Assert.areEqual( |
| 255 | - '<strong>6</strong> \u2192 <strong>6</strong> of 256 results', |
| 256 | - index.getContent()); |
| 257 | - } |
| 258 | -})); |
| 259 | - |
| 260 | -suite.add(new Y.Test.Case({ |
| 261 | - name: 'first_batch', |
| 262 | - |
| 263 | - setUp: function() { |
| 264 | - this.target = Y.Node.create('<div></div>').set( |
| 265 | - 'id', 'client-listing'); |
| 266 | - Y.one('body').appendChild(this.target); |
| 267 | - }, |
| 268 | - |
| 269 | - tearDown: function() { |
| 270 | - this.target.remove(); |
| 271 | - delete this.target; |
| 272 | - }, |
| 273 | - |
| 274 | - /** |
| 275 | - * Return a ListingNavigator ordered by 'intensity' |
| 276 | - */ |
| 277 | - get_intensity_listing: function() { |
| 278 | - mock_io = new Y.lp.testing.mockio.MockIo(); |
| 279 | +/* Copyright (c) 2012, Canonical Ltd. All rights reserved. */ |
| 280 | + |
| 281 | +YUI.add('lp.app.listing_navigator.test', function (Y) { |
| 282 | + var module = Y.lp.app.listing_navigator; |
| 283 | + |
| 284 | + /** |
| 285 | + * This is required in teardown to blank out the browser history which |
| 286 | + * gets pulled into the next text automatically. |
| 287 | + */ |
| 288 | + var reset_history = function () { |
| 289 | + var win = Y.config.win; |
| 290 | + var originalURL = (win && win.location.toString()) || ''; |
| 291 | + win.history.replaceState(null, null, originalURL); |
| 292 | + }; |
| 293 | + |
| 294 | + var TestListingNavigator = Y.Base.create('test-listing-navigator', |
| 295 | + module.ListingNavigator, [], { |
| 296 | + update_from_cache: function() { |
| 297 | + this.constructor.superclass.update_from_cache.apply(this, |
| 298 | + arguments); |
| 299 | + this.pre_fetch_batches(); |
| 300 | + this.render(); |
| 301 | + }, |
| 302 | + get_search_params: function(config) { |
| 303 | + return config.search_params; |
| 304 | + } |
| 305 | + }, {}); |
| 306 | + |
| 307 | + var get_navigator = function(url, config) { |
| 308 | + var mock_io = new Y.lp.testing.mockio.MockIo(); |
| 309 | + if (Y.Lang.isUndefined(url)){ |
| 310 | + url = ''; |
| 311 | + } |
| 312 | + if (Y.Lang.isUndefined(config)){ |
| 313 | + config = {}; |
| 314 | + } |
| 315 | + var target = config.target; |
| 316 | + if (!Y.Lang.isValue(target)){ |
| 317 | + var target_parent = Y.Node.create('<div></div>'); |
| 318 | + target = Y.Node.create('<div "id=#client-listing"></div>'); |
| 319 | + target_parent.appendChild(target); |
| 320 | + } |
| 321 | lp_cache = { |
| 322 | context: { |
| 323 | resource_type_link: 'http://foo_type', |
| 324 | web_link: 'http://foo/bar' |
| 325 | }, |
| 326 | view_name: '+items', |
| 327 | - mustache_model: { |
| 328 | - foo: 'bar', |
| 329 | - items: [] |
| 330 | - }, |
| 331 | - next: null, |
| 332 | - prev: null, |
| 333 | - field_visibility: {}, |
| 334 | - field_visibility_defaults: {} |
| 335 | - }; |
| 336 | - var navigator = new TestListingNavigator({ |
| 337 | - current_url: |
| 338 | - "http://yahoo.com?start=5&memo=6&direction=backwards", |
| 339 | - cache: lp_cache, |
| 340 | - template: "<ol>" + "{{#item}}<li>{{name}}</li>{{/item}}</ol>", |
| 341 | - target: this.target, |
| 342 | - io_provider: mock_io |
| 343 | - }); |
| 344 | - navigator.first_batch('intensity'); |
| 345 | - Y.Assert.areEqual('', navigator.get('target').getContent()); |
| 346 | - mock_io.last_request.successJSON({ |
| 347 | - context: { |
| 348 | - resource_type_link: 'http://foo_type', |
| 349 | - web_link: 'http://foo/bar' |
| 350 | - }, |
| 351 | - mustache_model: |
| 352 | - { |
| 353 | - item: [ |
| 354 | - {name: 'first'}, |
| 355 | - {name: 'second'}], |
| 356 | - items: [] |
| 357 | - }, |
| 358 | - order_by: 'intensity', |
| 359 | - start: 0, |
| 360 | - forwards: true, |
| 361 | - memo: null, |
| 362 | - next: null, |
| 363 | - prev: null |
| 364 | - }); |
| 365 | - return navigator; |
| 366 | - }, |
| 367 | - test_first_batch: function() { |
| 368 | - /* first_batch retrieves a listing for the new ordering and |
| 369 | - * displays it */ |
| 370 | - var navigator = this.get_intensity_listing(); |
| 371 | - var mock_io = navigator.get('io_provider'); |
| 372 | - Y.Assert.areEqual('<ol><li>first</li><li>second</li></ol>', |
| 373 | - navigator.get('target').getContent()); |
| 374 | - Y.Assert.areEqual('/bar/+items/++model++?orderby=intensity&start=0', |
| 375 | - mock_io.last_request.url); |
| 376 | - }, |
| 377 | - test_first_batch_uses_cache: function() { |
| 378 | - /* first_batch will use the cached value instead of making a |
| 379 | - * second AJAX request. */ |
| 380 | - var navigator = this.get_intensity_listing(); |
| 381 | - Y.Assert.areEqual(1, navigator.get('io_provider').requests.length); |
| 382 | - navigator.first_batch('intensity'); |
| 383 | - Y.Assert.areEqual(1, navigator.get('io_provider').requests.length); |
| 384 | - }, |
| 385 | - test_io_error: function() { |
| 386 | - var overlay_node; |
| 387 | - var navigator = this.get_intensity_listing(); |
| 388 | - navigator.first_batch('failure'); |
| 389 | - navigator.get('io_provider').failure(); |
| 390 | - overlay_node = Y.one('.yui3-lazr-formoverlay-errors'); |
| 391 | - Y.Assert.isTrue(Y.Lang.isValue(overlay_node)); |
| 392 | - } |
| 393 | -})); |
| 394 | - |
| 395 | -suite.add(new Y.Test.Case({ |
| 396 | - name: 'Batch caching', |
| 397 | - |
| 398 | - setUp: function() { |
| 399 | - this.target = Y.Node.create('<div></div>').set( |
| 400 | - 'id', 'client-listing'); |
| 401 | - Y.one('body').appendChild(this.target); |
| 402 | - }, |
| 403 | - |
| 404 | - tearDown: function() { |
| 405 | - this.target.remove(); |
| 406 | - delete this.target; |
| 407 | - }, |
| 408 | - |
| 409 | - test_update_from_new_model_caches: function() { |
| 410 | - /* update_from_new_model caches the settings in the module.batches. */ |
| 411 | - var lp_cache = { |
| 412 | - context: { |
| 413 | - resource_type_link: 'http://foo_type', |
| 414 | - web_link: 'http://foo/bar' |
| 415 | - }, |
| 416 | - mustache_model: { |
| 417 | - foo: 'bar' |
| 418 | - }, |
| 419 | - next: null, |
| 420 | - prev: null, |
| 421 | - field_visibility: {}, |
| 422 | - field_visibility_defaults: {} |
| 423 | - }; |
| 424 | - var template = "<ol>" + |
| 425 | - "{{#item}}<li>{{name}}</li>{{/item}}</ol>"; |
| 426 | - var navigator = new TestListingNavigator({ |
| 427 | - current_url: window.location, |
| 428 | - cache: lp_cache, |
| 429 | - template: template, |
| 430 | - target: this.target |
| 431 | - }); |
| 432 | - var key = module.get_batch_key({ |
| 433 | - order_by: "intensity", |
| 434 | - memo: 'memo1', |
| 435 | - forwards: true, |
| 436 | - start: 5, |
| 437 | - target: this.target |
| 438 | - }); |
| 439 | - var batch = { |
| 440 | - order_by: 'intensity', |
| 441 | - memo: 'memo1', |
| 442 | - forwards: true, |
| 443 | - start: 5, |
| 444 | - next: null, |
| 445 | - prev: null, |
| 446 | - mustache_model: { |
| 447 | - item: [ |
| 448 | - {name: 'first'}, |
| 449 | - {name: 'second'} |
| 450 | - ], |
| 451 | - items: ['a', 'b', 'c'] |
| 452 | - }}; |
| 453 | - var query = navigator.get_batch_query(batch); |
| 454 | - navigator.update_from_new_model(query, true, batch); |
| 455 | - Y.lp.testing.assert.assert_equal_structure( |
| 456 | - batch, navigator.get('batches')[key]); |
| 457 | - }, |
| 458 | - /** |
| 459 | - * get_batch_key returns a JSON-serialized list. |
| 460 | - */ |
| 461 | - test_get_batch_key: function() { |
| 462 | - var key = module.get_batch_key({ |
| 463 | - order_by: 'order_by1', |
| 464 | - memo: 'memo1', |
| 465 | - forwards: true, |
| 466 | - target: this.target, |
| 467 | - start: 5}); |
| 468 | - Y.Assert.areSame('["order_by1","memo1",true,5]', key); |
| 469 | - } |
| 470 | -})); |
| 471 | - |
| 472 | -suite.add(new Y.Test.Case({ |
| 473 | - name: 'get_query', |
| 474 | - |
| 475 | - test_get_query: function() { |
| 476 | - // get_query returns the query portion of a URL in structured form. |
| 477 | - var query = module.get_query('http://yahoo.com?me=you&a=b&a=c'); |
| 478 | - Y.lp.testing.assert.assert_equal_structure( |
| 479 | - {me: 'you', a: ['b', 'c']}, query); |
| 480 | - } |
| 481 | -})); |
| 482 | - |
| 483 | - |
| 484 | -suite.add(new Y.Test.Case({ |
| 485 | - name: 'get_batch_url', |
| 486 | - |
| 487 | - setUp: function() { |
| 488 | - this.target = Y.Node.create('<div></div>').set( |
| 489 | - 'id', 'client-listing'); |
| 490 | - Y.one('body').appendChild(this.target); |
| 491 | - }, |
| 492 | - |
| 493 | - tearDown: function() { |
| 494 | - this.target.remove(); |
| 495 | - delete this.target; |
| 496 | - }, |
| 497 | - |
| 498 | - /** |
| 499 | - * get_batch_query accepts the order_by param. |
| 500 | - */ |
| 501 | - test_get_batch_query_orderby: function() { |
| 502 | - var navigator = new TestListingNavigator({ |
| 503 | - search_params: { |
| 504 | - param: 1 |
| 505 | - }, |
| 506 | - target: this.target, |
| 507 | - cache: {next: null, prev: null} |
| 508 | - }); |
| 509 | - var query = navigator.get_batch_query({order_by: 'importance'}); |
| 510 | - Y.Assert.areSame('importance', query.orderby); |
| 511 | - Y.Assert.areSame(1, query.param); |
| 512 | - }, |
| 513 | - /** |
| 514 | - * get_batch_query accepts the memo param. |
| 515 | - */ |
| 516 | - test_get_batch_query_memo: function() { |
| 517 | - var navigator = new TestListingNavigator({ |
| 518 | - search_params: { |
| 519 | - param: 'foo' |
| 520 | - }, |
| 521 | - target: this.target, |
| 522 | - cache: {next: null, prev: null} |
| 523 | - }); |
| 524 | - var query = navigator.get_batch_query({memo: 'pi'}); |
| 525 | - Y.Assert.areSame('pi', query.memo); |
| 526 | - Y.Assert.areSame('foo', query.param); |
| 527 | - }, |
| 528 | - /** |
| 529 | - * When memo is null, query.memo is undefined. |
| 530 | - */ |
| 531 | - test_get_batch_null_memo: function() { |
| 532 | - var navigator = new TestListingNavigator({ |
| 533 | - search_params: {}, |
| 534 | - cache: {next: null, prev: null}, |
| 535 | - target: this.target |
| 536 | - }); |
| 537 | - var query = navigator.get_batch_query({memo: null}); |
| 538 | - Y.Assert.areSame(undefined, query.memo); |
| 539 | - }, |
| 540 | - /** |
| 541 | - * If 'forwards' is true, direction does not appear. |
| 542 | - */ |
| 543 | - test_get_batch_query_forwards: function() { |
| 544 | - var navigator = new TestListingNavigator({ |
| 545 | - search_params: { |
| 546 | - param: 'pi' |
| 547 | - }, |
| 548 | - cache: {next: null, prev: null}, |
| 549 | - target: this.target |
| 550 | - }); |
| 551 | - var query = navigator.get_batch_query({forwards: true}); |
| 552 | - Y.Assert.areSame('pi', query.param); |
| 553 | - Y.Assert.areSame(undefined, query.direction); |
| 554 | - }, |
| 555 | - /** |
| 556 | - * If 'forwards' is false, direction is set to backwards. |
| 557 | - */ |
| 558 | - test_get_batch_query_backwards: function() { |
| 559 | - var navigator = new TestListingNavigator({ |
| 560 | - search_params: { |
| 561 | - param: 'pi' |
| 562 | - }, |
| 563 | - cache: {next: null, prev: null}, |
| 564 | - target: this.target |
| 565 | - }); |
| 566 | - var query = navigator.get_batch_query({forwards: false}); |
| 567 | - Y.Assert.areSame('pi', query.param); |
| 568 | - Y.Assert.areSame('backwards', query.direction); |
| 569 | - }, |
| 570 | - /** |
| 571 | - * If start is provided, it overrides existing values. |
| 572 | - */ |
| 573 | - test_get_batch_query_start: function() { |
| 574 | - var navigator = new TestListingNavigator({ |
| 575 | - search_params: {}, |
| 576 | - cache: {next: null, prev:null}, |
| 577 | - target: this.target |
| 578 | - }); |
| 579 | - var query = navigator.get_batch_query({}); |
| 580 | - Y.Assert.areSame(undefined, query.start); |
| 581 | - query = navigator.get_batch_query({start: 1}); |
| 582 | - Y.Assert.areSame(1, query.start); |
| 583 | - query = navigator.get_batch_query({start: null}); |
| 584 | - Y.lp.testing.assert.assert_equal_structure({}, query); |
| 585 | - } |
| 586 | -})); |
| 587 | - |
| 588 | -var get_navigator = function(url, config) { |
| 589 | - var mock_io = new Y.lp.testing.mockio.MockIo(); |
| 590 | - if (Y.Lang.isUndefined(url)){ |
| 591 | - url = ''; |
| 592 | - } |
| 593 | - if (Y.Lang.isUndefined(config)){ |
| 594 | - config = {}; |
| 595 | - } |
| 596 | - var target = config.target; |
| 597 | - if (!Y.Lang.isValue(target)){ |
| 598 | - var target_parent = Y.Node.create('<div></div>'); |
| 599 | - target = Y.Node.create('<div "id=#client-listing"></div>'); |
| 600 | - target_parent.appendChild(target); |
| 601 | - } |
| 602 | - lp_cache = { |
| 603 | - context: { |
| 604 | - resource_type_link: 'http://foo_type', |
| 605 | - web_link: 'http://foo/bar' |
| 606 | - }, |
| 607 | - view_name: '+items', |
| 608 | - next: { |
| 609 | - memo: 467, |
| 610 | - start: 500 |
| 611 | - }, |
| 612 | - prev: { |
| 613 | - memo: 457, |
| 614 | - start: 400 |
| 615 | - }, |
| 616 | - forwards: true, |
| 617 | - order_by: 'foo', |
| 618 | - memo: 457, |
| 619 | - start: 450, |
| 620 | - last_start: 23, |
| 621 | - field_visibility: {}, |
| 622 | - field_visibility_defaults: {} |
| 623 | - }; |
| 624 | - if (config.no_next){ |
| 625 | - lp_cache.next = null; |
| 626 | - } |
| 627 | - if (config.no_prev){ |
| 628 | - lp_cache.prev = null; |
| 629 | - } |
| 630 | - var navigator_config = { |
| 631 | - current_url: url, |
| 632 | - cache: lp_cache, |
| 633 | - io_provider: mock_io, |
| 634 | - pre_fetch: config.pre_fetch, |
| 635 | - target: target, |
| 636 | - template: '' |
| 637 | - }; |
| 638 | - return new TestListingNavigator(navigator_config); |
| 639 | -}; |
| 640 | - |
| 641 | -suite.add(new Y.Test.Case({ |
| 642 | - name: 'navigation', |
| 643 | - |
| 644 | - setUp: function() { |
| 645 | - this.target = Y.Node.create('<div></div>').set( |
| 646 | - 'id', 'client-listing'); |
| 647 | - Y.one('body').appendChild(this.target); |
| 648 | - }, |
| 649 | - |
| 650 | - tearDown: function() { |
| 651 | - this.target.remove(); |
| 652 | - delete this.target; |
| 653 | - }, |
| 654 | - |
| 655 | - test_model_uses_view_name: function() { |
| 656 | - var navigator = get_navigator('', {target: this.target}); |
| 657 | - navigator.get_current_batch().view_name = '+funitems'; |
| 658 | - navigator.load_model({}); |
| 659 | - Y.Assert.areSame( |
| 660 | - '/bar/+funitems/++model++', |
| 661 | - navigator.get('io_provider').last_request.url); |
| 662 | - }, |
| 663 | - |
| 664 | - /** |
| 665 | - * last_batch uses memo="", start=navigator.current_batch.last_start, |
| 666 | - * direction=backwards, orderby=navigator.current_batch.order_by. |
| 667 | - */ |
| 668 | - test_last_batch: function() { |
| 669 | - var navigator = get_navigator( |
| 670 | - '?memo=pi&direction=backwards&start=57', {target: this.target}); |
| 671 | - navigator.last_batch(); |
| 672 | - Y.Assert.areSame( |
| 673 | - '/bar/+items/++model++?orderby=foo&memo=&start=23&' + |
| 674 | - 'direction=backwards', |
| 675 | - navigator.get('io_provider').last_request.url); |
| 676 | - }, |
| 677 | - |
| 678 | - /** |
| 679 | - * first_batch omits memo and direction, start=0, |
| 680 | - * orderby=navigator.current_batch.order_by. |
| 681 | - */ |
| 682 | - test_first_batch: function() { |
| 683 | - var navigator = get_navigator( |
| 684 | - '?memo=pi&start=26', {target: this.target}); |
| 685 | - navigator.first_batch(); |
| 686 | - Y.Assert.areSame( |
| 687 | - '/bar/+items/++model++?orderby=foo&start=0', |
| 688 | - navigator.get('io_provider').last_request.url); |
| 689 | - }, |
| 690 | - |
| 691 | - /** |
| 692 | - * next_batch uses values from current_batch.next + |
| 693 | - * current_batch.ordering. |
| 694 | - */ |
| 695 | - test_next_batch: function() { |
| 696 | - var navigator = get_navigator( |
| 697 | - '?memo=pi&start=26', {target: this.target}); |
| 698 | - navigator.next_batch(); |
| 699 | - Y.Assert.areSame( |
| 700 | - '/bar/+items/++model++?orderby=foo&memo=467&start=500', |
| 701 | - navigator.get('io_provider').last_request.url); |
| 702 | - }, |
| 703 | - |
| 704 | - /** |
| 705 | - * Calling next_batch when there is none is a no-op. |
| 706 | - */ |
| 707 | - test_next_batch_missing: function() { |
| 708 | - var navigator = get_navigator( |
| 709 | - '?memo=pi&start=26', {no_next: true, target: this.target}); |
| 710 | - navigator.next_batch(); |
| 711 | - Y.Assert.areSame( |
| 712 | - null, navigator.get('io_provider').last_request); |
| 713 | - }, |
| 714 | - |
| 715 | - /** |
| 716 | - * prev_batch uses values from current_batch.prev + direction=backwards |
| 717 | - * and ordering=current_batch.ordering. |
| 718 | - */ |
| 719 | - test_prev_batch: function() { |
| 720 | - var navigator = get_navigator( |
| 721 | - '?memo=pi&start=26', {target: this.target}); |
| 722 | - navigator.prev_batch(); |
| 723 | - Y.Assert.areSame( |
| 724 | - '/bar/+items/++model++?orderby=foo&memo=457&start=400&' + |
| 725 | - 'direction=backwards', |
| 726 | - navigator.get('io_provider').last_request.url); |
| 727 | - }, |
| 728 | - |
| 729 | - /** |
| 730 | - * Calling prev_batch when there is none is a no-op. |
| 731 | - */ |
| 732 | - test_prev_batch_missing: function() { |
| 733 | - var navigator = get_navigator( |
| 734 | - '?memo=pi&start=26', |
| 735 | - {no_prev: true, no_next: true, target: this.target}); |
| 736 | - navigator.prev_batch(); |
| 737 | - Y.Assert.areSame( |
| 738 | - null, navigator.get('io_provider').last_request); |
| 739 | - }, |
| 740 | - |
| 741 | - /** |
| 742 | - * Verify we get a reasonable default context if there is no context |
| 743 | - * available as is the case with the BugsBugTaskSearchListingView. |
| 744 | - */ |
| 745 | - test_default_context: function () { |
| 746 | - var navigator = get_navigator('', {target: this.target}); |
| 747 | - // now remove the context |
| 748 | - var batch = navigator.get_current_batch(); |
| 749 | - delete batch.context; |
| 750 | - |
| 751 | - navigator.get_current_batch().view_name = '+funitems'; |
| 752 | - navigator.load_model({}); |
| 753 | - |
| 754 | - // the start of the url used will be whatever the current |
| 755 | - // location.href is for the window object. We can make sure we did get |
| 756 | - // a nicely generated url though by checking they end built correctly. |
| 757 | - var generated_url = navigator.get('io_provider').last_request.url; |
| 758 | - |
| 759 | - Y.Assert.areSame( |
| 760 | - '+funitems/++model++', |
| 761 | - generated_url.substr(generated_url.indexOf('+'))); |
| 762 | - } |
| 763 | - |
| 764 | -})); |
| 765 | - |
| 766 | -suite.add(new Y.Test.Case({ |
| 767 | - name: "pre-fetching batches", |
| 768 | - setUp: function() { |
| 769 | - this.target = Y.Node.create('<div></div>').set( |
| 770 | - 'id', 'client-listing'); |
| 771 | - Y.one('body').appendChild(this.target); |
| 772 | - }, |
| 773 | - tearDown: function() { |
| 774 | - this.target.remove(); |
| 775 | - delete this.target; |
| 776 | - }, |
| 777 | - /** |
| 778 | - * get_pre_fetch_configs should return a config for the next batch. |
| 779 | - */ |
| 780 | - test_get_pre_fetch_configs: function() { |
| 781 | - var navigator = get_navigator('', {target: this.target}); |
| 782 | - var configs = navigator.get_pre_fetch_configs(); |
| 783 | - var batch_keys = []; |
| 784 | - Y.each(configs, function(value) { |
| 785 | - batch_keys.push(module.get_batch_key(value)); |
| 786 | - }); |
| 787 | - Y.Assert.areSame('["foo",467,true,500]', batch_keys[0]); |
| 788 | - Y.Assert.areSame(1, batch_keys.length); |
| 789 | - }, |
| 790 | - |
| 791 | - /** |
| 792 | - * get_pre_fetch_configs should return an empty list if no next batch. |
| 793 | - */ |
| 794 | - test_get_pre_fetch_configs_no_next: function() { |
| 795 | - var navigator = get_navigator( |
| 796 | - '', {no_next: true, target: this.target}); |
| 797 | - var configs = navigator.get_pre_fetch_configs(); |
| 798 | - var batch_keys = []; |
| 799 | - Y.each(configs, function(value) { |
| 800 | - batch_keys.push(module.get_batch_key(value)); |
| 801 | - }); |
| 802 | - Y.Assert.areSame(0, batch_keys.length); |
| 803 | - }, |
| 804 | - |
| 805 | - get_pre_fetch_navigator: function(config) { |
| 806 | - var navigator = get_navigator('', config); |
| 807 | - var batch = navigator.get_current_batch(); |
| 808 | - batch.next = {memo: 57, start: 56}; |
| 809 | - batch.order_by = ''; |
| 810 | - return navigator; |
| 811 | - }, |
| 812 | - |
| 813 | - /** |
| 814 | - * Calling pre_fetch_batches should produce a request for the next batch. |
| 815 | - */ |
| 816 | - test_pre_fetch_batches: function() { |
| 817 | - var navigator = this.get_pre_fetch_navigator({target: this.target}); |
| 818 | - var io_provider = navigator.get('io_provider'); |
| 819 | - navigator.set('pre_fetch', true); |
| 820 | - Y.Assert.isNull(io_provider.last_request); |
| 821 | - navigator.pre_fetch_batches(); |
| 822 | - Y.Assert.areSame( |
| 823 | - io_provider.last_request.url, |
| 824 | - '/bar/+items/++model++?orderby=&memo=57&start=56'); |
| 825 | - }, |
| 826 | - |
| 827 | - /** |
| 828 | - * Calling pre_fetch_batches should not produce a request for the next |
| 829 | - * batch if Navigator.get('pre_fetch') is false. |
| 830 | - */ |
| 831 | - test_pre_fetch_disabled: function() { |
| 832 | - var last_url; |
| 833 | - var navigator = this.get_pre_fetch_navigator({target: this.target}); |
| 834 | - navigator.pre_fetch_batches(); |
| 835 | - Y.Assert.areSame(null, navigator.get('io_provider').last_request); |
| 836 | - }, |
| 837 | - |
| 838 | - /** |
| 839 | - * Initialization does a pre-fetch. |
| 840 | - */ |
| 841 | - test_pre_fetch_on_init: function() { |
| 842 | - var navigator = get_navigator( |
| 843 | - '', {pre_fetch: true, target:this.target}); |
| 844 | - var last_url = navigator.get('io_provider').last_request.url; |
| 845 | - Y.Assert.areSame( |
| 846 | - last_url, |
| 847 | - '/bar/+items/++model++?orderby=foo&memo=467&start=500'); |
| 848 | - }, |
| 849 | - /** |
| 850 | - * update_from_new_model does a pre-fetch. |
| 851 | - */ |
| 852 | - test_pre_fetch_on_update_from_new_model: function() { |
| 853 | - var navigator = get_navigator('', {target: this.target}); |
| 854 | - var io_provider = navigator.get('io_provider'); |
| 855 | - var lp_client = new Y.lp.client.Launchpad(); |
| 856 | - var batch = lp_client.wrap_resource(null, { |
| 857 | - context: { |
| 858 | - resource_type_link: 'http://foo_type', |
| 859 | - web_link: 'http://foo/bar' |
| 860 | - }, |
| 861 | - view_name: '+items', |
| 862 | - order_by: 'baz', |
| 863 | - memo: 'memo1', |
| 864 | - next: { |
| 865 | - memo: "pi", |
| 866 | - start: 314 |
| 867 | - }, |
| 868 | - prev: null, |
| 869 | - forwards: true, |
| 870 | - start: 5, |
| 871 | - mustache_model: { |
| 872 | - item: [ |
| 873 | - {name: 'first'}, |
| 874 | - {name: 'second'} |
| 875 | - ], |
| 876 | - items: ['a', 'b', 'c'] |
| 877 | - }}); |
| 878 | - Y.Assert.isNull(io_provider.last_request); |
| 879 | - navigator.set('pre_fetch', true); |
| 880 | - navigator.update_from_new_model({}, false, batch); |
| 881 | - Y.Assert.areSame( |
| 882 | - io_provider.last_request.url, |
| 883 | - '/bar/+items/++model++?orderby=baz&memo=pi&start=314'); |
| 884 | - } |
| 885 | -})); |
| 886 | - |
| 887 | - |
| 888 | -suite.add(new Y.Test.Case({ |
| 889 | - name: "Test indicators", |
| 890 | - |
| 891 | - /** |
| 892 | - * Update starts showing the pending indicator |
| 893 | - */ |
| 894 | - test_show_on_update: function() { |
| 895 | - var navigator = get_navigator(); |
| 896 | - navigator.update({}); |
| 897 | - Y.Assert.isTrue(navigator.indicator.get('visible')); |
| 898 | - }, |
| 899 | - /** |
| 900 | - * A fetch-only update starts ignores the pending indicator |
| 901 | - */ |
| 902 | - test_ignore_on_fetch_only_update: function() { |
| 903 | - var navigator = get_navigator(); |
| 904 | - navigator.update({fetch_only: true}); |
| 905 | - Y.Assert.isFalse(navigator.indicator.get('visible')); |
| 906 | - }, |
| 907 | - /** |
| 908 | - * A successful IO operation clears the pending indicator. |
| 909 | - */ |
| 910 | - test_hide_on_success: function() { |
| 911 | - var navigator = get_navigator(); |
| 912 | - navigator.update({}); |
| 913 | - navigator.get('io_provider').last_request.successJSON({ |
| 914 | - mustache_model: {items: []}, |
| 915 | - next: null, |
| 916 | - prev: null |
| 917 | - }); |
| 918 | - Y.Assert.isFalse(navigator.indicator.get('visible')); |
| 919 | - }, |
| 920 | - /** |
| 921 | - * A successful fetch-only IO operation ignores the pending indicator. |
| 922 | - */ |
| 923 | - test_no_hide_on_fetch_only_success: function() { |
| 924 | - var navigator = get_navigator(); |
| 925 | - navigator.indicator.setBusy(); |
| 926 | - navigator.update({fetch_only: true}); |
| 927 | - navigator.get('io_provider').last_request.successJSON({ |
| 928 | - mustache_model: {items: []}, |
| 929 | - next: null, |
| 930 | - prev: null |
| 931 | - }); |
| 932 | - Y.Assert.isTrue(navigator.indicator.get('visible')); |
| 933 | - }, |
| 934 | - /** |
| 935 | - * A failed IO operation hides the pending indicator. |
| 936 | - */ |
| 937 | - test_hide_on_failure: function() { |
| 938 | - var navigator = get_navigator(); |
| 939 | - navigator.update({}); |
| 940 | - navigator.get('io_provider').failure(); |
| 941 | - Y.Assert.isFalse(navigator.indicator.get('visible')); |
| 942 | - }, |
| 943 | - /** |
| 944 | - * A failed fetch-only IO operation does not hide the pending indicator. |
| 945 | - */ |
| 946 | - test_no_hide_on_fetch_only_failure: function() { |
| 947 | - var navigator = get_navigator(); |
| 948 | - navigator.indicator.setBusy(); |
| 949 | - navigator.update({fetch_only: true}); |
| 950 | - navigator.get('io_provider').failure(); |
| 951 | - Y.Assert.isTrue(navigator.indicator.get('visible')); |
| 952 | - } |
| 953 | -})); |
| 954 | - |
| 955 | - |
| 956 | -suite.add(new Y.Test.Case({ |
| 957 | - name: "Find batch aliases", |
| 958 | - |
| 959 | - test_get_batch_key_list: function() { |
| 960 | - var keys = module.get_batch_key_list({ |
| 961 | - prev: null, |
| 962 | - next:null, |
| 963 | - memo: 'pi', |
| 964 | - start: -1, |
| 965 | - forwards: true, |
| 966 | - order_by: 'ordering' |
| 967 | - }); |
| 968 | - Y.ArrayAssert.itemsAreSame( |
| 969 | - [null, '["ordering","pi",true,-1]', null], keys); |
| 970 | - keys = module.get_batch_key_list({ |
| 971 | - prev: { |
| 972 | - memo: "pi", |
| 973 | - start: -2 |
| 974 | - }, |
| 975 | - next: { |
| 976 | - memo: "e", |
| 977 | - start: 0 |
| 978 | - }, |
| 979 | - memo: 'pi', |
| 980 | - start: -1, |
| 981 | - forwards: true, |
| 982 | - order_by: 'ordering' |
| 983 | - }); |
| 984 | - Y.ArrayAssert.itemsAreSame([ |
| 985 | - '["ordering","pi",false,-2]', |
| 986 | - '["ordering","pi",true,-1]', |
| 987 | - '["ordering","e",true,0]'], keys); |
| 988 | - }, |
| 989 | - |
| 990 | - /* Detect batch aliases for forward movement (next). */ |
| 991 | - test_find_batch_alias_moving_forward: function() { |
| 992 | - var prev_batch = ['a', 'b', 'c']; |
| 993 | - var next_batch = ["b'", 'c', 'd']; |
| 994 | - var result = module.find_batch_alias(prev_batch, next_batch); |
| 995 | - Y.Assert.areSame(result[0], 'b'); |
| 996 | - Y.Assert.areSame(result[1], "b'"); |
| 997 | - result = module.find_batch_alias(next_batch, prev_batch); |
| 998 | - Y.Assert.areSame(result[0], 'b'); |
| 999 | - Y.Assert.areSame(result[1], "b'"); |
| 1000 | - }, |
| 1001 | - |
| 1002 | - /* Detect batch aliases for backward movement (prev). */ |
| 1003 | - test_find_batch_alias_moving_backward: function() { |
| 1004 | - var prev_batch = ['a', 'b', 'c']; |
| 1005 | - var next_batch = ['b', "c'", 'd']; |
| 1006 | - var result = module.find_batch_alias(prev_batch, next_batch); |
| 1007 | - Y.Assert.areSame(result[0], 'c'); |
| 1008 | - Y.Assert.areSame(result[1], "c'"); |
| 1009 | - result = module.find_batch_alias(next_batch, prev_batch); |
| 1010 | - Y.Assert.areSame(result[0], 'c'); |
| 1011 | - Y.Assert.areSame(result[1], "c'"); |
| 1012 | - }, |
| 1013 | - |
| 1014 | - /* Do not detect aliases if batches are unrelated */ |
| 1015 | - test_find_batch_alias_unrelated: function() { |
| 1016 | - var prev_batch = ['a', 'b', 'c']; |
| 1017 | - var next_batch = ['d', 'e', 'f']; |
| 1018 | - var result = module.find_batch_alias(next_batch, prev_batch); |
| 1019 | - Y.Assert.isNull(result); |
| 1020 | - }, |
| 1021 | - |
| 1022 | - /** |
| 1023 | - * When dealias_batches is called on the next batch, the current batch is |
| 1024 | - * re-added to the batches mapping, under its alias from the next batch. |
| 1025 | - */ |
| 1026 | - test_dealias_batches_next: function() { |
| 1027 | - var navigator = get_navigator(); |
| 1028 | - var next_batch = { |
| 1029 | - memo: 467, |
| 1030 | - start: 500, |
| 1031 | - order_by: 'foo', |
| 1032 | - forwards: true, |
| 1033 | - prev: { |
| 1034 | - memo: 467, |
| 1035 | - start: 450 |
| 1036 | - }, |
| 1037 | - next: null |
| 1038 | - }; |
| 1039 | - var prev_batch_config = module.prev_batch_config(next_batch); |
| 1040 | - var prev_batch_key = module.get_batch_key( |
| 1041 | - prev_batch_config); |
| 1042 | - navigator.dealias_batches(next_batch); |
| 1043 | - Y.Assert.areSame( |
| 1044 | - navigator.get('batches')[prev_batch_key], |
| 1045 | - navigator.get_current_batch() |
| 1046 | - ); |
| 1047 | - Y.Assert.areNotSame( |
| 1048 | - prev_batch_key, navigator.get('model').get_batch_key()); |
| 1049 | - }, |
| 1050 | - /** |
| 1051 | - * When dealias_batches is called on the previous batch, the current batch |
| 1052 | - * is re-added to the batches mapping, under its alias from the previous |
| 1053 | - * batch. |
| 1054 | - */ |
| 1055 | - test_dealias_batches_prev: function() { |
| 1056 | - var navigator = get_navigator(); |
| 1057 | - var prev_batch = { |
| 1058 | - memo: 457, |
| 1059 | - start: 400, |
| 1060 | - order_by: 'foo', |
| 1061 | - forwards: false, |
| 1062 | - next: { |
| 1063 | - memo: 467, |
| 1064 | - start: 450 |
| 1065 | - }, |
| 1066 | - prev: null |
| 1067 | - }; |
| 1068 | - var next_batch_config = module.next_batch_config(prev_batch); |
| 1069 | - var next_batch_key = module.get_batch_key( |
| 1070 | - next_batch_config); |
| 1071 | - navigator.dealias_batches(prev_batch); |
| 1072 | - Y.Assert.areSame( |
| 1073 | - navigator.get('batches')[next_batch_key], |
| 1074 | - navigator.get_current_batch() |
| 1075 | - ); |
| 1076 | - Y.Assert.areNotSame( |
| 1077 | - next_batch_key, navigator.get('model').get_batch_key()); |
| 1078 | - } |
| 1079 | -})); |
| 1080 | - |
| 1081 | -var TestListingNavigatorWithHistory = function() { |
| 1082 | - this.constructor.superclass.constructor.apply(this, arguments); |
| 1083 | -}; |
| 1084 | - |
| 1085 | -suite.add(new Y.Test.Case({ |
| 1086 | - name: 'browser history', |
| 1087 | - |
| 1088 | - setUp: function() { |
| 1089 | - this.target = Y.Node.create('<div></div>').set( |
| 1090 | - 'id', 'client-listing'); |
| 1091 | - Y.one('body').appendChild(this.target); |
| 1092 | - }, |
| 1093 | - |
| 1094 | - tearDown: function() { |
| 1095 | - this.target.remove(); |
| 1096 | - delete this.target; |
| 1097 | - }, |
| 1098 | - |
| 1099 | - /** |
| 1100 | - * Update from cache generates a change event for the specified batch. |
| 1101 | - */ |
| 1102 | - test_update_from_cache_generates_event: function() { |
| 1103 | - var navigator = get_navigator('', {target: this.target}); |
| 1104 | - var e = null; |
| 1105 | - navigator.get('model').get('history').on('change', function(inner_e) { |
| 1106 | - e = inner_e; |
| 1107 | - }); |
| 1108 | - navigator.get('batches')['some-batch-key'] = { |
| 1109 | - mustache_model: { |
| 1110 | - items: [] |
| 1111 | - }, |
| 1112 | - next: null, |
| 1113 | - prev: null |
| 1114 | - }; |
| 1115 | - navigator.update_from_cache({foo: 'bar'}, 'some-batch-key'); |
| 1116 | - Y.Assert.areEqual('some-batch-key', e.newVal.batch_key); |
| 1117 | - Y.Assert.areEqual('?foo=bar', e._options.url); |
| 1118 | - }, |
| 1119 | - |
| 1120 | - /** |
| 1121 | - * When a change event is emitted, the relevant batch becomes the current |
| 1122 | - * batch and is rendered. |
| 1123 | - */ |
| 1124 | - test_change_event_renders_cache: function() { |
| 1125 | - var navigator = get_navigator('', {target: this.target}); |
| 1126 | - var batch = { |
| 1127 | - mustache_model: { |
| 1128 | - items: [], |
| 1129 | - foo: 'bar' |
| 1130 | - }, |
| 1131 | - next: null, |
| 1132 | - prev: null |
| 1133 | - }; |
| 1134 | - navigator.set('template', '{{foo}}'); |
| 1135 | - navigator.get('batches')['some-batch-key'] = batch; |
| 1136 | - navigator.get('model').get('history').addValue( |
| 1137 | - 'batch_key', 'some-batch-key'); |
| 1138 | - Y.Assert.areEqual(batch, navigator.get_current_batch()); |
| 1139 | - Y.Assert.areEqual('bar', navigator.get('target').getContent()); |
| 1140 | - } |
| 1141 | -})); |
| 1142 | - |
| 1143 | - |
| 1144 | -var handle_complete = function(data) { |
| 1145 | - window.status = '::::' + JSON.stringify(data); |
| 1146 | - }; |
| 1147 | -Y.Test.Runner.on('complete', handle_complete); |
| 1148 | -Y.Test.Runner.add(suite); |
| 1149 | - |
| 1150 | -var console = new Y.Console({newestOnTop: false}); |
| 1151 | -console.render('#log'); |
| 1152 | - |
| 1153 | -Y.on('domready', function() { |
| 1154 | - Y.Test.Runner.run(); |
| 1155 | -}); |
| 1156 | + next: { |
| 1157 | + memo: 467, |
| 1158 | + start: 500 |
| 1159 | + }, |
| 1160 | + prev: { |
| 1161 | + memo: 457, |
| 1162 | + start: 400 |
| 1163 | + }, |
| 1164 | + forwards: true, |
| 1165 | + order_by: 'foo', |
| 1166 | + memo: 457, |
| 1167 | + start: 450, |
| 1168 | + last_start: 23, |
| 1169 | + field_visibility: {}, |
| 1170 | + field_visibility_defaults: {} |
| 1171 | + }; |
| 1172 | + if (config.no_next){ |
| 1173 | + lp_cache.next = null; |
| 1174 | + } |
| 1175 | + if (config.no_prev){ |
| 1176 | + lp_cache.prev = null; |
| 1177 | + } |
| 1178 | + var navigator_config = { |
| 1179 | + current_url: url, |
| 1180 | + cache: lp_cache, |
| 1181 | + io_provider: mock_io, |
| 1182 | + pre_fetch: config.pre_fetch, |
| 1183 | + target: target, |
| 1184 | + template: '' |
| 1185 | + }; |
| 1186 | + return new TestListingNavigator(navigator_config); |
| 1187 | + }; |
| 1188 | + |
| 1189 | + |
| 1190 | + var tests = Y.namespace('lp.app.listing_navigator.test'); |
| 1191 | + tests.suite = new Y.Test.Suite('Listing Navigator Tests'); |
| 1192 | + |
| 1193 | + tests.suite.add(new Y.Test.Case({ |
| 1194 | + name: 'render', |
| 1195 | + |
| 1196 | + setUp: function() { |
| 1197 | + this.target = Y.Node.create('<div></div>').set( |
| 1198 | + 'id', 'client-listing'); |
| 1199 | + Y.one('body').appendChild(this.target); |
| 1200 | + }, |
| 1201 | + |
| 1202 | + tearDown: function() { |
| 1203 | + Y.one('#fixture').setContent(''); |
| 1204 | + this.target.remove(); |
| 1205 | + delete this.target; |
| 1206 | + reset_history(); |
| 1207 | + }, |
| 1208 | + |
| 1209 | + get_render_navigator: function() { |
| 1210 | + var lp_cache = { |
| 1211 | + mustache_model: { |
| 1212 | + items: [{foo: 'bar', show_foo: true}] |
| 1213 | + }, |
| 1214 | + next: null, |
| 1215 | + prev: null, |
| 1216 | + start: 5, |
| 1217 | + total: 256, |
| 1218 | + field_visibility: {show_foo: true}, |
| 1219 | + field_visibility_defaults: {show_foo: false} |
| 1220 | + }; |
| 1221 | + var template = "{{#items}}{{#show_foo}}{{foo}}{{/show_foo}}" + |
| 1222 | + "{{/items}}"; |
| 1223 | + var navigator = new TestListingNavigator({ |
| 1224 | + cache: lp_cache, |
| 1225 | + template: template, |
| 1226 | + target: this.target |
| 1227 | + }); |
| 1228 | + var index = Y.Node.create( |
| 1229 | + '<div><strong>3</strong> → <strong>4</strong>' + |
| 1230 | + ' of 512 results</div>'); |
| 1231 | + navigator.get('navigation_indices').push(index); |
| 1232 | + navigator.get('backwards_navigation').push( |
| 1233 | + Y.Node.create('<div></div>')); |
| 1234 | + navigator.get('forwards_navigation').push( |
| 1235 | + Y.Node.create('<div></div>')); |
| 1236 | + return navigator; |
| 1237 | + }, |
| 1238 | + test_render: function() { |
| 1239 | + // Rendering should work with #client-listing supplied. |
| 1240 | + var navigator = this.get_render_navigator(); |
| 1241 | + navigator.render(); |
| 1242 | + Y.Assert.areEqual('bar', navigator.get('target').getContent()); |
| 1243 | + }, |
| 1244 | + /** |
| 1245 | + * update_navigation_links should disable "previous" and "first" if |
| 1246 | + * there is no previous batch (i.e. we're at the beginning.) |
| 1247 | + */ |
| 1248 | + test_update_navigation_links_disables_backwards_navigation_if_no_prev: |
| 1249 | + function() { |
| 1250 | + var navigator = this.get_render_navigator(); |
| 1251 | + var action = navigator.get('backwards_navigation').item(0); |
| 1252 | + navigator.update_navigation_links(); |
| 1253 | + Y.Assert.isTrue(action.hasClass('inactive')); |
| 1254 | + }, |
| 1255 | + /** |
| 1256 | + * update_navigation_links should enable "previous" and "first" if |
| 1257 | + * there is a previous batch (i.e. we're not at the beginning.) |
| 1258 | + */ |
| 1259 | + test_update_navigation_links_enables_backwards_navigation_if_prev: |
| 1260 | + function() { |
| 1261 | + var navigator = this.get_render_navigator(); |
| 1262 | + var action = navigator.get('backwards_navigation').item(0); |
| 1263 | + action.addClass('inactive'); |
| 1264 | + navigator.get_current_batch().prev = { |
| 1265 | + start: 1, memo: 'pi' |
| 1266 | + }; |
| 1267 | + navigator.update_navigation_links(); |
| 1268 | + Y.Assert.isFalse(action.hasClass('inactive')); |
| 1269 | + }, |
| 1270 | + /** |
| 1271 | + * update_navigation_links should disable "next" and "last" if there is |
| 1272 | + * no next batch (i.e. we're at the end.) |
| 1273 | + */ |
| 1274 | + test_update_navigation_links_disables_forwards_navigation_if_no_next: |
| 1275 | + function() { |
| 1276 | + var navigator = this.get_render_navigator(); |
| 1277 | + var action = navigator.get('forwards_navigation').item(0); |
| 1278 | + navigator.update_navigation_links(); |
| 1279 | + Y.Assert.isTrue(action.hasClass('inactive')); |
| 1280 | + }, |
| 1281 | + /** |
| 1282 | + * update_navigation_links should enable "next" and "last" if there is a |
| 1283 | + * next batch (i.e. we're not at the end.) |
| 1284 | + */ |
| 1285 | + test_update_navigation_links_enables_forwards_navigation_if_next: |
| 1286 | + function() { |
| 1287 | + var navigator = this.get_render_navigator(); |
| 1288 | + var action = navigator.get('forwards_navigation').item(0); |
| 1289 | + action.addClass('inactive'); |
| 1290 | + navigator.get_current_batch().next = { |
| 1291 | + start: 1, memo: 'pi' |
| 1292 | + }; |
| 1293 | + navigator.update_navigation_links(); |
| 1294 | + Y.Assert.isFalse(action.hasClass('inactive')); |
| 1295 | + }, |
| 1296 | + /** |
| 1297 | + * linkify_navigation should convert previous, next, first last into |
| 1298 | + * hyperlinks, while retaining the original content. |
| 1299 | + */ |
| 1300 | + test_linkify_navigation: function() { |
| 1301 | + Y.one('#fixture').setContent( |
| 1302 | + '<span class="previous">PreVious</span>' + |
| 1303 | + '<span class="next">NeXt</span>' + |
| 1304 | + '<span class="first">FiRST</span>' + |
| 1305 | + '<span class="last">lAst</span>'); |
| 1306 | + module.linkify_navigation(); |
| 1307 | + function checkNav(selector, content) { |
| 1308 | + var node = Y.one(selector); |
| 1309 | + Y.Assert.areEqual('a', node.get('tagName').toLowerCase()); |
| 1310 | + Y.Assert.areEqual(content, node.getContent()); |
| 1311 | + Y.Assert.areEqual('#', node.get('href').substr(-1, 1)); |
| 1312 | + } |
| 1313 | + checkNav('.previous', 'PreVious'); |
| 1314 | + checkNav('.next', 'NeXt'); |
| 1315 | + checkNav('.first', 'FiRST'); |
| 1316 | + checkNav('.last', 'lAst'); |
| 1317 | + }, |
| 1318 | + /** |
| 1319 | + * Render should update the navigation_indices with the result info. |
| 1320 | + */ |
| 1321 | + test_update_navigation_links_indices: function() { |
| 1322 | + var navigator = this.get_render_navigator(); |
| 1323 | + var index = navigator.get('navigation_indices').item(0); |
| 1324 | + Y.Assert.areEqual( |
| 1325 | + '<strong>3</strong> \u2192 <strong>4</strong> of 512 results', |
| 1326 | + index.getContent()); |
| 1327 | + navigator.render(); |
| 1328 | + Y.Assert.areEqual( |
| 1329 | + '<strong>6</strong> \u2192 <strong>6</strong> of 256 results', |
| 1330 | + index.getContent()); |
| 1331 | + } |
| 1332 | + })); |
| 1333 | + |
| 1334 | + tests.suite.add(new Y.Test.Case({ |
| 1335 | + name: 'first_batch', |
| 1336 | + |
| 1337 | + setUp: function() { |
| 1338 | + this.target = Y.Node.create('<div></div>').set( |
| 1339 | + 'id', 'client-listing'); |
| 1340 | + Y.one('body').appendChild(this.target); |
| 1341 | + console.log('setup', Y.config.win.history.state); |
| 1342 | + Y.config.win.history.state = {}; |
| 1343 | + }, |
| 1344 | + |
| 1345 | + tearDown: function() { |
| 1346 | + this.target.remove(); |
| 1347 | + delete this.target; |
| 1348 | + reset_history(); |
| 1349 | + }, |
| 1350 | + |
| 1351 | + /** |
| 1352 | + * Return a ListingNavigator ordered by 'intensity' |
| 1353 | + */ |
| 1354 | + get_intensity_listing: function() { |
| 1355 | + mock_io = new Y.lp.testing.mockio.MockIo(); |
| 1356 | + lp_cache = { |
| 1357 | + context: { |
| 1358 | + resource_type_link: 'http://foo_type', |
| 1359 | + web_link: 'http://foo/bar' |
| 1360 | + }, |
| 1361 | + view_name: '+items', |
| 1362 | + mustache_model: { |
| 1363 | + foo: 'bar', |
| 1364 | + items: [] |
| 1365 | + }, |
| 1366 | + next: null, |
| 1367 | + prev: null, |
| 1368 | + field_visibility: {}, |
| 1369 | + field_visibility_defaults: {} |
| 1370 | + }; |
| 1371 | + |
| 1372 | + var navigator = new TestListingNavigator({ |
| 1373 | + current_url: |
| 1374 | + "http://yahoo.com?start=5&memo=6&direction=backwards", |
| 1375 | + cache: lp_cache, |
| 1376 | + template: "<ol>" + "{{#item}}<li>{{name}}</li>{{/item}}</ol>", |
| 1377 | + target: this.target, |
| 1378 | + io_provider: mock_io |
| 1379 | + }); |
| 1380 | + navigator.first_batch('intensity'); |
| 1381 | + Y.Assert.areEqual('', navigator.get('target').getContent()); |
| 1382 | + mock_io.last_request.successJSON({ |
| 1383 | + context: { |
| 1384 | + resource_type_link: 'http://foo_type', |
| 1385 | + web_link: 'http://foo/bar' |
| 1386 | + }, |
| 1387 | + mustache_model: |
| 1388 | + { |
| 1389 | + item: [ |
| 1390 | + {name: 'first'}, |
| 1391 | + {name: 'second'}], |
| 1392 | + items: [] |
| 1393 | + }, |
| 1394 | + order_by: 'intensity', |
| 1395 | + start: 0, |
| 1396 | + forwards: true, |
| 1397 | + memo: null, |
| 1398 | + next: null, |
| 1399 | + prev: null |
| 1400 | + }); |
| 1401 | + return navigator; |
| 1402 | + }, |
| 1403 | + |
| 1404 | + test_first_batch: function() { |
| 1405 | + /* first_batch retrieves a listing for the new ordering and |
| 1406 | + * displays it */ |
| 1407 | + var navigator = this.get_intensity_listing(); |
| 1408 | + var mock_io = navigator.get('io_provider'); |
| 1409 | + Y.Assert.areEqual('<ol><li>first</li><li>second</li></ol>', |
| 1410 | + navigator.get('target').getContent()); |
| 1411 | + Y.Assert.areEqual('/bar/+items/++model++?orderby=intensity&start=0', |
| 1412 | + mock_io.last_request.url); |
| 1413 | + }, |
| 1414 | + |
| 1415 | + test_first_batch_uses_cache: function() { |
| 1416 | + /* first_batch will use the cached value instead of making a |
| 1417 | + * second AJAX request. */ |
| 1418 | + var navigator = this.get_intensity_listing(); |
| 1419 | + Y.Assert.areEqual(1, navigator.get('io_provider').requests.length); |
| 1420 | + navigator.first_batch('intensity'); |
| 1421 | + Y.Assert.areEqual(1, navigator.get('io_provider').requests.length); |
| 1422 | + }, |
| 1423 | + |
| 1424 | + test_io_error: function() { |
| 1425 | + var overlay_node; |
| 1426 | + var navigator = this.get_intensity_listing(); |
| 1427 | + navigator.first_batch('failure'); |
| 1428 | + navigator.get('io_provider').failure(); |
| 1429 | + overlay_node = Y.one('.yui3-lazr-formoverlay-errors'); |
| 1430 | + Y.Assert.isTrue(Y.Lang.isValue(overlay_node)); |
| 1431 | + } |
| 1432 | + })); |
| 1433 | + |
| 1434 | + |
| 1435 | + tests.suite.add(new Y.Test.Case({ |
| 1436 | + name: 'Batch caching', |
| 1437 | + |
| 1438 | + setUp: function() { |
| 1439 | + this.target = Y.Node.create('<div></div>').set( |
| 1440 | + 'id', 'client-listing'); |
| 1441 | + Y.one('body').appendChild(this.target); |
| 1442 | + }, |
| 1443 | + |
| 1444 | + tearDown: function() { |
| 1445 | + this.target.remove(); |
| 1446 | + delete this.target; |
| 1447 | + reset_history(); |
| 1448 | + }, |
| 1449 | + |
| 1450 | + test_update_from_new_model_caches: function() { |
| 1451 | + /* |
| 1452 | + * update_from_new_model caches the settings in the |
| 1453 | + * module.batches. |
| 1454 | + */ |
| 1455 | + var lp_cache = { |
| 1456 | + context: { |
| 1457 | + resource_type_link: 'http://foo_type', |
| 1458 | + web_link: 'http://foo/bar' |
| 1459 | + }, |
| 1460 | + mustache_model: { |
| 1461 | + foo: 'bar' |
| 1462 | + }, |
| 1463 | + next: null, |
| 1464 | + prev: null, |
| 1465 | + field_visibility: {}, |
| 1466 | + field_visibility_defaults: {} |
| 1467 | + }; |
| 1468 | + var template = "<ol>" + |
| 1469 | + "{{#item}}<li>{{name}}</li>{{/item}}</ol>"; |
| 1470 | + var navigator = new TestListingNavigator({ |
| 1471 | + current_url: window.location, |
| 1472 | + cache: lp_cache, |
| 1473 | + template: template, |
| 1474 | + target: this.target |
| 1475 | + }); |
| 1476 | + var key = module.get_batch_key({ |
| 1477 | + order_by: "intensity", |
| 1478 | + memo: 'memo1', |
| 1479 | + forwards: true, |
| 1480 | + start: 5, |
| 1481 | + target: this.target |
| 1482 | + }); |
| 1483 | + var batch = { |
| 1484 | + order_by: 'intensity', |
| 1485 | + memo: 'memo1', |
| 1486 | + forwards: true, |
| 1487 | + start: 5, |
| 1488 | + next: null, |
| 1489 | + prev: null, |
| 1490 | + mustache_model: { |
| 1491 | + item: [ |
| 1492 | + {name: 'first'}, |
| 1493 | + {name: 'second'} |
| 1494 | + ], |
| 1495 | + items: ['a', 'b', 'c'] |
| 1496 | + }}; |
| 1497 | + var query = navigator.get_batch_query(batch); |
| 1498 | + navigator.update_from_new_model(query, true, batch); |
| 1499 | + Y.lp.testing.assert.assert_equal_structure( |
| 1500 | + batch, navigator.get('batches')[key]); |
| 1501 | + }, |
| 1502 | + /** |
| 1503 | + * get_batch_key returns a JSON-serialized list. |
| 1504 | + */ |
| 1505 | + test_get_batch_key: function() { |
| 1506 | + var key = module.get_batch_key({ |
| 1507 | + order_by: 'order_by1', |
| 1508 | + memo: 'memo1', |
| 1509 | + forwards: true, |
| 1510 | + target: this.target, |
| 1511 | + start: 5}); |
| 1512 | + Y.Assert.areSame('["order_by1","memo1",true,5]', key); |
| 1513 | + } |
| 1514 | + })); |
| 1515 | + |
| 1516 | + tests.suite.add(new Y.Test.Case({ |
| 1517 | + name: 'get_query', |
| 1518 | + |
| 1519 | + test_get_query: function() { |
| 1520 | + // get_query returns the query portion of a URL in structured form. |
| 1521 | + var query = module.get_query('http://yahoo.com?me=you&a=b&a=c'); |
| 1522 | + Y.lp.testing.assert.assert_equal_structure( |
| 1523 | + {me: 'you', a: ['b', 'c']}, query); |
| 1524 | + } |
| 1525 | + })); |
| 1526 | + |
| 1527 | + tests.suite.add(new Y.Test.Case({ |
| 1528 | + name: 'get_batch_url', |
| 1529 | + |
| 1530 | + setUp: function() { |
| 1531 | + this.target = Y.Node.create('<div></div>').set( |
| 1532 | + 'id', 'client-listing'); |
| 1533 | + Y.one('body').appendChild(this.target); |
| 1534 | + }, |
| 1535 | + |
| 1536 | + tearDown: function() { |
| 1537 | + this.target.remove(); |
| 1538 | + delete this.target; |
| 1539 | + reset_history(); |
| 1540 | + }, |
| 1541 | + |
| 1542 | + /** |
| 1543 | + * get_batch_query accepts the order_by param. |
| 1544 | + */ |
| 1545 | + test_get_batch_query_orderby: function() { |
| 1546 | + var navigator = new TestListingNavigator({ |
| 1547 | + search_params: { |
| 1548 | + param: 1 |
| 1549 | + }, |
| 1550 | + target: this.target, |
| 1551 | + cache: {next: null, prev: null} |
| 1552 | + }); |
| 1553 | + var query = navigator.get_batch_query({order_by: 'importance'}); |
| 1554 | + Y.Assert.areSame('importance', query.orderby); |
| 1555 | + Y.Assert.areSame(1, query.param); |
| 1556 | + }, |
| 1557 | + /** |
| 1558 | + * get_batch_query accepts the memo param. |
| 1559 | + */ |
| 1560 | + test_get_batch_query_memo: function() { |
| 1561 | + var navigator = new TestListingNavigator({ |
| 1562 | + search_params: { |
| 1563 | + param: 'foo' |
| 1564 | + }, |
| 1565 | + target: this.target, |
| 1566 | + cache: {next: null, prev: null} |
| 1567 | + }); |
| 1568 | + var query = navigator.get_batch_query({memo: 'pi'}); |
| 1569 | + Y.Assert.areSame('pi', query.memo); |
| 1570 | + Y.Assert.areSame('foo', query.param); |
| 1571 | + }, |
| 1572 | + /** |
| 1573 | + * When memo is null, query.memo is undefined. |
| 1574 | + */ |
| 1575 | + test_get_batch_null_memo: function() { |
| 1576 | + var navigator = new TestListingNavigator({ |
| 1577 | + search_params: {}, |
| 1578 | + cache: {next: null, prev: null}, |
| 1579 | + target: this.target |
| 1580 | + }); |
| 1581 | + var query = navigator.get_batch_query({memo: null}); |
| 1582 | + Y.Assert.areSame(undefined, query.memo); |
| 1583 | + }, |
| 1584 | + /** |
| 1585 | + * If 'forwards' is true, direction does not appear. |
| 1586 | + */ |
| 1587 | + test_get_batch_query_forwards: function() { |
| 1588 | + var navigator = new TestListingNavigator({ |
| 1589 | + search_params: { |
| 1590 | + param: 'pi' |
| 1591 | + }, |
| 1592 | + cache: {next: null, prev: null}, |
| 1593 | + target: this.target |
| 1594 | + }); |
| 1595 | + var query = navigator.get_batch_query({forwards: true}); |
| 1596 | + Y.Assert.areSame('pi', query.param); |
| 1597 | + Y.Assert.areSame(undefined, query.direction); |
| 1598 | + }, |
| 1599 | + /** |
| 1600 | + * If 'forwards' is false, direction is set to backwards. |
| 1601 | + */ |
| 1602 | + test_get_batch_query_backwards: function() { |
| 1603 | + var navigator = new TestListingNavigator({ |
| 1604 | + search_params: { |
| 1605 | + param: 'pi' |
| 1606 | + }, |
| 1607 | + cache: {next: null, prev: null}, |
| 1608 | + target: this.target |
| 1609 | + }); |
| 1610 | + var query = navigator.get_batch_query({forwards: false}); |
| 1611 | + Y.Assert.areSame('pi', query.param); |
| 1612 | + Y.Assert.areSame('backwards', query.direction); |
| 1613 | + }, |
| 1614 | + /** |
| 1615 | + * If start is provided, it overrides existing values. |
| 1616 | + */ |
| 1617 | + test_get_batch_query_start: function() { |
| 1618 | + var navigator = new TestListingNavigator({ |
| 1619 | + search_params: {}, |
| 1620 | + cache: {next: null, prev:null}, |
| 1621 | + target: this.target |
| 1622 | + }); |
| 1623 | + var query = navigator.get_batch_query({}); |
| 1624 | + Y.Assert.areSame(undefined, query.start); |
| 1625 | + query = navigator.get_batch_query({start: 1}); |
| 1626 | + Y.Assert.areSame(1, query.start); |
| 1627 | + query = navigator.get_batch_query({start: null}); |
| 1628 | + Y.lp.testing.assert.assert_equal_structure({}, query); |
| 1629 | + } |
| 1630 | + })); |
| 1631 | + |
| 1632 | + |
| 1633 | + tests.suite.add(new Y.Test.Case({ |
| 1634 | + name: 'navigation', |
| 1635 | + |
| 1636 | + setUp: function() { |
| 1637 | + this.target = Y.Node.create('<div></div>').set( |
| 1638 | + 'id', 'client-listing'); |
| 1639 | + Y.one('body').appendChild(this.target); |
| 1640 | + }, |
| 1641 | + |
| 1642 | + tearDown: function() { |
| 1643 | + this.target.remove(); |
| 1644 | + delete this.target; |
| 1645 | + reset_history(); |
| 1646 | + }, |
| 1647 | + |
| 1648 | + test_model_uses_view_name: function() { |
| 1649 | + var navigator = get_navigator('', {target: this.target}); |
| 1650 | + navigator.get_current_batch().view_name = '+funitems'; |
| 1651 | + navigator.load_model({}); |
| 1652 | + Y.Assert.areSame( |
| 1653 | + '/bar/+funitems/++model++', |
| 1654 | + navigator.get('io_provider').last_request.url); |
| 1655 | + }, |
| 1656 | + |
| 1657 | + /** |
| 1658 | + * last_batch uses memo="", start=navigator.current_batch.last_start, |
| 1659 | + * direction=backwards, orderby=navigator.current_batch.order_by. |
| 1660 | + */ |
| 1661 | + test_last_batch: function() { |
| 1662 | + var navigator = get_navigator( |
| 1663 | + '?memo=pi&direction=backwards&start=57', {target: this.target}); |
| 1664 | + navigator.last_batch(); |
| 1665 | + Y.Assert.areSame( |
| 1666 | + '/bar/+items/++model++?orderby=foo&memo=&start=23&' + |
| 1667 | + 'direction=backwards', |
| 1668 | + navigator.get('io_provider').last_request.url); |
| 1669 | + }, |
| 1670 | + |
| 1671 | + /** |
| 1672 | + * first_batch omits memo and direction, start=0, |
| 1673 | + * orderby=navigator.current_batch.order_by. |
| 1674 | + */ |
| 1675 | + test_first_batch: function() { |
| 1676 | + var navigator = get_navigator( |
| 1677 | + '?memo=pi&start=26', {target: this.target}); |
| 1678 | + navigator.first_batch(); |
| 1679 | + Y.Assert.areSame( |
| 1680 | + '/bar/+items/++model++?orderby=foo&start=0', |
| 1681 | + navigator.get('io_provider').last_request.url); |
| 1682 | + }, |
| 1683 | + |
| 1684 | + /** |
| 1685 | + * next_batch uses values from current_batch.next + |
| 1686 | + * current_batch.ordering. |
| 1687 | + */ |
| 1688 | + test_next_batch: function() { |
| 1689 | + var navigator = get_navigator( |
| 1690 | + '?memo=pi&start=26', {target: this.target}); |
| 1691 | + navigator.next_batch(); |
| 1692 | + Y.Assert.areSame( |
| 1693 | + '/bar/+items/++model++?orderby=foo&memo=467&start=500', |
| 1694 | + navigator.get('io_provider').last_request.url); |
| 1695 | + }, |
| 1696 | + |
| 1697 | + /** |
| 1698 | + * Calling next_batch when there is none is a no-op. |
| 1699 | + */ |
| 1700 | + test_next_batch_missing: function() { |
| 1701 | + var navigator = get_navigator( |
| 1702 | + '?memo=pi&start=26', {no_next: true, target: this.target}); |
| 1703 | + navigator.next_batch(); |
| 1704 | + Y.Assert.areSame( |
| 1705 | + null, navigator.get('io_provider').last_request); |
| 1706 | + }, |
| 1707 | + |
| 1708 | + /** |
| 1709 | + * prev_batch uses values from current_batch.prev + direction=backwards |
| 1710 | + * and ordering=current_batch.ordering. |
| 1711 | + */ |
| 1712 | + test_prev_batch: function() { |
| 1713 | + var navigator = get_navigator( |
| 1714 | + '?memo=pi&start=26', {target: this.target}); |
| 1715 | + navigator.prev_batch(); |
| 1716 | + Y.Assert.areSame( |
| 1717 | + '/bar/+items/++model++?orderby=foo&memo=457&start=400&' + |
| 1718 | + 'direction=backwards', |
| 1719 | + navigator.get('io_provider').last_request.url); |
| 1720 | + }, |
| 1721 | + |
| 1722 | + /** |
| 1723 | + * Calling prev_batch when there is none is a no-op. |
| 1724 | + */ |
| 1725 | + test_prev_batch_missing: function() { |
| 1726 | + var navigator = get_navigator( |
| 1727 | + '?memo=pi&start=26', |
| 1728 | + {no_prev: true, no_next: true, target: this.target}); |
| 1729 | + navigator.prev_batch(); |
| 1730 | + Y.Assert.areSame( |
| 1731 | + null, navigator.get('io_provider').last_request); |
| 1732 | + }, |
| 1733 | + |
| 1734 | + /** |
| 1735 | + * Verify we get a reasonable default context if there is no context |
| 1736 | + * available as is the case with the BugsBugTaskSearchListingView. |
| 1737 | + */ |
| 1738 | + test_default_context: function () { |
| 1739 | + var navigator = get_navigator('', {target: this.target}); |
| 1740 | + // now remove the context |
| 1741 | + var batch = navigator.get_current_batch(); |
| 1742 | + delete batch.context; |
| 1743 | + |
| 1744 | + navigator.get_current_batch().view_name = '+funitems'; |
| 1745 | + navigator.load_model({}); |
| 1746 | + |
| 1747 | + // the start of the url used will be whatever the current |
| 1748 | + // location.href is for the window object. We can make sure we did |
| 1749 | + // get a nicely generated url though by checking they end built |
| 1750 | + // correctly. |
| 1751 | + var generated_url = navigator.get('io_provider').last_request.url; |
| 1752 | + |
| 1753 | + Y.Assert.areSame( |
| 1754 | + '+funitems/++model++', |
| 1755 | + generated_url.substr(generated_url.indexOf('+'))); |
| 1756 | + } |
| 1757 | + |
| 1758 | + })); |
| 1759 | + |
| 1760 | + tests.suite.add(new Y.Test.Case({ |
| 1761 | + name: "pre-fetching batches", |
| 1762 | + setUp: function() { |
| 1763 | + this.target = Y.Node.create('<div></div>').set( |
| 1764 | + 'id', 'client-listing'); |
| 1765 | + Y.one('body').appendChild(this.target); |
| 1766 | + }, |
| 1767 | + tearDown: function() { |
| 1768 | + this.target.remove(); |
| 1769 | + delete this.target; |
| 1770 | + reset_history(); |
| 1771 | + }, |
| 1772 | + /** |
| 1773 | + * get_pre_fetch_configs should return a config for the next batch. |
| 1774 | + */ |
| 1775 | + test_get_pre_fetch_configs: function() { |
| 1776 | + var navigator = get_navigator('', {target: this.target}); |
| 1777 | + var configs = navigator.get_pre_fetch_configs(); |
| 1778 | + var batch_keys = []; |
| 1779 | + Y.each(configs, function(value) { |
| 1780 | + batch_keys.push(module.get_batch_key(value)); |
| 1781 | + }); |
| 1782 | + Y.Assert.areSame('["foo",467,true,500]', batch_keys[0]); |
| 1783 | + Y.Assert.areSame(1, batch_keys.length); |
| 1784 | + }, |
| 1785 | + |
| 1786 | + /** |
| 1787 | + * get_pre_fetch_configs should return an empty list if no next batch. |
| 1788 | + */ |
| 1789 | + test_get_pre_fetch_configs_no_next: function() { |
| 1790 | + var navigator = get_navigator( |
| 1791 | + '', {no_next: true, target: this.target}); |
| 1792 | + var configs = navigator.get_pre_fetch_configs(); |
| 1793 | + var batch_keys = []; |
| 1794 | + Y.each(configs, function(value) { |
| 1795 | + batch_keys.push(module.get_batch_key(value)); |
| 1796 | + }); |
| 1797 | + Y.Assert.areSame(0, batch_keys.length); |
| 1798 | + }, |
| 1799 | + |
| 1800 | + get_pre_fetch_navigator: function(config) { |
| 1801 | + var navigator = get_navigator('', config); |
| 1802 | + var batch = navigator.get_current_batch(); |
| 1803 | + batch.next = {memo: 57, start: 56}; |
| 1804 | + batch.order_by = ''; |
| 1805 | + return navigator; |
| 1806 | + }, |
| 1807 | + |
| 1808 | + /** |
| 1809 | + * Calling pre_fetch_batches should produce a request for the next |
| 1810 | + * batch. |
| 1811 | + */ |
| 1812 | + test_pre_fetch_batches: function() { |
| 1813 | + var navigator = this.get_pre_fetch_navigator({target: this.target}); |
| 1814 | + var io_provider = navigator.get('io_provider'); |
| 1815 | + navigator.set('pre_fetch', true); |
| 1816 | + Y.Assert.isNull(io_provider.last_request); |
| 1817 | + navigator.pre_fetch_batches(); |
| 1818 | + Y.Assert.areSame( |
| 1819 | + io_provider.last_request.url, |
| 1820 | + '/bar/+items/++model++?orderby=&memo=57&start=56'); |
| 1821 | + }, |
| 1822 | + |
| 1823 | + /** |
| 1824 | + * Calling pre_fetch_batches should not produce a request for the next |
| 1825 | + * batch if Navigator.get('pre_fetch') is false. |
| 1826 | + */ |
| 1827 | + test_pre_fetch_disabled: function() { |
| 1828 | + var last_url; |
| 1829 | + var navigator = this.get_pre_fetch_navigator({target: this.target}); |
| 1830 | + navigator.pre_fetch_batches(); |
| 1831 | + Y.Assert.areSame(null, navigator.get('io_provider').last_request); |
| 1832 | + }, |
| 1833 | + |
| 1834 | + /** |
| 1835 | + * Initialization does a pre-fetch. |
| 1836 | + */ |
| 1837 | + test_pre_fetch_on_init: function() { |
| 1838 | + var navigator = get_navigator( |
| 1839 | + '', {pre_fetch: true, target:this.target}); |
| 1840 | + var last_url = navigator.get('io_provider').last_request.url; |
| 1841 | + Y.Assert.areSame( |
| 1842 | + last_url, |
| 1843 | + '/bar/+items/++model++?orderby=foo&memo=467&start=500'); |
| 1844 | + }, |
| 1845 | + /** |
| 1846 | + * update_from_new_model does a pre-fetch. |
| 1847 | + */ |
| 1848 | + test_pre_fetch_on_update_from_new_model: function() { |
| 1849 | + var navigator = get_navigator('', {target: this.target}); |
| 1850 | + var io_provider = navigator.get('io_provider'); |
| 1851 | + var lp_client = new Y.lp.client.Launchpad(); |
| 1852 | + var batch = lp_client.wrap_resource(null, { |
| 1853 | + context: { |
| 1854 | + resource_type_link: 'http://foo_type', |
| 1855 | + web_link: 'http://foo/bar' |
| 1856 | + }, |
| 1857 | + view_name: '+items', |
| 1858 | + order_by: 'baz', |
| 1859 | + memo: 'memo1', |
| 1860 | + next: { |
| 1861 | + memo: "pi", |
| 1862 | + start: 314 |
| 1863 | + }, |
| 1864 | + prev: null, |
| 1865 | + forwards: true, |
| 1866 | + start: 5, |
| 1867 | + mustache_model: { |
| 1868 | + item: [ |
| 1869 | + {name: 'first'}, |
| 1870 | + {name: 'second'} |
| 1871 | + ], |
| 1872 | + items: ['a', 'b', 'c'] |
| 1873 | + }}); |
| 1874 | + Y.Assert.isNull(io_provider.last_request); |
| 1875 | + navigator.set('pre_fetch', true); |
| 1876 | + navigator.update_from_new_model({}, false, batch); |
| 1877 | + Y.Assert.areSame( |
| 1878 | + io_provider.last_request.url, |
| 1879 | + '/bar/+items/++model++?orderby=baz&memo=pi&start=314'); |
| 1880 | + } |
| 1881 | + })); |
| 1882 | + |
| 1883 | + tests.suite.add(new Y.Test.Case({ |
| 1884 | + name: "Test indicators", |
| 1885 | + |
| 1886 | + tearDown: function () { |
| 1887 | + reset_history(); |
| 1888 | + }, |
| 1889 | + |
| 1890 | + /** |
| 1891 | + * Update starts showing the pending indicator |
| 1892 | + */ |
| 1893 | + test_show_on_update: function() { |
| 1894 | + var navigator = get_navigator(); |
| 1895 | + navigator.update({}); |
| 1896 | + Y.Assert.isTrue(navigator.indicator.get('visible')); |
| 1897 | + }, |
| 1898 | + /** |
| 1899 | + * A fetch-only update starts ignores the pending indicator |
| 1900 | + */ |
| 1901 | + test_ignore_on_fetch_only_update: function() { |
| 1902 | + var navigator = get_navigator(); |
| 1903 | + navigator.update({fetch_only: true}); |
| 1904 | + Y.Assert.isFalse(navigator.indicator.get('visible')); |
| 1905 | + }, |
| 1906 | + /** |
| 1907 | + * A successful IO operation clears the pending indicator. |
| 1908 | + */ |
| 1909 | + test_hide_on_success: function() { |
| 1910 | + var navigator = get_navigator(); |
| 1911 | + navigator.update({}); |
| 1912 | + navigator.get('io_provider').last_request.successJSON({ |
| 1913 | + mustache_model: {items: []}, |
| 1914 | + next: null, |
| 1915 | + prev: null |
| 1916 | + }); |
| 1917 | + Y.Assert.isFalse(navigator.indicator.get('visible')); |
| 1918 | + }, |
| 1919 | + /** |
| 1920 | + * A successful fetch-only IO operation ignores the pending indicator. |
| 1921 | + */ |
| 1922 | + test_no_hide_on_fetch_only_success: function() { |
| 1923 | + var navigator = get_navigator(); |
| 1924 | + navigator.indicator.setBusy(); |
| 1925 | + navigator.update({fetch_only: true}); |
| 1926 | + navigator.get('io_provider').last_request.successJSON({ |
| 1927 | + mustache_model: {items: []}, |
| 1928 | + next: null, |
| 1929 | + prev: null |
| 1930 | + }); |
| 1931 | + Y.Assert.isTrue(navigator.indicator.get('visible')); |
| 1932 | + }, |
| 1933 | + /** |
| 1934 | + * A failed IO operation hides the pending indicator. |
| 1935 | + */ |
| 1936 | + test_hide_on_failure: function() { |
| 1937 | + var navigator = get_navigator(); |
| 1938 | + navigator.update({}); |
| 1939 | + navigator.get('io_provider').failure(); |
| 1940 | + Y.Assert.isFalse(navigator.indicator.get('visible')); |
| 1941 | + }, |
| 1942 | + /** |
| 1943 | + * A failed fetch-only IO operation does not hide the pending indicator. |
| 1944 | + */ |
| 1945 | + test_no_hide_on_fetch_only_failure: function() { |
| 1946 | + var navigator = get_navigator(); |
| 1947 | + navigator.indicator.setBusy(); |
| 1948 | + navigator.update({fetch_only: true}); |
| 1949 | + navigator.get('io_provider').failure(); |
| 1950 | + Y.Assert.isTrue(navigator.indicator.get('visible')); |
| 1951 | + } |
| 1952 | + })); |
| 1953 | + |
| 1954 | + tests.suite.add(new Y.Test.Case({ |
| 1955 | + name: "Find batch aliases", |
| 1956 | + |
| 1957 | + test_get_batch_key_list: function() { |
| 1958 | + var keys = module.get_batch_key_list({ |
| 1959 | + prev: null, |
| 1960 | + next:null, |
| 1961 | + memo: 'pi', |
| 1962 | + start: -1, |
| 1963 | + forwards: true, |
| 1964 | + order_by: 'ordering' |
| 1965 | + }); |
| 1966 | + Y.ArrayAssert.itemsAreSame( |
| 1967 | + [null, '["ordering","pi",true,-1]', null], keys); |
| 1968 | + keys = module.get_batch_key_list({ |
| 1969 | + prev: { |
| 1970 | + memo: "pi", |
| 1971 | + start: -2 |
| 1972 | + }, |
| 1973 | + next: { |
| 1974 | + memo: "e", |
| 1975 | + start: 0 |
| 1976 | + }, |
| 1977 | + memo: 'pi', |
| 1978 | + start: -1, |
| 1979 | + forwards: true, |
| 1980 | + order_by: 'ordering' |
| 1981 | + }); |
| 1982 | + Y.ArrayAssert.itemsAreSame([ |
| 1983 | + '["ordering","pi",false,-2]', |
| 1984 | + '["ordering","pi",true,-1]', |
| 1985 | + '["ordering","e",true,0]'], keys); |
| 1986 | + }, |
| 1987 | + |
| 1988 | + /* Detect batch aliases for forward movement (next). */ |
| 1989 | + test_find_batch_alias_moving_forward: function() { |
| 1990 | + var prev_batch = ['a', 'b', 'c']; |
| 1991 | + var next_batch = ["b'", 'c', 'd']; |
| 1992 | + var result = module.find_batch_alias(prev_batch, next_batch); |
| 1993 | + Y.Assert.areSame(result[0], 'b'); |
| 1994 | + Y.Assert.areSame(result[1], "b'"); |
| 1995 | + result = module.find_batch_alias(next_batch, prev_batch); |
| 1996 | + Y.Assert.areSame(result[0], 'b'); |
| 1997 | + Y.Assert.areSame(result[1], "b'"); |
| 1998 | + }, |
| 1999 | + |
| 2000 | + /* Detect batch aliases for backward movement (prev). */ |
| 2001 | + test_find_batch_alias_moving_backward: function() { |
| 2002 | + var prev_batch = ['a', 'b', 'c']; |
| 2003 | + var next_batch = ['b', "c'", 'd']; |
| 2004 | + var result = module.find_batch_alias(prev_batch, next_batch); |
| 2005 | + Y.Assert.areSame(result[0], 'c'); |
| 2006 | + Y.Assert.areSame(result[1], "c'"); |
| 2007 | + result = module.find_batch_alias(next_batch, prev_batch); |
| 2008 | + Y.Assert.areSame(result[0], 'c'); |
| 2009 | + Y.Assert.areSame(result[1], "c'"); |
| 2010 | + }, |
| 2011 | + |
| 2012 | + /* Do not detect aliases if batches are unrelated */ |
| 2013 | + test_find_batch_alias_unrelated: function() { |
| 2014 | + var prev_batch = ['a', 'b', 'c']; |
| 2015 | + var next_batch = ['d', 'e', 'f']; |
| 2016 | + var result = module.find_batch_alias(next_batch, prev_batch); |
| 2017 | + Y.Assert.isNull(result); |
| 2018 | + }, |
| 2019 | + |
| 2020 | + /** |
| 2021 | + * When dealias_batches is called on the next batch, the current batch |
| 2022 | + * is re-added to the batches mapping, under its alias from the next |
| 2023 | + * batch. |
| 2024 | + */ |
| 2025 | + test_dealias_batches_next: function() { |
| 2026 | + var navigator = get_navigator(); |
| 2027 | + var next_batch = { |
| 2028 | + memo: 467, |
| 2029 | + start: 500, |
| 2030 | + order_by: 'foo', |
| 2031 | + forwards: true, |
| 2032 | + prev: { |
| 2033 | + memo: 467, |
| 2034 | + start: 450 |
| 2035 | + }, |
| 2036 | + next: null |
| 2037 | + }; |
| 2038 | + var prev_batch_config = module.prev_batch_config(next_batch); |
| 2039 | + var prev_batch_key = module.get_batch_key( |
| 2040 | + prev_batch_config); |
| 2041 | + navigator.dealias_batches(next_batch); |
| 2042 | + Y.Assert.areSame( |
| 2043 | + navigator.get('batches')[prev_batch_key], |
| 2044 | + navigator.get_current_batch() |
| 2045 | + ); |
| 2046 | + Y.Assert.areNotSame( |
| 2047 | + prev_batch_key, navigator.get('model').get_batch_key()); |
| 2048 | + }, |
| 2049 | + /** |
| 2050 | + * When dealias_batches is called on the previous batch, the current |
| 2051 | + * batch is re-added to the batches mapping, under its alias from the |
| 2052 | + * previous batch. |
| 2053 | + */ |
| 2054 | + test_dealias_batches_prev: function() { |
| 2055 | + var navigator = get_navigator(); |
| 2056 | + var prev_batch = { |
| 2057 | + memo: 457, |
| 2058 | + start: 400, |
| 2059 | + order_by: 'foo', |
| 2060 | + forwards: false, |
| 2061 | + next: { |
| 2062 | + memo: 467, |
| 2063 | + start: 450 |
| 2064 | + }, |
| 2065 | + prev: null |
| 2066 | + }; |
| 2067 | + var next_batch_config = module.next_batch_config(prev_batch); |
| 2068 | + var next_batch_key = module.get_batch_key( |
| 2069 | + next_batch_config); |
| 2070 | + navigator.dealias_batches(prev_batch); |
| 2071 | + Y.Assert.areSame( |
| 2072 | + navigator.get('batches')[next_batch_key], |
| 2073 | + navigator.get_current_batch() |
| 2074 | + ); |
| 2075 | + Y.Assert.areNotSame( |
| 2076 | + next_batch_key, navigator.get('model').get_batch_key()); |
| 2077 | + } |
| 2078 | + })); |
| 2079 | + |
| 2080 | + tests.suite.add(new Y.Test.Case({ |
| 2081 | + name: 'browser history', |
| 2082 | + |
| 2083 | + setUp: function() { |
| 2084 | + this.target = Y.Node.create('<div></div>').set( |
| 2085 | + 'id', 'client-listing'); |
| 2086 | + Y.one('body').appendChild(this.target); |
| 2087 | + }, |
| 2088 | + |
| 2089 | + tearDown: function() { |
| 2090 | + this.target.remove(); |
| 2091 | + delete this.target; |
| 2092 | + reset_history(); |
| 2093 | + }, |
| 2094 | + |
| 2095 | + /** |
| 2096 | + * Update from cache generates a change event for the specified batch. |
| 2097 | + */ |
| 2098 | + test_update_from_cache_generates_event: function() { |
| 2099 | + var navigator = get_navigator('', {target: this.target}); |
| 2100 | + var e = null; |
| 2101 | + navigator.get('model').get('history').on('change', |
| 2102 | + function(inner_e) { |
| 2103 | + e = inner_e; |
| 2104 | + }); |
| 2105 | + navigator.get('batches')['some-batch-key'] = { |
| 2106 | + mustache_model: { |
| 2107 | + items: [] |
| 2108 | + }, |
| 2109 | + next: null, |
| 2110 | + prev: null |
| 2111 | + }; |
| 2112 | + navigator.update_from_cache({foo: 'bar'}, 'some-batch-key'); |
| 2113 | + Y.Assert.areEqual('some-batch-key', e.newVal.batch_key); |
| 2114 | + Y.Assert.areEqual('?foo=bar', e._options.url); |
| 2115 | + }, |
| 2116 | + |
| 2117 | + /** |
| 2118 | + * When a change event is emitted, the relevant batch becomes the |
| 2119 | + * current batch and is rendered. |
| 2120 | + */ |
| 2121 | + test_change_event_renders_cache: function() { |
| 2122 | + var navigator = get_navigator('', {target: this.target}); |
| 2123 | + var batch = { |
| 2124 | + mustache_model: { |
| 2125 | + items: [], |
| 2126 | + foo: 'bar' |
| 2127 | + }, |
| 2128 | + next: null, |
| 2129 | + prev: null |
| 2130 | + }; |
| 2131 | + navigator.set('template', '{{foo}}'); |
| 2132 | + navigator.get('batches')['some-batch-key'] = batch; |
| 2133 | + navigator.get('model').get('history').addValue( |
| 2134 | + 'batch_key', 'some-batch-key'); |
| 2135 | + Y.Assert.areEqual(batch, navigator.get_current_batch()); |
| 2136 | + Y.Assert.areEqual('bar', navigator.get('target').getContent()); |
| 2137 | + } |
| 2138 | + })); |
| 2139 | + |
| 2140 | +}, '0.1', { |
| 2141 | + 'requires': ['base', 'test', 'console', 'lp.app.listing_navigator', |
| 2142 | + 'lp.testing.mockio', 'lp.testing.assert', 'history'] |
| 2143 | }); |

This branch looks good Richard, thank you.
As we discussed on IRC, you added 'node' as a requirement because in the code a NodeList is used at one point.
The tests pass.