// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. // /// /// /// module WinJSTests { "use strict"; // @TODO, need tests for release/retain // NOTE: because of auto-batching in BindingListDataSource you have two options for how to write tests: // // 1) explicit dataSource.beginEdits()/endEdits() calls around all edits // // 2) using promises and logger.assertEmptyAsync() to make sure you make assertions after the endEdits has occured // function errorHandler(msg) { try { LiveUnit.Assert.fail('There was an unhandled error in your test: ' + msg); } catch (ex) { } } class LoggingNotificationHandler implements WinJS.UI.IListNotificationHandler { expected = []; log = null; beginNotifications; changed; endNotifications; inserted; indexChanged; countChanged; moved; removed; reload; constructor(retain = false) { this.beginNotifications = this.assert.bind(this, "beginNotifications"); this.changed = this.assert.bind(this, "changed"); this.endNotifications = this.assert.bind(this, "endNotifications"); if (retain) { this.inserted = function (itemPromise) { itemPromise.retain(); this.assert("inserted"); }; } else { this.inserted = this.assert.bind(this, "inserted"); } this.indexChanged = this.assert.bind(this, "indexChanged"); this.countChanged = this.assert.bind(this, "countChanged"); this.moved = this.assert.bind(this, "moved"); this.removed = this.assert.bind(this, "removed"); this.reload = this.assert.bind(this, "reload"); } // Used for developing tests / debugging startLogging = function () { this.log = []; } stopLogging() { var l = this.log; this.log = null; return l; } setExpected(list) { this.expected = list; return this; } appendExpected(...args) { args.forEach((arg) => { this.expected.push(arg); }) return this; } appendExpectedN(entry, n = 1) { for (var i = 0; i < n; i++) { this.expected.push(entry); } return this; } assertEmpty(comment?) { LiveUnit.Assert.areEqual(0, this.expected.length, "All expected notifications should be fired: " + comment); } assertEmptyAsync(comment?) { return WinJS.Utilities.Scheduler.schedulePromiseHigh(null, "BindingListTests.assertEmptyAsync").then(() => { this.assertEmpty(comment); }); } assert(name) { var entry = this.expected.shift(); if (entry) { LiveUnit.Assert.areEqual(entry, name, "Recieved event doesn't match expected event"); } if (this.log) { this.log.push(name); } } itemAvailable(item) { } } function CountingNotificationHandler() { var count = 0; this.getCount = function () { return count; }; this.clearCount = function () { count = 0; }; function increment() { count++; } this.beginNotifications = increment; this.changed = increment; this.endNotifications = increment; this.inserted = function (itemPromise) { itemPromise.retain(); increment(); }; this.indexChanged = increment; this.countChanged = increment; this.moved = increment; this.removed = increment; this.reload = increment; } function listSortedAndFilteredToEvens(count, options) { // Creating a sorted even number list var list = new WinJS.Binding.List([], options); for (var i = 0; i < count; ++i) { list.push(i); } var sorted = list.createSorted(function (l, r) { return l - r; }); return sorted.createFiltered(function (num) { return Math.abs(num) % 2 === 0; }); } function listGroupedByOddAndEven(count = 0) { var list = new WinJS.Binding.List(); var compare = function (num) { return (num % 2 === 0) ? "even" : "odd"; }; var sort = function (l, r) { return l.length - r.length; }; for (var i = 0; i < count; ++i) { list.push(i); } return list.createGrouped(compare, compare, sort); } function sortedList() { var list = new WinJS.Binding.List(); return list.createSorted(function (l, r) { return (l - r); }); } function oddListFilter() { var list = new WinJS.Binding.List(); return list.createFiltered(function (num) { return !!(num % 2); }); } export class BindingListTests { testBindingListDecreasingTheLenghtNotifications(complete) { var logger = new LoggingNotificationHandler(true); var list = new WinJS.Binding.List(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); // Be explicit about setup so that these notifications don't // get mixed up with the ones we care about. dataSource.beginEdits(); list.push(1, 2, 3, 4, 5, 6, 7, 8, 9); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "removed", "removed", "countChanged", "endNotifications" ]); list.length = list.length - 2; logger.assertEmptyAsync() .then(null, errorHandler) .then(complete); } testReloadNotificationsInListBinding() { var logger = new LoggingNotificationHandler(true); var list = new WinJS.Binding.List(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); dataSource.beginEdits(); list.push(1, 2, 3, -1, 0, 3); dataSource.endEdits(); logger.setExpected([ "reload" ]); list.sort(function (l, r) { return l - r; }); logger.assertEmpty(); logger.setExpected([ "reload" ]); list.reverse(); logger.assertEmpty(); } testBindingListEditingNotifications(complete) { var logger = new LoggingNotificationHandler(true); var list = new WinJS.Binding.List(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); WinJS.Promise.wrap() .then(function () { logger.setExpected([ "beginNotifications", "inserted", "inserted", "inserted", "countChanged", "endNotifications" ]); list.push(1, 2, 3); return logger.assertEmptyAsync(); }) .then(function () { logger.setExpected([ "beginNotifications", "removed", "countChanged", "endNotifications" ]); list.pop(); return logger.assertEmptyAsync(); }) .then(function () { logger.setExpected([ "beginNotifications", "indexChanged", "indexChanged", "moved", "endNotifications" ]); list.move(0, 1); return logger.assertEmptyAsync(); }) .then(function () { logger.setExpected([ "beginNotifications", "removed" ]). appendExpectedN("indexChanged", list.length - 1). appendExpected( "countChanged", "endNotifications" ); list.shift(); return logger.assertEmptyAsync("checking correct shift"); }) .then(function () { logger.setExpected([ "beginNotifications", "inserted" ]). appendExpectedN("indexChanged", list.length). appendExpected( "countChanged", "endNotifications" ); list.unshift(300); return logger.assertEmptyAsync("checking correct unshift"); }) .then(function () { logger.setExpected([ "beginNotifications", "changed", "endNotifications" ]); list.setAt(0, 100); return logger.assertEmptyAsync("checking correct modification"); }) .then(function () { logger.setExpected([ "beginNotifications", "inserted", "countChanged", "endNotifications" ]); list.splice(list.length, 0, 100); return logger.assertEmptyAsync("checking correct splice"); }) .then(function () { logger.setExpected([ "beginNotifications", "removed", "indexChanged", "indexChanged", "countChanged", "endNotifications" ]); list.splice(list.length - 3, 1); return logger.assertEmptyAsync("checking correct splice"); }) .then(null, errorHandler) .then(complete); } testBindingListEditingNotificationsWithExplicitBatching() { var logger = new LoggingNotificationHandler(true); var list = new WinJS.Binding.List(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); logger.setExpected([ "beginNotifications" ]); dataSource.beginEdits(); logger.assertEmpty(); logger.setExpected([ "inserted", "inserted", "inserted", ]); list.push(1, 2, 3); logger.assertEmpty(); logger.setExpected([ "removed", ]); list.pop(); logger.assertEmpty(); logger.setExpected([ "countChanged", "endNotifications" ]); dataSource.endEdits(); logger.assertEmpty(); logger.setExpected([ "beginNotifications" ]); dataSource.beginEdits(); logger.assertEmpty(); list.move(0, 1); logger.assertEmpty(); // We get an index changed notifications for the two items that swapped and a moved // notification for the one item which was explicitly moved. // logger.setExpected([ "indexChanged", "indexChanged", "moved", "endNotifications" ]); dataSource.endEdits(); logger.assertEmpty(); logger.setExpected([ "beginNotifications" ]); dataSource.beginEdits(); logger.assertEmpty(); logger.setExpected([ "removed" ]); list.shift(); logger.assertEmpty("checking correct shift"); logger.setExpected([]). appendExpectedN("indexChanged", list.length). appendExpected( "countChanged", "endNotifications" ); dataSource.endEdits(); logger.assertEmpty(); } } function verifyListContent(list, expected) { for (var i = 0, len = list.length; i < len; i++) { if (list.getAt(i) !== expected[i]) { return false; } } return list.length === expected.length; } function scanFor(listBinding, value) { return function scan(item) { if (item.data === value) { return item; } return listBinding.next().then(scan); }; } export class BindingListFilteredProjectionTests { testBindingListFiltersDecreasingTheLenghtNotifications() { var logger = new LoggingNotificationHandler(true); var list = oddListFilter(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); dataSource.beginEdits(); list.push(1, 2, 3, 4, 5, 6, 7, 8, 9); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "removed", "removed", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.length = list.length - 2; dataSource.endEdits(); logger.assertEmpty("checking correct decreasing length of the list"); } testBindingListFiltersDecreasingTheLenghtNotificationsAutoBatching(complete) { var logger = new LoggingNotificationHandler(true); var list = oddListFilter(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); list.push(1, 2, 3, 4, 5, 6, 7, 8, 9); WinJS.Promise.timeout() .then(function () { logger.setExpected([ "beginNotifications", "removed", "removed", "countChanged", "endNotifications" ]); list.length = list.length - 2; return logger.assertEmptyAsync("checking correct decreasing length of the list"); }) .then(null, errorHandler) .then(complete); } testBindingListFiltersEditingNotifications(complete) { var logger = new LoggingNotificationHandler(true); var list = oddListFilter(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); WinJS.Promise.wrap() .then(function () { logger.setExpected([ "beginNotifications", "inserted", "inserted", "countChanged", "endNotifications" ]); list.push(1, 2, 3); return logger.assertEmptyAsync("checking correct insertion"); }) .then(function () { logger.setExpected([ "beginNotifications", "removed", "removed", "countChanged", "endNotifications" ]); list.pop(); list.pop(); list.pop(); list.pop(); return logger.assertEmptyAsync("checking correct pop"); }) .then(function () { logger.setExpected([ "beginNotifications", "inserted", "inserted", "countChanged", "endNotifications" ]); list.push(1); list.push(3); return logger.assertEmptyAsync("checking correct push in empty list"); }) .then(function () { logger.setExpected([ "beginNotifications", "indexChanged", "indexChanged", "moved", "endNotifications" ]); list.move(0, 1); return logger.assertEmptyAsync("checking correct move"); }) .then(function () { list.push(5, 7, 9, 10); return logger.assertEmptyAsync(); }) .then(function () { logger.setExpected([ "beginNotifications", "removed" ]). appendExpectedN("indexChanged", list.length - 1). appendExpected( "countChanged", "endNotifications" ); list.shift(); return logger.assertEmptyAsync("checking correct shift"); }) .then(function () { logger.setExpected([]); list.unshift(300); return logger.assertEmptyAsync("checking correct unshift element with false predicate"); }) .then(function () { logger.setExpected([ "beginNotifications", "inserted" ]). appendExpectedN("indexChanged", list.length). appendExpected( "countChanged", "endNotifications" ); list.unshift(17); return logger.assertEmptyAsync("checking correct unshift element with true predicate"); }) .then(function () { logger.setExpected([ "beginNotifications", "removed" ]). appendExpectedN("indexChanged", list.length - 1). appendExpected( "countChanged", "endNotifications" ); list.setAt(0, 100); return logger.assertEmptyAsync("checking correct setAt to false predicate"); }) .then(function () { logger.setExpected([]); list.splice(list.length, 0, 100); return logger.assertEmptyAsync("checking correct splice at the end"); }) .then(function () { logger.setExpected([ "beginNotifications", "removed", "indexChanged", "indexChanged", "countChanged", "endNotifications" ]); list.splice(list.length - 3, 1); return logger.assertEmptyAsync("checking correct splice to delete"); }) .then(function () { logger.setExpected([ "beginNotifications", "inserted", "indexChanged", "indexChanged", "indexChanged", "countChanged", "endNotifications" ]); list.splice(list.length - 3, 0, 11); return logger.assertEmptyAsync("checking correct splice to insert in the middle of the list"); }) .then(null, errorHandler) .then(complete); } testBindingListSortedDecreasingTheLenghtNotifications() { var logger = new LoggingNotificationHandler(true); var list = sortedList(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); dataSource.beginEdits(); list.push(9, 8, 7, 6, 5, 4, 3, 2, 1); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "removed", "removed", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.length = list.length - 2; dataSource.endEdits(); logger.assertEmpty("checking correct decreasing length of the list"); } testBindingListSortedProjectionUnshiftFunction() { var logger = new LoggingNotificationHandler(true); var list = sortedList(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); logger.setExpected([ "beginNotifications", "inserted", "inserted", "inserted", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.push(1, 2, 3); dataSource.endEdits(); logger.assertEmpty("checking correct insertion"); logger.setExpected([ "beginNotifications", "inserted", "indexChanged", "indexChanged", "indexChanged", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.push(0); dataSource.endEdits(); logger.assertEmpty("checking correct insertion"); logger.setExpected([ "beginNotifications", "removed", "removed", "removed", "removed", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.pop(); list.pop(); list.pop(); list.pop(); dataSource.endEdits(); logger.assertEmpty("checking correct pop"); dataSource.beginEdits(); list.push(1); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "inserted", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.push(3); dataSource.endEdits(); logger.assertEmpty("checking correct push in empty list"); logger.setExpected([]); dataSource.beginEdits(); list.move(0, 1); dataSource.endEdits(); logger.assertEmpty("checking correct move"); dataSource.beginEdits(); list.push(10, 8, 7, 5); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "inserted" ]). appendExpectedN("indexChanged", list.length). appendExpected( "countChanged", "endNotifications" ); dataSource.beginEdits(); list.unshift(1); dataSource.endEdits(); logger.assertEmpty("checking correct unshift element in the begining"); logger.setExpected([ "beginNotifications", "inserted", "indexChanged", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.unshift(9); dataSource.endEdits(); logger.assertEmpty("checking correct unshift element in the middle"); logger.setExpected([ "beginNotifications", "inserted", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.unshift(11); dataSource.endEdits(); logger.assertEmpty("checking correct unshift element in the end"); logger.setExpected([ "beginNotifications", "removed", "inserted" ]). appendExpectedN("indexChanged", list.length - 1). appendExpected( "endNotifications" ); dataSource.beginEdits(); list.setAt(0, 100); dataSource.endEdits(); logger.assertEmpty("checking correct setAt to false predicate"); } testBindingListSortedProjectionSetAtFunction() { var logger = new LoggingNotificationHandler(true); var list = sortedList(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); logger.setExpected([ "beginNotifications", "inserted", "inserted", "inserted", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.push(1, 2, 3); dataSource.endEdits(); logger.assertEmpty("checking correct insertion"); logger.setExpected([ "beginNotifications", "inserted", "indexChanged", "indexChanged", "indexChanged", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.push(0); dataSource.endEdits(); logger.assertEmpty("checking correct insertion"); dataSource.beginEdits(); list.pop(); list.pop(); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "removed", "removed", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.pop(); list.pop(); list.pop(); dataSource.endEdits(); logger.assertEmpty("checking correct pop"); dataSource.beginEdits(); list.push(1); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "inserted", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.push(3); dataSource.endEdits(); logger.assertEmpty("checking correct push in empty list"); logger.setExpected([]); dataSource.beginEdits(); list.move(0, 1); dataSource.endEdits(); logger.assertEmpty("checking correct move"); dataSource.beginEdits(); list.push(10, 8, 7, 5); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "removed", "inserted", ]). appendExpectedN("indexChanged", list.length - 1). appendExpected( "endNotifications" ); dataSource.beginEdits(); list.setAt(0, 100); dataSource.endEdits(); logger.assertEmpty("checking correct setAt to false predicate"); logger.setExpected([]); dataSource.beginEdits(); list.splice(list.length, 0, 100); dataSource.endEdits(); logger.assertEmpty("checking correct splice at the end"); logger.setExpected([ "beginNotifications", "removed", "indexChanged", "indexChanged", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.splice(list.length - 3, 1); dataSource.endEdits(); logger.assertEmpty("checking correct splice to delete"); } testBindingListSortedProjectionMutationFunction() { var logger = new LoggingNotificationHandler(true); var list = sortedList(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); logger.setExpected([ "beginNotifications", "inserted", "inserted", "inserted", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.push(1, 2, 3); dataSource.endEdits(); logger.assertEmpty("checking correct insertion"); logger.setExpected([ "beginNotifications", "inserted", "indexChanged", "indexChanged", "indexChanged", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.push(0); dataSource.endEdits(); logger.assertEmpty("checking correct insertion"); dataSource.beginEdits(); list.pop(); list.pop(); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "removed", "removed", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.pop(); list.pop(); list.pop(); dataSource.endEdits(); logger.assertEmpty("checking correct pop"); dataSource.beginEdits(); list.push(1); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "inserted", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.push(3); dataSource.endEdits(); logger.assertEmpty("checking correct push in empty list"); dataSource.beginEdits(); list.move(0, 1); list.push(10, 8, 7, 5); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "inserted", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.splice(list.length, 0, 100); dataSource.endEdits(); logger.assertEmpty("checking correct splice at the end"); } testBindingListSortedProjectionSplice() { var logger = new LoggingNotificationHandler(true); var list = sortedList(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); logger.setExpected([ "beginNotifications", "inserted", "inserted", "inserted", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.push(1, 2, 3); dataSource.endEdits(); logger.assertEmpty("checking correct insertion"); logger.setExpected([ "beginNotifications", "inserted", "indexChanged", "indexChanged", "indexChanged", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.push(0); dataSource.endEdits(); logger.assertEmpty("checking correct insertion"); dataSource.beginEdits(); list.pop(); list.pop(); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "removed", "removed", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.pop(); list.pop(); list.pop(); dataSource.endEdits(); logger.assertEmpty("checking correct pop"); dataSource.beginEdits(); list.push(1); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "inserted", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.push(3); dataSource.endEdits(); logger.assertEmpty("checking correct push in empty list"); dataSource.beginEdits(); list.move(0, 1); list.push(10, 8, 7, 5); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "inserted", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.splice(list.length, 0, 100); dataSource.endEdits(); logger.assertEmpty("checking correct splice at the end"); logger.setExpected([ "beginNotifications", "inserted", "indexChanged", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.splice(list.length - 3, 0, 11); dataSource.endEdits(); logger.assertEmpty("checking correct splice to insert in the middle of the list"); logger.setExpected([ "beginNotifications", "removed", "indexChanged", "indexChanged", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.splice(list.length - 3, 1); dataSource.endEdits(); logger.assertEmpty("checking correct splice to delete"); logger.setExpected([ "beginNotifications", "inserted", ]). appendExpectedN("indexChanged", list.length). appendExpected( "countChanged", "endNotifications" ); dataSource.beginEdits(); list.splice(list.length - 3, 0, -2); dataSource.endEdits(); logger.assertEmpty("checking correct splice to insert in the begining of the list"); } testBindingListSortedWithShift() { var logger = new LoggingNotificationHandler(true); var list = sortedList(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); logger.setExpected([ "beginNotifications", "inserted", "inserted", "inserted", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.push(1, 2, 3); dataSource.endEdits(); logger.assertEmpty("checking correct insertion"); logger.setExpected([ "beginNotifications", "inserted", "indexChanged", "indexChanged", "indexChanged", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.push(0); dataSource.endEdits(); logger.assertEmpty("checking correct insertion"); dataSource.beginEdits(); list.pop(); list.pop(); dataSource.endEdits(); LiveUnit.Assert.areEqual(2, list.length); logger.setExpected([ "beginNotifications", "removed", "removed", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.pop(); list.pop(); list.pop(); dataSource.endEdits(); logger.assertEmpty("checking correct pop"); dataSource.beginEdits(); list.push(1); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "inserted", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.push(3); dataSource.endEdits(); logger.assertEmpty("checking correct push in empty list"); dataSource.beginEdits(); list.move(0, 1); list.push(10, 8, 7, 5); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "removed" ]). appendExpectedN("indexChanged", list.length - 1). appendExpected( "countChanged", "endNotifications" ); dataSource.beginEdits(); list.shift(); dataSource.endEdits(); logger.assertEmpty("checking correct shift"); } testBindingListDecreasingTheLenghInGroupSorted() { var logger = new LoggingNotificationHandler(true); var list = listGroupedByOddAndEven(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); dataSource.beginEdits(); list.push(1, 2, 3, 4, 5, 6, 7, 8, 9); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "removed", "removed", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.length = list.length - 2; dataSource.endEdits(); logger.assertEmpty("checking correct decreasing length in groupSorted"); } testBindingListDataSourcePushInGroupSorted() { var logger = new LoggingNotificationHandler(true); var list = listGroupedByOddAndEven(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); logger.setExpected([ "beginNotifications", "inserted", "inserted", "inserted", "indexChanged", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.push(1, 2, 3); dataSource.endEdits(); logger.assertEmpty("checking correct push in groupSortedProjection"); } testBindingListDataSourcePopInGroupSorted() { var logger = new LoggingNotificationHandler(true); var list = listGroupedByOddAndEven(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); dataSource.beginEdits(); list.push(1, 2, 3); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "removed", "removed", "removed", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.pop(); list.pop(); list.pop(); list.pop(); dataSource.endEdits(); logger.assertEmpty("checking correct pop in groupSortedProjection"); } testBindingListDataSourceMoveInGroupSorted() { var logger = new LoggingNotificationHandler(true); var list = listGroupedByOddAndEven(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); dataSource.beginEdits(); list.push(1, 2, 3, 4); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "indexChanged", "indexChanged", "moved", "endNotifications" ]); dataSource.beginEdits(); list.move(0, 1); dataSource.endEdits(); logger.assertEmpty("checking correct move"); dataSource.beginEdits(); list.splice(0, 1); dataSource.endEdits(); dataSource.beginEdits(); list.move(0, 3); dataSource.endEdits(); } testBindingListDataSourceShiftInGroupSorted() { var logger = new LoggingNotificationHandler(true); var list = listGroupedByOddAndEven(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); dataSource.beginEdits(); list.push(1, 2, 3, 4, 5, 8, 7, 10, 9); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "removed" ]). appendExpectedN("indexChanged", list.length - 1). appendExpected( "countChanged", "endNotifications" ); dataSource.beginEdits(); list.shift(); dataSource.endEdits(); logger.assertEmpty("checking correct shift in groupSorted"); } testBindingListDataSourceUnShiftInGroupSorted() { var logger = new LoggingNotificationHandler(true); var list = listGroupedByOddAndEven(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); dataSource.beginEdits(); list.push(1, 2, 3, 4, 5, 8, 7, 10, 9); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "inserted" ]). appendExpectedN("indexChanged", list.length). appendExpected( "countChanged", "endNotifications" ); dataSource.beginEdits(); list.unshift(11); dataSource.endEdits(); logger.assertEmpty("checking correct unshift in groupSorted"); var numOfEvens = (function (list) { var count = 0; for (var i = 0; i < list.length; i++) { if (list.getAt(i) % 2 === 0) { count++; } } return count; })(list); logger.setExpected([ "beginNotifications", "inserted" ]). appendExpectedN("indexChanged", numOfEvens). appendExpected( "countChanged", "endNotifications" ); dataSource.beginEdits(); list.unshift(6); dataSource.endEdits(); logger.assertEmpty("checking correct unshift in groupSorted"); } testBindingListDataSourceSpliceInGroupSortedWithSpeicalStableInsert() { var logger = new LoggingNotificationHandler(true); var list = listGroupedByOddAndEven(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); dataSource.beginEdits(); list.push(1, 2, 3, 4, 5, 8, 7, 10, 9); dataSource.endEdits(); //before splice: 1, 3, 5, 7, 9, 2, 4, 8, 10 logger.setExpected([ "beginNotifications", "removed" ]). appendExpectedN("indexChanged", list.length - 1). appendExpected( "countChanged", "endNotifications" ); dataSource.beginEdits(); list.splice(0, 1); dataSource.endEdits(); logger.assertEmpty("testing splice to delete from the begining in groupSorted"); var ind = 3; logger.setExpected([ "beginNotifications", "inserted" ]). appendExpectedN("indexChanged", list.length - ind). appendExpected( "countChanged", "endNotifications" ); dataSource.beginEdits(); list.splice(ind, 0, 11); dataSource.endEdits(); //before splice: 3, 5, 7, 9, 2, 4, 8, 10 //After splice: 3, 5, 7, 11, 9, 2, 4, 8, 10 logger.assertEmpty("checking the correct adding of an element using splice"); logger.setExpected([ "beginNotifications", "inserted" ]). appendExpectedN("indexChanged", 3). appendExpected( "countChanged", "endNotifications" ); dataSource.beginEdits(); list.splice(0, 0, 4); dataSource.endEdits(); //before splice: 3, 5, 7, 11, 9, 2, 4, 8, 10 //After splice: 3, 5, 7, 11, 9, 2, 4, 4, 8, 10 logger.assertEmpty("checking deleting elements using splice"); } testBindingListDataSourceSpliceInGroupSorted() { var logger = new LoggingNotificationHandler(true); var list = listGroupedByOddAndEven(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); dataSource.beginEdits(); list.push(1, 2, 3, 4, 5, 8, 7, 10, 9); dataSource.endEdits(); //before splice: 1, 3, 5, 7, 9, 2, 4, 8, 10 logger.setExpected([ "beginNotifications", "removed" ]). appendExpectedN("indexChanged", list.length - 1). appendExpected( "countChanged", "endNotifications" ); dataSource.beginEdits(); list.splice(0, 1); dataSource.endEdits(); logger.assertEmpty("testing splice to delete from the begining in groupSorted"); var ind = 3; logger.setExpected([ "beginNotifications", "inserted" ]). appendExpectedN("indexChanged", list.length - ind). appendExpected( "countChanged", "endNotifications" ); dataSource.beginEdits(); list.splice(ind, 0, 11); dataSource.endEdits(); //before splice: 3, 5, 7, 9, 2, 4, 8, 10 //After splice: 3, 5, 7, 11, 9, 2, 4, 8, 10 logger.assertEmpty("checking the correct adding of an element using splice"); } testBindingListDataSourceSetAtInGroupSorted() { var logger = new LoggingNotificationHandler(true); var list = listGroupedByOddAndEven(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); dataSource.beginEdits(); list.push(1, 2, 3, 4, 5, 8, 7, 10, 9); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "removed", "inserted" ]). appendExpectedN("indexChanged", 4). appendExpected( "endNotifications" ); //before setAt: 1, 3, 5, 7, 9, 2, 4, 8, 10 //After setAt: 3, 5, 7, 9, 6, 2, 4, 8, 10 dataSource.beginEdits(); list.setAt(0, 6); dataSource.endEdits(); logger.assertEmpty("checking the correctness of setAt in GroupSorted"); } testBindingListDataSourceFilterOfFilter() { var options = [undefined, { proxy: true }, { binding: true }, { proxy: true, binding: true }]; for (var i = 0; i < options.length; i++) { var logger = new LoggingNotificationHandler(true); var list = listSortedAndFilteredToEvens(0, options[i]); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); var sorted = (list)._list; dataSource.beginEdits(); list.push(10, 8, 7, 12, 3, 4, -1, 0, -2, 11); dataSource.endEdits(); // sorted list :[-2, -1, 0, 3, 4, 7, 8, 10, 11, 12] //Even sorted list: [-2, 0, 4, 8, 10, 12]; logger.setExpected([ "beginNotifications", "inserted", ]). appendExpectedN("indexChanged", 4). appendExpected( "countChanged", "endNotifications" ); dataSource.beginEdits(); list.push(13, 15, 7, 2, 21); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "removed", ]). appendExpectedN("indexChanged", list.length - 1). appendExpected( "countChanged", "endNotifications" ); dataSource.beginEdits(); list.setAt(0, 1); dataSource.endEdits(); //After setAt Even sorted list: [0, 2, 4, 8, 10, 12]; logger.assertEmpty("checking the correctness of push in filter of filter"); logger.setExpected([ "beginNotifications", "removed", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.pop(); dataSource.endEdits(); //After pop Even sorted list: [0, 2, 4, 8, 10]; logger.assertEmpty("checking the correctness of push in filter of filter"); LiveUnit.Assert.areEqual(5, list.length, "Checking the length after pop and setAt"); // sorted list :[-1, 1, 2, 3, 4, 7, 8, 10] dataSource.beginEdits(); sorted.pop(); dataSource.endEdits(); logger.assertEmpty("making sure that poping an even element does not affect the filter of filter"); logger.setExpected([ "beginNotifications", "inserted" ]). appendExpectedN("indexChanged", list.length). appendExpected( "countChanged", "endNotifications" ); dataSource.beginEdits(); sorted.setAt(sorted.length - 1, -12); dataSource.endEdits(); logger.assertEmpty("checking setAt from the main filter"); //After setAt Even sorted list: [-12, 0, 2, 4, 8, 10]; logger.setExpected([ "beginNotifications", "removed", "removed", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.length = list.length - 2; dataSource.endEdits(); //After changing the length: Even sorted list: [-12, 0, 2, 4]; logger.assertEmpty("checking the correctness of notificatios after changing the length"); logger.setExpected([ "beginNotifications", "removed", ]). appendExpectedN("indexChanged", list.length - 1). appendExpected( "countChanged", "endNotifications" ); dataSource.beginEdits(); list.shift(); dataSource.endEdits(); logger.assertEmpty("checking the correctness of notificatios after shifting an element"); dataSource.beginEdits(); list.unshift(13); dataSource.endEdits(); logger.setExpected([ "beginNotifications", "inserted", "inserted", "inserted" ]). appendExpectedN("indexChanged", list.length + 1). appendExpected( "countChanged", "endNotifications" ); dataSource.beginEdits(); list.unshift(-52); list.unshift(52); list.unshift(50); dataSource.endEdits(); logger.assertEmpty("checking the correctness of notificatios after unshifting invalid number"); logger.setExpected([ "beginNotifications", "removed", "inserted", "inserted" ]). appendExpectedN("indexChanged", list.length). appendExpected( "countChanged", "endNotifications" ); dataSource.beginEdits(); list.splice(0, 1); list.splice(0, 0, 56); list.splice(0, 0, 43); sorted.splice(0, 0, 54); sorted.splice(0, 0, 53); dataSource.endEdits(); logger.assertEmpty("checking the correctness of notificatios after splice"); } } testBindingListDataSourceMutationFunction(complete) { var logger = new LoggingNotificationHandler(); var list = new WinJS.Binding.List(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); logger.setExpected([ "beginNotifications", "inserted", "countChanged", "endNotifications" ]); dataSource.beginEdits(); dataSource.insertAtEnd(null, 100); dataSource.endEdits(); LiveUnit.Assert.isTrue(verifyListContent(list, [100])); logger.assertEmpty(); dataSource.beginEdits(); dataSource.insertAtEnd(null, 90); LiveUnit.Assert.isTrue(verifyListContent(list, [100, 90])); dataSource.insertAtStart(null, 80); LiveUnit.Assert.isTrue(verifyListContent(list, [80, 100, 90])); list.pop(); list.pop(); list.pop(); dataSource.insertAtStart(null, 80); LiveUnit.Assert.isTrue(verifyListContent(list, [80])); dataSource.insertAtStart(null, 70); LiveUnit.Assert.isTrue(verifyListContent(list, [70, 80])); dataSource.beginEdits(); listBinding.next() .then(scanFor(listBinding, 70)) .then(function (item) { dataSource.insertBefore(null, 60, item.key); dataSource.insertAfter(null, 75, item.key); LiveUnit.Assert.isTrue(verifyListContent(list, [60, 70, 75, 80]), "checking the correctness of insertAfter and before"); return listBinding.next(); }) .then(function (item) { dataSource.moveToStart(item.key); LiveUnit.Assert.isTrue(verifyListContent(list, [75, 60, 70, 80]), "checking the correctness of moveToStart"); return listBinding.previous(); }) .then(function (item) { dataSource.moveToEnd(item.key); LiveUnit.Assert.isTrue(verifyListContent(list, [75, 70, 80, 60]), "checking the correctness of moveToEnd"); dataSource.change(item.key, 100); LiveUnit.Assert.isTrue(verifyListContent(list, [75, 70, 80, 100]), "checking the correctness of change"); return listBinding.previous(); }) .then(function (item) { dataSource.remove(item.key); LiveUnit.Assert.isTrue(verifyListContent(list, [70, 80, 100]), "checking the correctness of remove"); dataSource.insertAtStart(null, 50); dataSource.insertAtStart(null, 40); LiveUnit.Assert.isTrue(verifyListContent(list, [40, 50, 70, 80, 100]), "checking the correctness of insertion after multiple mutations"); return WinJS.Promise.join({ current: listBinding.current(), // 70 next: listBinding.next(), // 80 nextNext: listBinding.next() // 100 }); }) .then(function (items) { dataSource.moveBefore(items.next.key, items.current.key); dataSource.moveAfter(items.nextNext.key, items.next.key); LiveUnit.Assert.isTrue(verifyListContent(list, [40, 50, 80, 100, 70]), "checking the correctness of list after multiple moves"); dataSource.moveBefore(items.current.key, items.current.key); //move before with same keys should be a noop dataSource.moveAfter(items.next.key, items.next.key); //move after with same keys should be a noop LiveUnit.Assert.isTrue(verifyListContent(list, [40, 50, 80, 100, 70]), "checking the correctness of list after noop moves"); return WinJS.Promise.timeout(); }) .then(null, errorHandler) .then(complete); } testBindingListMoveBeforeAndAFterWithSameKey(complete) { var logger = new LoggingNotificationHandler(); var list = new WinJS.Binding.List(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); logger.setExpected([ "beginNotifications", "inserted", "countChanged", "endNotifications" ]); dataSource.beginEdits(); dataSource.insertAtEnd(null, 100); dataSource.endEdits(); LiveUnit.Assert.isTrue(verifyListContent(list, [100])); logger.assertEmpty(); dataSource.beginEdits(); dataSource.insertAtEnd(null, 90); LiveUnit.Assert.isTrue(verifyListContent(list, [100, 90])); dataSource.insertAtStart(null, 80); LiveUnit.Assert.isTrue(verifyListContent(list, [80, 100, 90])); dataSource.insertAtEnd(null, 110); LiveUnit.Assert.isTrue(verifyListContent(list, [80, 100, 90, 110])); listBinding.next() .then(scanFor(listBinding, 100)) .then(function (item) { dataSource.moveBefore(item.key, item.key); LiveUnit.Assert.isTrue(verifyListContent(list, [80, 100, 90, 110]), "checking the correctness of moveBefore"); return listBinding.next(); }) .then(function (item) { dataSource.moveAfter(item.key, item.key); LiveUnit.Assert.isTrue(verifyListContent(list, [80, 100, 90, 110]), "checking the correctness of moveAfter"); }) .then(null, errorHandler) .then(complete); } testBindingFilteredListDataSourceMutationFunction(complete) { var logger = new LoggingNotificationHandler(true); var list = oddListFilter(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); dataSource.beginEdits(); dataSource.insertAtEnd(null, 100); dataSource.endEdits(); LiveUnit.Assert.isTrue(verifyListContent(list, [])); logger.setExpected([ "beginNotifications", "inserted", "countChanged", "endNotifications" ]); dataSource.beginEdits(); dataSource.insertAtEnd(null, 101); dataSource.endEdits(); LiveUnit.Assert.isTrue(verifyListContent(list, [101])); logger.assertEmpty(); dataSource.insertAtEnd(null, 91); LiveUnit.Assert.isTrue(verifyListContent(list, [101, 91])); dataSource.insertAtStart(null, 80); LiveUnit.Assert.isTrue(verifyListContent(list, [101, 91])); dataSource.insertAtStart(null, 81); LiveUnit.Assert.isTrue(verifyListContent(list, [81, 101, 91])); list.pop(); list.pop(); list.pop(); dataSource.insertAtStart(null, 80); LiveUnit.Assert.isTrue(verifyListContent(list, [])); dataSource.insertAtStart(null, 81); dataSource.insertAtStart(null, 71); LiveUnit.Assert.isTrue(verifyListContent(list, [71, 81])); listBinding.next() .then(scanFor(listBinding, 71)) .then(function (item) { var key = item.key; dataSource.insertBefore(null, 60, key); dataSource.insertBefore(null, 61, key); dataSource.insertAfter(null, 75, key); dataSource.insertAfter(null, 70, key); LiveUnit.Assert.isTrue(verifyListContent(list, [61, 71, 75, 81]), "checking the correctness of insertAfter and before"); return listBinding.next(); }) .then(function (item) { dataSource.moveToStart(item.key); LiveUnit.Assert.isTrue(verifyListContent(list, [75, 61, 71, 81]), "checking the correctness of moveToStart"); return listBinding.previous(); }) .then(function (item) { dataSource.moveToEnd(item.key); LiveUnit.Assert.isTrue(verifyListContent(list, [75, 71, 81, 61]), "checking the correctness of moveToEnd"); dataSource.change(item.key, 100); LiveUnit.Assert.isTrue(verifyListContent(list, [75, 71, 81]), "checking the correctness of change"); dataSource.insertAtEnd(item.key, 101); return listBinding.previous(); }) .then(function (item) { dataSource.remove(item.key); LiveUnit.Assert.isTrue(verifyListContent(list, [71, 81, 101]), "checking the correctness of remove"); dataSource.insertAtStart(null, 51); dataSource.insertAtStart(null, 41); LiveUnit.Assert.isTrue(verifyListContent(list, [41, 51, 71, 81, 101]), "checking the correctness of insertion after multiple mutations"); return WinJS.Promise.join({ current: listBinding.current(), // 71 next: listBinding.next(), // 81 nextNext: listBinding.next() // 101 }); }) .then(function (items) { dataSource.moveBefore(items.next.key, items.current.key); dataSource.moveAfter(items.nextNext.key, items.next.key); LiveUnit.Assert.isTrue(verifyListContent(list, [41, 51, 81, 101, 71]), "checking the correctness of list after multiple moves"); return WinJS.Promise.timeout(); }) .then(null, errorHandler) .then(complete); } testBindingSortedListDataSourceMutationFunction(complete) { var logger = new LoggingNotificationHandler(true); var list = sortedList(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); logger.setExpected([ "beginNotifications", "inserted", "countChanged", "endNotifications" ]); dataSource.beginEdits(); dataSource.insertAtEnd(null, 101); dataSource.endEdits(); LiveUnit.Assert.isTrue(verifyListContent(list, [101])); logger.assertEmpty(); dataSource.insertAtEnd(null, 91); LiveUnit.Assert.isTrue(verifyListContent(list, [91, 101])); dataSource.insertAtStart(null, 80); LiveUnit.Assert.isTrue(verifyListContent(list, [80, 91, 101])); dataSource.insertAtStart(null, 81); LiveUnit.Assert.isTrue(verifyListContent(list, [80, 81, 91, 101])); listBinding.next() .then(scanFor(listBinding, 80)) .then(function (item) { var key = item.key; dataSource.insertBefore(null, 60, key); dataSource.insertAfter(null, 75, key); LiveUnit.Assert.isTrue(verifyListContent(list, [60, 75, 80, 81, 91, 101]), "checking the correctness of insertAfter and before"); return listBinding.next(); }) .then(function (item) { dataSource.moveToStart(item.key); LiveUnit.Assert.isTrue(verifyListContent(list, [60, 75, 80, 81, 91, 101]), "checking the correctness of moveToStart"); return listBinding.previous(); }) .then(function (item) { dataSource.moveToEnd(item.key); LiveUnit.Assert.isTrue(verifyListContent(list, [60, 75, 80, 81, 91, 101]), "checking the correctness of moveToEnd"); dataSource.change(item.key, -100); LiveUnit.Assert.isTrue(verifyListContent(list, [-100, 60, 75, 81, 91, 101]), "checking the correctness of change"); return listBinding.previous(); }) .then(function (item) { dataSource.remove(item.key); LiveUnit.Assert.isTrue(verifyListContent(list, [-100, 60, 81, 91, 101]), "checking the correctness of remove"); dataSource.insertAtStart(null, 50); dataSource.insertAtStart(null, 40); LiveUnit.Assert.isTrue(verifyListContent(list, [-100, 40, 50, 60, 81, 91, 101]), "checking the correctness of insertion after multiple mutations"); return WinJS.Promise.join({ current: listBinding.current(), next: listBinding.next(), nextNext: listBinding.next() }); }) .then(function (items) { dataSource.moveBefore(items.next.key, items.current.key); dataSource.moveAfter(items.nextNext.key, items.next.key); LiveUnit.Assert.isTrue(verifyListContent(list, [-100, 40, 50, 60, 81, 91, 101]), "checking the correctness of list after multiple moves"); dataSource.moveBefore(items.current.key, items.current.key); //move before with same keys should be a noop dataSource.moveAfter(items.next.key, items.next.key); //move after with same keys should be a noop LiveUnit.Assert.isTrue(verifyListContent(list, [-100, 40, 50, 60, 81, 91, 101]), "checking the correctness of list after noop moves"); return WinJS.Promise.timeout(); }) .then(null, errorHandler) .then(complete); } testBindingListInGroupSorted() { var logger = new LoggingNotificationHandler(true); var list = listGroupedByOddAndEven(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); dataSource.beginEdits(); list.push(1, 2, 3, 4); dataSource.endEdits(); //1, 3, 2, 4 logger.setExpected([ "beginNotifications", "inserted", "inserted", "indexChanged", "indexChanged", "indexChanged", "countChanged", "endNotifications" ]); dataSource.beginEdits(); list.push(0); list.push(5); dataSource.endEdits(); //1, 3, 5, 2, 4, 0 LiveUnit.Assert.isTrue(verifyListContent(list, [1, 3, 5, 2, 4, 0])); logger.assertEmpty(); logger.setExpected([ "beginNotifications", "removed", "removed" ]) .appendExpectedN("indexChanged", list.length - 2) .appendExpected( "countChanged", "endNotifications" ); dataSource.beginEdits(); list.splice(0, 2); dataSource.endEdits(); //5, 2, 4, 0 LiveUnit.Assert.isTrue(verifyListContent(list, [5, 2, 4, 0])); logger.assertEmpty(); dataSource.beginEdits(); list.pop(); list.pop(); list.pop(); list.pop(); list.push(1, 2, 3, 4, 5, 6); dataSource.endEdits(); //1, 3, 5, 2, 4, 6 LiveUnit.Assert.isTrue(verifyListContent(list, [1, 3, 5, 2, 4, 6])); logger.setExpected([ "beginNotifications", "indexChanged", "indexChanged", "moved", "endNotifications" ]); dataSource.beginEdits(); list.move(0, 1); dataSource.endEdits(); logger.assertEmpty(); } testBindingGroupSortedListDataSourceMutationFunction() { var logger = new LoggingNotificationHandler(true); var list = listGroupedByOddAndEven(); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); logger.setExpected([ "beginNotifications", "inserted", "countChanged", "endNotifications" ]); dataSource.beginEdits(); dataSource.insertAtEnd(null, 101); dataSource.endEdits(); LiveUnit.Assert.isTrue(verifyListContent(list, [101])); logger.assertEmpty(); dataSource.insertAtEnd(null, 90); LiveUnit.Assert.isTrue(verifyListContent(list, [101, 90])); LiveUnit.Assert.areEqual("odd", list.groups.getAt(0), "checking the group content"); LiveUnit.Assert.areEqual("even", list.groups.getAt(1), "checking the group content"); dataSource.insertAtStart(null, 80); LiveUnit.Assert.isTrue(verifyListContent(list, [101, 80, 90])); dataSource.insertAtStart(null, 81); LiveUnit.Assert.isTrue(verifyListContent(list, [81, 101, 80, 90])); } testBindingGroupSortedListDataSourceMutationFunction2(complete) { var logger = new LoggingNotificationHandler(true); var list = listGroupedByOddAndEven(5); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); dataSource.insertAtEnd(null, 101); LiveUnit.Assert.isTrue(verifyListContent(list, [1, 3, 101, 0, 2, 4])); dataSource.insertAtEnd(null, 90); LiveUnit.Assert.isTrue(verifyListContent(list, [1, 3, 101, 0, 2, 4, 90])); LiveUnit.Assert.areEqual("odd", list.groups.getAt(0), "checking the group content"); LiveUnit.Assert.areEqual("even", list.groups.getAt(1), "checking the group content"); listBinding.next() .then(scanFor(listBinding, 3)) .then(function (item) { var key = item.key; dataSource.insertBefore(null, 60, key); dataSource.insertAfter(null, 75, key); LiveUnit.Assert.isTrue(verifyListContent(list, [1, 3, 75, 101, 0, 2, 60, 4, 90]), "checking the correctness of insertAfter and before"); return listBinding.next(); }) .then(function (item) { dataSource.moveToStart(item.key); LiveUnit.Assert.isTrue(verifyListContent(list, [75, 1, 3, 101, 0, 2, 60, 4, 90]), "checking the correctness of moveToStart"); return listBinding.previous(); }) .then(function (item) { dataSource.moveToEnd(item.key); LiveUnit.Assert.isTrue(verifyListContent(list, [75, 3, 101, 1, 0, 2, 60, 4, 90]), "checking the correctness of moveToEnd"); return listBinding.current(); }) .then(function (item) { dataSource.change(item.key, 100); LiveUnit.Assert.isTrue(verifyListContent(list, [75, 101, 1, 0, 2, 60, 100, 4, 90]), "checking the correctness of change"); }) .then(null, errorHandler) .then(complete); } testBindingGroupSortedListDataSourceMutationFunction3(complete) { var logger = new LoggingNotificationHandler(true); var list = listGroupedByOddAndEven(5); var dataSource = list.dataSource; var listBinding = dataSource.createListBinding(logger); dataSource.insertAtEnd(null, 101); LiveUnit.Assert.isTrue(verifyListContent(list, [1, 3, 101, 0, 2, 4])); dataSource.insertAtEnd(null, 90); LiveUnit.Assert.isTrue(verifyListContent(list, [1, 3, 101, 0, 2, 4, 90])); LiveUnit.Assert.areEqual("odd", list.groups.getAt(0), "checking the group content"); LiveUnit.Assert.areEqual("even", list.groups.getAt(1), "checking the group content"); listBinding.next() .then(scanFor(listBinding, 3)) .then(function (item) { var key = item.key; dataSource.insertBefore(null, 60, key); dataSource.insertAfter(null, 75, key); LiveUnit.Assert.isTrue(verifyListContent(list, [1, 3, 75, 101, 0, 2, 60, 4, 90]), "checking the correctness of insertAfter and before"); return listBinding.next(); }) .then(function (item) { dataSource.moveToStart(item.key); LiveUnit.Assert.isTrue(verifyListContent(list, [75, 1, 3, 101, 0, 2, 60, 4, 90]), "checking the correctness of moveToStart"); return listBinding.previous(); }) .then(function (item) { dataSource.moveToEnd(item.key); LiveUnit.Assert.isTrue(verifyListContent(list, [75, 3, 101, 1, 0, 2, 60, 4, 90]), "checking the correctness of moveToEnd"); return WinJS.Promise.join({ current: listBinding.next(), next: listBinding.next(), nextNext: listBinding.next() }); }) .then(function (items) { dataSource.moveBefore(items.next.key, items.current.key); dataSource.moveAfter(items.nextNext.key, items.next.key); LiveUnit.Assert.isTrue(verifyListContent(list, [75, 3, 1, 101, 2, 60, 4, 0, 90]), "checking the correctness of list after multiple moves"); dataSource.moveBefore(items.current.key, items.current.key); //move before with same keys should be a noop dataSource.moveAfter(items.next.key, items.next.key); //move after with same keys should be a noop LiveUnit.Assert.isTrue(verifyListContent(list, [75, 3, 1, 101, 2, 60, 4, 0, 90]), "checking the correctness of list after noop moves"); dataSource.insertAtStart(null, 50); dataSource.insertAtStart(null, 40); LiveUnit.Assert.isTrue(verifyListContent(list, [75, 3, 1, 101, 50, 40, 2, 60, 4, 0, 90]), "checking the correctness of insertion after multiple mutations"); }) .then(null, errorHandler) .then(complete); } testBindingGroupSortedListMutatingGroup(complete) { function groupKeySelector(item) { return item.group.key; } function groupDataSelector(item) { return { title: item.group.key, } } var list = new WinJS.Binding.List<{ group: { key: string }; title: string }>(); var groupedItems = list.createGrouped(groupKeySelector, groupDataSelector); var logger = new LoggingNotificationHandler(true); var dataSource = groupedItems.dataSource; var listBinding = dataSource.createListBinding(logger); var groupsListBinding = groupedItems.groups.dataSource.createListBinding(); dataSource.beginEdits(); list.push({ group: { key: "1" }, title: "Banana" }); list.push({ group: { key: "2" }, title: "Peach" }); list.push({ group: { key: "1" }, title: "Blueberry" }); list.push({ group: { key: "2" }, title: "Plum" }); dataSource.endEdits(); LiveUnit.Assert.areEqual("Banana,Blueberry,Peach,Plum", groupedItems.map(function (item) { return item.title; }).join()); groupedItems.getAt(0).group.key = "2"; logger.setExpected([ "beginNotifications", "removed", "inserted", "indexChanged", "endNotifications" ]); dataSource.beginEdits(); groupedItems.notifyMutated(0); dataSource.endEdits(); logger.assertEmpty(); LiveUnit.Assert.areEqual("Blueberry,Banana,Peach,Plum", groupedItems.map(function (item) { return item.title; }).join()); var assertItems = listBinding.next() .then(function (item) { LiveUnit.Assert.areEqual("Blueberry", item.data.title); LiveUnit.Assert.areEqual("1", item.groupKey); return listBinding.next(); }) .then(function (item) { LiveUnit.Assert.areEqual("Banana", item.data.title); LiveUnit.Assert.areEqual("2", item.groupKey); return listBinding.next(); }) .then(function (item) { LiveUnit.Assert.areEqual("Peach", item.data.title); LiveUnit.Assert.areEqual("2", item.groupKey); return listBinding.next(); }) .then(function (item) { LiveUnit.Assert.areEqual("Plum", item.data.title); LiveUnit.Assert.areEqual("2", item.groupKey); }); var assertGroups = groupsListBinding.next() .then(function (group: any) { LiveUnit.Assert.areEqual("1", group.data.title); LiveUnit.Assert.areEqual(1, group.groupSize); LiveUnit.Assert.areEqual(0, group.firstItemIndexHint); LiveUnit.Assert.areEqual(list.getItem(2).key, group.firstItemKey); return groupsListBinding.next(); }) .then(function (group: any) { LiveUnit.Assert.areEqual("2", group.data.title); LiveUnit.Assert.areEqual(3, group.groupSize); LiveUnit.Assert.areEqual(1, group.firstItemIndexHint); LiveUnit.Assert.areEqual(list.getItem(0).key, group.firstItemKey); }); WinJS.Promise.join([assertItems, assertGroups]) .then(null, errorHandler) .then(complete); } testBindingListDirectAccess(complete) { var testArray = [10, 20, 30, 40, 50], testIndex = 2; var list = new WinJS.Binding.List(testArray), dataSource = list.dataSource; dataSource.itemFromIndex(testIndex) .then(function (item) { LiveUnit.Assert.areEqual(testIndex, item.index); LiveUnit.Assert.areEqual(testArray[testIndex], item.data); return dataSource.itemFromKey(item.key); }) .then(function (item) { LiveUnit.Assert.areEqual(testIndex, item.index); LiveUnit.Assert.areEqual(testArray[testIndex], item.data); }) .then(complete); } } function parent(element) { document.body.appendChild(element); return function () { document.body.removeChild(element); }; } export class BindingListWithListViewTests { testListViewInstantiation(complete) { var div = document.createElement("DIV"); var cleanup = parent(div); var list = new WinJS.Binding.List([1, 2, 3]); var lv = new WinJS.UI.ListView(div); lv.itemDataSource = list.dataSource; Helper.ListView.waitForReady(lv)() .then(function () { LiveUnit.Assert.areEqual(3, div.querySelectorAll(".win-container").length); }) .then(null, errorHandler) .then(cleanup) .done(complete); } }; // Register the object as a test class by passing in the name LiveUnit.registerTestClass("WinJSTests.BindingListTests"); LiveUnit.registerTestClass("WinJSTests.BindingListFilteredProjectionTests"); LiveUnit.registerTestClass("WinJSTests.BindingListWithListViewTests"); }