michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: 'use strict'; michael@0: michael@0: module.metadata = { michael@0: 'engines': { michael@0: 'Firefox': '*' michael@0: } michael@0: }; michael@0: michael@0: const { Cc, Ci } = require('chrome'); michael@0: const { defer, all } = require('sdk/core/promise'); michael@0: const { setTimeout } = require('sdk/timers'); michael@0: const { newURI } = require('sdk/url/utils'); michael@0: const { send } = require('sdk/addon/events'); michael@0: const { set } = require('sdk/preferences/service'); michael@0: const { before, after } = require('sdk/test/utils'); michael@0: michael@0: require('sdk/places/host/host-bookmarks'); michael@0: require('sdk/places/host/host-tags'); michael@0: require('sdk/places/host/host-query'); michael@0: const { michael@0: invalidResolve, invalidReject, createTree, michael@0: compareWithHost, createBookmark, createBookmarkTree, resetPlaces michael@0: } = require('../places-helper'); michael@0: michael@0: const bmsrv = Cc['@mozilla.org/browser/nav-bookmarks-service;1']. michael@0: getService(Ci.nsINavBookmarksService); michael@0: const hsrv = Cc['@mozilla.org/browser/nav-history-service;1']. michael@0: getService(Ci.nsINavHistoryService); michael@0: const tagsrv = Cc['@mozilla.org/browser/tagging-service;1']. michael@0: getService(Ci.nsITaggingService); michael@0: michael@0: exports.testBookmarksCreate = function (assert, done) { michael@0: let items = [{ michael@0: title: 'my title', michael@0: url: 'http://test-places-host.com/testBookmarksCreate/', michael@0: tags: ['some', 'tags', 'yeah'], michael@0: type: 'bookmark' michael@0: }, { michael@0: title: 'my folder', michael@0: type: 'group', michael@0: group: bmsrv.bookmarksMenuFolder michael@0: }, { michael@0: type: 'separator', michael@0: group: bmsrv.unfiledBookmarksFolder michael@0: }]; michael@0: michael@0: all(items.map(function (item) { michael@0: return send('sdk-places-bookmarks-create', item).then(function (data) { michael@0: compareWithHost(assert, data); michael@0: }, invalidReject(assert)); michael@0: })).then(function () { michael@0: done(); michael@0: }, invalidReject(assert)); michael@0: }; michael@0: michael@0: exports.testBookmarksCreateFail = function (assert, done) { michael@0: let items = [{ michael@0: title: 'my title', michael@0: url: 'not-a-url', michael@0: type: 'bookmark' michael@0: }, { michael@0: type: 'group', michael@0: group: bmsrv.bookmarksMenuFolder michael@0: }, { michael@0: group: bmsrv.unfiledBookmarksFolder michael@0: }]; michael@0: all(items.map(function (item) { michael@0: return send('sdk-places-bookmarks-create', item).then(null, function (reason) { michael@0: assert.ok(reason, 'bookmark create should fail'); michael@0: }); michael@0: })).then(done); michael@0: }; michael@0: michael@0: exports.testBookmarkLastUpdated = function (assert, done) { michael@0: let timestamp; michael@0: let item; michael@0: createBookmark({ michael@0: url: 'http://test-places-host.com/testBookmarkLastUpdated' michael@0: }).then(function (data) { michael@0: item = data; michael@0: timestamp = item.updated; michael@0: return send('sdk-places-bookmarks-last-updated', { id: item.id }); michael@0: }).then(function (updated) { michael@0: let { resolve, promise } = defer(); michael@0: assert.equal(timestamp, updated, 'should return last updated time'); michael@0: item.title = 'updated mozilla'; michael@0: setTimeout(() => { michael@0: resolve(send('sdk-places-bookmarks-save', item)); michael@0: }, 100); michael@0: return promise; michael@0: }).then(function (data) { michael@0: assert.ok(data.updated > timestamp, 'time has elapsed and updated the updated property'); michael@0: done(); michael@0: }); michael@0: }; michael@0: michael@0: exports.testBookmarkRemove = function (assert, done) { michael@0: let id; michael@0: createBookmark({ michael@0: url: 'http://test-places-host.com/testBookmarkRemove/' michael@0: }).then(function (data) { michael@0: id = data.id; michael@0: compareWithHost(assert, data); // ensure bookmark exists michael@0: bmsrv.getItemTitle(id); // does not throw an error michael@0: return send('sdk-places-bookmarks-remove', data); michael@0: }).then(function () { michael@0: assert.throws(function () { michael@0: bmsrv.getItemTitle(id); michael@0: }, 'item should no longer exist'); michael@0: done(); michael@0: }, assert.fail); michael@0: }; michael@0: michael@0: exports.testBookmarkGet = function (assert, done) { michael@0: let bookmark; michael@0: createBookmark({ michael@0: url: 'http://test-places-host.com/testBookmarkGet/' michael@0: }).then(function (data) { michael@0: bookmark = data; michael@0: return send('sdk-places-bookmarks-get', { id: data.id }); michael@0: }).then(function (data) { michael@0: 'title url index group updated type tags'.split(' ').map(function (prop) { michael@0: if (prop === 'tags') { michael@0: for (let tag of bookmark.tags) { michael@0: assert.ok(~data.tags.indexOf(tag), michael@0: 'correctly fetched tag ' + tag); michael@0: } michael@0: assert.equal(bookmark.tags.length, data.tags.length, michael@0: 'same amount of tags'); michael@0: } michael@0: else michael@0: assert.equal(bookmark[prop], data[prop], 'correctly fetched ' + prop); michael@0: }); michael@0: done(); michael@0: }); michael@0: }; michael@0: michael@0: exports.testTagsTag = function (assert, done) { michael@0: let url; michael@0: createBookmark({ michael@0: url: 'http://test-places-host.com/testTagsTag/', michael@0: }).then(function (data) { michael@0: url = data.url; michael@0: return send('sdk-places-tags-tag', { michael@0: url: data.url, tags: ['mozzerella', 'foxfire'] michael@0: }); michael@0: }).then(function () { michael@0: let tags = tagsrv.getTagsForURI(newURI(url)); michael@0: assert.ok(~tags.indexOf('mozzerella'), 'first tag found'); michael@0: assert.ok(~tags.indexOf('foxfire'), 'second tag found'); michael@0: assert.ok(~tags.indexOf('firefox'), 'default tag found'); michael@0: assert.equal(tags.length, 3, 'no extra tags'); michael@0: done(); michael@0: }); michael@0: }; michael@0: michael@0: exports.testTagsUntag = function (assert, done) { michael@0: let item; michael@0: createBookmark({ michael@0: url: 'http://test-places-host.com/testTagsUntag/', michael@0: tags: ['tag1', 'tag2', 'tag3'] michael@0: }).then(data => { michael@0: item = data; michael@0: return send('sdk-places-tags-untag', { michael@0: url: item.url, michael@0: tags: ['tag2', 'firefox'] michael@0: }); michael@0: }).then(function () { michael@0: let tags = tagsrv.getTagsForURI(newURI(item.url)); michael@0: assert.ok(~tags.indexOf('tag1'), 'first tag persisted'); michael@0: assert.ok(~tags.indexOf('tag3'), 'second tag persisted'); michael@0: assert.ok(!~tags.indexOf('firefox'), 'first tag removed'); michael@0: assert.ok(!~tags.indexOf('tag2'), 'second tag removed'); michael@0: assert.equal(tags.length, 2, 'no extra tags'); michael@0: done(); michael@0: }); michael@0: }; michael@0: michael@0: exports.testTagsGetURLsByTag = function (assert, done) { michael@0: let item; michael@0: createBookmark({ michael@0: url: 'http://test-places-host.com/testTagsGetURLsByTag/' michael@0: }).then(function (data) { michael@0: item = data; michael@0: return send('sdk-places-tags-get-urls-by-tag', { michael@0: tag: 'firefox' michael@0: }); michael@0: }).then(function(urls) { michael@0: assert.equal(item.url, urls[0], 'returned correct url'); michael@0: assert.equal(urls.length, 1, 'returned only one url'); michael@0: done(); michael@0: }); michael@0: }; michael@0: michael@0: exports.testTagsGetTagsByURL = function (assert, done) { michael@0: let item; michael@0: createBookmark({ michael@0: url: 'http://test-places-host.com/testTagsGetURLsByTag/', michael@0: tags: ['firefox', 'mozilla', 'metal'] michael@0: }).then(function (data) { michael@0: item = data; michael@0: return send('sdk-places-tags-get-tags-by-url', { michael@0: url: data.url, michael@0: }); michael@0: }).then(function(tags) { michael@0: assert.ok(~tags.indexOf('firefox'), 'returned first tag'); michael@0: assert.ok(~tags.indexOf('mozilla'), 'returned second tag'); michael@0: assert.ok(~tags.indexOf('metal'), 'returned third tag'); michael@0: assert.equal(tags.length, 3, 'returned all tags'); michael@0: done(); michael@0: }); michael@0: }; michael@0: michael@0: exports.testHostQuery = function (assert, done) { michael@0: all([ michael@0: createBookmark({ michael@0: url: 'http://firefox.com/testHostQuery/', michael@0: tags: ['firefox', 'mozilla'] michael@0: }), michael@0: createBookmark({ michael@0: url: 'http://mozilla.com/testHostQuery/', michael@0: tags: ['mozilla'] michael@0: }), michael@0: createBookmark({ url: 'http://thunderbird.com/testHostQuery/' }) michael@0: ]).then(data => { michael@0: return send('sdk-places-query', { michael@0: queries: { tags: ['mozilla'] }, michael@0: options: { sortingMode: 6, queryType: 1 } // sort by URI ascending, bookmarks only michael@0: }); michael@0: }).then(results => { michael@0: assert.equal(results.length, 2, 'should only return two'); michael@0: assert.equal(results[0].url, michael@0: 'http://mozilla.com/testHostQuery/', 'is sorted by URI asc'); michael@0: return send('sdk-places-query', { michael@0: queries: { tags: ['mozilla'] }, michael@0: options: { sortingMode: 5, queryType: 1 } // sort by URI descending, bookmarks only michael@0: }); michael@0: }).then(results => { michael@0: assert.equal(results.length, 2, 'should only return two'); michael@0: assert.equal(results[0].url, michael@0: 'http://firefox.com/testHostQuery/', 'is sorted by URI desc'); michael@0: done(); michael@0: }); michael@0: }; michael@0: michael@0: exports.testHostMultiQuery = function (assert, done) { michael@0: all([ michael@0: createBookmark({ michael@0: url: 'http://firefox.com/testHostMultiQuery/', michael@0: tags: ['firefox', 'mozilla'] michael@0: }), michael@0: createBookmark({ michael@0: url: 'http://mozilla.com/testHostMultiQuery/', michael@0: tags: ['mozilla'] michael@0: }), michael@0: createBookmark({ url: 'http://thunderbird.com/testHostMultiQuery/' }) michael@0: ]).then(data => { michael@0: return send('sdk-places-query', { michael@0: queries: [{ tags: ['firefox'] }, { uri: 'http://thunderbird.com/testHostMultiQuery/' }], michael@0: options: { sortingMode: 5, queryType: 1 } // sort by URI descending, bookmarks only michael@0: }); michael@0: }).then(results => { michael@0: assert.equal(results.length, 2, 'should return 2 results ORing queries'); michael@0: assert.equal(results[0].url, michael@0: 'http://firefox.com/testHostMultiQuery/', 'should match URL or tag'); michael@0: assert.equal(results[1].url, michael@0: 'http://thunderbird.com/testHostMultiQuery/', 'should match URL or tag'); michael@0: return send('sdk-places-query', { michael@0: queries: [{ tags: ['firefox'], url: 'http://mozilla.com/testHostMultiQuery/' }], michael@0: options: { sortingMode: 5, queryType: 1 } // sort by URI descending, bookmarks only michael@0: }); michael@0: }).then(results => { michael@0: assert.equal(results.length, 0, 'query props should be AND\'d'); michael@0: done(); michael@0: }); michael@0: }; michael@0: michael@0: exports.testGetAllBookmarks = function (assert, done) { michael@0: createBookmarkTree().then(() => { michael@0: return send('sdk-places-bookmarks-get-all', {}); michael@0: }).then(res => { michael@0: assert.equal(res.length, 8, 'all bookmarks returned'); michael@0: done(); michael@0: }, assert.fail); michael@0: }; michael@0: michael@0: exports.testGetAllChildren = function (assert, done) { michael@0: createBookmarkTree().then(results => { michael@0: return send('sdk-places-bookmarks-get-children', { michael@0: id: results.filter(({title}) => title === 'mozgroup')[0].id michael@0: }); michael@0: }).then(results => { michael@0: assert.equal(results.length, 5, michael@0: 'should return all children and folders at a single depth'); michael@0: done(); michael@0: }); michael@0: }; michael@0: michael@0: before(exports, (name, assert, done) => resetPlaces(done)); michael@0: after(exports, (name, assert, done) => resetPlaces(done));