/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; // Test the Runtime remote object add_task(async function ({ client }) { const firstContext = await testRuntimeEnable(client); const contextId = firstContext.id; await testGetOwnSimpleProperties(client, contextId); await testGetCustomProperty(client, contextId); await testGetPrototypeProperties(client, contextId); await testGetGetterSetterProperties(client, contextId); }); async function testRuntimeEnable({ Runtime }) { // Enable watching for new execution context await Runtime.enable(); info("Runtime domain has been enabled"); // Calling Runtime.enable will emit executionContextCreated for the existing contexts const { context } = await Runtime.executionContextCreated(); ok(!!context.id, "The execution context has an id"); ok(context.auxData.isDefault, "The execution context is the default one"); ok(!!context.auxData.frameId, "The execution context has a frame id set"); return context; } async function testGetOwnSimpleProperties({ Runtime }, contextId) { const { result } = await Runtime.evaluate({ contextId, expression: "({ bool: true, fun() {}, int: 1, object: {}, string: 'foo' })", }); is(result.subtype, undefined, "JS Object has no subtype"); is(result.type, "object", "The type is correct"); ok(!!result.objectId, "Got an object id"); const { result: result2 } = await Runtime.getProperties({ objectId: result.objectId, ownProperties: true, }); is( result2.length, 5, "ownProperties=true allows to iterate only over direct object properties (i.e. ignore prototype)" ); result2.sort((a, b) => a.name > b.name); is(result2[0].name, "bool"); is(result2[0].configurable, true); is(result2[0].enumerable, true); is(result2[0].writable, true); is(result2[0].value.type, "boolean"); is(result2[0].value.value, true); is(result2[0].isOwn, true); is(result2[1].name, "fun"); is(result2[1].configurable, true); is(result2[1].enumerable, true); is(result2[1].writable, true); is(result2[1].value.type, "function"); ok(!!result2[1].value.objectId); is(result2[1].isOwn, true); is(result2[2].name, "int"); is(result2[2].configurable, true); is(result2[2].enumerable, true); is(result2[2].writable, true); is(result2[2].value.type, "number"); is(result2[2].value.value, 1); is(result2[2].isOwn, true); is(result2[3].name, "object"); is(result2[3].configurable, true); is(result2[3].enumerable, true); is(result2[3].writable, true); is(result2[3].value.type, "object"); ok(!!result2[3].value.objectId); is(result2[3].isOwn, true); is(result2[4].name, "string"); is(result2[4].configurable, true); is(result2[4].enumerable, true); is(result2[4].writable, true); is(result2[4].value.type, "string"); is(result2[4].value.value, "foo"); is(result2[4].isOwn, true); } async function testGetPrototypeProperties({ Runtime }, contextId) { const { result } = await Runtime.evaluate({ contextId, expression: "({ foo: 42 })", }); is(result.subtype, undefined, "JS Object has no subtype"); is(result.type, "object", "The type is correct"); ok(!!result.objectId, "Got an object id"); const { result: result2 } = await Runtime.getProperties({ objectId: result.objectId, ownProperties: false, }); Assert.greater( result2.length, 1, "We have more properties than just the object one" ); const foo = result2.find(p => p.name == "foo"); ok(foo, "The object property is described"); ok(foo.isOwn, "and is reported as 'own' property"); const toString = result2.find(p => p.name == "toString"); ok( toString, "Function from Object's prototype are also described like toString" ); ok(!toString.isOwn, "but are reported as not being an 'own' property"); } async function testGetGetterSetterProperties({ Runtime }, contextId) { const { result } = await Runtime.evaluate({ contextId, expression: "({ get prop() { return this.x; }, set prop(v) { this.x = v; } })", }); is(result.subtype, undefined, "JS Object has no subtype"); is(result.type, "object", "The type is correct"); ok(!!result.objectId, "Got an object id"); const { result: result2 } = await Runtime.getProperties({ objectId: result.objectId, ownProperties: true, }); is(result2.length, 1); is(result2[0].name, "prop"); is(result2[0].configurable, true); is(result2[0].enumerable, true); is( result2[0].writable, undefined, "writable is only set for data properties" ); is(result2[0].get.type, "function"); ok(!!result2[0].get.objectId); is(result2[0].set.type, "function"); ok(!!result2[0].set.objectId); is(result2[0].isOwn, true); const { result: result3 } = await Runtime.callFunctionOn({ executionContextId: contextId, functionDeclaration: "(set, get) => { set(42); return get(); }", arguments: [ { objectId: result2[0].set.objectId }, { objectId: result2[0].get.objectId }, ], }); is(result3.type, "number", "The type is correct"); is(result3.subtype, undefined, "The subtype is undefined for numbers"); is(result3.value, 42, "The getter returned the value set by the setter"); } async function testGetCustomProperty({ Runtime }, contextId) { const { result } = await Runtime.evaluate({ contextId, expression: `const obj = {}; Object.defineProperty(obj, "prop", { value: 42 }); obj`, }); is(result.subtype, undefined, "JS Object has no subtype"); is(result.type, "object", "The type is correct"); ok(!!result.objectId, "Got an object id"); const { result: result2 } = await Runtime.getProperties({ objectId: result.objectId, ownProperties: true, }); is(result2.length, 1, "We only get the one object's property"); is(result2[0].name, "prop"); is(result2[0].configurable, false); is(result2[0].enumerable, false); is(result2[0].writable, false); is(result2[0].value.type, "number"); is(result2[0].value.value, 42); is(result2[0].isOwn, true); }