addon-sdk/source/test/addons/places/tests/test-places-bookmarks.js

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4 'use strict';
michael@0 5
michael@0 6 module.metadata = {
michael@0 7 'engines': {
michael@0 8 'Firefox': '*'
michael@0 9 }
michael@0 10 };
michael@0 11
michael@0 12 const { Cc, Ci } = require('chrome');
michael@0 13 const { request } = require('sdk/addon/host');
michael@0 14 const { filter } = require('sdk/event/utils');
michael@0 15 const { on, off } = require('sdk/event/core');
michael@0 16 const { setTimeout } = require('sdk/timers');
michael@0 17 const { newURI } = require('sdk/url/utils');
michael@0 18 const { defer, all } = require('sdk/core/promise');
michael@0 19 const { defer: async } = require('sdk/lang/functional');
michael@0 20 const { before, after } = require('sdk/test/utils');
michael@0 21
michael@0 22 const {
michael@0 23 Bookmark, Group, Separator,
michael@0 24 save, search, remove,
michael@0 25 MENU, TOOLBAR, UNSORTED
michael@0 26 } = require('sdk/places/bookmarks');
michael@0 27 const {
michael@0 28 invalidResolve, invalidReject, createTree,
michael@0 29 compareWithHost, createBookmark, createBookmarkItem,
michael@0 30 createBookmarkTree, addVisits, resetPlaces
michael@0 31 } = require('../places-helper');
michael@0 32 const { promisedEmitter } = require('sdk/places/utils');
michael@0 33 const bmsrv = Cc['@mozilla.org/browser/nav-bookmarks-service;1'].
michael@0 34 getService(Ci.nsINavBookmarksService);
michael@0 35 const tagsrv = Cc['@mozilla.org/browser/tagging-service;1'].
michael@0 36 getService(Ci.nsITaggingService);
michael@0 37
michael@0 38 exports.testDefaultFolders = function (assert) {
michael@0 39 var ids = [
michael@0 40 bmsrv.bookmarksMenuFolder,
michael@0 41 bmsrv.toolbarFolder,
michael@0 42 bmsrv.unfiledBookmarksFolder
michael@0 43 ];
michael@0 44 [MENU, TOOLBAR, UNSORTED].forEach(function (g, i) {
michael@0 45 assert.ok(g.id === ids[i], ' default group matches id');
michael@0 46 });
michael@0 47 };
michael@0 48
michael@0 49 exports.testValidation = function (assert) {
michael@0 50 assert.throws(() => {
michael@0 51 Bookmark({ title: 'a title' });
michael@0 52 }, /The `url` property must be a valid URL/, 'throws empty URL error');
michael@0 53
michael@0 54 assert.throws(() => {
michael@0 55 Bookmark({ title: 'a title', url: 'not.a.url' });
michael@0 56 }, /The `url` property must be a valid URL/, 'throws invalid URL error');
michael@0 57
michael@0 58 assert.throws(() => {
michael@0 59 Bookmark({ url: 'http://foo.com' });
michael@0 60 }, /The `title` property must be defined/, 'throws title error');
michael@0 61
michael@0 62 assert.throws(() => {
michael@0 63 Bookmark();
michael@0 64 }, /./, 'throws any error');
michael@0 65
michael@0 66 assert.throws(() => {
michael@0 67 Group();
michael@0 68 }, /The `title` property must be defined/, 'throws title error for group');
michael@0 69
michael@0 70 assert.throws(() => {
michael@0 71 Bookmark({ url: 'http://foo.com', title: 'my title', tags: 'a tag' });
michael@0 72 }, /The `tags` property must be a Set, or an array/, 'throws error for non set/array tag');
michael@0 73 };
michael@0 74
michael@0 75 exports.testCreateBookmarks = function (assert, done) {
michael@0 76 var bm = Bookmark({
michael@0 77 title: 'moz',
michael@0 78 url: 'http://mozilla.org',
michael@0 79 tags: ['moz1', 'moz2', 'moz3']
michael@0 80 });
michael@0 81
michael@0 82 save(bm).on('data', (bookmark, input) => {
michael@0 83 assert.equal(input, bm, 'input is original input item');
michael@0 84 assert.ok(bookmark.id, 'Bookmark has ID');
michael@0 85 assert.equal(bookmark.title, 'moz');
michael@0 86 assert.equal(bookmark.url, 'http://mozilla.org');
michael@0 87 assert.equal(bookmark.group, UNSORTED, 'Unsorted folder is default parent');
michael@0 88 assert.ok(bookmark !== bm, 'bookmark should be a new instance');
michael@0 89 compareWithHost(assert, bookmark);
michael@0 90 }).on('end', bookmarks => {
michael@0 91 assert.equal(bookmarks.length, 1, 'returned bookmarks in end');
michael@0 92 assert.equal(bookmarks[0].url, 'http://mozilla.org');
michael@0 93 assert.equal(bookmarks[0].tags.has('moz1'), true, 'has first tag');
michael@0 94 assert.equal(bookmarks[0].tags.has('moz2'), true, 'has second tag');
michael@0 95 assert.equal(bookmarks[0].tags.has('moz3'), true, 'has third tag');
michael@0 96 assert.pass('end event is called');
michael@0 97 done();
michael@0 98 });
michael@0 99 };
michael@0 100
michael@0 101 exports.testCreateGroup = function (assert, done) {
michael@0 102 save(Group({ title: 'mygroup', group: MENU })).on('data', g => {
michael@0 103 assert.ok(g.id, 'Bookmark has ID');
michael@0 104 assert.equal(g.title, 'mygroup', 'matches title');
michael@0 105 assert.equal(g.group, MENU, 'Menu folder matches');
michael@0 106 compareWithHost(assert, g);
michael@0 107 }).on('end', results => {
michael@0 108 assert.equal(results.length, 1);
michael@0 109 assert.pass('end event is called');
michael@0 110 done();
michael@0 111 });
michael@0 112 };
michael@0 113
michael@0 114 exports.testCreateSeparator = function (assert, done) {
michael@0 115 save(Separator({ group: MENU })).on('data', function (s) {
michael@0 116 assert.ok(s.id, 'Separator has id');
michael@0 117 assert.equal(s.group, MENU, 'Parent group matches');
michael@0 118 compareWithHost(assert, s);
michael@0 119 }).on('end', function (results) {
michael@0 120 assert.equal(results.length, 1);
michael@0 121 assert.pass('end event is called');
michael@0 122 done();
michael@0 123 });
michael@0 124 };
michael@0 125
michael@0 126 exports.testCreateError = function (assert, done) {
michael@0 127 let bookmarks = [
michael@0 128 { title: 'moz1', url: 'http://moz1.com', type: 'bookmark'},
michael@0 129 { title: 'moz2', url: 'invalidurl', type: 'bookmark'},
michael@0 130 { title: 'moz3', url: 'http://moz3.com', type: 'bookmark'}
michael@0 131 ];
michael@0 132
michael@0 133 let dataCount = 0, errorCount = 0;
michael@0 134 save(bookmarks).on('data', bookmark => {
michael@0 135 assert.ok(/moz[1|3]/.test(bookmark.title), 'valid bookmarks complete');
michael@0 136 dataCount++;
michael@0 137 }).on('error', (reason, item) => {
michael@0 138 assert.ok(
michael@0 139 /The `url` property must be a valid URL/.test(reason),
michael@0 140 'Error event called with correct reason');
michael@0 141 assert.equal(item, bookmarks[1], 'returns input that failed in event');
michael@0 142 errorCount++;
michael@0 143 }).on('end', items => {
michael@0 144 assert.equal(dataCount, 2, 'data event called twice');
michael@0 145 assert.equal(errorCount, 1, 'error event called once');
michael@0 146 assert.equal(items.length, bookmarks.length, 'all items should be in result');
michael@0 147 assert.equal(items[0].toString(), '[object Bookmark]',
michael@0 148 'should be a saved instance');
michael@0 149 assert.equal(items[2].toString(), '[object Bookmark]',
michael@0 150 'should be a saved instance');
michael@0 151 assert.equal(items[1], bookmarks[1], 'should be original, unsaved object');
michael@0 152
michael@0 153 search({ query: 'moz' }).on('end', items => {
michael@0 154 assert.equal(items.length, 2, 'only two items were successfully saved');
michael@0 155 bookmarks[1].url = 'http://moz2.com/';
michael@0 156 dataCount = errorCount = 0;
michael@0 157 save(bookmarks).on('data', bookmark => {
michael@0 158 dataCount++;
michael@0 159 }).on('error', reason => errorCount++)
michael@0 160 .on('end', items => {
michael@0 161 assert.equal(items.length, 3, 'all 3 items saved');
michael@0 162 assert.equal(dataCount, 3, '3 data events called');
michael@0 163 assert.equal(errorCount, 0, 'no error events called');
michael@0 164 search({ query: 'moz' }).on('end', items => {
michael@0 165 assert.equal(items.length, 3, 'only 3 items saved');
michael@0 166 items.map(item =>
michael@0 167 assert.ok(/moz\d\.com/.test(item.url), 'correct item'))
michael@0 168 done();
michael@0 169 });
michael@0 170 });
michael@0 171 });
michael@0 172 });
michael@0 173 };
michael@0 174
michael@0 175 exports.testSaveDucktypes = function (assert, done) {
michael@0 176 save({
michael@0 177 title: 'moz',
michael@0 178 url: 'http://mozilla.org',
michael@0 179 type: 'bookmark'
michael@0 180 }).on('data', (bookmark) => {
michael@0 181 compareWithHost(assert, bookmark);
michael@0 182 done();
michael@0 183 });
michael@0 184 };
michael@0 185
michael@0 186 exports.testSaveDucktypesParent = function (assert, done) {
michael@0 187 let folder = { title: 'myfolder', type: 'group' };
michael@0 188 let bookmark = { title: 'mozzie', url: 'http://moz.com', group: folder, type: 'bookmark' };
michael@0 189 let sep = { type: 'separator', group: folder };
michael@0 190 save([sep, bookmark]).on('end', (res) => {
michael@0 191 compareWithHost(assert, res[0]);
michael@0 192 compareWithHost(assert, res[1]);
michael@0 193 assert.equal(res[0].group.title, 'myfolder', 'parent is ducktyped group');
michael@0 194 assert.equal(res[1].group.title, 'myfolder', 'parent is ducktyped group');
michael@0 195 done();
michael@0 196 });
michael@0 197 };
michael@0 198
michael@0 199 /*
michael@0 200 * Tests the scenario where the original bookmark item is resaved
michael@0 201 * and does not have an ID or an updated date, but should still be
michael@0 202 * mapped to the item it created previously
michael@0 203 */
michael@0 204 exports.testResaveOriginalItemMapping = function (assert, done) {
michael@0 205 let bookmark = Bookmark({ title: 'moz', url: 'http://moz.org' });
michael@0 206 save(bookmark).on('data', newBookmark => {
michael@0 207 bookmark.title = 'new moz';
michael@0 208 save(bookmark).on('data', newNewBookmark => {
michael@0 209 assert.equal(newBookmark.id, newNewBookmark.id, 'should be the same bookmark item');
michael@0 210 assert.equal(bmsrv.getItemTitle(newBookmark.id), 'new moz', 'should have updated title');
michael@0 211 done();
michael@0 212 });
michael@0 213 });
michael@0 214 };
michael@0 215
michael@0 216 exports.testCreateMultipleBookmarks = function (assert, done) {
michael@0 217 let data = [
michael@0 218 Bookmark({title: 'bm1', url: 'http://bm1.com'}),
michael@0 219 Bookmark({title: 'bm2', url: 'http://bm2.com'}),
michael@0 220 Bookmark({title: 'bm3', url: 'http://bm3.com'}),
michael@0 221 ];
michael@0 222 save(data).on('data', function (bookmark, input) {
michael@0 223 let stored = data.filter(({title}) => title === bookmark.title)[0];
michael@0 224 assert.equal(input, stored, 'input is original input item');
michael@0 225 assert.equal(bookmark.title, stored.title, 'titles match');
michael@0 226 assert.equal(bookmark.url, stored.url, 'urls match');
michael@0 227 compareWithHost(assert, bookmark);
michael@0 228 }).on('end', function (bookmarks) {
michael@0 229 assert.equal(bookmarks.length, 3, 'all bookmarks returned');
michael@0 230 done();
michael@0 231 });
michael@0 232 };
michael@0 233
michael@0 234 exports.testCreateImplicitParent = function (assert, done) {
michael@0 235 let folder = Group({ title: 'my parent' });
michael@0 236 let bookmarks = [
michael@0 237 Bookmark({ title: 'moz1', url: 'http://moz1.com', group: folder }),
michael@0 238 Bookmark({ title: 'moz2', url: 'http://moz2.com', group: folder }),
michael@0 239 Bookmark({ title: 'moz3', url: 'http://moz3.com', group: folder })
michael@0 240 ];
michael@0 241 save(bookmarks).on('data', function (bookmark) {
michael@0 242 if (bookmark.type === 'bookmark') {
michael@0 243 assert.equal(bookmark.group.title, folder.title, 'parent is linked');
michael@0 244 compareWithHost(assert, bookmark);
michael@0 245 } else if (bookmark.type === 'group') {
michael@0 246 assert.equal(bookmark.group.id, UNSORTED.id, 'parent ID of group is correct');
michael@0 247 compareWithHost(assert, bookmark);
michael@0 248 }
michael@0 249 }).on('end', function (results) {
michael@0 250 assert.equal(results.length, 3, 'results should only hold explicit saves');
michael@0 251 done();
michael@0 252 });
michael@0 253 };
michael@0 254
michael@0 255 exports.testCreateExplicitParent = function (assert, done) {
michael@0 256 let folder = Group({ title: 'my parent' });
michael@0 257 let bookmarks = [
michael@0 258 Bookmark({ title: 'moz1', url: 'http://moz1.com', group: folder }),
michael@0 259 Bookmark({ title: 'moz2', url: 'http://moz2.com', group: folder }),
michael@0 260 Bookmark({ title: 'moz3', url: 'http://moz3.com', group: folder })
michael@0 261 ];
michael@0 262 save(bookmarks.concat(folder)).on('data', function (bookmark) {
michael@0 263 if (bookmark.type === 'bookmark') {
michael@0 264 assert.equal(bookmark.group.title, folder.title, 'parent is linked');
michael@0 265 compareWithHost(assert, bookmark);
michael@0 266 } else if (bookmark.type === 'group') {
michael@0 267 assert.equal(bookmark.group.id, UNSORTED.id, 'parent ID of group is correct');
michael@0 268 compareWithHost(assert, bookmark);
michael@0 269 }
michael@0 270 }).on('end', function () {
michael@0 271 done();
michael@0 272 });
michael@0 273 };
michael@0 274
michael@0 275 exports.testCreateNested = function (assert, done) {
michael@0 276 let topFolder = Group({ title: 'top', group: MENU });
michael@0 277 let midFolder = Group({ title: 'middle', group: topFolder });
michael@0 278 let bookmarks = [
michael@0 279 Bookmark({ title: 'moz1', url: 'http://moz1.com', group: midFolder }),
michael@0 280 Bookmark({ title: 'moz2', url: 'http://moz2.com', group: midFolder }),
michael@0 281 Bookmark({ title: 'moz3', url: 'http://moz3.com', group: midFolder })
michael@0 282 ];
michael@0 283 let dataEventCount = 0;
michael@0 284 save(bookmarks).on('data', function (bookmark) {
michael@0 285 if (bookmark.type === 'bookmark') {
michael@0 286 assert.equal(bookmark.group.title, midFolder.title, 'parent is linked');
michael@0 287 } else if (bookmark.title === 'top') {
michael@0 288 assert.equal(bookmark.group.id, MENU.id, 'parent ID of top group is correct');
michael@0 289 } else {
michael@0 290 assert.equal(bookmark.group.title, topFolder.title, 'parent title of middle group is correct');
michael@0 291 }
michael@0 292 dataEventCount++;
michael@0 293 compareWithHost(assert, bookmark);
michael@0 294 }).on('end', () => {
michael@0 295 assert.equal(dataEventCount, 5, 'data events for all saves have occurred');
michael@0 296 assert.ok('end event called');
michael@0 297 done();
michael@0 298 });
michael@0 299 };
michael@0 300
michael@0 301 /*
michael@0 302 * Was a scenario when implicitly saving a bookmark that was already created,
michael@0 303 * it was not being properly fetched and attempted to recreate
michael@0 304 */
michael@0 305 exports.testAddingToExistingParent = function (assert, done) {
michael@0 306 let group = { type: 'group', title: 'mozgroup' };
michael@0 307 let bookmarks = [
michael@0 308 { title: 'moz1', url: 'http://moz1.com', type: 'bookmark', group: group },
michael@0 309 { title: 'moz2', url: 'http://moz2.com', type: 'bookmark', group: group },
michael@0 310 { title: 'moz3', url: 'http://moz3.com', type: 'bookmark', group: group }
michael@0 311 ],
michael@0 312 firstBatch, secondBatch;
michael@0 313
michael@0 314 saveP(bookmarks).then(data => {
michael@0 315 firstBatch = data;
michael@0 316 return saveP([
michael@0 317 { title: 'moz4', url: 'http://moz4.com', type: 'bookmark', group: group },
michael@0 318 { title: 'moz5', url: 'http://moz5.com', type: 'bookmark', group: group }
michael@0 319 ]);
michael@0 320 }, assert.fail).then(data => {
michael@0 321 secondBatch = data;
michael@0 322 assert.equal(firstBatch[0].group.id, secondBatch[0].group.id,
michael@0 323 'successfully saved to the same parent');
michael@0 324 done();
michael@0 325 }, assert.fail);
michael@0 326 };
michael@0 327
michael@0 328 exports.testUpdateParent = function (assert, done) {
michael@0 329 let group = { type: 'group', title: 'mozgroup' };
michael@0 330 saveP(group).then(item => {
michael@0 331 item[0].title = 'mozgroup-resave';
michael@0 332 return saveP(item[0]);
michael@0 333 }).then(item => {
michael@0 334 assert.equal(item[0].title, 'mozgroup-resave', 'group saved successfully');
michael@0 335 done();
michael@0 336 });
michael@0 337 };
michael@0 338
michael@0 339 exports.testUpdateSeparator = function (assert, done) {
michael@0 340 let sep = [Separator(), Separator(), Separator()];
michael@0 341 saveP(sep).then(item => {
michael@0 342 item[0].index = 2;
michael@0 343 return saveP(item[0]);
michael@0 344 }).then(item => {
michael@0 345 assert.equal(item[0].index, 2, 'updated index of separator');
michael@0 346 done();
michael@0 347 });
michael@0 348 };
michael@0 349
michael@0 350 exports.testPromisedSave = function (assert, done) {
michael@0 351 let topFolder = Group({ title: 'top', group: MENU });
michael@0 352 let midFolder = Group({ title: 'middle', group: topFolder });
michael@0 353 let bookmarks = [
michael@0 354 Bookmark({ title: 'moz1', url: 'http://moz1.com', group: midFolder}),
michael@0 355 Bookmark({ title: 'moz2', url: 'http://moz2.com', group: midFolder}),
michael@0 356 Bookmark({ title: 'moz3', url: 'http://moz3.com', group: midFolder})
michael@0 357 ];
michael@0 358 let first, second, third;
michael@0 359 saveP(bookmarks).then(bms => {
michael@0 360 first = bms.filter(b => b.title === 'moz1')[0];
michael@0 361 second = bms.filter(b => b.title === 'moz2')[0];
michael@0 362 third = bms.filter(b => b.title === 'moz3')[0];
michael@0 363 assert.equal(first.index, 0);
michael@0 364 assert.equal(second.index, 1);
michael@0 365 assert.equal(third.index, 2);
michael@0 366 first.index = 3;
michael@0 367 return saveP(first);
michael@0 368 }).then(() => {
michael@0 369 assert.equal(bmsrv.getItemIndex(first.id), 2, 'properly moved bookmark');
michael@0 370 assert.equal(bmsrv.getItemIndex(second.id), 0, 'other bookmarks adjusted');
michael@0 371 assert.equal(bmsrv.getItemIndex(third.id), 1, 'other bookmarks adjusted');
michael@0 372 done();
michael@0 373 });
michael@0 374 };
michael@0 375
michael@0 376 exports.testPromisedErrorSave = function (assert, done) {
michael@0 377 let bookmarks = [
michael@0 378 { title: 'moz1', url: 'http://moz1.com', type: 'bookmark'},
michael@0 379 { title: 'moz2', url: 'invalidurl', type: 'bookmark'},
michael@0 380 { title: 'moz3', url: 'http://moz3.com', type: 'bookmark'}
michael@0 381 ];
michael@0 382 saveP(bookmarks).then(invalidResolve, reason => {
michael@0 383 assert.ok(
michael@0 384 /The `url` property must be a valid URL/.test(reason),
michael@0 385 'Error event called with correct reason');
michael@0 386
michael@0 387 bookmarks[1].url = 'http://moz2.com';
michael@0 388 return saveP(bookmarks);
michael@0 389 }).then(res => {
michael@0 390 return searchP({ query: 'moz' });
michael@0 391 }).then(res => {
michael@0 392 assert.equal(res.length, 3, 'all 3 should be saved upon retry');
michael@0 393 res.map(item => assert.ok(/moz\d\.com/.test(item.url), 'correct item'));
michael@0 394 done();
michael@0 395 }, invalidReject);
michael@0 396 };
michael@0 397
michael@0 398 exports.testMovingChildren = function (assert, done) {
michael@0 399 let topFolder = Group({ title: 'top', group: MENU });
michael@0 400 let midFolder = Group({ title: 'middle', group: topFolder });
michael@0 401 let bookmarks = [
michael@0 402 Bookmark({ title: 'moz1', url: 'http://moz1.com', group: midFolder}),
michael@0 403 Bookmark({ title: 'moz2', url: 'http://moz2.com', group: midFolder}),
michael@0 404 Bookmark({ title: 'moz3', url: 'http://moz3.com', group: midFolder})
michael@0 405 ];
michael@0 406 save(bookmarks).on('end', bms => {
michael@0 407 let first = bms.filter(b => b.title === 'moz1')[0];
michael@0 408 let second = bms.filter(b => b.title === 'moz2')[0];
michael@0 409 let third = bms.filter(b => b.title === 'moz3')[0];
michael@0 410 assert.equal(first.index, 0);
michael@0 411 assert.equal(second.index, 1);
michael@0 412 assert.equal(third.index, 2);
michael@0 413 /* When moving down in the same container we take
michael@0 414 * into account the removal of the original item. If you want
michael@0 415 * to move from index X to index Y > X you must use
michael@0 416 * moveItem(id, folder, Y + 1)
michael@0 417 */
michael@0 418 first.index = 3;
michael@0 419 save(first).on('end', () => {
michael@0 420 assert.equal(bmsrv.getItemIndex(first.id), 2, 'properly moved bookmark');
michael@0 421 assert.equal(bmsrv.getItemIndex(second.id), 0, 'other bookmarks adjusted');
michael@0 422 assert.equal(bmsrv.getItemIndex(third.id), 1, 'other bookmarks adjusted');
michael@0 423 done();
michael@0 424 });
michael@0 425 });
michael@0 426 };
michael@0 427
michael@0 428 exports.testMovingChildrenNewFolder = function (assert, done) {
michael@0 429 let topFolder = Group({ title: 'top', group: MENU });
michael@0 430 let midFolder = Group({ title: 'middle', group: topFolder });
michael@0 431 let newFolder = Group({ title: 'new', group: MENU });
michael@0 432 let bookmarks = [
michael@0 433 Bookmark({ title: 'moz1', url: 'http://moz1.com', group: midFolder}),
michael@0 434 Bookmark({ title: 'moz2', url: 'http://moz2.com', group: midFolder}),
michael@0 435 Bookmark({ title: 'moz3', url: 'http://moz3.com', group: midFolder})
michael@0 436 ];
michael@0 437 save(bookmarks).on('end', bms => {
michael@0 438 let first = bms.filter(b => b.title === 'moz1')[0];
michael@0 439 let second = bms.filter(b => b.title === 'moz2')[0];
michael@0 440 let third = bms.filter(b => b.title === 'moz3')[0];
michael@0 441 let definedMidFolder = first.group;
michael@0 442 let definedNewFolder;
michael@0 443 first.group = newFolder;
michael@0 444 assert.equal(first.index, 0);
michael@0 445 assert.equal(second.index, 1);
michael@0 446 assert.equal(third.index, 2);
michael@0 447 save(first).on('data', (data) => {
michael@0 448 if (data.type === 'group') definedNewFolder = data;
michael@0 449 }).on('end', (moved) => {
michael@0 450 assert.equal(bmsrv.getItemIndex(second.id), 0, 'other bookmarks adjusted');
michael@0 451 assert.equal(bmsrv.getItemIndex(third.id), 1, 'other bookmarks adjusted');
michael@0 452 assert.equal(bmsrv.getItemIndex(first.id), 0, 'properly moved bookmark');
michael@0 453 assert.equal(bmsrv.getFolderIdForItem(first.id), definedNewFolder.id,
michael@0 454 'bookmark has new parent');
michael@0 455 assert.equal(bmsrv.getFolderIdForItem(second.id), definedMidFolder.id,
michael@0 456 'sibling bookmarks did not move');
michael@0 457 assert.equal(bmsrv.getFolderIdForItem(third.id), definedMidFolder.id,
michael@0 458 'sibling bookmarks did not move');
michael@0 459 done();
michael@0 460 });
michael@0 461 });
michael@0 462 };
michael@0 463
michael@0 464 exports.testRemoveFunction = function (assert) {
michael@0 465 let topFolder = Group({ title: 'new', group: MENU });
michael@0 466 let midFolder = Group({ title: 'middle', group: topFolder });
michael@0 467 let bookmarks = [
michael@0 468 Bookmark({ title: 'moz1', url: 'http://moz1.com', group: midFolder}),
michael@0 469 Bookmark({ title: 'moz2', url: 'http://moz2.com', group: midFolder}),
michael@0 470 Bookmark({ title: 'moz3', url: 'http://moz3.com', group: midFolder})
michael@0 471 ];
michael@0 472 remove([midFolder, topFolder].concat(bookmarks)).map(item => {
michael@0 473 assert.equal(item.remove, true, 'remove toggled `remove` property to true');
michael@0 474 });
michael@0 475 };
michael@0 476
michael@0 477 exports.testRemove = function (assert, done) {
michael@0 478 let id;
michael@0 479 createBookmarkItem().then(data => {
michael@0 480 id = data.id;
michael@0 481 compareWithHost(assert, data); // ensure bookmark exists
michael@0 482 save(remove(data)).on('data', (res) => {
michael@0 483 assert.pass('data event should be called');
michael@0 484 assert.ok(!res, 'response should be empty');
michael@0 485 }).on('end', () => {
michael@0 486 assert.throws(function () {
michael@0 487 bmsrv.getItemTitle(id);
michael@0 488 }, 'item should no longer exist');
michael@0 489 done();
michael@0 490 });
michael@0 491 });
michael@0 492 };
michael@0 493
michael@0 494 /*
michael@0 495 * Tests recursively removing children when removing a group
michael@0 496 */
michael@0 497 exports.testRemoveAllChildren = function (assert, done) {
michael@0 498 let topFolder = Group({ title: 'new', group: MENU });
michael@0 499 let midFolder = Group({ title: 'middle', group: topFolder });
michael@0 500 let bookmarks = [
michael@0 501 Bookmark({ title: 'moz1', url: 'http://moz1.com', group: midFolder}),
michael@0 502 Bookmark({ title: 'moz2', url: 'http://moz2.com', group: midFolder}),
michael@0 503 Bookmark({ title: 'moz3', url: 'http://moz3.com', group: midFolder})
michael@0 504 ];
michael@0 505
michael@0 506 let saved = [];
michael@0 507 save(bookmarks).on('data', (data) => saved.push(data)).on('end', () => {
michael@0 508 save(remove(topFolder)).on('end', () => {
michael@0 509 assert.equal(saved.length, 5, 'all items should have been saved');
michael@0 510 saved.map((item) => {
michael@0 511 assert.throws(function () {
michael@0 512 bmsrv.getItemTitle(item.id);
michael@0 513 }, 'item should no longer exist');
michael@0 514 });
michael@0 515 done();
michael@0 516 });
michael@0 517 });
michael@0 518 };
michael@0 519
michael@0 520 exports.testResolution = function (assert, done) {
michael@0 521 let firstSave, secondSave;
michael@0 522 createBookmarkItem().then((item) => {
michael@0 523 firstSave = item;
michael@0 524 assert.ok(item.updated, 'bookmark has updated time');
michael@0 525 item.title = 'my title';
michael@0 526 // Ensure delay so a different save time is set
michael@0 527 return delayed(item);
michael@0 528 }).then(saveP)
michael@0 529 .then(items => {
michael@0 530 let item = items[0];
michael@0 531 secondSave = item;
michael@0 532 assert.ok(firstSave.updated < secondSave.updated, 'snapshots have different update times');
michael@0 533 firstSave.title = 'updated title';
michael@0 534 return saveP(firstSave, { resolve: (mine, theirs) => {
michael@0 535 assert.equal(mine.title, 'updated title', 'correct data for my object');
michael@0 536 assert.equal(theirs.title, 'my title', 'correct data for their object');
michael@0 537 assert.equal(mine.url, theirs.url, 'other data is equal');
michael@0 538 assert.equal(mine.group, theirs.group, 'other data is equal');
michael@0 539 assert.ok(mine !== firstSave, 'instance is not passed in');
michael@0 540 assert.ok(theirs !== secondSave, 'instance is not passed in');
michael@0 541 assert.equal(mine.toString(), '[object Object]', 'serialized objects');
michael@0 542 assert.equal(theirs.toString(), '[object Object]', 'serialized objects');
michael@0 543 mine.title = 'a new title';
michael@0 544 return mine;
michael@0 545 }});
michael@0 546 }).then((results) => {
michael@0 547 let result = results[0];
michael@0 548 assert.equal(result.title, 'a new title', 'resolve handles results');
michael@0 549 done();
michael@0 550 });
michael@0 551 };
michael@0 552
michael@0 553 /*
michael@0 554 * Same as the resolution test, but with the 'unsaved' snapshot
michael@0 555 */
michael@0 556 exports.testResolutionMapping = function (assert, done) {
michael@0 557 let bookmark = Bookmark({ title: 'moz', url: 'http://bookmarks4life.com/' });
michael@0 558 let saved;
michael@0 559 saveP(bookmark).then(data => {
michael@0 560 saved = data[0];
michael@0 561 saved.title = 'updated title';
michael@0 562 // Ensure a delay for different updated times
michael@0 563 return delayed(saved);
michael@0 564 }).then(saveP)
michael@0 565 .then(() => {
michael@0 566 bookmark.title = 'conflicting title';
michael@0 567 return saveP(bookmark, { resolve: (mine, theirs) => {
michael@0 568 assert.equal(mine.title, 'conflicting title', 'correct data for my object');
michael@0 569 assert.equal(theirs.title, 'updated title', 'correct data for their object');
michael@0 570 assert.equal(mine.url, theirs.url, 'other data is equal');
michael@0 571 assert.equal(mine.group, theirs.group, 'other data is equal');
michael@0 572 assert.ok(mine !== bookmark, 'instance is not passed in');
michael@0 573 assert.ok(theirs !== saved, 'instance is not passed in');
michael@0 574 assert.equal(mine.toString(), '[object Object]', 'serialized objects');
michael@0 575 assert.equal(theirs.toString(), '[object Object]', 'serialized objects');
michael@0 576 mine.title = 'a new title';
michael@0 577 return mine;
michael@0 578 }});
michael@0 579 }).then((results) => {
michael@0 580 let result = results[0];
michael@0 581 assert.equal(result.title, 'a new title', 'resolve handles results');
michael@0 582 done();
michael@0 583 });
michael@0 584 };
michael@0 585
michael@0 586 exports.testUpdateTags = function (assert, done) {
michael@0 587 createBookmarkItem({ tags: ['spidermonkey'] }).then(bookmark => {
michael@0 588 bookmark.tags.add('jagermonkey');
michael@0 589 bookmark.tags.add('ionmonkey');
michael@0 590 bookmark.tags.delete('spidermonkey');
michael@0 591 save(bookmark).on('data', saved => {
michael@0 592 assert.equal(saved.tags.size, 2, 'should have 2 tags');
michael@0 593 assert.ok(saved.tags.has('jagermonkey'), 'should have added tag');
michael@0 594 assert.ok(saved.tags.has('ionmonkey'), 'should have added tag');
michael@0 595 assert.ok(!saved.tags.has('spidermonkey'), 'should not have removed tag');
michael@0 596 done();
michael@0 597 });
michael@0 598 });
michael@0 599 };
michael@0 600
michael@0 601 /*
michael@0 602 * View `createBookmarkTree` in `./places-helper.js` to see
michael@0 603 * expected tree construction
michael@0 604 */
michael@0 605
michael@0 606 exports.testSearchByGroupSimple = function (assert, done) {
michael@0 607 createBookmarkTree().then(() => {
michael@0 608 // In initial release of Places API, groups can only be queried
michael@0 609 // via a 'simple query', which is one folder set, and no other
michael@0 610 // parameters
michael@0 611 return searchP({ group: UNSORTED });
michael@0 612 }).then(results => {
michael@0 613 let groups = results.filter(({type}) => type === 'group');
michael@0 614 assert.equal(groups.length, 2, 'returns folders');
michael@0 615 assert.equal(results.length, 7,
michael@0 616 'should return all bookmarks and folders under UNSORTED');
michael@0 617 assert.equal(groups[0].toString(), '[object Group]', 'returns instance');
michael@0 618 return searchP({
michael@0 619 group: groups.filter(({title}) => title === 'mozgroup')[0]
michael@0 620 });
michael@0 621 }).then(results => {
michael@0 622 let groups = results.filter(({type}) => type === 'group');
michael@0 623 assert.equal(groups.length, 1, 'returns one subfolder');
michael@0 624 assert.equal(results.length, 6,
michael@0 625 'returns all children bookmarks/folders');
michael@0 626 assert.ok(results.filter(({url}) => url === 'http://w3schools.com/'),
michael@0 627 'returns nested children');
michael@0 628 done();
michael@0 629 }).then(null, assert.fail);
michael@0 630 };
michael@0 631
michael@0 632 exports.testSearchByGroupComplex = function (assert, done) {
michael@0 633 let mozgroup;
michael@0 634 createBookmarkTree().then(results => {
michael@0 635 mozgroup = results.filter(({title}) => title === 'mozgroup')[0];
michael@0 636 return searchP({ group: mozgroup, query: 'javascript' });
michael@0 637 }).then(results => {
michael@0 638 assert.equal(results.length, 1, 'only one javascript result under mozgroup');
michael@0 639 assert.equal(results[0].url, 'http://w3schools.com/', 'correct result');
michael@0 640 return searchP({ group: mozgroup, url: '*.mozilla.org' });
michael@0 641 }).then(results => {
michael@0 642 assert.equal(results.length, 2, 'expected results');
michael@0 643 assert.ok(
michael@0 644 !results.filter(({url}) => /developer.mozilla/.test(url)).length,
michael@0 645 'does not find results from other folders');
michael@0 646 done();
michael@0 647 }, assert.fail);
michael@0 648 };
michael@0 649
michael@0 650 exports.testSearchEmitters = function (assert, done) {
michael@0 651 createBookmarkTree().then(() => {
michael@0 652 let count = 0;
michael@0 653 search({ tags: ['mozilla', 'firefox'] }).on('data', data => {
michael@0 654 assert.ok(/mozilla|firefox/.test(data.title), 'one of the correct items');
michael@0 655 assert.ok(data.tags.has('firefox'), 'has firefox tag');
michael@0 656 assert.ok(data.tags.has('mozilla'), 'has mozilla tag');
michael@0 657 assert.equal(data + '', '[object Bookmark]', 'returns bookmark');
michael@0 658 count++;
michael@0 659 }).on('end', data => {
michael@0 660 assert.equal(count, 3, 'data event was called for each item');
michael@0 661 assert.equal(data.length, 3,
michael@0 662 'should return two bookmarks that have both mozilla AND firefox');
michael@0 663 assert.equal(data[0].title, 'mozilla.com', 'returns correct bookmark');
michael@0 664 assert.equal(data[1].title, 'mozilla.org', 'returns correct bookmark');
michael@0 665 assert.equal(data[2].title, 'firefox', 'returns correct bookmark');
michael@0 666 assert.equal(data[0] + '', '[object Bookmark]', 'returns bookmarks');
michael@0 667 done();
michael@0 668 });
michael@0 669 });
michael@0 670 };
michael@0 671
michael@0 672 exports.testSearchTags = function (assert, done) {
michael@0 673 createBookmarkTree().then(() => {
michael@0 674 // AND tags
michael@0 675 return searchP({ tags: ['mozilla', 'firefox'] });
michael@0 676 }).then(data => {
michael@0 677 assert.equal(data.length, 3,
michael@0 678 'should return two bookmarks that have both mozilla AND firefox');
michael@0 679 assert.equal(data[0].title, 'mozilla.com', 'returns correct bookmark');
michael@0 680 assert.equal(data[1].title, 'mozilla.org', 'returns correct bookmark');
michael@0 681 assert.equal(data[2].title, 'firefox', 'returns correct bookmark');
michael@0 682 assert.equal(data[0] + '', '[object Bookmark]', 'returns bookmarks');
michael@0 683 return searchP([{tags: ['firefox']}, {tags: ['javascript']}]);
michael@0 684 }).then(data => {
michael@0 685 // OR tags
michael@0 686 assert.equal(data.length, 6,
michael@0 687 'should return all bookmarks with firefox OR javascript tag');
michael@0 688 done();
michael@0 689 });
michael@0 690 };
michael@0 691
michael@0 692 /*
michael@0 693 * Tests 4 scenarios
michael@0 694 * '*.mozilla.com'
michael@0 695 * 'mozilla.com'
michael@0 696 * 'http://mozilla.com/'
michael@0 697 * 'http://mozilla.com/*'
michael@0 698 */
michael@0 699 exports.testSearchURL = function (assert, done) {
michael@0 700 createBookmarkTree().then(() => {
michael@0 701 return searchP({ url: 'mozilla.org' });
michael@0 702 }).then(data => {
michael@0 703 assert.equal(data.length, 2, 'only URLs with host domain');
michael@0 704 assert.equal(data[0].url, 'http://mozilla.org/');
michael@0 705 assert.equal(data[1].url, 'http://mozilla.org/thunderbird/');
michael@0 706 return searchP({ url: '*.mozilla.org' });
michael@0 707 }).then(data => {
michael@0 708 assert.equal(data.length, 3, 'returns domain and when host is other than domain');
michael@0 709 assert.equal(data[0].url, 'http://mozilla.org/');
michael@0 710 assert.equal(data[1].url, 'http://mozilla.org/thunderbird/');
michael@0 711 assert.equal(data[2].url, 'http://developer.mozilla.org/en-US/');
michael@0 712 return searchP({ url: 'http://mozilla.org' });
michael@0 713 }).then(data => {
michael@0 714 assert.equal(data.length, 1, 'only exact URL match');
michael@0 715 assert.equal(data[0].url, 'http://mozilla.org/');
michael@0 716 return searchP({ url: 'http://mozilla.org/*' });
michael@0 717 }).then(data => {
michael@0 718 assert.equal(data.length, 2, 'only URLs that begin with query');
michael@0 719 assert.equal(data[0].url, 'http://mozilla.org/');
michael@0 720 assert.equal(data[1].url, 'http://mozilla.org/thunderbird/');
michael@0 721 return searchP([{ url: 'mozilla.org' }, { url: 'component.fm' }]);
michael@0 722 }).then(data => {
michael@0 723 assert.equal(data.length, 3, 'returns URLs that match EITHER query');
michael@0 724 assert.equal(data[0].url, 'http://mozilla.org/');
michael@0 725 assert.equal(data[1].url, 'http://mozilla.org/thunderbird/');
michael@0 726 assert.equal(data[2].url, 'http://component.fm/');
michael@0 727 }).then(() => {
michael@0 728 done();
michael@0 729 });
michael@0 730 };
michael@0 731
michael@0 732 /*
michael@0 733 * Searches url, title, tags
michael@0 734 */
michael@0 735 exports.testSearchQuery = function (assert, done) {
michael@0 736 createBookmarkTree().then(() => {
michael@0 737 return searchP({ query: 'thunder' });
michael@0 738 }).then(data => {
michael@0 739 assert.equal(data.length, 3);
michael@0 740 assert.equal(data[0].title, 'mozilla.com', 'query matches tag, url, or title');
michael@0 741 assert.equal(data[1].title, 'mozilla.org', 'query matches tag, url, or title');
michael@0 742 assert.equal(data[2].title, 'thunderbird', 'query matches tag, url, or title');
michael@0 743 return searchP([{ query: 'rust' }, { query: 'component' }]);
michael@0 744 }).then(data => {
michael@0 745 // rust OR component
michael@0 746 assert.equal(data.length, 3);
michael@0 747 assert.equal(data[0].title, 'mozilla.com', 'query matches tag, url, or title');
michael@0 748 assert.equal(data[1].title, 'mozilla.org', 'query matches tag, url, or title');
michael@0 749 assert.equal(data[2].title, 'web audio components', 'query matches tag, url, or title');
michael@0 750 return searchP([{ query: 'moz', tags: ['javascript']}]);
michael@0 751 }).then(data => {
michael@0 752 assert.equal(data.length, 1);
michael@0 753 assert.equal(data[0].title, 'mdn',
michael@0 754 'only one item matches moz query AND has a javascript tag');
michael@0 755 }).then(() => {
michael@0 756 done();
michael@0 757 });
michael@0 758 };
michael@0 759
michael@0 760 /*
michael@0 761 * Test caching on bulk calls.
michael@0 762 * Each construction of a bookmark item snapshot results in
michael@0 763 * the recursive lookup of parent groups up to the root groups --
michael@0 764 * ensure that the appropriate instances equal each other, and no duplicate
michael@0 765 * fetches are called
michael@0 766 *
michael@0 767 * Implementation-dependent, this checks the host event `sdk-places-bookmarks-get`,
michael@0 768 * and if implementation changes, this could increase or decrease
michael@0 769 */
michael@0 770
michael@0 771 exports.testCaching = function (assert, done) {
michael@0 772 let count = 0;
michael@0 773 let stream = filter(request, ({event}) =>
michael@0 774 /sdk-places-bookmarks-get/.test(event));
michael@0 775 on(stream, 'data', handle);
michael@0 776
michael@0 777 let group = { type: 'group', title: 'mozgroup' };
michael@0 778 let bookmarks = [
michael@0 779 { title: 'moz1', url: 'http://moz1.com', type: 'bookmark', group: group },
michael@0 780 { title: 'moz2', url: 'http://moz2.com', type: 'bookmark', group: group },
michael@0 781 { title: 'moz3', url: 'http://moz3.com', type: 'bookmark', group: group }
michael@0 782 ];
michael@0 783
michael@0 784 /*
michael@0 785 * Use timeout in tests since the platform calls are synchronous
michael@0 786 * and the counting event shim may not have occurred yet
michael@0 787 */
michael@0 788
michael@0 789 saveP(bookmarks).then(() => {
michael@0 790 assert.equal(count, 0, 'all new items and root group, no fetches should occur');
michael@0 791 count = 0;
michael@0 792 return saveP([
michael@0 793 { title: 'moz4', url: 'http://moz4.com', type: 'bookmark', group: group },
michael@0 794 { title: 'moz5', url: 'http://moz5.com', type: 'bookmark', group: group }
michael@0 795 ]);
michael@0 796 // Test `save` look-up
michael@0 797 }).then(() => {
michael@0 798 assert.equal(count, 1, 'should only look up parent once');
michael@0 799 count = 0;
michael@0 800 return searchP({ query: 'moz' });
michael@0 801 }).then(results => {
michael@0 802 // Should query for each bookmark (5) from the query (id -> data),
michael@0 803 // their parent during `construct` (1) and the root shouldn't
michael@0 804 // require a lookup
michael@0 805 assert.equal(count, 6, 'lookup occurs once for each item and parent');
michael@0 806 off(stream, 'data', handle);
michael@0 807 done();
michael@0 808 });
michael@0 809
michael@0 810 function handle ({data}) count++
michael@0 811 };
michael@0 812
michael@0 813 /*
michael@0 814 * Search Query Options
michael@0 815 */
michael@0 816
michael@0 817 exports.testSearchCount = function (assert, done) {
michael@0 818 let max = 8;
michael@0 819 createBookmarkTree()
michael@0 820 .then(testCount(1))
michael@0 821 .then(testCount(2))
michael@0 822 .then(testCount(3))
michael@0 823 .then(testCount(5))
michael@0 824 .then(testCount(10))
michael@0 825 .then(() => {
michael@0 826 done();
michael@0 827 });
michael@0 828
michael@0 829 function testCount (n) {
michael@0 830 return function () {
michael@0 831 return searchP({}, { count: n }).then(results => {
michael@0 832 if (n > max) n = max;
michael@0 833 assert.equal(results.length, n,
michael@0 834 'count ' + n + ' returns ' + n + ' results');
michael@0 835 });
michael@0 836 };
michael@0 837 }
michael@0 838 };
michael@0 839
michael@0 840 exports.testSearchSort = function (assert, done) {
michael@0 841 let urls = [
michael@0 842 'http://mozilla.com/', 'http://webaud.io/', 'http://mozilla.com/webfwd/',
michael@0 843 'http://developer.mozilla.com/', 'http://bandcamp.com/'
michael@0 844 ];
michael@0 845
michael@0 846 saveP(
michael@0 847 urls.map(url =>
michael@0 848 Bookmark({ url: url, title: url.replace(/http:\/\/|\//g,'')}))
michael@0 849 ).then(() => {
michael@0 850 return searchP({}, { sort: 'title' });
michael@0 851 }).then(results => {
michael@0 852 checkOrder(results, [4,3,0,2,1]);
michael@0 853 return searchP({}, { sort: 'title', descending: true });
michael@0 854 }).then(results => {
michael@0 855 checkOrder(results, [1,2,0,3,4]);
michael@0 856 return searchP({}, { sort: 'url' });
michael@0 857 }).then(results => {
michael@0 858 checkOrder(results, [4,3,0,2,1]);
michael@0 859 return searchP({}, { sort: 'url', descending: true });
michael@0 860 }).then(results => {
michael@0 861 checkOrder(results, [1,2,0,3,4]);
michael@0 862 return addVisits(['http://mozilla.com/', 'http://mozilla.com']);
michael@0 863 }).then(() =>
michael@0 864 saveP(Bookmark({ url: 'http://github.com', title: 'github.com' }))
michael@0 865 ).then(() => addVisits('http://bandcamp.com/'))
michael@0 866 .then(() => searchP({ query: 'webfwd' }))
michael@0 867 .then(results => {
michael@0 868 results[0].title = 'new title for webfwd';
michael@0 869 return saveP(results[0]);
michael@0 870 })
michael@0 871 .then(() =>
michael@0 872 searchP({}, { sort: 'visitCount' })
michael@0 873 ).then(results => {
michael@0 874 assert.equal(results[5].url, 'http://mozilla.com/',
michael@0 875 'last entry is the highest visit count');
michael@0 876 return searchP({}, { sort: 'visitCount', descending: true });
michael@0 877 }).then(results => {
michael@0 878 assert.equal(results[0].url, 'http://mozilla.com/',
michael@0 879 'first entry is the highest visit count');
michael@0 880 return searchP({}, { sort: 'date' });
michael@0 881 }).then(results => {
michael@0 882 assert.equal(results[5].url, 'http://bandcamp.com/',
michael@0 883 'latest visited should be first');
michael@0 884 return searchP({}, { sort: 'date', descending: true });
michael@0 885 }).then(results => {
michael@0 886 assert.equal(results[0].url, 'http://bandcamp.com/',
michael@0 887 'latest visited should be at the end');
michael@0 888 return searchP({}, { sort: 'dateAdded' });
michael@0 889 }).then(results => {
michael@0 890 assert.equal(results[5].url, 'http://github.com/',
michael@0 891 'last added should be at the end');
michael@0 892 return searchP({}, { sort: 'dateAdded', descending: true });
michael@0 893 }).then(results => {
michael@0 894 assert.equal(results[0].url, 'http://github.com/',
michael@0 895 'last added should be first');
michael@0 896 return searchP({}, { sort: 'lastModified' });
michael@0 897 }).then(results => {
michael@0 898 assert.equal(results[5].url, 'http://mozilla.com/webfwd/',
michael@0 899 'last modified should be last');
michael@0 900 return searchP({}, { sort: 'lastModified', descending: true });
michael@0 901 }).then(results => {
michael@0 902 assert.equal(results[0].url, 'http://mozilla.com/webfwd/',
michael@0 903 'last modified should be first');
michael@0 904 }).then(() => {
michael@0 905 done();
michael@0 906 });
michael@0 907
michael@0 908 function checkOrder (results, nums) {
michael@0 909 assert.equal(results.length, nums.length, 'expected return count');
michael@0 910 for (let i = 0; i < nums.length; i++) {
michael@0 911 assert.equal(results[i].url, urls[nums[i]], 'successful order');
michael@0 912 }
michael@0 913 }
michael@0 914 };
michael@0 915
michael@0 916 exports.testSearchComplexQueryWithOptions = function (assert, done) {
michael@0 917 createBookmarkTree().then(() => {
michael@0 918 return searchP([
michael@0 919 { tags: ['rust'], url: '*.mozilla.org' },
michael@0 920 { tags: ['javascript'], query: 'mozilla' }
michael@0 921 ], { sort: 'title' });
michael@0 922 }).then(results => {
michael@0 923 let expected = [
michael@0 924 'http://developer.mozilla.org/en-US/',
michael@0 925 'http://mozilla.org/'
michael@0 926 ];
michael@0 927 for (let i = 0; i < expected.length; i++)
michael@0 928 assert.equal(results[i].url, expected[i], 'correct ordering and item');
michael@0 929 done();
michael@0 930 });
michael@0 931 };
michael@0 932
michael@0 933 exports.testCheckSaveOrder = function (assert, done) {
michael@0 934 let group = Group({ title: 'mygroup' });
michael@0 935 let bookmarks = [
michael@0 936 Bookmark({ url: 'http://url1.com', title: 'url1', group: group }),
michael@0 937 Bookmark({ url: 'http://url2.com', title: 'url2', group: group }),
michael@0 938 Bookmark({ url: 'http://url3.com', title: 'url3', group: group }),
michael@0 939 Bookmark({ url: 'http://url4.com', title: 'url4', group: group }),
michael@0 940 Bookmark({ url: 'http://url5.com', title: 'url5', group: group })
michael@0 941 ];
michael@0 942 saveP(bookmarks).then(results => {
michael@0 943 for (let i = 0; i < bookmarks.length; i++)
michael@0 944 assert.equal(results[i].url, bookmarks[i].url,
michael@0 945 'correct ordering of bookmark results');
michael@0 946 done();
michael@0 947 });
michael@0 948 };
michael@0 949
michael@0 950 before(exports, (name, assert, done) => resetPlaces(done));
michael@0 951 after(exports, (name, assert, done) => resetPlaces(done));
michael@0 952
michael@0 953 function saveP () {
michael@0 954 return promisedEmitter(save.apply(null, Array.slice(arguments)));
michael@0 955 }
michael@0 956
michael@0 957 function searchP () {
michael@0 958 return promisedEmitter(search.apply(null, Array.slice(arguments)));
michael@0 959 }
michael@0 960
michael@0 961 function delayed (value, ms) {
michael@0 962 let { promise, resolve } = defer();
michael@0 963 setTimeout(() => resolve(value), ms || 10);
michael@0 964 return promise;
michael@0 965 }

mercurial