blob: 8d52d498d52c97819a65886095591e021012e60f [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// bookmarks api test
// browser_tests.exe --gtest_filter=ExtensionApiTest.Bookmarks
// This is global state that is maintained across tests as a reference
// to compare against what's fetched from the browser (using compareTrees).
// TODO(erikkay) It would be better if each test was self-contained and
// didn't depend on global state.
var expected = [
{"children": [
{children:[], id:"1", parentId:"0", index:0, title:"Bookmarks bar"},
{children:[], id:"2", parentId:"0", index:1, title:"Other bookmarks"},
{id:"4", parentId:"0", index:3, title:"Managed bookmarks",
unmodifiable:"managed", children:[
{id:"5", parentId:"4", index:0, title:"Managed Bookmark",
url:"http://www.chromium.org/", unmodifiable:"managed"},
{id:"6", parentId:"4", index:1, title:"Managed Folder",
children:[], unmodifiable:"managed"}
]
}
],
id:"0", title:""
}
];
function bookmarksBar() { return expected[0].children[0]; }
function otherBookmarks() { return expected[0].children[1]; }
// Some variables that are used across multiple tests.
var node1 = {parentId:"1", title:"bar baz",
url:"http://www.example.com/hello"};
var node2 = {parentId:"1", title:"foo quux",
url:"http://www.example.com/bar"};
var node3 = {parentId:"1", title:"Foo bar baz",
url:"http://www.google.com/hello/quux"};
var pass = chrome.test.callbackPass;
var fail = chrome.test.callbackFail;
function compareNode(left, right) {
//chrome.test.log("compareNode()");
//chrome.test.log(JSON.stringify(left, null, 2));
//chrome.test.log(JSON.stringify(right, null, 2));
// TODO(erikkay): do some comparison of dateAdded
if (left.id != right.id)
return "id mismatch: " + left.id + " != " + right.id;
if (left.title != right.title) {
// TODO(erikkay): This resource dependency still isn't working reliably.
// See bug 19866.
// return "title mismatch: " + left.title + " != " + right.title;
chrome.test.log("title mismatch: " + left.title + " != " + right.title);
}
if (left.url != right.url)
return "url mismatch: " + left.url + " != " + right.url;
// Check only when optional 'index' property exist.
if (left.index != undefined && left.index != right.index)
return "index mismatch: " + left.index + " != " + right.index;
if (left.unmodifiable != right.unmodifiable) {
return "unmodifiable mismatch: " + left.unmodifiable +
" != " + right.unmodifiable;
}
return true;
}
function compareTrees(left, right, verbose) {
if (verbose) {
chrome.test.log(JSON.stringify(left) || "<null>");
chrome.test.log(JSON.stringify(right) || "<null>");
}
if (left == null && right == null) {
return true;
}
if (left == null || right == null)
return left + " != " + right;
if (left.length != right.length)
return "count mismatch: " + left.length + " != " + right.length;
for (var i = 0; i < left.length; i++) {
var result = compareNode(left[i], right[i]);
if (result !== true) {
chrome.test.log(result);
chrome.test.log(JSON.stringify(left, null, 2));
chrome.test.log(JSON.stringify(right, null, 2));
return result;
}
result = compareTrees(left[i].children, right[i].children);
if (result !== true)
return result;
}
return true;
}
// |expectedParent| is a child within the global |expected| that each node in
// the array|nodes| should be added to. |callback| will be called when all of
// the nodes have been successfully created.
function createNodes(expectedParent, nodes, callback) {
function createNext() {
if (nodes.length) {
var node = nodes.shift();
chrome.bookmarks.create(node, function(results) {
node.id = results.id;
node.index = results.index;
expectedParent.children.push(node);
// Create each node a minimum of 1ms apart. This ensures that each
// node will have a unique timestamp.
setTimeout(createNext, 1);
});
} else {
callback();
}
}
createNext();
}
// Calls getTree and verifies that the results match the global |expected|
// state. Assigns over expected in the end since getTree has more data
// (e.g. createdDate) which tests may want to depend on.
function verifyTreeIsExpected(callback) {
chrome.bookmarks.getTree(pass(function(results) {
chrome.test.assertTrue(compareTrees(expected, results),
"getTree() result != expected");
expected = results;
callback();
}));
}
function run() {
chrome.test.runTests([
function getTree() {
verifyTreeIsExpected(pass());
},
function get() {
chrome.bookmarks.get("1", pass(function(results) {
chrome.test.assertTrue(compareNode(results[0], expected[0].children[0]));
}));
chrome.bookmarks.get("5", pass(function(results) {
chrome.test.assertTrue(compareNode(
results[0], expected[0].children[2].children[0]));
}));
chrome.bookmarks.get("42", fail("Can't find bookmark for id."));
},
function getArray() {
chrome.bookmarks.get(["1", "2"], pass(function(results) {
chrome.test.assertTrue(compareNode(results[0], expected[0].children[0]),
"get() result != expected");
chrome.test.assertTrue(compareNode(results[1], expected[0].children[1]),
"get() result != expected");
}));
},
function getChildren() {
chrome.bookmarks.getChildren("0", pass(function(results) {
chrome.test.assertTrue(compareNode(results[0], expected[0].children[0]),
"getChildren() result != expected");
chrome.test.assertTrue(compareNode(results[1], expected[0].children[1]),
"getChildren() result != expected");
}));
},
function create() {
var node = {parentId:"1", title:"google", url:"http://www.google.com/"};
chrome.test.listenOnce(chrome.bookmarks.onCreated, function(id, created) {
node.id = created.id;
node.index = 0;
chrome.test.assertEq(id, node.id);
chrome.test.assertTrue(compareNode(node, created));
});
chrome.bookmarks.create(node, pass(function(results) {
node.id = results.id; // since we couldn't know this going in
node.index = 0;
chrome.test.assertTrue(compareNode(node, results),
"created node != source");
expected[0].children[0].children.push(node);
}));
},
function createNoParentId() {
var node = {title:"google", url:"http://www.google.com/"};
chrome.test.listenOnce(chrome.bookmarks.onCreated, function(id, created) {
node.id = created.id;
node.index = 0;
chrome.test.assertEq(id, node.id);
// Make sure the parentId defaults to the Other Bookmarks folder.
chrome.test.assertEq(expected[0].children[1].id, created.parentId);
chrome.test.assertTrue(compareNode(node, created));
expected[0].children[1].children.push(node);
});
chrome.bookmarks.create(node, pass(function(results) {
node.id = results.id; // since we couldn't know this going in
node.index = 0;
chrome.test.assertTrue(compareNode(node, results),
"created node != source");
}));
},
function createInRoot() {
const error = "Can't modify the root bookmark folders.";
var node = {parentId:"0", title:"g404", url:"http://www.google.com/404"};
chrome.bookmarks.create(node, fail(error));
},
function createInManaged() {
const error = "Can't modify managed bookmarks.";
var node = {parentId:"4", title:"g404", url:"http://www.google.com/404"};
chrome.bookmarks.create(node, fail(error));
},
function createFolder() {
var node = {parentId:"1", title:"foo bar"}; // folder
chrome.test.listenOnce(chrome.bookmarks.onCreated, function(id, created) {
node.id = created.id;
node.index = 1;
node.children = [];
chrome.test.assertTrue(compareNode(node, created));
});
chrome.bookmarks.create(node, pass(function(results) {
node.id = results.id; // since we couldn't know this going in
node.index = 1;
node.children = [];
chrome.test.assertTrue(compareNode(node, results),
"created node != source");
expected[0].children[0].children.push(node);
}));
},
function getSubTree() {
chrome.bookmarks.getSubTree(expected[0].children[0].id,
pass(function(results) {
chrome.test.assertTrue(compareTrees([expected[0].children[0]],
results), "getTree() result != expected");
}));
},
function moveSetup() {
createNodes(bookmarksBar(), [node1, node2, node3], pass(function() {
verifyTreeIsExpected(pass());
}));
},
function move() {
// Move node1, node2, and node3 from their current location (the bookmark
// bar) to be under the "foo bar" folder (created in createFolder()).
// Then move that folder to be under the "other bookmarks" folder.
var folder = expected[0].children[0].children[1];
var old_node1 = expected[0].children[0].children[2];
chrome.test.listenOnce(chrome.bookmarks.onMoved, function(id, moveInfo) {
chrome.test.assertEq(node1.id, id);
chrome.test.assertEq(moveInfo.parentId, folder.id);
chrome.test.assertEq(moveInfo.index, 0);
chrome.test.assertEq(moveInfo.oldParentId, old_node1.parentId);
chrome.test.assertEq(moveInfo.oldIndex, old_node1.index);
});
chrome.bookmarks.move(node1.id, {parentId:folder.id},
pass(function(results) {
chrome.test.assertEq(results.parentId, folder.id);
node1.parentId = results.parentId;
node1.index = 0;
}));
chrome.bookmarks.move(node2.id, {parentId:folder.id},
pass(function(results) {
chrome.test.assertEq(results.parentId, folder.id);
node2.parentId = results.parentId;
node2.index = 1;
}));
// Insert node3 at index 1 rather than at the end. This should result in
// an order of node1, node3, node2.
chrome.bookmarks.move(node3.id, {parentId:folder.id, index:1},
pass(function(results) {
chrome.test.assertEq(results.parentId, folder.id);
chrome.test.assertEq(results.index, 1);
node3.parentId = results.parentId;
node3.index = 1;
node2.index = 2;
// update expected to match
expected[0].children[0].children.pop();
expected[0].children[0].children.pop();
expected[0].children[0].children.pop();
folder.children.push(node1);
folder.children.push(node3);
folder.children.push(node2);
verifyTreeIsExpected(pass());
}));
// Move folder (and its children) to be a child of Other Bookmarks.
var other = expected[0].children[1];
chrome.bookmarks.move(folder.id, {parentId:other.id},
pass(function(results) {
chrome.test.assertEq(results.parentId, other.id);
folder.parentId = results.parentId;
folder.index = results.index;
var folder2 = expected[0].children[0].children.pop();
chrome.test.assertEq(folder2.id, folder.id);
expected[0].children[1].children.push(folder2);
verifyTreeIsExpected(pass());
}));
},
function moveToManaged() {
var managed_node = expected[0].children[2];
chrome.test.assertEq("4", managed_node.id);
const error = "Can't modify managed bookmarks.";
chrome.bookmarks.move(node1.id, {parentId:managed_node.id}, fail(error));
verifyTreeIsExpected(pass());
},
function moveFromManaged() {
var managed_node = expected[0].children[2];
var moving_node = managed_node.children[0];
var other = expected[0].children[1];
const error = "Can't modify managed bookmarks.";
chrome.bookmarks.move(moving_node.id, {parentId:other.id}, fail(error));
verifyTreeIsExpected(pass());
},
function search() {
chrome.bookmarks.search("baz bar", pass(function(results) {
// matches node1 & node3
chrome.test.assertEq(2, results.length);
}));
chrome.bookmarks.search("www hello", pass(function(results) {
// matches node1 & node3
chrome.test.assertEq(2, results.length);
}));
chrome.bookmarks.search("bar example",
pass(function(results) {
// matches node2
chrome.test.assertEq(1, results.length);
}));
chrome.bookmarks.search("foo bar", pass(function(results) {
// matches node3 & folder "foo bar" from createFolder
chrome.test.assertEq(2, results.length);
}));
chrome.bookmarks.search("quux", pass(function(results) {
// matches node2 & node1
chrome.test.assertEq(2, results.length);
}));
chrome.bookmarks.search("Bookmark Bar", pass(function(results) {
// Does not match any node since permanent nodes are stripped from search
chrome.test.assertEq(0, results.length);
}));
chrome.bookmarks.search("Managed", pass(function(results) {
// Matches the Managed Bookmark and the Managed Folder but not the
// managed_node.
chrome.test.assertEq(2, results.length);
}));
},
function update() {
var title = "hello world";
chrome.test.listenOnce(chrome.bookmarks.onChanged, function(id, changes) {
chrome.test.assertEq(title, changes.title);
});
chrome.bookmarks.update(node1.id, {"title": title}, pass(function(results) {
chrome.test.assertEq(title, results.title);
}));
var url = "http://example.com/hello";
chrome.bookmarks.update(node1.id, {"url": url}, pass(function(results) {
// Make sure that leaving out the title does not set the title to empty.
chrome.test.assertEq(title, results.title);
chrome.test.assertEq(url, results.url);
// Empty or invalid URLs should not change the URL.
var bad_url = "";
chrome.bookmarks.update(node1.id, {"url": bad_url},
pass(function(results) {
chrome.bookmarks.get(node1.id, pass(function(results) {
chrome.test.assertEq(url, results[0].url);
chrome.test.log("URL UNCHANGED");
}));
})
);
// Invalid URLs also generate an error.
bad_url = "I am not an URL";
chrome.bookmarks.update(node1.id, {"url": bad_url}, fail("Invalid URL.",
function(results) {
chrome.bookmarks.get(node1.id, pass(function(results) {
chrome.test.assertEq(url, results[0].url);
chrome.test.log("URL UNCHANGED");
}));
})
);
}));
// Update test data for next tests.
node1.title = title;
node1.url = url;
},
function updateManaged() {
var managed_node = expected[0].children[2];
var updating_node = managed_node.children[0];
const error = "Can't modify managed bookmarks.";
chrome.bookmarks.update(updating_node.id, {"title": "New"}, fail(error));
},
function remove() {
var parentId = node1.parentId;
chrome.test.listenOnce(chrome.bookmarks.onRemoved,
function(id, removeInfo) {
chrome.test.assertEq(id, node1.id);
chrome.test.assertEq(removeInfo.parentId, parentId);
chrome.test.assertEq(removeInfo.index, node1.index);
chrome.test.assertEq(removeInfo.node.title, node1.title);
chrome.test.assertEq(removeInfo.node.url, node1.url);
});
chrome.bookmarks.remove(node1.id, pass(function() {
// Update expected to match.
// We removed node1, which means that the index of the other two nodes
// changes as well.
expected[0].children[1].children[1].children.shift();
expected[0].children[1].children[1].children[0].index = 0;
expected[0].children[1].children[1].children[1].index = 1;
verifyTreeIsExpected(pass());
}));
},
function removeManaged() {
var managed_node = expected[0].children[2];
var removing_node = managed_node.children[0];
const error = "Can't modify managed bookmarks.";
chrome.bookmarks.remove(removing_node.id, fail(error));
},
function searchRemoved() {
// Search for deleted node
chrome.bookmarks.search("baz bar", pass(function(results) {
// matches only node3 since node1 was removed
chrome.test.assertEq(1, results.length);
}));
},
function removeTree() {
var parentId = node2.parentId;
var folder = expected[0].children[1].children[1];
chrome.test.listenOnce(chrome.bookmarks.onRemoved,
function(id, removeInfo) {
chrome.test.assertEq(id, folder.id);
chrome.test.assertEq(removeInfo.parentId, folder.parentId);
chrome.test.assertEq(removeInfo.index, folder.index);
chrome.test.assertTrue(compareNode(removeInfo.node, folder));
});
chrome.bookmarks.removeTree(parentId, pass(function(){
// Update expected to match.
expected[0].children[1].children.pop();
verifyTreeIsExpected(pass());
}));
},
function removeManagedTree() {
var managed_node = expected[0].children[2];
var managed_folder = managed_node.children[1];
const error = "Can't modify managed bookmarks.";
chrome.bookmarks.removeTree(managed_folder.id, fail(error));
},
function searchRemovedTree() {
// Search for deleted folder and enclosed node3
chrome.bookmarks.search("foo bar", pass(function(results) {
// Does not match anything since folder was removed with node3 in it
chrome.test.assertEq(0, results.length);
}));
},
function getRecentSetup() {
Promise.all([removeAllChildren('1'), removeAllChildren('2')]).then(
pass(afterRemove));
function removeTreePromise(id) {
return new Promise(pass(function(resolve) {
chrome.bookmarks.removeTree(id, resolve);
}));
}
// Clean up tree
function removeAllChildren(id) {
return new Promise(pass(function(resolve) {
chrome.bookmarks.getChildren(id, pass(function(children) {
Promise.all(children.map((child) => removeTreePromise(child.id)))
.then(resolve);
}));
}));
}
function afterRemove() {
// Once done add 3 nodes
chrome.bookmarks.getTree(pass(function(results) {
chrome.test.assertEq(0, results[0].children[0].children.length);
chrome.test.assertEq(0, results[0].children[1].children.length);
expected = results;
// Reset the nodes
node1 = {parentId:"1", title:"bar baz",
url:"http://www.example.com/hello"};
node2 = {parentId:"1", title:"foo quux",
url:"http://www.example.com/bar"};
node3 = {parentId:"1", title:"Foo bar baz",
url:"http://www.google.com/hello/quux"};
createNodes(bookmarksBar(), [node1, node2, node3], pass(function() {
verifyTreeIsExpected(pass());
}));
}));
}
},
function getRecent() {
var failed = false;
try {
chrome.bookmarks.getRecent(0, function() {});
} catch (ex) {
failed = true;
}
chrome.test.assertTrue(failed, "Calling with 0 should fail");
chrome.bookmarks.getRecent(10000, pass(function(results) {
// Should include the "Managed Bookmark".
chrome.test.assertEq(4, results.length,
"Should have gotten all recent bookmarks");
}));
chrome.bookmarks.getRecent(2, pass(function(results) {
chrome.test.assertEq(2, results.length,
"Should only get the last 2 bookmarks");
chrome.test.assertTrue(compareNode(node3, results[0]));
chrome.test.assertTrue(compareNode(node2, results[1]));
}));
},
function updateFolder() {
chrome.bookmarks.create({title: 'folder'}, function(folder) {
var newTitle = 'changedFolder';
chrome.test.listenOnce(chrome.bookmarks.onChanged, pass(
function(id, changes) {
chrome.test.assertEq(folder.id, id);
chrome.test.assertEq(newTitle, changes.title);
chrome.test.assertFalse('url' in changes);
}));
chrome.bookmarks.update(folder.id, {title: newTitle}, pass(
function(result) {
chrome.test.assertEq(newTitle, result.title);
chrome.test.assertFalse('url' in result)
}));
});
}
]);
}
run();