summaryrefslogtreecommitdiffstats
path: root/toolkit/components/places/tests/history/test_update.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/places/tests/history/test_update.js')
-rw-r--r--toolkit/components/places/tests/history/test_update.js626
1 files changed, 626 insertions, 0 deletions
diff --git a/toolkit/components/places/tests/history/test_update.js b/toolkit/components/places/tests/history/test_update.js
new file mode 100644
index 0000000000..e0b0759ead
--- /dev/null
+++ b/toolkit/components/places/tests/history/test_update.js
@@ -0,0 +1,626 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests for `History.update` as implemented in History.jsm
+
+"use strict";
+
+add_task(async function test_error_cases() {
+ Assert.throws(
+ () => PlacesUtils.history.update("not an object"),
+ /Error: PageInfo: Input should be a valid object/,
+ "passing a string as pageInfo should throw an Error"
+ );
+ Assert.throws(
+ () => PlacesUtils.history.update(null),
+ /Error: PageInfo: Input should be/,
+ "passing a null as pageInfo should throw an Error"
+ );
+ Assert.throws(
+ () =>
+ PlacesUtils.history.update({
+ description: "Test description",
+ }),
+ /Error: PageInfo: The following properties were expected: url, guid/,
+ "not included a url or a guid should throw"
+ );
+ Assert.throws(
+ () => PlacesUtils.history.update({ url: "not a valid url string" }),
+ /Error: PageInfo: Invalid value for property/,
+ "passing an invalid url should throw an Error"
+ );
+ Assert.throws(
+ () =>
+ PlacesUtils.history.update({
+ url: "http://valid.uri.com",
+ description: 123,
+ }),
+ /Error: PageInfo: Invalid value for property/,
+ "passing a non-string description in pageInfo should throw an Error"
+ );
+ Assert.throws(
+ () =>
+ PlacesUtils.history.update({
+ url: "http://valid.uri.com",
+ guid: "invalid guid",
+ description: "Test description",
+ }),
+ /Error: PageInfo: Invalid value for property/,
+ "passing a invalid guid in pageInfo should throw an Error"
+ );
+ Assert.throws(
+ () =>
+ PlacesUtils.history.update({
+ url: "http://valid.uri.com",
+ previewImageURL: "not a valid url string",
+ }),
+ /Error: PageInfo: Invalid value for property/,
+ "passing an invlid preview image url in pageInfo should throw an Error"
+ );
+ Assert.throws(
+ () => {
+ let imageName = "a-very-long-string".repeat(10000);
+ let previewImageURL = `http://valid.uri.com/${imageName}.png`;
+ PlacesUtils.history.update({
+ url: "http://valid.uri.com",
+ previewImageURL,
+ });
+ },
+ /Error: PageInfo: Invalid value for property/,
+ "passing an oversized previewImageURL in pageInfo should throw an Error"
+ );
+ Assert.throws(
+ () => PlacesUtils.history.update({ url: "http://valid.uri.com" }),
+ /TypeError: pageInfo object must at least/,
+ "passing a pageInfo with neither description, previewImageURL, nor annotations should throw a TypeError"
+ );
+ Assert.throws(
+ () =>
+ PlacesUtils.history.update({
+ url: "http://valid.uri.com",
+ annotations: "asd",
+ }),
+ /Error: PageInfo: Invalid value for property/,
+ "passing a pageInfo with incorrect annotations type should throw an Error"
+ );
+ Assert.throws(
+ () =>
+ PlacesUtils.history.update({
+ url: "http://valid.uri.com",
+ annotations: new Map(),
+ }),
+ /Error: PageInfo: Invalid value for property/,
+ "passing a pageInfo with an empty annotations type should throw an Error"
+ );
+ Assert.throws(
+ () =>
+ PlacesUtils.history.update({
+ url: "http://valid.uri.com",
+ annotations: new Map([[1234, "value"]]),
+ }),
+ /Error: PageInfo: Invalid value for property/,
+ "passing a pageInfo with an invalid key type should throw an Error"
+ );
+ Assert.throws(
+ () =>
+ PlacesUtils.history.update({
+ url: "http://valid.uri.com",
+ annotations: new Map([["test", ["myarray"]]]),
+ }),
+ /Error: PageInfo: Invalid value for property/,
+ "passing a pageInfo with an invalid key type should throw an Error"
+ );
+ Assert.throws(
+ () =>
+ PlacesUtils.history.update({
+ url: "http://valid.uri.com",
+ annotations: new Map([["test", { anno: "value" }]]),
+ }),
+ /Error: PageInfo: Invalid value for property/,
+ "passing a pageInfo with an invalid key type should throw an Error"
+ );
+});
+
+add_task(async function test_description_change_saved() {
+ await PlacesUtils.history.clear();
+
+ let TEST_URL = "http://mozilla.org/test_description_change_saved";
+ await PlacesTestUtils.addVisits(TEST_URL);
+ Assert.ok(await PlacesTestUtils.isPageInDB(TEST_URL));
+
+ let description = "Test description";
+ await PlacesUtils.history.update({ url: TEST_URL, description });
+ let descriptionInDB = await PlacesTestUtils.fieldInDB(
+ TEST_URL,
+ "description"
+ );
+ Assert.equal(
+ description,
+ descriptionInDB,
+ "description should be updated via URL as expected"
+ );
+
+ description = "";
+ await PlacesUtils.history.update({ url: TEST_URL, description });
+ descriptionInDB = await PlacesTestUtils.fieldInDB(TEST_URL, "description");
+ Assert.strictEqual(
+ null,
+ descriptionInDB,
+ "an empty description should set it to null in the database"
+ );
+
+ let guid = await PlacesTestUtils.fieldInDB(TEST_URL, "guid");
+ description = "Test description";
+ await PlacesUtils.history.update({ url: TEST_URL, guid, description });
+ descriptionInDB = await PlacesTestUtils.fieldInDB(TEST_URL, "description");
+ Assert.equal(
+ description,
+ descriptionInDB,
+ "description should be updated via GUID as expected"
+ );
+
+ description = "Test descipriton".repeat(1000);
+ await PlacesUtils.history.update({ url: TEST_URL, description });
+ descriptionInDB = await PlacesTestUtils.fieldInDB(TEST_URL, "description");
+ Assert.ok(
+ !!descriptionInDB.length < description.length,
+ "a long description should be truncated"
+ );
+
+ description = null;
+ await PlacesUtils.history.update({ url: TEST_URL, description });
+ descriptionInDB = await PlacesTestUtils.fieldInDB(TEST_URL, "description");
+ Assert.strictEqual(
+ description,
+ descriptionInDB,
+ "a null description should set it to null in the database"
+ );
+});
+
+add_task(async function test_siteName_change_saved() {
+ await PlacesUtils.history.clear();
+
+ let TEST_URL = "http://mozilla.org/test_siteName_change_saved";
+ await PlacesTestUtils.addVisits(TEST_URL);
+ Assert.ok(await PlacesTestUtils.isPageInDB(TEST_URL));
+
+ let siteName = "Test site name";
+ await PlacesUtils.history.update({ url: TEST_URL, siteName });
+ let siteNameInDB = await PlacesTestUtils.fieldInDB(TEST_URL, "site_name");
+ Assert.equal(
+ siteName,
+ siteNameInDB,
+ "siteName should be updated via URL as expected"
+ );
+
+ siteName = "";
+ await PlacesUtils.history.update({ url: TEST_URL, siteName });
+ siteNameInDB = await PlacesTestUtils.fieldInDB(TEST_URL, "site_name");
+ Assert.strictEqual(
+ null,
+ siteNameInDB,
+ "an empty siteName should set it to null in the database"
+ );
+
+ let guid = await PlacesTestUtils.fieldInDB(TEST_URL, "guid");
+ siteName = "Test site name";
+ await PlacesUtils.history.update({ url: TEST_URL, guid, siteName });
+ siteNameInDB = await PlacesTestUtils.fieldInDB(TEST_URL, "site_name");
+ Assert.equal(
+ siteName,
+ siteNameInDB,
+ "siteName should be updated via GUID as expected"
+ );
+
+ siteName = "Test site name".repeat(1000);
+ await PlacesUtils.history.update({ url: TEST_URL, siteName });
+ siteNameInDB = await PlacesTestUtils.fieldInDB(TEST_URL, "site_name");
+ Assert.ok(
+ !!siteNameInDB.length < siteName.length,
+ "a long siteName should be truncated"
+ );
+
+ siteName = null;
+ await PlacesUtils.history.update({ url: TEST_URL, siteName });
+ siteNameInDB = await PlacesTestUtils.fieldInDB(TEST_URL, "site_name");
+ Assert.strictEqual(
+ siteName,
+ siteNameInDB,
+ "a null siteName should set it to null in the database"
+ );
+});
+
+add_task(async function test_previewImageURL_change_saved() {
+ await PlacesUtils.history.clear();
+
+ let TEST_URL = "http://mozilla.org/test_previewImageURL_change_saved";
+ let IMAGE_URL = "http://mozilla.org/test_preview_image.png";
+ await PlacesTestUtils.addVisits(TEST_URL);
+ Assert.ok(await PlacesTestUtils.isPageInDB(TEST_URL));
+
+ let previewImageURL = IMAGE_URL;
+ await PlacesUtils.history.update({ url: TEST_URL, previewImageURL });
+ let previewImageURLInDB = await PlacesTestUtils.fieldInDB(
+ TEST_URL,
+ "preview_image_url"
+ );
+ Assert.equal(
+ previewImageURL,
+ previewImageURLInDB,
+ "previewImageURL should be updated via URL as expected"
+ );
+
+ previewImageURL = null;
+ await PlacesUtils.history.update({ url: TEST_URL, previewImageURL });
+ previewImageURLInDB = await PlacesTestUtils.fieldInDB(
+ TEST_URL,
+ "preview_image_url"
+ );
+ Assert.strictEqual(
+ null,
+ previewImageURLInDB,
+ "a null previewImageURL should set it to null in the database"
+ );
+
+ let guid = await PlacesTestUtils.fieldInDB(TEST_URL, "guid");
+ previewImageURL = IMAGE_URL;
+ await PlacesUtils.history.update({ guid, previewImageURL });
+ previewImageURLInDB = await PlacesTestUtils.fieldInDB(
+ TEST_URL,
+ "preview_image_url"
+ );
+ Assert.equal(
+ previewImageURL,
+ previewImageURLInDB,
+ "previewImageURL should be updated via GUID as expected"
+ );
+
+ previewImageURL = "";
+ await PlacesUtils.history.update({ url: TEST_URL, previewImageURL });
+ previewImageURLInDB = await PlacesTestUtils.fieldInDB(
+ TEST_URL,
+ "preview_image_url"
+ );
+ Assert.strictEqual(
+ null,
+ previewImageURLInDB,
+ "an empty previewImageURL should set it to null in the database"
+ );
+});
+
+add_task(async function test_change_description_and_preview_saved() {
+ await PlacesUtils.history.clear();
+
+ let TEST_URL = "http://mozilla.org/test_change_both_saved";
+ await PlacesTestUtils.addVisits(TEST_URL);
+ Assert.ok(await PlacesTestUtils.isPageInDB(TEST_URL));
+
+ let description = "Test description";
+ let previewImageURL = "http://mozilla.org/test_preview_image.png";
+
+ await PlacesUtils.history.update({
+ url: TEST_URL,
+ description,
+ previewImageURL,
+ });
+ let descriptionInDB = await PlacesTestUtils.fieldInDB(
+ TEST_URL,
+ "description"
+ );
+ let previewImageURLInDB = await PlacesTestUtils.fieldInDB(
+ TEST_URL,
+ "preview_image_url"
+ );
+ Assert.equal(
+ description,
+ descriptionInDB,
+ "description should be updated via URL as expected"
+ );
+ Assert.equal(
+ previewImageURL,
+ previewImageURLInDB,
+ "previewImageURL should be updated via URL as expected"
+ );
+
+ // Update description should not touch other fields
+ description = null;
+ await PlacesUtils.history.update({ url: TEST_URL, description });
+ descriptionInDB = await PlacesTestUtils.fieldInDB(TEST_URL, "description");
+ previewImageURLInDB = await PlacesTestUtils.fieldInDB(
+ TEST_URL,
+ "preview_image_url"
+ );
+ Assert.strictEqual(
+ description,
+ descriptionInDB,
+ "description should be updated via URL as expected"
+ );
+ Assert.equal(
+ previewImageURL,
+ previewImageURLInDB,
+ "previewImageURL should not be updated"
+ );
+});
+
+/**
+ * Gets annotation information from the database for the specified URL and
+ * annotation name.
+ *
+ * @param {String} pageUrl The URL to search for.
+ * @param {String} annoName The name of the annotation to search for.
+ * @return {Array} An array of objects containing the annotations found.
+ */
+async function getAnnotationInfoFromDB(pageUrl, annoName) {
+ let db = await PlacesUtils.promiseDBConnection();
+
+ let rows = await db.execute(
+ `
+ SELECT a.content, a.flags, a.expiration, a.type FROM moz_anno_attributes n
+ JOIN moz_annos a ON n.id = a.anno_attribute_id
+ JOIN moz_places h ON h.id = a.place_id
+ WHERE h.url_hash = hash(:pageUrl) AND h.url = :pageUrl
+ AND n.name = :annoName
+ `,
+ { annoName, pageUrl }
+ );
+
+ let result = rows.map(row => {
+ return {
+ content: row.getResultByName("content"),
+ flags: row.getResultByName("flags"),
+ expiration: row.getResultByName("expiration"),
+ type: row.getResultByName("type"),
+ };
+ });
+
+ return result;
+}
+
+add_task(async function test_simple_change_annotations() {
+ await PlacesUtils.history.clear();
+
+ const TEST_URL = "http://mozilla.org/test_change_both_saved";
+ await PlacesTestUtils.addVisits(TEST_URL);
+ Assert.ok(
+ await PlacesTestUtils.isPageInDB(TEST_URL),
+ "Should have inserted the page into the database."
+ );
+
+ await PlacesUtils.history.update({
+ url: TEST_URL,
+ annotations: new Map([["test/annotation", "testContent"]]),
+ });
+
+ let pageInfo = await PlacesUtils.history.fetch(TEST_URL, {
+ includeAnnotations: true,
+ });
+
+ Assert.equal(
+ pageInfo.annotations.size,
+ 1,
+ "Should have one annotation for the page"
+ );
+ Assert.equal(
+ pageInfo.annotations.get("test/annotation"),
+ "testContent",
+ "Should have the correct annotation"
+ );
+
+ let annotationInfo = await getAnnotationInfoFromDB(
+ TEST_URL,
+ "test/annotation"
+ );
+ Assert.deepEqual(
+ {
+ content: "testContent",
+ flags: 0,
+ type: PlacesUtils.history.ANNOTATION_TYPE_STRING,
+ expiration: PlacesUtils.history.ANNOTATION_EXPIRE_NEVER,
+ },
+ annotationInfo[0],
+ "Should have stored the correct annotation data in the db"
+ );
+
+ await PlacesUtils.history.update({
+ url: TEST_URL,
+ annotations: new Map([["test/annotation2", "testAnno"]]),
+ });
+
+ pageInfo = await PlacesUtils.history.fetch(TEST_URL, {
+ includeAnnotations: true,
+ });
+
+ Assert.equal(
+ pageInfo.annotations.size,
+ 2,
+ "Should have two annotations for the page"
+ );
+ Assert.equal(
+ pageInfo.annotations.get("test/annotation"),
+ "testContent",
+ "Should have the correct value for the first annotation"
+ );
+ Assert.equal(
+ pageInfo.annotations.get("test/annotation2"),
+ "testAnno",
+ "Should have the correct value for the second annotation"
+ );
+
+ await PlacesUtils.history.update({
+ url: TEST_URL,
+ annotations: new Map([["test/annotation", 1234]]),
+ });
+
+ pageInfo = await PlacesUtils.history.fetch(TEST_URL, {
+ includeAnnotations: true,
+ });
+
+ Assert.equal(
+ pageInfo.annotations.size,
+ 2,
+ "Should still have two annotations for the page"
+ );
+ Assert.equal(
+ pageInfo.annotations.get("test/annotation"),
+ 1234,
+ "Should have the updated the first annotation value"
+ );
+ Assert.equal(
+ pageInfo.annotations.get("test/annotation2"),
+ "testAnno",
+ "Should have kept the value for the second annotation"
+ );
+
+ annotationInfo = await getAnnotationInfoFromDB(TEST_URL, "test/annotation");
+ Assert.deepEqual(
+ {
+ content: 1234,
+ flags: 0,
+ type: PlacesUtils.history.ANNOTATION_TYPE_INT64,
+ expiration: PlacesUtils.history.ANNOTATION_EXPIRE_NEVER,
+ },
+ annotationInfo[0],
+ "Should have updated the annotation data in the db"
+ );
+
+ await PlacesUtils.history.update({
+ url: TEST_URL,
+ annotations: new Map([["test/annotation", null]]),
+ });
+
+ pageInfo = await PlacesUtils.history.fetch(TEST_URL, {
+ includeAnnotations: true,
+ });
+
+ Assert.equal(
+ pageInfo.annotations.size,
+ 1,
+ "Should have removed only the first annotation"
+ );
+ Assert.strictEqual(
+ pageInfo.annotations.get("test/annotation"),
+ undefined,
+ "Should have removed only the first annotation"
+ );
+ Assert.equal(
+ pageInfo.annotations.get("test/annotation2"),
+ "testAnno",
+ "Should have kept the value for the second annotation"
+ );
+
+ await PlacesUtils.history.update({
+ url: TEST_URL,
+ annotations: new Map([["test/annotation2", null]]),
+ });
+
+ pageInfo = await PlacesUtils.history.fetch(TEST_URL, {
+ includeAnnotations: true,
+ });
+
+ Assert.equal(pageInfo.annotations.size, 0, "Should have no annotations left");
+
+ let db = await PlacesUtils.promiseDBConnection();
+ let rows = await db.execute(`
+ SELECT * FROM moz_annos
+ `);
+ Assert.equal(rows.length, 0, "Should be no annotations left in the db");
+});
+
+add_task(async function test_change_multiple_annotations() {
+ await PlacesUtils.history.clear();
+
+ const TEST_URL = "http://mozilla.org/test_change_both_saved";
+ await PlacesTestUtils.addVisits(TEST_URL);
+ Assert.ok(
+ await PlacesTestUtils.isPageInDB(TEST_URL),
+ "Should have inserted the page into the database."
+ );
+
+ await PlacesUtils.history.update({
+ url: TEST_URL,
+ annotations: new Map([
+ ["test/annotation", "testContent"],
+ ["test/annotation2", "testAnno"],
+ ]),
+ });
+
+ let pageInfo = await PlacesUtils.history.fetch(TEST_URL, {
+ includeAnnotations: true,
+ });
+
+ Assert.equal(
+ pageInfo.annotations.size,
+ 2,
+ "Should have inserted the two annotations for the page."
+ );
+ Assert.equal(
+ pageInfo.annotations.get("test/annotation"),
+ "testContent",
+ "Should have the correct value for the first annotation"
+ );
+ Assert.equal(
+ pageInfo.annotations.get("test/annotation2"),
+ "testAnno",
+ "Should have the correct value for the second annotation"
+ );
+
+ await PlacesUtils.history.update({
+ url: TEST_URL,
+ annotations: new Map([
+ ["test/annotation", 123456],
+ ["test/annotation2", 135246],
+ ]),
+ });
+
+ pageInfo = await PlacesUtils.history.fetch(TEST_URL, {
+ includeAnnotations: true,
+ });
+
+ Assert.equal(
+ pageInfo.annotations.size,
+ 2,
+ "Should have two annotations for the page"
+ );
+ Assert.equal(
+ pageInfo.annotations.get("test/annotation"),
+ 123456,
+ "Should have the correct value for the first annotation"
+ );
+ Assert.equal(
+ pageInfo.annotations.get("test/annotation2"),
+ 135246,
+ "Should have the correct value for the second annotation"
+ );
+
+ await PlacesUtils.history.update({
+ url: TEST_URL,
+ annotations: new Map([
+ ["test/annotation", null],
+ ["test/annotation2", null],
+ ]),
+ });
+
+ pageInfo = await PlacesUtils.history.fetch(TEST_URL, {
+ includeAnnotations: true,
+ });
+
+ Assert.equal(pageInfo.annotations.size, 0, "Should have no annotations left");
+});
+
+add_task(async function test_annotations_nonexisting_page() {
+ info("Adding annotations to a non existing page should be silent");
+ await PlacesUtils.history.update({
+ url: "http://nonexisting.moz/",
+ annotations: new Map([["test/annotation", null]]),
+ });
+});
+
+add_task(async function test_annotations_nonexisting_page() {
+ info("Adding annotations to a non existing page should be silent");
+ await PlacesUtils.history.update({
+ url: "http://nonexisting.moz/",
+ annotations: new Map([["test/annotation", null]]),
+ });
+});