// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. // // /// /// module Tests { "use strict"; var List = WinJS.Binding.List; var join = WinJS.Promise.join; function errorHandler(msg) { try { LiveUnit.Assert.fail('There was an unhandled error in your test: ' + msg); } catch (ex) { } } function range(l, h) { var res = []; for (; l < h; l++) { res.push(l); } return res; } function asyncSequence(workFunctions) { return workFunctions.reduce(function (p, work) { return WinJS.Promise.as(p).then(function () { return WinJS.Promise.as(work()).then(function () { return WinJS.Promise.timeout(); }); }); }, WinJS.Promise.as()); } var seed = 0; function rand(nMax) { seed = (seed + 0.81282849124) * 2375.238208308; seed -= Math.floor(seed); return Math.floor(seed * nMax); } function resetSeed() { seed = 0; } function elementsAt(listItem, obj?) { var elements = []; if (obj) { for (var i in obj) { elements.push(listItem[i]); } } else { for (i in listItem) { elements.push(listItem[i]); } } return elements; } function walkDom(element, f) { f(element); if (element.children) { for (var i = 0, len = element.children.length; i < len; i++) { walkDom(element.children[i], f); } } } function verifyListView(listView, list, obj?) { var length = listViewLength(listView); for (var i = 0; i < length; i++) { var listViewElement = listView.winControl.elementFromIndex(i); var listViewElements = []; walkDom(listViewElement, function (el) { if (!el.children.length && el.textContent) { listViewElements.push(el.textContent); } }); var elementsAtList = elementsAt(list.getAt(i), obj); for (var j = 0; j < listViewElements.length; j++) { if (listViewElements[j] != elementsAtList[j]) { return false; } } if (elementsAtList.length !== listViewElements.length) { return false; } } return length === list.length; } function valid(str) { for (var i = 0, len = str.length; i < len && len === 1; i++) { if (str.charAt(i) === '\r' || str.charAt(i) === '\n' || str.charAt(i) === ' ') { return false; } } return str.length !== 0; } function clear(arr) { var validArray = []; for (var i = 0; i < arr.length; i++) { if (valid(arr[i])) { validArray.push(arr[i]); } } return validArray; } function listViewLength(listView) { var count = 0; while (listView.winControl.elementFromIndex(count++)); return (count === 0) ? 0 : count - 1; } function parent(element) { document.body.appendChild(element); element.cleanup = function () { WinJS.Utilities.disposeSubTree(element); document.body.removeChild(element); }; return element; } function moveRandom(list) { var target = rand(list.length); var source = rand(list.length); list.move(source, target); } function spliceRandom(list) { var target = rand(list.length); var element = { title: target, detail: "New Item spliced at " + target }; list.splice(target, 0, element); } function setAtRandom(list) { var target = rand(list.length); var oldElement = list.getAt(target); var newElement = { title: oldElement.title, detail: oldElement.title + " additional(" + target + ")" }; list.setAt(target, newElement); } function unshiftAndShiftRandom(list, order, iteration) { iteration = iteration; var shift = true; if (order && order.length) { shift = order.pop() ? false : true; } else { shift = rand(2) ? false : true; } if (shift && list.length) { var element = list.shift(); } else { var newElement = { title: iteration, detail: "New element unshifted on, iteration: " + iteration }; list.unshift(newElement); } } function pushAndPopRandom(list, order, iteration) { iteration = iteration || 0; var pop = true; if (order && order.length) { pop = order.pop() ? false : true; } else { pop = rand(2) ? false : true; } if (pop && list.length) { list.pop(); } else { var newElement = { title: iteration, detail: "New element pushed on, iteration: " + iteration.toString() }; list.push(newElement); } } function createDataSource(dataSource, groupDataSource) { var holder: any = document.createElement("div"); holder.msParentSelectorScope = true; holder.className = "dataSource"; holder.dataSource = dataSource; holder.groupDataSource = groupDataSource; return holder; } function createTemplate() { var holder: any = document.createElement("div"); holder.msParentSelectorScope = true; holder.id = "testTemplateWithListView"; holder.innerHTML = "
" + "
" + "
" + "
"; return holder; } function createGroupedListView() { var holder: any = document.createElement("div"); holder.msParentSelectorScope = true; holder.cssText = "height:100%;width:100%;overflow:scroll"; var listView = document.createElement("div"); listView.className = "listViewExample"; listView.setAttribute("data-win-control", "WinJS.UI.ListView "); listView.setAttribute("data-win-options", "{itemDataSource : select('.dataSource').dataSource , groupDataSource: select('.dataSource').groupDataSource, layout:{type:WinJS.UI.GridLayout}, itemTemplate: select('.sampleTemplate'), selectionMode:'single'} "); listView.style.height = "20000px"; listView.style.width = "500px"; holder.appendChild(listView); return holder; } function createListView() { var holder: any = document.createElement("div"); holder.msParentSelectorScope = true; holder.cssText = "height:100%;width:100%;overflow:scroll"; var listView = document.createElement("div"); listView.className = "listViewExample"; listView.setAttribute("data-win-control", "WinJS.UI.ListView "); listView.setAttribute("data-win-options", "{itemDataSource : select('.dataSource').dataSource , layout:{type:WinJS.UI.ListLayout}, itemTemplate: select('.sampleTemplate'), selectionMode:'single'} "); listView.style.height = "2000px"; listView.style.width = "1000px"; holder.appendChild(listView); return holder; } function createTestElements(listView, dataSource, groupDataSource?) { var holder: any = document.createElement("div"); holder.appendChild(createDataSource(dataSource, groupDataSource)); holder.appendChild(createTemplate()); holder.appendChild(listView); return holder; } function getCount(listViewContent, search) { var index = listViewContent.indexOf(search); var count = 0; while (index >= 0 && index < listViewContent.length) { count++; index = listViewContent.indexOf(search, index + 1); } return count; } function setAtRandomSpecial(list) { var target = rand(list.length); var oldElement = list.getAt(target); var newElement = { title: list.getAt(target).title + 2, detail: oldElement.title + " additional(" + target + ")" }; list.setAt(target, newElement); list.notifyMutated(target); } export class ListViewIntegrationTestingWithBindingList { setUp() { WinJS.Application.start(); Helper.initUnhandledErrors(); } tearDown() { WinJS.Application.stop(); Helper.cleanupUnhandledErrors(); } testReversingListViewWithListBinding = function (complete) { //BugID: 629543 var sampleDataSource = range(0, 20).map(function (i) { return { title: i, detail: "Javascript Toolkit_" + i }; }); var list = new WinJS.Binding.List(sampleDataSource); var elements = parent(createTestElements(createListView(), list.dataSource)); var listView = elements.querySelector(".listViewExample"); WinJS.UI.processAll(). then(Helper.ListView.waitForReady(listView)). then(function () { list.reverse(); // listView.winControl.forceLayout(); }). then(Helper.ListView.waitForReady(listView, 1000)). then(function () { LiveUnit.Assert.isTrue(verifyListView(listView, list), "checking the correctness of reversing a list"); }). then(elements.cleanup). then(resetSeed). then(Helper.validateUnhandledErrorsOnIdle). done(complete); } testSortingListViewWithListBinding = function (complete) { //BugID: 629543 var sampleDataSource = [] for (var i = 20; i > 0; i--) { var t = i; var d = "Javascript Toolkit_" + i; sampleDataSource.push({ title: t, detail: d }); } var list = new WinJS.Binding.List(sampleDataSource); var elements = parent(createTestElements(createListView(), list.dataSource)); var listView = elements.querySelector(".listViewExample"); WinJS.UI.processAll(). then(Helper.ListView.waitForReady(listView)). then(function () { list.sort(function (l, r) { return l.title - r.title; }); // listView.winControl.forceLayout(); }). then(Helper.ListView.waitForReady(listView, 1000)). then(function () { LiveUnit.Assert.isTrue(verifyListView(listView, list), "checking the correctness of sorting a list"); }). then(elements.cleanup). then(resetSeed). then(Helper.validateUnhandledErrorsOnIdle). done(complete); } testListViewWithEmptyFiltered = function (complete) { //BugID: 629543 var sampleDataSource = []; var sorted = new WinJS.Binding.List(sampleDataSource); var list = sorted.createFiltered(function (num) { return num.title % 2 === 0 }); var elements = parent(createTestElements(createListView(), list.dataSource)); var listView = elements.querySelector(".listViewExample"); WinJS.UI.processAll(). then(Helper.ListView.waitForReady(listView)). then(function () { list.push({ title: 1, detail: "first element" }); listView.winControl.forceLayout(); }). then(Helper.ListView.waitForReady(listView, -1)). then(function () { LiveUnit.Assert.isTrue(verifyListView(listView, list), "verfying the listView filter empty insertion"); }). then(elements.cleanup). then(resetSeed). then(Helper.validateUnhandledErrorsOnIdle). done(complete); } testListViewWithOneElementAndThenDeletedAndThenAdded = function (complete) { //BugID: 629543 var sampleDataSource = [{ title: 3, detail: "hello world" }]; var sorted = new WinJS.Binding.List(sampleDataSource); var list = sorted.createFiltered(function (num) { return num.title % 2 === 0 }); var elements = parent(createTestElements(createListView(), list.dataSource)); var listView = elements.querySelector(".listViewExample"); WinJS.UI.processAll(). then(Helper.ListView.waitForReady(listView)). then(function () { list.pop(); }). then(Helper.ListView.waitForReady(listView)). then(function () { LiveUnit.Assert.isTrue(verifyListView(listView, list), "checking the correctness of popping the last element"); list.push({ title: 2, detail: "hello world2" }); listView.winControl.forceLayout(); }). then(Helper.ListView.waitForReady(listView, -1)). then(function () { LiveUnit.Assert.isTrue(verifyListView(listView, list), "checking the correctness of pushing the first element"); }). then(elements.cleanup). then(resetSeed). then(Helper.validateUnhandledErrorsOnIdle). done(complete); } testListViewWithBindingEnabledInSortedList = function (complete) { //BugID: 629543 var sampleDataSource = []; for (var i = 0; i < 20; i++) { var d = "Corsica_" + i; var t = i; sampleDataSource.push({ title: t, detail: d }); } var list = new WinJS.Binding.List(sampleDataSource, { binding: true }); var objToCompare = { title: 1, detail: "temp" }; var elements = parent(createTestElements(createListView(), list.dataSource)); var listView = elements.querySelector(".listViewExample"); function assertListView(i) { return function () { list.getAt(i).detail = list.getAt(i).detail + '_' + i; } } WinJS.UI.processAll(). then(function () { return asyncSequence(range(10, list.length).map(assertListView)); }). then(Helper.ListView.waitForReady(listView, -1)). then(function () { LiveUnit.Assert.isTrue(verifyListView(listView, list, objToCompare), "checking the correctness of the listView after all Mutations are over"); }). then(elements.cleanup). then(resetSeed). then(Helper.validateUnhandledErrorsOnIdle). done(complete); } testBindingWithFiltered = function (complete) { //BugID: 629543 var sampleDataSource = []; for (var i = 0; i < 20; i++) { var d = "Corsica_" + i; var t = i; sampleDataSource.push({ title: t, detail: d }); } var objToCompare = { title: 1, detail: 1 }; var sort = new WinJS.Binding.List(sampleDataSource, { binding: true }); var list = sort.createFiltered(function (num) { return (num.title % 2 === 0); }); var elements = parent(createTestElements(createListView(), list.dataSource)); var listView = elements.querySelector(".listViewExample"); function assertListView(i) { return function () { if (list.getAt(i)) { list.getAt(i).title = list.getAt(i).title + i + (i % 3); list.notifyMutated(i); } }; } WinJS.UI.processAll(). then(function () { return asyncSequence(range(0, list.length).map(assertListView)); }). then(Helper.ListView.waitForReady(listView, -1)). then(function () { LiveUnit.Assert.isTrue(verifyListView(listView, list, objToCompare), "checking the correctness of the listView after all Mutations are over"); }). then(elements.cleanup). then(resetSeed). then(Helper.validateUnhandledErrorsOnIdle). done(complete); } testBindingWithSorted = function (complete) { //BugID: 629543 var sampleDataSource = []; var objToCompare = { title: 1, detail: 1 }; for (var i = 0; i < 20; i++) { var d = "Corsica_" + i; var t = i; sampleDataSource.push({ title: t, detail: d }); } var sort = new WinJS.Binding.List(sampleDataSource, { binding: true }); var list = sort.createSorted(function (l, r) { return r.title - l.title; }); var elements = parent(createTestElements(createListView(), list.dataSource)); var listView = elements.querySelector(".listViewExample"); function assertListView(i) { return function () { list.getAt(i).title = list.getAt(i).title + i * 10; list.notifyMutated(i); } } WinJS.UI.processAll(). then(function () { return asyncSequence(range(0, list.length).map(assertListView)); }). then(Helper.ListView.waitForReady(listView, -1)). then(function () { LiveUnit.Assert.isTrue(verifyListView(listView, list, objToCompare), "checking the correctness of the listView after all Mutations are over"); }). then(elements.cleanup). then(resetSeed). then(Helper.validateUnhandledErrorsOnIdle). done(complete); } testGroupSorted = function (complete) { //BugID: 629543 var sampleDataSource = range(0, 20).map(function (i) { return { title: i, detail: "Corsica_" + i }; }); var sorted = new WinJS.Binding.List(sampleDataSource, { binding: true }); var compare = function (num) { return (num.title % 2 === 0) ? "even" : "odd"; }; var list = sorted.createGrouped(compare, compare); var elements = parent(createTestElements(createGroupedListView(), list.dataSource, list.groups.dataSource)); var listView = elements.querySelector(".listViewExample"); var waitForInitPost = function () { return WinJS.Promise.timeout(300); }; // There has to be a better way to test this than waiting for 1s between edits... var itemUpdatePost = function (item) { return WinJS.Promise.timeout(1000).then(function () { return item; }); }; function assertListView(i) { return function () { switch (rand(4)) { case 0: spliceRandom(list); break; case 1: moveRandom(list); break; case 2: setAtRandom(list); break; case 3: pushAndPopRandom(list, order, i); break; default: throw "NYI"; } } } var order = [0, 1, 0, 0, 1, 1, 1, 0, 0, 0]; WinJS.UI.processAll(). then(waitForInitPost). then(function () { return asyncSequence(range(0, 50).map(assertListView)); }). then(itemUpdatePost). then(function () { LiveUnit.Assert.areEqual(1, getCount(listView.textContent, "even"), "should be 1 even group"); LiveUnit.Assert.areEqual(1, getCount(listView.textContent, "odd"), "should be 1 odd group"); }). then(elements.cleanup). then(resetSeed). then(Helper.validateUnhandledErrorsOnIdle). done(complete); } // Issue #135 xtestGroupSortedWithBinding = function (complete) { //BugID: 629543 var sampleDataSource = []; var objToCompare = { title: 1, detail: 1 }; function assertListView(i) { return function () { list.getAt(i).title++; list.notifyMutated(i); }; } for (var i = 0; i < 20; i++) { var d = "Corsica_" + i; var t = i; sampleDataSource.push({ title: t, detail: d }); } var sorted = new WinJS.Binding.List(sampleDataSource, { binding: true }); var compare = function (num) { return (num.title % 2 === 0) ? "even" : "odd"; }; var list = sorted.createGrouped(compare, compare); var elements = parent(createTestElements(createGroupedListView(), list.dataSource, list.groups.dataSource)); var listView = elements.querySelector(".listViewExample"); WinJS.UI.processAll(). then(function () { return asyncSequence(range(0, list.length).map(assertListView)); }). then(Helper.ListView.waitForReady(listView, -1)). then(function () { LiveUnit.Assert.isTrue(verifyListView(listView, list, objToCompare), "checking the correctness of the listView after all Mutations are over"); }). then(elements.cleanup). then(resetSeed). then(Helper.validateUnhandledErrorsOnIdle). done(complete); } testListViewWithSortedProjectionSpecialCases = function (complete) { //BugID: 629543 var sampleDataSource = []; for (var i = 0; i < 10; i++) { sampleDataSource.push({ title: i, detail: "hello world " + i }); } var sorted = new WinJS.Binding.List(sampleDataSource); var list = sorted.createFiltered(function (num) { return num.title % 2 === 0 }); var elements = parent(createTestElements(createListView(), list.dataSource)); var listView = elements.querySelector(".listViewExample"); function assertListView(i) { return function () { if (i <= 11) { sorted.push({ title: i, detail: "hello world " + i }); } else if (i < 14) { list.push({ title: i, detail: "hello world " + i }); } else if (i == 14) { sorted.length = 6; } else { list.length = 2; } }; } WinJS.UI.processAll(). then(function () { return asyncSequence(range(10, 16).map(assertListView)); }). then(Helper.ListView.waitForReady(listView, -1)). then(function () { LiveUnit.Assert.isTrue(verifyListView(listView, list), "checking the correctness of the listView after all Mutations are over"); }). then(elements.cleanup). then(resetSeed). then(Helper.validateUnhandledErrorsOnIdle). done(complete); } testListViewWithListMutations = function (complete) { //BugID: 629543 var sampleDataSource = []; for (var i = 0; i < 20; i++) { var t = "Corsica_" + i; var d = "Javascript Toolkit_" + i; sampleDataSource.push({ title: t, detail: d }); } var list = new WinJS.Binding.List(sampleDataSource); var elements = parent(createTestElements(createListView(), list.dataSource)); var listView = elements.querySelector(".listViewExample"); var order = [0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0]; function assertListView(i) { return function () { switch (rand(4)) { case 0: spliceRandom(list); break; case 1: moveRandom(list); break; case 2: setAtRandom(list); break; case 3: pushAndPopRandom(list, order, i); break; default: throw "NYI"; } }; } WinJS.UI.processAll(). then(Helper.ListView.waitForReady(listView)). then(function () { return asyncSequence(range(0, 20).map(assertListView)); }). then(Helper.ListView.waitForReady(listView)). then(function () { LiveUnit.Assert.isTrue(verifyListView(listView, list), "checking the correctness of the listView after all Mutations are over"); }). then(elements.cleanup). then(resetSeed). then(Helper.validateUnhandledErrorsOnIdle). done(complete); } testListViewWithSortedListMutations = function (complete) { //BugID: 629543 var sampleDataSource = []; for (var i = 0; i < 20; i++) { var t = "Corsica_" + i; var d = "Javascript Toolkit_" + i; sampleDataSource.push({ title: t, detail: d }); } var sorted = new WinJS.Binding.List(sampleDataSource); var list = sorted.createSorted(function (l, r) { return r.title - l.title; }); var elements = parent(createTestElements(createListView(), list.dataSource)); var listView = elements.querySelector(".listViewExample"); var order = [0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0]; function assertListView(i) { return function () { switch (rand(4)) { case 0: spliceRandom(list); break; case 1: moveRandom(list); break; case 2: setAtRandom(list); break; case 3: pushAndPopRandom(list, order, i); break; default: throw "NYI"; } }; } WinJS.UI.processAll(). then(Helper.ListView.waitForReady(listView)). then(function () { return asyncSequence(range(0, 20).map(assertListView)); }). then(Helper.ListView.waitForReady(listView, -1)). then(function () { LiveUnit.Assert.isTrue(verifyListView(listView, list), "checking the correctness of the listView after all Mutations are over"); }). then(elements.cleanup). then(resetSeed). then(Helper.validateUnhandledErrorsOnIdle). done(complete); } testListViewWithFilteredListMutation = function (complete) { //BugID: 629543 var sampleDataSource = []; for (var i = 0; i < 20; i++) { var d = "Corsica_" + i; var t = i; sampleDataSource.push({ title: t, detail: d }); } var sorted = new WinJS.Binding.List(sampleDataSource); var list = sorted.createFiltered(function (num) { return num.title % 2 === 0 }); var elements = parent(createTestElements(createListView(), list.dataSource)); var listView = elements.querySelector(".listViewExample"); var order = [0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0]; function assertListView(i) { return function () { switch (rand(4)) { case 0: spliceRandom(list); break; case 1: moveRandom(list); break; case 2: setAtRandomSpecial(list); break; case 3: pushAndPopRandom(list, order, i); break; default: throw "NYI"; } } } WinJS.UI.processAll(). then(function () { return asyncSequence(range(0, 30).map(assertListView)); }). then(Helper.ListView.waitForReady(listView, -1)). then(function () { LiveUnit.Assert.isTrue(verifyListView(listView, list), "checking the correctness of the listView after all Mutations are over"); }). then(elements.cleanup). then(resetSeed). then(Helper.validateUnhandledErrorsOnIdle). done(complete); } testListViewWithSpecialGroupSortedCases = function (complete) { //BugID: 629543 var list = new WinJS.Binding.List(range(0, 20).map(function (i) { return { title: i, detail: "Corsica_" + i }; })); var groupKey = function (item) { return item.title % 2 === 0 ? "even" : "odd"; }; var grouped = list.createGrouped(groupKey, groupKey); var elements = parent(createTestElements(createGroupedListView(), grouped.dataSource, grouped.groups.dataSource)); var listView = elements.querySelector(".listViewExample"); WinJS.UI.processAll(). then(Helper.ListView.waitForReady(listView)). then(function () { LiveUnit.Assert.areEqual(1, getCount(listView.textContent, "even"), "should be 1 even group"); LiveUnit.Assert.areEqual(1, getCount(listView.textContent, "odd"), "should be 1 odd group"); LiveUnit.Assert.areEqual(list.length, getCount(listView.textContent, "Corsica_")); var odd: any = grouped.groups.getItem(1); grouped.splice(odd.firstItemIndexHint, grouped.length - odd.firstItemIndexHint); LiveUnit.Assert.areEqual(1, grouped.groups.length, "should now only be an even group"); LiveUnit.Assert.areEqual("even", grouped.groups.getAt(0)); }). then(Helper.ListView.waitForReady(listView, -1)). then(function () { LiveUnit.Assert.areEqual(1, getCount(listView.textContent, "even"), "should be 1 even group"); LiveUnit.Assert.areEqual(0, getCount(listView.textContent, "odd"), "should be 0 odd groups"); LiveUnit.Assert.areEqual(list.length, getCount(listView.textContent, "Corsica_")); return grouped.shift(); }). then(Helper.ListView.waitForReady(listView, -1)). then(function (item) { LiveUnit.Assert.areEqual(1, getCount(listView.textContent, "even"), "should be 1 even group"); LiveUnit.Assert.areEqual(0, getCount(listView.textContent, "odd"), "should be 0 odd groups"); LiveUnit.Assert.areEqual(list.length, getCount(listView.textContent, "Corsica_")); LiveUnit.Assert.areEqual(0, getCount(listView.textContent, item.detail), "removed item should not be in list view"); return grouped.pop(); }). then(Helper.ListView.waitForReady(listView, -1)). then(function (item) { LiveUnit.Assert.areEqual(1, getCount(listView.textContent, "even"), "should be 1 even group"); LiveUnit.Assert.areEqual(0, getCount(listView.textContent, "odd"), "should be 0 odd groups"); LiveUnit.Assert.areEqual(list.length, getCount(listView.textContent, "Corsica_")); LiveUnit.Assert.areEqual(0, getCount(listView.textContent, item.detail), "removed item should not be in list view"); var newItem = { title: 13, detail: "Added_13" }; grouped.push(newItem); LiveUnit.Assert.areEqual(2, grouped.groups.length, "should now only be an even group"); LiveUnit.Assert.areEqual("even", grouped.groups.getAt(0)); LiveUnit.Assert.areEqual("odd", grouped.groups.getAt(1)); return newItem; }). then(Helper.ListView.waitForReady(listView, -1)). then(function (item) { LiveUnit.Assert.areEqual(1, getCount(listView.textContent, "even"), "should be 1 even group"); LiveUnit.Assert.areEqual(1, getCount(listView.textContent, "odd"), "should be 1 odd group"); LiveUnit.Assert.areEqual(list.length - 1, getCount(listView.textContent, "Corsica_")); LiveUnit.Assert.areEqual(1, getCount(listView.textContent, item.detail), "added item should be in list view"); return grouped.shift(); }). then(Helper.ListView.waitForReady(listView, -1)). then(function (item) { LiveUnit.Assert.areEqual(1, getCount(listView.textContent, "even"), "should be 1 even group"); LiveUnit.Assert.areEqual(1, getCount(listView.textContent, "odd"), "should be 1 odd group"); LiveUnit.Assert.areEqual(list.length - 1, getCount(listView.textContent, "Corsica_")); LiveUnit.Assert.areEqual(1, getCount(listView.textContent, "Added_")); LiveUnit.Assert.areEqual(0, getCount(listView.textContent, item.detail), "removed item should not be in list view"); }). then(elements.cleanup). then(resetSeed). then(Helper.validateUnhandledErrorsOnIdle). done(complete); }; testListViewUsingGroupSortedWithMutations = function (complete) { //BugID: 629543 var sampleDataSource = []; for (var i = 0; i < 20; i++) { var d = "Corsica_" + i; var t = i; sampleDataSource.push({ title: t, detail: d }); } var sorted = new WinJS.Binding.List(sampleDataSource); var compare = function (num) { return (num.title % 2 === 0) ? "even" : "odd"; }; var list = sorted.createGrouped(compare, compare); var elements = parent(createTestElements(createGroupedListView(), list.dataSource, list.groups.dataSource)); var listView = elements.querySelector(".listViewExample"); var order = [0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0]; function assertListView(i) { return function () { switch (rand(4)) { case 0: spliceRandom(list); break; case 1: moveRandom(list); break; case 2: setAtRandoms(); break; case 3: pushAndPopRandom(list, order, i); break; default: throw "NYI"; } }; } WinJS.UI.processAll(). then(Helper.ListView.waitForReady(listView)). then(function () { listView.winControl.itemDataSource.beginEdits(); listView.winControl.groupDataSource.beginEdits(); return asyncSequence(range(0, 30).map(assertListView)); }). then(function () { listView.winControl.itemDataSource.endEdits(); listView.winControl.groupDataSource.endEdits(); }). then(Helper.ListView.waitForReady(listView, -1)). then(function () { var evenCount = getCount(listView.textContent, "even"); var oddCount = getCount(listView.textContent, "odd"); LiveUnit.Assert.areEqual(1, oddCount, "number of odd groups should be only 1"); LiveUnit.Assert.areEqual(1, evenCount, "number of even groups should be only 1"); LiveUnit.Assert.isTrue(verifyListView(listView, list), "checking the correctness of the listView after all Mutations are over"); }). then(elements.cleanup). then(resetSeed). then(Helper.validateUnhandledErrorsOnIdle). done(complete); function setAtRandoms() { var target = rand(list.length); var oldElement = list.getAt(target); var newElement = { title: list.getAt(target).title + 2, detail: oldElement.title + " additional(" + target + ")" }; list.setAt(target, newElement); list.notifyMutated(target); } } testAffectedRange = function (complete) { var rangeTester = { expectedRange: function (start, end) { this.start = start; this.end = end; return new WinJS.Promise(function (complete) { this.completePromise = complete; }.bind(this)); }, verify: function (range) { LiveUnit.Assert.areEqual(this.start, range.start); LiveUnit.Assert.areEqual(this.end, range.end); var that = this; WinJS.Utilities._setImmediate(function () { that.completePromise(); }); } } var sampleDataSource: { title: any; detail?: string; group?: any }[] = range(0, 100).map(function (i) { return { title: i, detail: "Javascript Toolkit_" + i }; }); var list = new WinJS.Binding.List(sampleDataSource); var dataSource = list.dataSource; var notificationHandler = { affectedRange: rangeTester.verify.bind(rangeTester) }; var binding = dataSource.createListBinding(notificationHandler); /* move from 0 to 10 -> insert at 5 */ LiveUnit.LoggingCore.logComment("Test: move from 0 to 10 -> insert at 5"); // Move from Index 0 to index 10 list.move(0, 10); // [start = 0, end = 11;) // Insert an item at index 5 list.splice(5, 0, { title: "N0", group: 0 }); // [start = 0, end = 12) var testPromise = rangeTester.expectedRange(0, 12).then(function () { /* change at 98 -> remove from 50 */ LiveUnit.LoggingCore.logComment("Test: change at 98 -> remove from 50"); // Change Item at index 98. list.setAt(98, { title: "N0", group: 0 }); // [start = 98, end = 99) // Remove item at index 50 list.splice(50, 1); // [start = 50, end = 98) return rangeTester.expectedRange(50, 98); }).then(function () { /* insert -> move -> insert -> change -> remove -> remove -> remove -> remove -> move -> change -> insert -> insert -> insert -> insert */ LiveUnit.LoggingCore.logComment("Test: batch of 'insert -> move -> insert -> change -> remove -> remove -> remove -> remove -> move -> change -> insert -> insert -> insert -> insert' operations"); // Insert item at index 89 list.splice(89, 0, { title: "N0", group: 0 }); // [start = 89, end = 90) // Move item from index 90 to index 20 list.move(90, 20); // [start = 20, end = 90) // Insert item at index 10 list.splice(10, 0, { title: "N0", group: 0 }); // [start = 10, end = 91) // Change item at index 9 list.setAt(9, { title: "N0", group: 0 }); // [start = 9, end = 91) // Remove 2 items from index 11 list.splice(11, 1) // [start = 9, end = 90) list.splice(11, 1) // [start = 9, end = 89) // Remove 2 items from index 6 list.splice(6, 2) // [start = 6, end = 87) // Move item at index 7 to index 87 list.move(7, 22) // [start = 6, end = 88) // Change item at index 66 list.setAt(66, { title: "N0", group: 0 }); // [start = 6, end = 88) // Insert item at index 7 list.splice(7, 0, { title: "N0", group: 0 }) // [start = 6, end = 89) // Insert item at index 6 list.splice(6, 0, { title: "N0", group: 0 }) // [start = 6, end = 90) // Insert item at index 5 list.splice(5, 0, { title: "N0", group: 0 }) // [start = 5, end = 91) // Insert item at index 90 list.splice(90, 0, { title: "N0", group: 0 }) // [start = 5, end = 92) return rangeTester.expectedRange(5, 92); }).then(function () { /* remove at index 33 */ LiveUnit.LoggingCore.logComment("Test: single remove at index 33"); list.splice(33, 1); // [start = 33, end = 33) return rangeTester.expectedRange(33, 33); }).then(function () { /* remove from the end */ LiveUnit.LoggingCore.logComment("Test: single remove from the end"); var end, start = end = list.length - 1; list.splice(list.length - 1, 1); // [start = list.length - 1, end = list.length - 1) return rangeTester.expectedRange(start, end); }).then(function () { /* remove at index 0 */ LiveUnit.LoggingCore.logComment("Test: single remove from index 0"); list.splice(0, 1); // [start = 0, end = 0) return rangeTester.expectedRange(0, 0); }).then(function () { /* insert at 0 */ LiveUnit.LoggingCore.logComment("Test: single insert at index 0"); list.splice(0, 0, { title: "N0", group: 0 });// [start = 0, end = 1) return rangeTester.expectedRange(0, 1); }).then(function () { /* insert at end */ LiveUnit.LoggingCore.logComment("Test: single insert at the end"); var start = list.length; var end = list.length + 1; list.splice(list.length, 0, { title: "N0", group: 0 });// [start = list.length, end = list.length + 1) return rangeTester.expectedRange(start, end); }).then(function () { /* insert at index 44*/ LiveUnit.LoggingCore.logComment("Test: single insert at index 44"); list.splice(44, 0, { title: "N0", group: 0 });// [start = 44, end = 45) return rangeTester.expectedRange(44, 45); }).then(function () { /* change at index 60 */ LiveUnit.LoggingCore.logComment("Test: change at index 60"); list.setAt(60, { title: "N0", group: 0 }); // [start = 60, end = 61) return rangeTester.expectedRange(60, 61); }).then(function () { /* change at index 0 */ LiveUnit.LoggingCore.logComment("Test: change at index 0"); list.setAt(0, { title: "N0", group: 0 }); // [start = 0, end = 1) return rangeTester.expectedRange(0, 1); }).then(function () { /* change last index */ LiveUnit.LoggingCore.logComment("Test: change at last index"); var start = list.length - 1; var end = list.length; list.setAt(list.length - 1, { title: "N0", group: 0 }); // [start = list.length - 1, end = list.length) return rangeTester.expectedRange(start, end); }).then(function () { /* Move from first index to last index */ LiveUnit.LoggingCore.logComment("Test: move item from first index to last index"); var start = 0; var end = list.length; list.move(0, list.length - 1);// [start = 0, end = list.length) return rangeTester.expectedRange(start, end); }).then(function () { /* Move from last index to first index */ LiveUnit.LoggingCore.logComment("Test: move item from last index to first index"); list.move(list.length - 1, 0); // [start = 0, end = list.length) return rangeTester.expectedRange(0, list.length); }).then(function () { /* Move from last index to somewhere inside of the range. */ LiveUnit.LoggingCore.logComment("Test: move an item from last index to the middle of the current range"); // establish a range from 0 to 11; list.move(0, 10); // [start = 0, end = 11) // perform the test. list.move(15, 5); // [start = 0, end = 16) return rangeTester.expectedRange(0, 16); }). then(resetSeed). then(Helper.validateUnhandledErrorsOnIdle). done(complete); } } } LiveUnit.registerTestClass("Tests.ListViewIntegrationTestingWithBindingList");