Commit 66725a53 authored by Dmitry Gozman's avatar Dmitry Gozman Committed by Commit Bot

[inspector] Prepend isolateId to remoteObjectId

This changes remoteObjectId format from
"{injectedScriptId:123,id:456}" to "<isolateId>.<contextId>.<id>".

Prepending isolateId fixes the problem that
remote object ids clash between processes. This is especially
troubling during cross-process navigation in Chromium, see bug.

We also stop producing and parsing unnecessary json for object ids.

Drive-by: fixed some tests dumping object ids. Most tests avoid
dumping unstable values like ids, but there were few that still did.

BUG=chromium:1137143

Change-Id: Ia019757fb95704ccb718d3ea6cc54bde1a133382
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2461731
Commit-Queue: Dmitry Gozman <dgozman@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70592}
parent 3768105b
...@@ -518,19 +518,9 @@ Response InjectedScript::getInternalAndPrivateProperties( ...@@ -518,19 +518,9 @@ Response InjectedScript::getInternalAndPrivateProperties(
} }
void InjectedScript::releaseObject(const String16& objectId) { void InjectedScript::releaseObject(const String16& objectId) {
std::vector<uint8_t> cbor; std::unique_ptr<RemoteObjectId> remoteId;
v8_crdtp::json::ConvertJSONToCBOR( Response response = RemoteObjectId::parse(objectId, &remoteId);
v8_crdtp::span<uint16_t>(objectId.characters16(), objectId.length()), if (response.IsSuccess()) unbindObject(remoteId->id());
&cbor);
std::unique_ptr<protocol::Value> parsedObjectId =
protocol::Value::parseBinary(cbor.data(), cbor.size());
if (!parsedObjectId) return;
protocol::DictionaryValue* object =
protocol::DictionaryValue::cast(parsedObjectId.get());
if (!object) return;
int boundId = 0;
if (!object->getInteger("id", &boundId)) return;
unbindObject(boundId);
} }
Response InjectedScript::wrapObject( Response InjectedScript::wrapObject(
...@@ -722,10 +712,12 @@ Response InjectedScript::resolveCallArgument( ...@@ -722,10 +712,12 @@ Response InjectedScript::resolveCallArgument(
Response response = Response response =
RemoteObjectId::parse(callArgument->getObjectId(""), &remoteObjectId); RemoteObjectId::parse(callArgument->getObjectId(""), &remoteObjectId);
if (!response.IsSuccess()) return response; if (!response.IsSuccess()) return response;
if (remoteObjectId->contextId() != m_context->contextId()) if (remoteObjectId->contextId() != m_context->contextId() ||
remoteObjectId->isolateId() != m_context->inspector()->isolateId()) {
return Response::ServerError( return Response::ServerError(
"Argument should belong to the same JavaScript world as target " "Argument should belong to the same JavaScript world as target "
"object"); "object");
}
return findObject(*remoteObjectId, result); return findObject(*remoteObjectId, result);
} }
if (callArgument->hasValue() || callArgument->hasUnserializableValue()) { if (callArgument->hasValue() || callArgument->hasUnserializableValue()) {
...@@ -1012,10 +1004,8 @@ String16 InjectedScript::bindObject(v8::Local<v8::Value> value, ...@@ -1012,10 +1004,8 @@ String16 InjectedScript::bindObject(v8::Local<v8::Value> value,
m_idToObjectGroupName[id] = groupName; m_idToObjectGroupName[id] = groupName;
m_nameToObjectGroup[groupName].push_back(id); m_nameToObjectGroup[groupName].push_back(id);
} }
// TODO(dgozman): get rid of "injectedScript" notion. return RemoteObjectId::serialize(m_context->inspector()->isolateId(),
return String16::concat( m_context->contextId(), id);
"{\"injectedScriptId\":", String16::fromInteger(m_context->contextId()),
",\"id\":", String16::fromInteger(id), "}");
} }
// static // static
......
...@@ -10,63 +10,68 @@ ...@@ -10,63 +10,68 @@
namespace v8_inspector { namespace v8_inspector {
RemoteObjectIdBase::RemoteObjectIdBase() : m_injectedScriptId(0) {} namespace {
std::unique_ptr<protocol::DictionaryValue> String16 serializeId(uint64_t isolateId, int injectedScriptId, int id) {
RemoteObjectIdBase::parseInjectedScriptId(const String16& objectId) { return String16::concat(
std::vector<uint8_t> cbor; String16::fromInteger64(static_cast<int64_t>(isolateId)), ".",
v8_crdtp::json::ConvertJSONToCBOR( String16::fromInteger(injectedScriptId), ".", String16::fromInteger(id));
v8_crdtp::span<uint16_t>(objectId.characters16(), objectId.length()),
&cbor);
std::unique_ptr<protocol::Value> parsedValue =
protocol::Value::parseBinary(cbor.data(), cbor.size());
if (!parsedValue || parsedValue->type() != protocol::Value::TypeObject)
return nullptr;
std::unique_ptr<protocol::DictionaryValue> parsedObjectId(
protocol::DictionaryValue::cast(parsedValue.release()));
bool success =
parsedObjectId->getInteger("injectedScriptId", &m_injectedScriptId);
if (success) return parsedObjectId;
return nullptr;
} }
RemoteObjectId::RemoteObjectId() : RemoteObjectIdBase(), m_id(0) {} } // namespace
RemoteObjectIdBase::RemoteObjectIdBase()
: m_isolateId(0), m_injectedScriptId(0), m_id(0) {}
bool RemoteObjectIdBase::parseId(const String16& objectId) {
const UChar dot = '.';
size_t firstDotPos = objectId.find(dot);
if (firstDotPos == String16::kNotFound) return false;
bool ok = false;
int64_t isolateId = objectId.substring(0, firstDotPos).toInteger64(&ok);
if (!ok) return false;
firstDotPos++;
size_t secondDotPos = objectId.find(dot, firstDotPos);
if (secondDotPos == String16::kNotFound) return false;
int injectedScriptId =
objectId.substring(firstDotPos, secondDotPos - firstDotPos)
.toInteger(&ok);
if (!ok) return false;
secondDotPos++;
int id = objectId.substring(secondDotPos).toInteger(&ok);
if (!ok) return false;
m_isolateId = static_cast<uint64_t>(isolateId);
m_injectedScriptId = injectedScriptId;
m_id = id;
return true;
}
Response RemoteObjectId::parse(const String16& objectId, Response RemoteObjectId::parse(const String16& objectId,
std::unique_ptr<RemoteObjectId>* result) { std::unique_ptr<RemoteObjectId>* result) {
std::unique_ptr<RemoteObjectId> remoteObjectId(new RemoteObjectId()); std::unique_ptr<RemoteObjectId> remoteObjectId(new RemoteObjectId());
std::unique_ptr<protocol::DictionaryValue> parsedObjectId = if (!remoteObjectId->parseId(objectId))
remoteObjectId->parseInjectedScriptId(objectId); return Response::ServerError("Invalid remote object id");
if (!parsedObjectId) return Response::ServerError("Invalid remote object id");
bool success = parsedObjectId->getInteger("id", &remoteObjectId->m_id);
if (!success) return Response::ServerError("Invalid remote object id");
*result = std::move(remoteObjectId); *result = std::move(remoteObjectId);
return Response::Success(); return Response::Success();
} }
RemoteCallFrameId::RemoteCallFrameId() String16 RemoteObjectId::serialize(uint64_t isolateId, int injectedScriptId,
: RemoteObjectIdBase(), m_frameOrdinal(0) {} int id) {
return serializeId(isolateId, injectedScriptId, id);
}
Response RemoteCallFrameId::parse(const String16& objectId, Response RemoteCallFrameId::parse(const String16& objectId,
std::unique_ptr<RemoteCallFrameId>* result) { std::unique_ptr<RemoteCallFrameId>* result) {
std::unique_ptr<RemoteCallFrameId> remoteCallFrameId(new RemoteCallFrameId()); std::unique_ptr<RemoteCallFrameId> remoteCallFrameId(new RemoteCallFrameId());
std::unique_ptr<protocol::DictionaryValue> parsedObjectId = if (!remoteCallFrameId->parseId(objectId))
remoteCallFrameId->parseInjectedScriptId(objectId); return Response::ServerError("Invalid call frame id");
if (!parsedObjectId) return Response::ServerError("Invalid call frame id");
bool success =
parsedObjectId->getInteger("ordinal", &remoteCallFrameId->m_frameOrdinal);
if (!success) return Response::ServerError("Invalid call frame id");
*result = std::move(remoteCallFrameId); *result = std::move(remoteCallFrameId);
return Response::Success(); return Response::Success();
} }
String16 RemoteCallFrameId::serialize(int injectedScriptId, int frameOrdinal) { String16 RemoteCallFrameId::serialize(uint64_t isolateId, int injectedScriptId,
return "{\"ordinal\":" + String16::fromInteger(frameOrdinal) + int frameOrdinal) {
",\"injectedScriptId\":" + String16::fromInteger(injectedScriptId) + return serializeId(isolateId, injectedScriptId, frameOrdinal);
"}";
} }
} // namespace v8_inspector } // namespace v8_inspector
...@@ -15,16 +15,18 @@ using protocol::Response; ...@@ -15,16 +15,18 @@ using protocol::Response;
class RemoteObjectIdBase { class RemoteObjectIdBase {
public: public:
uint64_t isolateId() const { return m_isolateId; }
int contextId() const { return m_injectedScriptId; } int contextId() const { return m_injectedScriptId; }
protected: protected:
RemoteObjectIdBase(); RemoteObjectIdBase();
~RemoteObjectIdBase() = default; ~RemoteObjectIdBase() = default;
std::unique_ptr<protocol::DictionaryValue> parseInjectedScriptId( bool parseId(const String16&);
const String16&);
uint64_t m_isolateId;
int m_injectedScriptId; int m_injectedScriptId;
int m_id;
}; };
class RemoteObjectId final : public RemoteObjectIdBase { class RemoteObjectId final : public RemoteObjectIdBase {
...@@ -33,10 +35,7 @@ class RemoteObjectId final : public RemoteObjectIdBase { ...@@ -33,10 +35,7 @@ class RemoteObjectId final : public RemoteObjectIdBase {
~RemoteObjectId() = default; ~RemoteObjectId() = default;
int id() const { return m_id; } int id() const { return m_id; }
private: static String16 serialize(uint64_t isolateId, int injectedScriptId, int id);
RemoteObjectId();
int m_id;
}; };
class RemoteCallFrameId final : public RemoteObjectIdBase { class RemoteCallFrameId final : public RemoteObjectIdBase {
...@@ -44,14 +43,10 @@ class RemoteCallFrameId final : public RemoteObjectIdBase { ...@@ -44,14 +43,10 @@ class RemoteCallFrameId final : public RemoteObjectIdBase {
static Response parse(const String16&, std::unique_ptr<RemoteCallFrameId>*); static Response parse(const String16&, std::unique_ptr<RemoteCallFrameId>*);
~RemoteCallFrameId() = default; ~RemoteCallFrameId() = default;
int frameOrdinal() const { return m_frameOrdinal; } int frameOrdinal() const { return m_id; }
static String16 serialize(int injectedScriptId, int frameOrdinal);
private:
RemoteCallFrameId();
int m_frameOrdinal; static String16 serialize(uint64_t isolateId, int injectedScriptId,
int frameOrdinal);
}; };
} // namespace v8_inspector } // namespace v8_inspector
......
...@@ -39,10 +39,12 @@ class String16 { ...@@ -39,10 +39,12 @@ class String16 {
static String16 fromInteger(int); static String16 fromInteger(int);
static String16 fromInteger(size_t); static String16 fromInteger(size_t);
static String16 fromInteger64(int64_t); static String16 fromInteger64(int64_t);
static String16 fromUInt64(uint64_t);
static String16 fromDouble(double); static String16 fromDouble(double);
static String16 fromDouble(double, int precision); static String16 fromDouble(double, int precision);
int64_t toInteger64(bool* ok = nullptr) const; int64_t toInteger64(bool* ok = nullptr) const;
uint64_t toUInt64(bool* ok = nullptr) const;
int toInteger(bool* ok = nullptr) const; int toInteger(bool* ok = nullptr) const;
String16 stripWhiteSpace() const; String16 stripWhiteSpace() const;
const UChar* characters16() const { return m_impl.c_str(); } const UChar* characters16() const { return m_impl.c_str(); }
......
...@@ -1446,8 +1446,8 @@ Response V8DebuggerAgentImpl::currentCallFrames( ...@@ -1446,8 +1446,8 @@ Response V8DebuggerAgentImpl::currentCallFrames(
int contextId = iterator->GetContextId(); int contextId = iterator->GetContextId();
InjectedScript* injectedScript = nullptr; InjectedScript* injectedScript = nullptr;
if (contextId) m_session->findInjectedScript(contextId, injectedScript); if (contextId) m_session->findInjectedScript(contextId, injectedScript);
String16 callFrameId = String16 callFrameId = RemoteCallFrameId::serialize(
RemoteCallFrameId::serialize(contextId, frameOrdinal); m_inspector->isolateId(), contextId, frameOrdinal);
v8::debug::Location loc = iterator->GetSourceLocation(); v8::debug::Location loc = iterator->GetSourceLocation();
......
...@@ -239,6 +239,8 @@ Response V8InspectorSessionImpl::findInjectedScript( ...@@ -239,6 +239,8 @@ Response V8InspectorSessionImpl::findInjectedScript(
Response V8InspectorSessionImpl::findInjectedScript( Response V8InspectorSessionImpl::findInjectedScript(
RemoteObjectIdBase* objectId, InjectedScript*& injectedScript) { RemoteObjectIdBase* objectId, InjectedScript*& injectedScript) {
if (objectId->isolateId() != m_inspector->isolateId())
return Response::ServerError("Cannot find context with specified id");
return findInjectedScript(objectId->contextId(), injectedScript); return findInjectedScript(objectId->contextId(), injectedScript);
} }
......
...@@ -593,7 +593,7 @@ class DebugWrapper { ...@@ -593,7 +593,7 @@ class DebugWrapper {
const column = frame.location.columnNumber; const column = frame.location.columnNumber;
const loc = %ScriptLocationFromLine2(scriptid, line, column, 0); const loc = %ScriptLocationFromLine2(scriptid, line, column, 0);
const func = { name : () => frame.functionName }; const func = { name : () => frame.functionName };
const index = JSON.parse(frame.callFrameId).ordinal; const index = +frame.callFrameId.split(".")[2];
function allScopes() { function allScopes() {
const scopes = []; const scopes = [];
......
...@@ -8,7 +8,7 @@ privateProperties on class A ...@@ -8,7 +8,7 @@ privateProperties on class A
value : { value : {
className : Function className : Function
description : #method() { debugger; } description : #method() { debugger; }
objectId : {"injectedScriptId":1,"id":39} objectId : <objectId>
type : function type : function
} }
} }
......
...@@ -43,7 +43,7 @@ InspectorTest.runAsyncTestSuite([ ...@@ -43,7 +43,7 @@ InspectorTest.runAsyncTestSuite([
let { result } = await Protocol.Runtime.getProperties({ let { result } = await Protocol.Runtime.getProperties({
objectId: frame.this.objectId objectId: frame.this.objectId
}); });
InspectorTest.logObject(result.privateProperties); InspectorTest.logMessage(result.privateProperties);
Protocol.Debugger.resume(); Protocol.Debugger.resume();
({ params: { callFrames } } = await Protocol.Debugger.oncePaused()); // B.test(); ({ params: { callFrames } } = await Protocol.Debugger.oncePaused()); // B.test();
......
...@@ -8,7 +8,7 @@ Get privateProperties of A in testStatic() ...@@ -8,7 +8,7 @@ Get privateProperties of A in testStatic()
value : { value : {
className : Function className : Function
description : #staticMethod() { return 1; } description : #staticMethod() { return 1; }
objectId : {"injectedScriptId":1,"id":34} objectId : <objectId>
type : function type : function
} }
} }
...@@ -20,19 +20,19 @@ Access A.#staticMethod() in testStatic() ...@@ -20,19 +20,19 @@ Access A.#staticMethod() in testStatic()
exception : { exception : {
className : ReferenceError className : ReferenceError
description : ReferenceError: A is not defined at eval (eval at testStatic (:1:1), <anonymous>:1:1) at Function.testStatic (<anonymous>:6:29) at run (<anonymous>:9:7) at <anonymous>:1:1 description : ReferenceError: A is not defined at eval (eval at testStatic (:1:1), <anonymous>:1:1) at Function.testStatic (<anonymous>:6:29) at run (<anonymous>:9:7) at <anonymous>:1:1
objectId : {"injectedScriptId":1,"id":36} objectId : <objectId>
subtype : error subtype : error
type : object type : object
} }
exceptionId : 1 exceptionId : <exceptionId>
lineNumber : 0 lineNumber : 0
scriptId : 5 scriptId : <scriptId>
text : Uncaught text : Uncaught
} }
result : { result : {
className : ReferenceError className : ReferenceError
description : ReferenceError: A is not defined at eval (eval at testStatic (:1:1), <anonymous>:1:1) at Function.testStatic (<anonymous>:6:29) at run (<anonymous>:9:7) at <anonymous>:1:1 description : ReferenceError: A is not defined at eval (eval at testStatic (:1:1), <anonymous>:1:1) at Function.testStatic (<anonymous>:6:29) at run (<anonymous>:9:7) at <anonymous>:1:1
objectId : {"injectedScriptId":1,"id":35} objectId : <objectId>
subtype : error subtype : error
type : object type : object
} }
...@@ -44,19 +44,19 @@ Access this.#staticMethod() in testStatic() ...@@ -44,19 +44,19 @@ Access this.#staticMethod() in testStatic()
exception : { exception : {
className : Error className : Error
description : Error: Unused static private method '#staticMethod' cannot be accessed at debug time at eval (eval at testStatic (:1:1), <anonymous>:1:1) at Function.testStatic (<anonymous>:6:29) at run (<anonymous>:9:7) at <anonymous>:1:1 description : Error: Unused static private method '#staticMethod' cannot be accessed at debug time at eval (eval at testStatic (:1:1), <anonymous>:1:1) at Function.testStatic (<anonymous>:6:29) at run (<anonymous>:9:7) at <anonymous>:1:1
objectId : {"injectedScriptId":1,"id":38} objectId : <objectId>
subtype : error subtype : error
type : object type : object
} }
exceptionId : 2 exceptionId : <exceptionId>
lineNumber : 0 lineNumber : 0
scriptId : 6 scriptId : <scriptId>
text : Uncaught text : Uncaught
} }
result : { result : {
className : Error className : Error
description : Error: Unused static private method '#staticMethod' cannot be accessed at debug time at eval (eval at testStatic (:1:1), <anonymous>:1:1) at Function.testStatic (<anonymous>:6:29) at run (<anonymous>:9:7) at <anonymous>:1:1 description : Error: Unused static private method '#staticMethod' cannot be accessed at debug time at eval (eval at testStatic (:1:1), <anonymous>:1:1) at Function.testStatic (<anonymous>:6:29) at run (<anonymous>:9:7) at <anonymous>:1:1
objectId : {"injectedScriptId":1,"id":37} objectId : <objectId>
subtype : error subtype : error
type : object type : object
} }
...@@ -68,7 +68,7 @@ get privateProperties of a in testInstance() ...@@ -68,7 +68,7 @@ get privateProperties of a in testInstance()
value : { value : {
className : Function className : Function
description : #instanceMethod() { return 2; } description : #instanceMethod() { return 2; }
objectId : {"injectedScriptId":1,"id":61} objectId : <objectId>
type : function type : function
} }
} }
......
...@@ -38,7 +38,7 @@ InspectorTest.runAsyncTestSuite([ ...@@ -38,7 +38,7 @@ InspectorTest.runAsyncTestSuite([
let { result } = await Protocol.Runtime.getProperties({ let { result } = await Protocol.Runtime.getProperties({
objectId: frame.this.objectId objectId: frame.this.objectId
}); });
InspectorTest.logObject(result.privateProperties); InspectorTest.logMessage(result.privateProperties);
// Variables not referenced in the source code are currently // Variables not referenced in the source code are currently
// considered "optimized away". // considered "optimized away".
...@@ -47,14 +47,14 @@ InspectorTest.runAsyncTestSuite([ ...@@ -47,14 +47,14 @@ InspectorTest.runAsyncTestSuite([
expression: 'A.#staticMethod();', expression: 'A.#staticMethod();',
callFrameId: callFrames[0].callFrameId callFrameId: callFrames[0].callFrameId
})); }));
InspectorTest.logObject(result); InspectorTest.logMessage(result);
InspectorTest.log('Access this.#staticMethod() in testStatic()'); InspectorTest.log('Access this.#staticMethod() in testStatic()');
({ result } = await Protocol.Debugger.evaluateOnCallFrame({ ({ result } = await Protocol.Debugger.evaluateOnCallFrame({
expression: 'this.#staticMethod();', expression: 'this.#staticMethod();',
callFrameId: callFrames[0].callFrameId callFrameId: callFrames[0].callFrameId
})); }));
InspectorTest.logObject(result); InspectorTest.logMessage(result);
Protocol.Debugger.resume(); Protocol.Debugger.resume();
({ params: { callFrames } } = await Protocol.Debugger.oncePaused()); // a.testInstatnce(); ({ params: { callFrames } } = await Protocol.Debugger.oncePaused()); // a.testInstatnce();
...@@ -64,14 +64,14 @@ InspectorTest.runAsyncTestSuite([ ...@@ -64,14 +64,14 @@ InspectorTest.runAsyncTestSuite([
({ result } = await Protocol.Runtime.getProperties({ ({ result } = await Protocol.Runtime.getProperties({
objectId: frame.this.objectId objectId: frame.this.objectId
})); }));
InspectorTest.logObject(result.privateProperties); InspectorTest.logMessage(result.privateProperties);
InspectorTest.log('Evaluating this.#instanceMethod() in testInstance()'); InspectorTest.log('Evaluating this.#instanceMethod() in testInstance()');
({ result } = await Protocol.Debugger.evaluateOnCallFrame({ ({ result } = await Protocol.Debugger.evaluateOnCallFrame({
expression: 'this.#instanceMethod();', expression: 'this.#instanceMethod();',
callFrameId: callFrames[0].callFrameId callFrameId: callFrames[0].callFrameId
})); }));
InspectorTest.logObject(result); InspectorTest.logMessage(result);
Protocol.Debugger.resume(); Protocol.Debugger.resume();
Protocol.Debugger.disable(); Protocol.Debugger.disable();
......
...@@ -2,7 +2,13 @@ RemoteObject.CustomPreview ...@@ -2,7 +2,13 @@ RemoteObject.CustomPreview
Dump custom previews.. Dump custom previews..
{ {
bodyGetterId : <bodyGetterId> bodyGetterId : <bodyGetterId>
header : ["span",{},"Header formatted by 1 ","a"] header : [
[0] : span
[1] : {
}
[2] : Header formatted by 1
[3] : a
]
} }
{ {
id : <messageId> id : <messageId>
...@@ -30,7 +36,13 @@ Dump custom previews.. ...@@ -30,7 +36,13 @@ Dump custom previews..
} }
{ {
bodyGetterId : <bodyGetterId> bodyGetterId : <bodyGetterId>
header : ["span",{},"Header formatted by 2 ","b"] header : [
[0] : span
[1] : {
}
[2] : Header formatted by 2
[3] : b
]
} }
{ {
id : <messageId> id : <messageId>
...@@ -49,7 +61,13 @@ Dump custom previews.. ...@@ -49,7 +61,13 @@ Dump custom previews..
} }
{ {
bodyGetterId : <bodyGetterId> bodyGetterId : <bodyGetterId>
header : ["span",{},"Header formatted by 1 ","c"] header : [
[0] : span
[1] : {
}
[2] : Header formatted by 1
[3] : c
]
} }
{ {
id : <messageId> id : <messageId>
...@@ -76,12 +94,36 @@ Dump custom previews.. ...@@ -76,12 +94,36 @@ Dump custom previews..
} }
} }
{ {
header : ["span",{},"Formatter with config ",["object",{"type":"object","className":"Object","description":"Object","objectId":"{\"injectedScriptId\":1,\"id\":10}","customPreview":{"header":"[\"span\",{},\"Header \",\"info: \",\"additional info\"]","bodyGetterId":"{\"injectedScriptId\":1,\"id\":11}"}}]] header : [
[0] : span
[1] : {
}
[2] : Formatter with config
[3] : [
[0] : object
[1] : {
className : Object
customPreview : {
bodyGetterId : <bodyGetterId>
header : ["span",{},"Header ","info: ","additional info"]
}
description : Object
objectId : <objectId>
type : object
}
]
]
} }
Change formatters order and dump again.. Change formatters order and dump again..
{ {
bodyGetterId : <bodyGetterId> bodyGetterId : <bodyGetterId>
header : ["span",{},"Header formatted by 1 ","a"] header : [
[0] : span
[1] : {
}
[2] : Header formatted by 1
[3] : a
]
} }
{ {
id : <messageId> id : <messageId>
...@@ -109,7 +151,13 @@ Change formatters order and dump again.. ...@@ -109,7 +151,13 @@ Change formatters order and dump again..
} }
{ {
bodyGetterId : <bodyGetterId> bodyGetterId : <bodyGetterId>
header : ["span",{},"Header formatted by 2 ","b"] header : [
[0] : span
[1] : {
}
[2] : Header formatted by 2
[3] : b
]
} }
{ {
id : <messageId> id : <messageId>
...@@ -128,7 +176,13 @@ Change formatters order and dump again.. ...@@ -128,7 +176,13 @@ Change formatters order and dump again..
} }
{ {
bodyGetterId : <bodyGetterId> bodyGetterId : <bodyGetterId>
header : ["span",{},"Header formatted by 2 ","c"] header : [
[0] : span
[1] : {
}
[2] : Header formatted by 2
[3] : c
]
} }
{ {
id : <messageId> id : <messageId>
...@@ -146,12 +200,36 @@ Change formatters order and dump again.. ...@@ -146,12 +200,36 @@ Change formatters order and dump again..
} }
} }
{ {
header : ["span",{},"Formatter with config ",["object",{"type":"object","className":"Object","description":"Object","objectId":"{\"injectedScriptId\":1,\"id\":21}","customPreview":{"header":"[\"span\",{},\"Header \",\"info: \",\"additional info\"]","bodyGetterId":"{\"injectedScriptId\":1,\"id\":22}"}}]] header : [
[0] : span
[1] : {
}
[2] : Formatter with config
[3] : [
[0] : object
[1] : {
className : Object
customPreview : {
bodyGetterId : <bodyGetterId>
header : ["span",{},"Header ","info: ","additional info"]
}
description : Object
objectId : <objectId>
type : object
}
]
]
} }
Test Runtime.getProperties Test Runtime.getProperties
{ {
bodyGetterId : <bodyGetterId> bodyGetterId : <bodyGetterId>
header : ["span",{},"Header formatted by 1 ","a"] header : [
[0] : span
[1] : {
}
[2] : Header formatted by 1
[3] : a
]
} }
{ {
id : <messageId> id : <messageId>
...@@ -162,7 +240,7 @@ Test Runtime.getProperties ...@@ -162,7 +240,7 @@ Test Runtime.getProperties
[0] : span [0] : span
[1] : { [1] : {
} }
[2] : Body formatted by 1 [2] : Body formatted by 1
[3] : a [3] : a
[4] : [ [4] : [
[0] : object [0] : object
......
...@@ -120,6 +120,8 @@ function dumpCustomPreviewForEvaluate(result) { ...@@ -120,6 +120,8 @@ function dumpCustomPreviewForEvaluate(result) {
async function dumpCustomPreview(result) { async function dumpCustomPreview(result) {
const { objectId, customPreview } = result; const { objectId, customPreview } = result;
if (customPreview.header)
customPreview.header = JSON.parse(customPreview.header);
InspectorTest.logMessage(customPreview); InspectorTest.logMessage(customPreview);
if (customPreview.bodyGetterId) { if (customPreview.bodyGetterId) {
const body = await Protocol.Runtime.callFunctionOn({ const body = await Protocol.Runtime.callFunctionOn({
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment