// 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";
var testRootEl;
var ListView = WinJS.UI.ListView;
function parent(element) {
testRootEl.appendChild(element);
return function () { testRootEl.removeChild(element); };
}
function errorHandler(msg) {
try {
LiveUnit.Assert.fail('There was an unhandled error in your test: ' + msg);
} catch (ex) { }
}
export class ListViewRegression {
setUp() {
testRootEl = document.createElement("div");
testRootEl.className = "file-listview-css";
document.body.appendChild(testRootEl);
}
tearDown() {
WinJS.Utilities.disposeSubTree(testRootEl);
document.body.removeChild(testRootEl);
}
testWin8_342083 = function (complete) {
var div = document.createElement("DIV");
var cleanup = parent(div);
WinJS.Promise.as().then(function () {
var lv = new WinJS.UI.ListView(div);
}).
then(null, errorHandler).
then(cleanup).
then(complete);
};
testWin8_312074 = function (complete) {
function createDataSource(steps) {
var count = 100,
step = 0;
var dataSource = {
itemsFromKey: function (key, countBefore, countAfter) {
return this.itemsFromIndex(parseInt(key, 10), countBefore, countAfter);
},
itemsFromIndex: function (index, countBefore, countAfter) {
var requestedCount = countBefore + countAfter + 1;
return WinJS.Promise.timeout(100).then(function () {
return new WinJS.Promise(function (complete, error) {
if (step < steps.length) {
count = steps[step];
step++;
}
if (index >= 0 && index < count) {
var startIndex = Math.max(0, index - countBefore),
endIndex = Math.min(index + Math.max(20, countAfter), count - 1),
size = endIndex - startIndex + 1;
var items = [];
for (var i = startIndex; i < startIndex + size; i++) {
var groupid = Math.floor(i / 8);
items.push({
key: i.toString(),
data: {
group: groupid,
title: groupid + " Lorem Ispum Dolor " + i
}
});
}
complete({
items: items,
offset: index - startIndex,
totalCount: count,
absoluteIndex: index
});
} else {
complete({});
}
});
});
},
getCount: function () {
return WinJS.Promise.timeout(100).then(function () {
return WinJS.Promise.wrap(count);
});
}
};
return new WinJS.UI.ListDataSource(dataSource);
}
var tests = [{
steps: [26]
}, {
steps: [75, 26]
}
// TODO: Uncomment when 363030 is fixed
// , {
// steps: [13]
// }
];
function runTest(t) {
if (t < tests.length) {
var test = tests[t];
var newNode = document.createElement("div");
newNode.style.width = "1000px";
newNode.style.height = "600px";
var cleanup = parent(newNode);
var listView = new WinJS.UI.ListView(newNode, {
layout: new WinJS.UI.GridLayout(),
itemDataSource: createDataSource(test.steps),
itemTemplate: function (itemPromise) {
function worker(item) {
if (item) {
var element = document.createElement("div");
element.textContent = item.data.title;
element.style.width = element.style.height = "100px";
return element;
} else {
return null;
}
}
return WinJS.Promise.as(itemPromise).then(worker);
}
});
var whenComplete = function whenComplete() {
if (listView.loadingState === "complete") {
listView.removeEventListener("loadingstatechanged", whenComplete, false);
cleanup();
runTest(t + 1);
}
};
listView.addEventListener("loadingstatechanged", whenComplete, false);
} else {
complete();
}
}
runTest(0);
};
testWin8_370759 = function (complete) {
function createDataSource() {
var count = 500,
returned = -1;
var dataSource = {
itemsFromIndex: function (index, countBefore, countAfter) {
return WinJS.Promise.timeout(100).then(function () {
return new WinJS.Promise(function (complete, error) {
var startIndex = Math.max(0, index - countBefore),
endIndex = Math.min(index + 20, count - 1),
size = endIndex - startIndex + 1;
var items = [];
for (var i = startIndex; i < startIndex + size; i++) {
var groupid = Math.floor(i / 8),
text = groupid + " Lorem Ispum Dolor " + i;
if (i <= returned) {
text = "Changed";
}
items.push({
key: i.toString(),
data: {
group: groupid,
title: text
}
});
}
returned = endIndex;
complete({
items: items,
offset: index - startIndex,
totalCount: count,
absoluteIndex: index
});
});
});
},
getCount: function () {
return WinJS.Promise.timeout(100).then(function () {
return WinJS.Promise.wrap(count);
});
}
};
return new WinJS.UI.ListDataSource(dataSource);
}
var newNode = document.createElement("div");
newNode.style.width = "1000px";
newNode.style.height = "600px";
var cleanup = parent(newNode);
var listView = new ListView(newNode, {
layout: new WinJS.UI.GridLayout(),
itemDataSource: createDataSource(),
itemTemplate: function (itemPromise) {
function worker(item) {
var element = document.createElement("div");
element.textContent = item.data.title;
element.style.width = element.style.height = "100px";
return element;
}
return itemPromise.then(worker);
}
});
var counter = 0,
range;
function readyStateHandler(eventObject) {
if (listView.loadingState === "complete") {
var sl = listView.scrollPosition;
if (!range) {
range = listView._canvas[listView._scrollLength];
}
if ((sl + 1000 < range) && (++counter < 10)) {
listView.scrollPosition = sl + 1000;
} else {
listView.removeEventListener("loadingstatechanged", readyStateHandler, false);
cleanup();
complete();
}
}
}
listView.addEventListener("loadingstatechanged", readyStateHandler, false);
};
testWin8_595149 = function (complete) {
var items = [];
for (var i = 0; i < 100; i++) {
items.push({ title: "Tile" + i });
}
var list = new WinJS.Binding.List(items);
var elements = [];
function renderer(itemPromise) {
return itemPromise.then(function (item) {
var element;
if (elements[item.index]) {
element = elements[item.index];
} else {
element = document.createElement("div");
elements[item.index] = element;
}
element.textContent = item.data.title;
element.style.width = element.style.height = "100px";
return element;
});
}
var newNode = document.createElement("div");
newNode.style.width = "600px";
newNode.style.height = "600px";
var cleanup = parent(newNode);
var listView = new WinJS.UI.ListView(newNode, {
layout: new WinJS.UI.GridLayout(),
itemDataSource: list.dataSource,
itemTemplate: renderer
});
function checkTile(listview, index, text) {
var tile = listview.elementFromIndex(index);
LiveUnit.Assert.areEqual(text, tile.textContent);
}
var tests = [
function () {
checkTile(listView, 0, "Tile0");
checkTile(listView, 1, "Tile1");
list.setAt(0, { title: "Changed" });
return true;
},
function () {
checkTile(listView, 0, "Changed");
checkTile(listView, 1, "Tile1");
cleanup();
complete();
},
];
Helper.ListView.runTests(listView, tests);
};
testWin8_725480 = function (complete) {
var items = [{
group: "A",
title: "Tile" + 0
}];
var list = new WinJS.Binding.List(items);
function groupKey(data) {
return data.group;
}
function groupData(data) {
return {
title: data.group
};
}
var myGroupedList = list.createGrouped(groupKey, groupData);
function renderer(itemPromise) {
return itemPromise.then(function (item) {
var element = document.createElement("div");
element.textContent = item.data.title;
element.style.width = element.style.height = "100px";
return element;
});
}
var newNode = document.createElement("div");
newNode.style.width = "700px";
newNode.style.height = "700px";
var cleanup = parent(newNode);
var listView = new WinJS.UI.ListView(newNode, {
layout: new WinJS.UI.GridLayout(),
itemDataSource: myGroupedList.dataSource,
groupDataSource: myGroupedList.groups.dataSource,
itemTemplate: renderer,
groupHeaderTemplate: renderer
});
function checkTile(listview, index, text) {
var tile = listview.elementFromIndex(index);
LiveUnit.Assert.areEqual(text, tile.textContent);
}
function addTile(label) {
var dataSource = listView.itemDataSource;
dataSource.beginEdits();
list.push({
group: "A",
title: label
});
dataSource.endEdits();
}
Helper.ListView.waitForReady(listView)().then(function () {
checkTile(listView, 0, "Tile0");
addTile("Tile1");
listView.forceLayout();
addTile("Tile2");
addTile("Tile3");
listView.forceLayout();
return WinJS.Promise.timeout();
}).then(function () {
addTile("Tile4");
listView.forceLayout();
addTile("Tile5");
addTile("Tile6");
listView.forceLayout();
return WinJS.Promise.timeout(50);
}).then(function () {
checkTile(listView, 0, "Tile0");
checkTile(listView, 6, "Tile6");
cleanup();
complete();
});
};
testWin8_769820 = function (complete) {
var items = [],
tiles = [];
for (var i = 0; i < 100; i++) {
items.push({ title: "Item" + i });
tiles.push({ title: "Tile" + i });
}
function renderer(itemPromise) {
return itemPromise.then(function (item) {
var element = document.createElement("div");
element.textContent = item.data.title;
element.style.width = element.style.height = "100px";
return element;
});
}
var newNode = document.createElement("div");
newNode.style.width = "600px";
newNode.style.height = "600px";
var cleanup = parent(newNode);
var listView = new WinJS.UI.ListView(newNode, {
layout: new WinJS.UI.GridLayout(),
itemDataSource: (new WinJS.Binding.List(items)).dataSource,
itemTemplate: renderer
});
function checkTile(listview, index, text) {
var tile = listview.elementFromIndex(index);
LiveUnit.Assert.areEqual(text, tile.textContent);
}
function whenComplete() {
if (listView.loadingState === "complete") {
listView.removeEventListener("loadingstatechanged", whenComplete, false);
checkTile(listView, 0, "Item0");
listView.itemDataSource = (new WinJS.Binding.List(tiles)).dataSource;
WinJS.Utilities._setImmediate(function () {
// template is changed while fadeOut animation is in progress
listView.itemTemplate = renderer;
listView.forceLayout();
Helper.ListView.whenLoadingComplete(listView, function () {
checkTile(listView, 0, "Tile0");
cleanup();
complete();
});
});
}
}
listView.addEventListener("loadingstatechanged", whenComplete, false);
};
testWin8_930766 = function (complete) {
var count = 500;
var rendererCalled = [],
rendererSignals = [];
for (var i = 0; i < count; i++) {
var signal = new WinJS._Signal();
rendererSignals.push(signal);
rendererCalled.push(signal.promise);
}
function createDataSource() {
var dataSource = {
itemsFromIndex: function (index, countBefore, countAfter) {
var startIndex = index,
size = 2;
var items = [];
for (var i = startIndex; (i < startIndex + size) && (i < count); i++) {
rendererSignals[i].complete();
items.push({
key: i.toString(),
data: {
title: "Item" + i
}
});
}
return WinJS.Promise.timeout(100).then(function () {
return new WinJS.Promise(function (complete, error) {
complete({
items: items,
offset: index - startIndex,
totalCount: count,
absoluteIndex: index
});
});
});
},
getCount: function () {
return WinJS.Promise.wrap(count);
}
};
return new WinJS.UI.ListDataSource(dataSource);
}
function renderer(itemPromise, recycledElement) {
var element = recycledElement;
if (!element) {
element = document.createElement("div");
element.appendChild(document.createElement("div"));
element.style.width = element.style.height = "100px";
}
LiveUnit.Assert.isTrue(element.hasChildNodes(), "Renderer has received a corrupted recycledElement");
return itemPromise.then(function (item) {
element.children[0].textContent = item.data.title;
return element;
});
}
var newNode = document.createElement("div");
newNode.style.width = "300px";
newNode.style.height = "301px";
var cleanup = parent(newNode);
var listView = new WinJS.UI.ListView(newNode, {
layout: new WinJS.UI.GridLayout(),
itemDataSource: createDataSource(),
itemTemplate: renderer
});
Helper.ListView.waitForReady(listView)().then(function () {
// this causes items from 45-53 to be rendered and releases items 0-5. Since there is more items to render than released items, items 51-53 will be rendered without recycling
listView.scrollPosition = 850;
return WinJS.Promise.join(rendererCalled.slice(45, 54));
}).then(function () {
// items 51-53 aren't yet rendered. ListView is waiting for data. Forcing scrolling at this point.
// This cancel the previous realizePass which is waiting for data for items 51-53 and starts a new realizePass.
// In middle of this new realize pass data for items 51-53 is delivered and items pool reuses wrappers corrupting items in in the pool
LiveUnit.Assert.areEqual("itemsLoading", listView.loadingState);
listView.scrollPosition = 4500;
}).then(Helper.ListView.waitForReady(listView)).then(function () {
cleanup();
complete();
});
};
testWinBlue_148641 = function (complete) {
var items = [],
tiles = [];
for (var i = 0; i < 100; i++) {
items.push({ title: "Item" + i });
tiles.push({ title: "Tile" + i });
}
function renderer(itemPromise) {
return itemPromise.then(function (item) {
var element = document.createElement("div");
element.textContent = item.data.title;
element.style.width = element.style.height = "100px";
return element;
});
}
var newNode = document.createElement("div");
newNode.style.width = "600px";
newNode.style.height = "600px";
var cleanup = parent(newNode);
var listView = new ListView(newNode, {
layout: new WinJS.UI.GridLayout(),
itemDataSource: (new WinJS.Binding.List(items)).dataSource,
itemTemplate: renderer
});
var newTabIndex = 999,
completed = false;
function whenComplete() {
if (listView.loadingState === "complete") {
listView.removeEventListener("loadingstatechanged", whenComplete, false);
var realOnPropertyChangeHandler = listView._onPropertyChange.bind(listView);
listView._onPropertyChange = function (list) {
realOnPropertyChangeHandler(list);
list.forEach(function (record) {
if (!completed && record.attributeName === "tabIndex") {
LiveUnit.Assert.areEqual(listView.element.tabIndex, -1);
LiveUnit.Assert.areEqual(listView.elementFromIndex(0).tabIndex, newTabIndex);
completed = true;
complete();
}
});
};
listView.element.tabIndex = newTabIndex;
}
}
listView.addEventListener("loadingstatechanged", whenComplete, false);
};
testWinBlue_256523 = function (complete) {
var items = [];
for (var i = 0; i < 100; i++) {
items.push({
title: "Item" + i,
group: Math.floor(i / 10).toString(),
});
}
var list = new WinJS.Binding.List(items);
function groupKey(data) {
return data.group;
}
function groupData(data) {
return {
title: data.group
};
}
var myGroupedList = list.createGrouped(groupKey, groupData);
function renderer(itemPromise) {
return itemPromise.then(function (item) {
var element = document.createElement("div");
element.textContent = item.data.title;
element.style.width = element.style.height = "100px";
return element;
});
}
var newNode = document.createElement("div");
newNode.style.width = "600px";
newNode.style.height = "600px";
var cleanup = parent(newNode);
var listView = new WinJS.UI.ListView(newNode, {
layout: new WinJS.UI.GridLayout(),
itemDataSource: myGroupedList.dataSource,
groupDataSource: myGroupedList.groups.dataSource,
itemTemplate: renderer,
groupHeaderTemplate: renderer
});
Helper.ListView.waitForReady(listView)().then(function () {
listView.ensureVisible(99);
return Helper.ListView.waitForReady(listView, -1)();
}).then(function () {
listView.itemDataSource = null;
return Helper.ListView.waitForReady(listView, -1)();
}).then(function () {
listView.scrollPosition = 100;
return Helper.ListView.waitForReady(listView, -1)();
}).then(function () {
cleanup();
complete();
});
};
testWinBlue_389800_EnsureVisibleOnHiddenListViewRTL = function (complete) {
Helper.initUnhandledErrors();
var lv = document.createElement("div");
lv.setAttribute("dir", "rtl")
testRootEl.appendChild(lv);
function renderer(itemPromise) {
var e = document.createElement("div");
e.style.width = e.style.height = "100px";
itemPromise.then(function (item) {
e.style.backgroundColor = "";
e.textContent = item.data.title;
});
return e;
}
var items = [];
for (var i = 0; i < 3000; i++) {
items.push({
title: "Tile" + i
});
}
var list = new WinJS.Binding.List(items);
var listView = new WinJS.UI.ListView(lv, {
itemDataSource: list.dataSource,
itemTemplate: renderer,
layout: new WinJS.UI.GridLayout()
});
Helper.ListView.waitForReady(listView)().then(function () {
lv.style.display = "none";
listView.ensureVisible(100);
Helper.ListView.waitForDeferredAction(listView)().then(function () {
Helper.validateUnhandledErrors();
testRootEl.removeChild(lv);
complete();
});
});
};
}
if (!Helper.Browser.isIE11) {
Helper.disableTest(ListViewRegression, "testWinBlue_148641");
Helper.disableTest(ListViewRegression, "testWin8_725480");
}
}
LiveUnit.registerTestClass("WinJSTests.ListViewRegression");