forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			714 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			714 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
"use strict";
 | 
						|
 | 
						|
let json = [
 | 
						|
  {
 | 
						|
    namespace: "MV2",
 | 
						|
    max_manifest_version: 2,
 | 
						|
 | 
						|
    properties: {
 | 
						|
      PROP1: { value: 20 },
 | 
						|
    },
 | 
						|
  },
 | 
						|
  {
 | 
						|
    namespace: "MV3",
 | 
						|
    min_manifest_version: 3,
 | 
						|
    properties: {
 | 
						|
      PROP1: { value: 20 },
 | 
						|
    },
 | 
						|
  },
 | 
						|
  {
 | 
						|
    namespace: "mixed",
 | 
						|
 | 
						|
    properties: {
 | 
						|
      PROP_any: { value: 20 },
 | 
						|
      PROP_mv3: {
 | 
						|
        $ref: "submodule",
 | 
						|
      },
 | 
						|
    },
 | 
						|
    types: [
 | 
						|
      {
 | 
						|
        id: "manifestTest",
 | 
						|
        type: "object",
 | 
						|
        properties: {
 | 
						|
          // An example of extending the base type for permissions
 | 
						|
          permissions: {
 | 
						|
            type: "array",
 | 
						|
            items: {
 | 
						|
              $ref: "BaseType",
 | 
						|
            },
 | 
						|
            optional: true,
 | 
						|
            default: [],
 | 
						|
          },
 | 
						|
          // An example of differentiating versions of a manifest entry
 | 
						|
          multiple_choice: {
 | 
						|
            optional: true,
 | 
						|
            choices: [
 | 
						|
              {
 | 
						|
                max_manifest_version: 2,
 | 
						|
                type: "array",
 | 
						|
                items: {
 | 
						|
                  type: "string",
 | 
						|
                },
 | 
						|
              },
 | 
						|
              {
 | 
						|
                min_manifest_version: 3,
 | 
						|
                type: "array",
 | 
						|
                items: {
 | 
						|
                  type: "boolean",
 | 
						|
                },
 | 
						|
              },
 | 
						|
              {
 | 
						|
                type: "array",
 | 
						|
                items: {
 | 
						|
                  type: "object",
 | 
						|
                  properties: {
 | 
						|
                    value: { type: "boolean" },
 | 
						|
                  },
 | 
						|
                },
 | 
						|
              },
 | 
						|
            ],
 | 
						|
          },
 | 
						|
          accepting_unrecognized_props: {
 | 
						|
            optional: true,
 | 
						|
            type: "object",
 | 
						|
            properties: {
 | 
						|
              mv2_only_prop: {
 | 
						|
                type: "string",
 | 
						|
                optional: true,
 | 
						|
                max_manifest_version: 2,
 | 
						|
              },
 | 
						|
              mv3_only_prop: {
 | 
						|
                type: "string",
 | 
						|
                optional: true,
 | 
						|
                min_manifest_version: 3,
 | 
						|
              },
 | 
						|
              mv2_only_prop_with_default: {
 | 
						|
                type: "string",
 | 
						|
                optional: true,
 | 
						|
                default: "only in MV2",
 | 
						|
                max_manifest_version: 2,
 | 
						|
              },
 | 
						|
              mv3_only_prop_with_default: {
 | 
						|
                type: "string",
 | 
						|
                optional: true,
 | 
						|
                default: "only in MV3",
 | 
						|
                min_manifest_version: 3,
 | 
						|
              },
 | 
						|
            },
 | 
						|
            additionalProperties: { $ref: "UnrecognizedProperty" },
 | 
						|
          },
 | 
						|
        },
 | 
						|
      },
 | 
						|
      {
 | 
						|
        id: "submodule",
 | 
						|
        type: "object",
 | 
						|
        min_manifest_version: 3,
 | 
						|
        functions: [
 | 
						|
          {
 | 
						|
            name: "sub_foo",
 | 
						|
            type: "function",
 | 
						|
            parameters: [],
 | 
						|
            returns: { type: "integer" },
 | 
						|
          },
 | 
						|
          {
 | 
						|
            name: "sub_no_match",
 | 
						|
            type: "function",
 | 
						|
            max_manifest_version: 2,
 | 
						|
            parameters: [],
 | 
						|
            returns: { type: "integer" },
 | 
						|
          },
 | 
						|
        ],
 | 
						|
      },
 | 
						|
      {
 | 
						|
        id: "BaseType",
 | 
						|
        choices: [
 | 
						|
          {
 | 
						|
            type: "string",
 | 
						|
            enum: ["base"],
 | 
						|
          },
 | 
						|
        ],
 | 
						|
      },
 | 
						|
      {
 | 
						|
        id: "type_any",
 | 
						|
        type: "string",
 | 
						|
        enum: ["value1", "value2", "value3"],
 | 
						|
      },
 | 
						|
      {
 | 
						|
        id: "type_mv2",
 | 
						|
        max_manifest_version: 2,
 | 
						|
        type: "string",
 | 
						|
        enum: ["value1", "value2", "value3"],
 | 
						|
      },
 | 
						|
      {
 | 
						|
        id: "type_mv3",
 | 
						|
        min_manifest_version: 3,
 | 
						|
        type: "string",
 | 
						|
        enum: ["value1", "value2", "value3"],
 | 
						|
      },
 | 
						|
      {
 | 
						|
        id: "param_type_changed",
 | 
						|
        type: "array",
 | 
						|
        items: {
 | 
						|
          choices: [
 | 
						|
            { max_manifest_version: 2, type: "string" },
 | 
						|
            {
 | 
						|
              min_manifest_version: 3,
 | 
						|
              type: "boolean",
 | 
						|
            },
 | 
						|
          ],
 | 
						|
        },
 | 
						|
      },
 | 
						|
      {
 | 
						|
        id: "object_type_changed",
 | 
						|
        type: "object",
 | 
						|
        properties: {
 | 
						|
          prop_mv2: {
 | 
						|
            type: "string",
 | 
						|
            max_manifest_version: 2,
 | 
						|
          },
 | 
						|
          prop_mv3: {
 | 
						|
            type: "string",
 | 
						|
            min_manifest_version: 3,
 | 
						|
          },
 | 
						|
          prop_any: {
 | 
						|
            type: "string",
 | 
						|
          },
 | 
						|
        },
 | 
						|
      },
 | 
						|
      {
 | 
						|
        id: "no_valid_choices",
 | 
						|
        type: "array",
 | 
						|
        items: {
 | 
						|
          choices: [
 | 
						|
            { max_manifest_version: 1, type: "string" },
 | 
						|
            {
 | 
						|
              min_manifest_version: 4,
 | 
						|
              type: "boolean",
 | 
						|
            },
 | 
						|
          ],
 | 
						|
        },
 | 
						|
      },
 | 
						|
    ],
 | 
						|
 | 
						|
    functions: [
 | 
						|
      {
 | 
						|
        name: "fun_param_type_versioned",
 | 
						|
        type: "function",
 | 
						|
        parameters: [{ name: "arg1", $ref: "param_type_changed" }],
 | 
						|
      },
 | 
						|
      {
 | 
						|
        name: "fun_mv2",
 | 
						|
        max_manifest_version: 2,
 | 
						|
        type: "function",
 | 
						|
        parameters: [
 | 
						|
          { name: "arg1", type: "integer", optional: true, default: 99 },
 | 
						|
          { name: "arg2", type: "boolean", optional: true },
 | 
						|
        ],
 | 
						|
      },
 | 
						|
      {
 | 
						|
        name: "fun_mv3",
 | 
						|
        min_manifest_version: 3,
 | 
						|
        type: "function",
 | 
						|
        parameters: [
 | 
						|
          { name: "arg1", type: "integer", optional: true, default: 99 },
 | 
						|
          { name: "arg2", type: "boolean", optional: true },
 | 
						|
        ],
 | 
						|
      },
 | 
						|
      {
 | 
						|
        name: "fun_param_change",
 | 
						|
        type: "function",
 | 
						|
        parameters: [{ name: "arg1", $ref: "object_type_changed" }],
 | 
						|
      },
 | 
						|
      {
 | 
						|
        name: "fun_no_valid_param",
 | 
						|
        type: "function",
 | 
						|
        parameters: [{ name: "arg1", $ref: "no_valid_choices" }],
 | 
						|
      },
 | 
						|
    ],
 | 
						|
    events: [
 | 
						|
      {
 | 
						|
        name: "onEvent_any",
 | 
						|
        type: "function",
 | 
						|
      },
 | 
						|
      {
 | 
						|
        name: "onEvent_mv2",
 | 
						|
        max_manifest_version: 2,
 | 
						|
        type: "function",
 | 
						|
      },
 | 
						|
      {
 | 
						|
        name: "onEvent_mv3",
 | 
						|
        min_manifest_version: 3,
 | 
						|
        type: "function",
 | 
						|
      },
 | 
						|
    ],
 | 
						|
  },
 | 
						|
  {
 | 
						|
    namespace: "mixed",
 | 
						|
    types: [
 | 
						|
      {
 | 
						|
        $extend: "BaseType",
 | 
						|
        choices: [
 | 
						|
          {
 | 
						|
            min_manifest_version: 3,
 | 
						|
            type: "string",
 | 
						|
            enum: ["extended"],
 | 
						|
          },
 | 
						|
        ],
 | 
						|
      },
 | 
						|
    ],
 | 
						|
  },
 | 
						|
  {
 | 
						|
    namespace: "mixed",
 | 
						|
    types: [
 | 
						|
      {
 | 
						|
        $extend: "manifestTest",
 | 
						|
        properties: {
 | 
						|
          versioned_extend: {
 | 
						|
            optional: true,
 | 
						|
            // just a simple type here
 | 
						|
            type: "string",
 | 
						|
            max_manifest_version: 2,
 | 
						|
          },
 | 
						|
        },
 | 
						|
      },
 | 
						|
    ],
 | 
						|
  },
 | 
						|
];
 | 
						|
 | 
						|
add_task(async function setup() {
 | 
						|
  let url = "data:," + JSON.stringify(json);
 | 
						|
  Schemas._rootSchema = null;
 | 
						|
  await Schemas.load(url);
 | 
						|
 | 
						|
  // We want the actual errors thrown here, and not warnings recast as errors.
 | 
						|
  ExtensionTestUtils.failOnSchemaWarnings(false);
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_inject_V2() {
 | 
						|
  // Test injecting into a V2 context.
 | 
						|
  let wrapper = getContextWrapper(2);
 | 
						|
 | 
						|
  let root = {};
 | 
						|
  Schemas.inject(root, wrapper);
 | 
						|
 | 
						|
  // Test elements available to both
 | 
						|
  Assert.equal(root.mixed.type_any.VALUE1, "value1", "type_any exists");
 | 
						|
  Assert.equal(root.mixed.PROP_any, 20, "mixed value property");
 | 
						|
 | 
						|
  // Test elements available to MV2
 | 
						|
  Assert.equal(root.MV2.PROP1, 20, "MV2 value property");
 | 
						|
  Assert.equal(root.mixed.type_mv2.VALUE2, "value2", "type_mv2 exists");
 | 
						|
 | 
						|
  // Test MV3 elements not available
 | 
						|
  Assert.equal(root.MV3, undefined, "MV3 not injected");
 | 
						|
  Assert.ok(!("MV3" in root), "MV3 not enumerable");
 | 
						|
  Assert.equal(
 | 
						|
    root.mixed.PROP_mv3,
 | 
						|
    undefined,
 | 
						|
    "mixed submodule property does not exist"
 | 
						|
  );
 | 
						|
  Assert.ok(
 | 
						|
    !("PROP_mv3" in root.mixed),
 | 
						|
    "mixed submodule property not enumerable"
 | 
						|
  );
 | 
						|
  Assert.equal(root.mixed.type_mv3, undefined, "type_mv3 does not exist");
 | 
						|
 | 
						|
  // Function tests
 | 
						|
  Assert.ok(
 | 
						|
    "fun_param_type_versioned" in root.mixed,
 | 
						|
    "fun_param_type_versioned exists"
 | 
						|
  );
 | 
						|
  Assert.ok(
 | 
						|
    !!root.mixed.fun_param_type_versioned,
 | 
						|
    "fun_param_type_versioned exists"
 | 
						|
  );
 | 
						|
  Assert.ok("fun_mv2" in root.mixed, "fun_mv2 exists");
 | 
						|
  Assert.ok(!!root.mixed.fun_mv2, "fun_mv2 exists");
 | 
						|
  Assert.ok(!("fun_mv3" in root.mixed), "fun_mv3 does not exist");
 | 
						|
  Assert.ok(!root.mixed.fun_mv3, "fun_mv3 does not exist");
 | 
						|
 | 
						|
  // Event tests
 | 
						|
  Assert.ok("onEvent_any" in root.mixed, "onEvent_any exists");
 | 
						|
  Assert.ok(!!root.mixed.onEvent_any, "onEvent_any exists");
 | 
						|
  Assert.ok("onEvent_mv2" in root.mixed, "onEvent_mv2 exists");
 | 
						|
  Assert.ok(!!root.mixed.onEvent_mv2, "onEvent_mv2 exists");
 | 
						|
  Assert.ok(!("onEvent_mv3" in root.mixed), "onEvent_mv3 does not exist");
 | 
						|
  Assert.ok(!root.mixed.onEvent_mv3, "onEvent_mv3 does not exist");
 | 
						|
 | 
						|
  // Function call tests
 | 
						|
  root.mixed.fun_param_type_versioned(["hello"]);
 | 
						|
  wrapper.verify("call", "mixed", "fun_param_type_versioned", [["hello"]]);
 | 
						|
  Assert.throws(
 | 
						|
    () => root.mixed.fun_param_type_versioned([true]),
 | 
						|
    /Expected string instead of true/,
 | 
						|
    "fun_param_type_versioned should throw for invalid type"
 | 
						|
  );
 | 
						|
 | 
						|
  let propObj = { prop_any: "prop_any", prop_mv2: "prop_mv2" };
 | 
						|
  root.mixed.fun_param_change(propObj);
 | 
						|
  wrapper.verify("call", "mixed", "fun_param_change", [propObj]);
 | 
						|
 | 
						|
  // Still throw same error as we did before we knew of the MV3 property.
 | 
						|
  Assert.throws(
 | 
						|
    () => root.mixed.fun_param_change({ prop_mv3: "prop_mv3", ...propObj }),
 | 
						|
    /Type error for parameter arg1 \(Unexpected property "prop_mv3"\)/,
 | 
						|
    "generic unexpected property message for MV3 property in MV2 extension"
 | 
						|
  );
 | 
						|
 | 
						|
  // But print the more specific and descriptive warning message to console.
 | 
						|
  wrapper.checkErrors([
 | 
						|
    `Property "prop_mv3" is unsupported in Manifest Version 2`,
 | 
						|
  ]);
 | 
						|
 | 
						|
  Assert.throws(
 | 
						|
    () => root.mixed.fun_no_valid_param("anything"),
 | 
						|
    /Incorrect argument types for mixed.fun_no_valid_param/,
 | 
						|
    "fun_no_valid_param should throw for versioned type"
 | 
						|
  );
 | 
						|
});
 | 
						|
 | 
						|
function normalizeTest(manifest, test, wrapper) {
 | 
						|
  let normalized = Schemas.normalize(manifest, "mixed.manifestTest", wrapper);
 | 
						|
  test(normalized);
 | 
						|
  // The test function should call wrapper.checkErrors if it expected errors.
 | 
						|
  // Here we call checkErrors again to ensure that there are not any unexpected
 | 
						|
  // errors left.
 | 
						|
  wrapper.checkErrors([]);
 | 
						|
}
 | 
						|
 | 
						|
add_task(async function test_normalize_V2() {
 | 
						|
  let wrapper = getContextWrapper(2);
 | 
						|
 | 
						|
  // Test normalize additions to the manifest structure
 | 
						|
  normalizeTest(
 | 
						|
    {
 | 
						|
      versioned_extend: "test",
 | 
						|
    },
 | 
						|
    normalized => {
 | 
						|
      Assert.equal(
 | 
						|
        normalized.value.versioned_extend,
 | 
						|
        "test",
 | 
						|
        "resources normalized"
 | 
						|
      );
 | 
						|
    },
 | 
						|
    wrapper
 | 
						|
  );
 | 
						|
 | 
						|
  // Test normalizing baseType
 | 
						|
  normalizeTest(
 | 
						|
    {
 | 
						|
      permissions: ["base"],
 | 
						|
    },
 | 
						|
    normalized => {
 | 
						|
      Assert.equal(
 | 
						|
        normalized.value.permissions[0],
 | 
						|
        "base",
 | 
						|
        "resources normalized"
 | 
						|
      );
 | 
						|
    },
 | 
						|
    wrapper
 | 
						|
  );
 | 
						|
 | 
						|
  normalizeTest(
 | 
						|
    {
 | 
						|
      permissions: ["extended"],
 | 
						|
    },
 | 
						|
    normalized => {
 | 
						|
      Assert.ok(
 | 
						|
        normalized.error.startsWith("Error processing permissions.0"),
 | 
						|
        `manifest normalized error ${normalized.error}`
 | 
						|
      );
 | 
						|
    },
 | 
						|
    wrapper
 | 
						|
  );
 | 
						|
 | 
						|
  // Test normalizing a value
 | 
						|
  normalizeTest(
 | 
						|
    {
 | 
						|
      multiple_choice: ["foo.html"],
 | 
						|
    },
 | 
						|
    normalized => {
 | 
						|
      Assert.equal(
 | 
						|
        normalized.value.multiple_choice[0],
 | 
						|
        "foo.html",
 | 
						|
        "resources normalized"
 | 
						|
      );
 | 
						|
    },
 | 
						|
    wrapper
 | 
						|
  );
 | 
						|
 | 
						|
  normalizeTest(
 | 
						|
    {
 | 
						|
      multiple_choice: [true],
 | 
						|
    },
 | 
						|
    normalized => {
 | 
						|
      Assert.ok(
 | 
						|
        normalized.error.startsWith("Error processing multiple_choice"),
 | 
						|
        "manifest error"
 | 
						|
      );
 | 
						|
    },
 | 
						|
    wrapper
 | 
						|
  );
 | 
						|
 | 
						|
  normalizeTest(
 | 
						|
    {
 | 
						|
      multiple_choice: [
 | 
						|
        {
 | 
						|
          value: true,
 | 
						|
        },
 | 
						|
      ],
 | 
						|
    },
 | 
						|
    normalized => {
 | 
						|
      Assert.ok(
 | 
						|
        normalized.value.multiple_choice[0].value,
 | 
						|
        "resources normalized"
 | 
						|
      );
 | 
						|
    },
 | 
						|
    wrapper
 | 
						|
  );
 | 
						|
 | 
						|
  // Tests that object definitions including additionalProperties can
 | 
						|
  // successfully accept objects from another manifest version, while ignoring
 | 
						|
  // the actual value from the non-matching manifest value.
 | 
						|
  normalizeTest(
 | 
						|
    {
 | 
						|
      accepting_unrecognized_props: {
 | 
						|
        mv2_only_prop: "mv2 here",
 | 
						|
        mv3_only_prop: "mv3 here",
 | 
						|
      },
 | 
						|
    },
 | 
						|
    normalized => {
 | 
						|
      equal(normalized.error, undefined, "no normalization error");
 | 
						|
      Assert.deepEqual(
 | 
						|
        normalized.value.accepting_unrecognized_props,
 | 
						|
        {
 | 
						|
          mv2_only_prop: "mv2 here",
 | 
						|
          mv2_only_prop_with_default: "only in MV2",
 | 
						|
        },
 | 
						|
        "Normalized object for MV2, without MV3-specific props"
 | 
						|
      );
 | 
						|
      wrapper.checkErrors([
 | 
						|
        `Property "mv3_only_prop" is unsupported in Manifest Version 2`,
 | 
						|
      ]);
 | 
						|
    },
 | 
						|
    wrapper
 | 
						|
  );
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_inject_V3() {
 | 
						|
  // Test injecting into a V3 context.
 | 
						|
  let wrapper = getContextWrapper(3);
 | 
						|
 | 
						|
  let root = {};
 | 
						|
  Schemas.inject(root, wrapper);
 | 
						|
 | 
						|
  // Test elements available to both
 | 
						|
  Assert.equal(root.mixed.type_any.VALUE1, "value1", "type_any exists");
 | 
						|
  Assert.equal(root.mixed.PROP_any, 20, "mixed value property");
 | 
						|
 | 
						|
  // Test elements available to MV2
 | 
						|
  Assert.equal(root.MV2, undefined, "MV2 value property");
 | 
						|
  Assert.ok(!("MV2" in root), "MV2 not enumerable");
 | 
						|
  Assert.equal(root.mixed.type_mv2, undefined, "type_mv2 does not exist");
 | 
						|
  Assert.ok(!("type_mv2" in root.mixed), "type_mv2 not enumerable");
 | 
						|
 | 
						|
  // Test MV3 elements not available
 | 
						|
  Assert.equal(root.MV3.PROP1, 20, "MV3 injected");
 | 
						|
  Assert.ok(!!root.mixed.PROP_mv3, "mixed submodule property exists");
 | 
						|
  Assert.equal(root.mixed.type_mv3.VALUE3, "value3", "type_mv3 exists");
 | 
						|
 | 
						|
  // Versioned submodule
 | 
						|
  Assert.ok(!!root.mixed.PROP_mv3.sub_foo, "mixed submodule sub_foo exists");
 | 
						|
  Assert.ok(
 | 
						|
    !root.mixed.PROP_mv3.sub_no_match,
 | 
						|
    "mixed submodule sub_no_match does not exist"
 | 
						|
  );
 | 
						|
  Assert.ok(
 | 
						|
    !("sub_no_match" in root.mixed.PROP_mv3),
 | 
						|
    "mixed submodule sub_no_match is not enumerable"
 | 
						|
  );
 | 
						|
 | 
						|
  // Function tests
 | 
						|
  Assert.ok(
 | 
						|
    "fun_param_type_versioned" in root.mixed,
 | 
						|
    "fun_param_type_versioned exists"
 | 
						|
  );
 | 
						|
  Assert.ok(
 | 
						|
    !!root.mixed.fun_param_type_versioned,
 | 
						|
    "fun_param_type_versioned exists"
 | 
						|
  );
 | 
						|
  Assert.ok(!("fun_mv2" in root.mixed), "fun_mv2 does not exist");
 | 
						|
  Assert.ok(!root.mixed.fun_mv2, "fun_mv2 does not exist");
 | 
						|
  Assert.ok("fun_mv3" in root.mixed, "fun_mv3 exists");
 | 
						|
  Assert.ok(!!root.mixed.fun_mv3, "fun_mv3 exists");
 | 
						|
 | 
						|
  // Event tests
 | 
						|
  Assert.ok("onEvent_any" in root.mixed, "onEvent_any exists");
 | 
						|
  Assert.ok(!!root.mixed.onEvent_any, "onEvent_any exists");
 | 
						|
  Assert.ok(!("onEvent_mv2" in root.mixed), "onEvent_mv2 not enumerable");
 | 
						|
  Assert.ok(!root.mixed.onEvent_mv2, "onEvent_mv2 does not exist");
 | 
						|
  Assert.ok("onEvent_mv3" in root.mixed, "onEvent_mv3 exists");
 | 
						|
  Assert.ok(!!root.mixed.onEvent_mv3, "onEvent_mv3 exists");
 | 
						|
 | 
						|
  // Function call tests
 | 
						|
  root.mixed.fun_param_type_versioned([true]);
 | 
						|
  wrapper.verify("call", "mixed", "fun_param_type_versioned", [[true]]);
 | 
						|
  Assert.throws(
 | 
						|
    () => root.mixed.fun_param_type_versioned(["hello"]),
 | 
						|
    /Expected boolean instead of "hello"/,
 | 
						|
    "should throw for invalid type"
 | 
						|
  );
 | 
						|
 | 
						|
  let propObj = { prop_any: "prop_any", prop_mv3: "prop_mv3" };
 | 
						|
  root.mixed.fun_param_change(propObj);
 | 
						|
  wrapper.verify("call", "mixed", "fun_param_change", [propObj]);
 | 
						|
  Assert.throws(
 | 
						|
    () => root.mixed.fun_param_change({ prop_mv2: "prop_mv2", ...propObj }),
 | 
						|
    /Unexpected property "prop_mv2"/,
 | 
						|
    "should throw for versioned type"
 | 
						|
  );
 | 
						|
  wrapper.checkErrors([
 | 
						|
    `Property "prop_mv2" is unsupported in Manifest Version 3`,
 | 
						|
  ]);
 | 
						|
 | 
						|
  root.mixed.PROP_mv3.sub_foo();
 | 
						|
  wrapper.verify("call", "mixed.PROP_mv3", "sub_foo", []);
 | 
						|
  Assert.throws(
 | 
						|
    () => root.mixed.PROP_mv3.sub_no_match(),
 | 
						|
    /TypeError: root.mixed.PROP_mv3.sub_no_match is not a function/,
 | 
						|
    "sub_no_match should throw"
 | 
						|
  );
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_normalize_V3() {
 | 
						|
  let wrapper = getContextWrapper(3);
 | 
						|
 | 
						|
  // Test normalize additions to the manifest structure
 | 
						|
  normalizeTest(
 | 
						|
    {
 | 
						|
      versioned_extend: "test",
 | 
						|
    },
 | 
						|
    normalized => {
 | 
						|
      Assert.equal(
 | 
						|
        normalized.error,
 | 
						|
        `Unexpected property "versioned_extend"`,
 | 
						|
        "expected manifest error"
 | 
						|
      );
 | 
						|
      wrapper.checkErrors([
 | 
						|
        `Property "versioned_extend" is unsupported in Manifest Version 3`,
 | 
						|
      ]);
 | 
						|
    },
 | 
						|
    wrapper
 | 
						|
  );
 | 
						|
 | 
						|
  // Test normalizing baseType
 | 
						|
  normalizeTest(
 | 
						|
    {
 | 
						|
      permissions: ["base"],
 | 
						|
    },
 | 
						|
    normalized => {
 | 
						|
      Assert.equal(
 | 
						|
        normalized.value.permissions[0],
 | 
						|
        "base",
 | 
						|
        "resources normalized"
 | 
						|
      );
 | 
						|
    },
 | 
						|
    wrapper
 | 
						|
  );
 | 
						|
 | 
						|
  normalizeTest(
 | 
						|
    {
 | 
						|
      permissions: ["extended"],
 | 
						|
    },
 | 
						|
    normalized => {
 | 
						|
      Assert.equal(
 | 
						|
        normalized.value.permissions[0],
 | 
						|
        "extended",
 | 
						|
        "resources normalized"
 | 
						|
      );
 | 
						|
    },
 | 
						|
    wrapper
 | 
						|
  );
 | 
						|
 | 
						|
  // Test normalizing a value
 | 
						|
  normalizeTest(
 | 
						|
    {
 | 
						|
      multiple_choice: ["foo.html"],
 | 
						|
    },
 | 
						|
    normalized => {
 | 
						|
      Assert.ok(
 | 
						|
        normalized.error.startsWith("Error processing multiple_choice"),
 | 
						|
        "manifest error"
 | 
						|
      );
 | 
						|
    },
 | 
						|
    wrapper
 | 
						|
  );
 | 
						|
 | 
						|
  normalizeTest(
 | 
						|
    {
 | 
						|
      multiple_choice: [true],
 | 
						|
    },
 | 
						|
    normalized => {
 | 
						|
      Assert.equal(
 | 
						|
        normalized.value.multiple_choice[0],
 | 
						|
        true,
 | 
						|
        "resources normalized"
 | 
						|
      );
 | 
						|
    },
 | 
						|
    wrapper
 | 
						|
  );
 | 
						|
 | 
						|
  normalizeTest(
 | 
						|
    {
 | 
						|
      multiple_choice: [
 | 
						|
        {
 | 
						|
          value: true,
 | 
						|
        },
 | 
						|
      ],
 | 
						|
    },
 | 
						|
    normalized => {
 | 
						|
      Assert.ok(
 | 
						|
        normalized.value.multiple_choice[0].value,
 | 
						|
        "resources normalized"
 | 
						|
      );
 | 
						|
    },
 | 
						|
    wrapper
 | 
						|
  );
 | 
						|
 | 
						|
  wrapper.tallied = null;
 | 
						|
 | 
						|
  normalizeTest(
 | 
						|
    {},
 | 
						|
    normalized => {
 | 
						|
      ok(!normalized.error, "manifest normalized");
 | 
						|
    },
 | 
						|
    wrapper
 | 
						|
  );
 | 
						|
 | 
						|
  // Tests that object definitions including additionalProperties can
 | 
						|
  // successfully accept objects from another manifest version, while ignoring
 | 
						|
  // the actual value from the non-matching manifest value.
 | 
						|
  normalizeTest(
 | 
						|
    {
 | 
						|
      accepting_unrecognized_props: {
 | 
						|
        mv2_only_prop: "mv2 here",
 | 
						|
        mv3_only_prop: "mv3 here",
 | 
						|
      },
 | 
						|
    },
 | 
						|
    normalized => {
 | 
						|
      equal(normalized.error, undefined, "no normalization error");
 | 
						|
      Assert.deepEqual(
 | 
						|
        normalized.value.accepting_unrecognized_props,
 | 
						|
        {
 | 
						|
          mv3_only_prop: "mv3 here",
 | 
						|
          mv3_only_prop_with_default: "only in MV3",
 | 
						|
        },
 | 
						|
        "Normalized object for MV3, without MV2-specific props"
 | 
						|
      );
 | 
						|
      wrapper.checkErrors([
 | 
						|
        `Property "mv2_only_prop" is unsupported in Manifest Version 3`,
 | 
						|
      ]);
 | 
						|
    },
 | 
						|
    wrapper
 | 
						|
  );
 | 
						|
});
 |