From ddc9bd1ff351f3259b7d90dcde7babcedbf2c155 Mon Sep 17 00:00:00 2001 From: Moti Zilberman Date: Thu, 18 Apr 2024 08:00:37 -0700 Subject: [PATCH] Refactor ConsoleApiTest to use stored Matchers instead of an intermediate struct Summary: bypass-github-export-checks Changelog: [Internal] Rewrites all `ConsoleApiTest` test cases to use matchers instead of a homegrown solution for buffering `EXPECT_*` calls. Reviewed By: robhogan Differential Revision: D55485495 fbshipit-source-id: 1aa50bbbb5a3b02280ed4a0bee59682716b4fd7e --- .../tests/ConsoleApiTest.cpp | 530 ++++++++++++------ .../tests/FollyDynamicMatchers.h | 9 + 2 files changed, 354 insertions(+), 185 deletions(-) diff --git a/packages/react-native/ReactCommon/jsinspector-modern/tests/ConsoleApiTest.cpp b/packages/react-native/ReactCommon/jsinspector-modern/tests/ConsoleApiTest.cpp index 326dd3a6dd6..87f9c6b52ce 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/tests/ConsoleApiTest.cpp +++ b/packages/react-native/ReactCommon/jsinspector-modern/tests/ConsoleApiTest.cpp @@ -47,11 +47,6 @@ struct Params { class ConsoleApiTest : public JsiIntegrationPortableTest, public WithParamInterface { - struct ExpectedConsoleApiCall { - std::string type; - std::string argsJson; - }; - protected: void SetUp() override { JsiIntegrationPortableTest::SetUp(); @@ -68,13 +63,11 @@ class ConsoleApiTest JsiIntegrationPortableTest::TearDown(); } - void expectConsoleApiCall(std::string type, std::string argsJson) { - ExpectedConsoleApiCall call{ - .type = std::move(type), .argsJson = std::move(argsJson)}; + void expectConsoleApiCall(Matcher paramsMatcher) { if (runtimeEnabled_) { - expectConsoleApiCallImpl(std::move(call)); + expectConsoleApiCallImpl(std::move(paramsMatcher)); } else { - expectedConsoleApiCalls_.emplace_back(call); + expectedConsoleApiCalls_.emplace_back(paramsMatcher); } } @@ -87,11 +80,10 @@ class ConsoleApiTest } private: - void expectConsoleApiCallImpl(ExpectedConsoleApiCall call) { + void expectConsoleApiCallImpl(Matcher paramsMatcher) { this->expectMessageFromPage(JsonParsed(AllOf( AtJsonPtr("/method", "Runtime.consoleAPICalled"), - AtJsonPtr("/params/type", call.type), - AtJsonPtr("/params/args", Eq(folly::parseJson(call.argsJson)))))); + AtJsonPtr("/params", std::move(paramsMatcher))))); } void enableRuntimeDomain() { @@ -143,7 +135,7 @@ class ConsoleApiTest } } - std::vector expectedConsoleApiCalls_; + std::vector> expectedConsoleApiCalls_; bool runtimeEnabled_{false}; }; @@ -171,91 +163,128 @@ class ConsoleApiTestWithPreExistingConsole : public ConsoleApiTest { TEST_P(ConsoleApiTest, testConsoleLog) { InSequence s; - expectConsoleApiCall("log", R"([{ - "type": "string", - "value": "hello" - }, { - "type": "string", - "value": "world" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "log"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "hello" + }, { + "type": "string", + "value": "world" + }])"_json))); eval("console.log('hello', 'world');"); } TEST_P(ConsoleApiTest, testConsoleDebug) { InSequence s; - expectConsoleApiCall("debug", R"([{ - "type": "string", - "value": "hello fusebox" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "debug"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "hello fusebox" + }])"_json))); eval("console.debug('hello fusebox');"); } TEST_P(ConsoleApiTest, testConsoleInfo) { InSequence s; - expectConsoleApiCall("info", R"([{ - "type": "string", - "value": "you should know this" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "info"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "you should know this" + }])"_json))); eval("console.info('you should know this');"); } TEST_P(ConsoleApiTest, testConsoleError) { InSequence s; - expectConsoleApiCall("error", R"([{ - "type": "string", - "value": "uh oh" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "error"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "uh oh" + }])"_json))); eval("console.error('uh oh');"); } TEST_P(ConsoleApiTest, testConsoleWarn) { InSequence s; - expectConsoleApiCall("warning", R"([{ - "type": "string", - "value": "careful" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "warning"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "careful" + }])"_json))); eval("console.warn('careful');"); } TEST_P(ConsoleApiTest, testConsoleDir) { InSequence s; - expectConsoleApiCall("dir", R"([{ - "type": "string", - "value": "something" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "dir"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "something" + }])"_json))); eval("console.dir('something');"); } TEST_P(ConsoleApiTest, testConsoleDirxml) { InSequence s; - expectConsoleApiCall("dirxml", R"([{ - "type": "string", - "value": "pretend this is a DOM element" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "dirxml"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "pretend this is a DOM element" + }])"_json))); eval("console.dirxml('pretend this is a DOM element');"); } TEST_P(ConsoleApiTest, testConsoleTable) { InSequence s; - expectConsoleApiCall("table", R"([{ - "type": "string", - "value": "pretend this is a complex object" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "table"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "pretend this is a complex object" + }])"_json))); eval("console.table('pretend this is a complex object');"); } TEST_P(ConsoleApiTest, testConsoleTrace) { InSequence s; - expectConsoleApiCall("trace", R"([{ - "type": "string", - "value": "trace trace" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "trace"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "trace trace" + }])"_json))); eval("console.trace('trace trace');"); } TEST_P(ConsoleApiTest, testConsoleClear) { InSequence s; - expectConsoleApiCall("clear", "[]"); + expectConsoleApiCall( + AllOf(AtJsonPtr("/type", "clear"), AtJsonPtr("/args", "[]"_json))); eval("console.clear();"); } @@ -264,27 +293,41 @@ TEST_P(ConsoleApiTest, testConsoleClearAfterOtherCall) { if (isRuntimeDomainEnabled()) { // This should only be delivered if console notifications are enabled, not // when they're being cached for later. - expectConsoleApiCall("log", R"([{ - "type": "string", - "value": "hello" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "log"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "hello" + }])"_json))); } - expectConsoleApiCall("clear", "[]"); + expectConsoleApiCall( + AllOf(AtJsonPtr("/type", "clear"), AtJsonPtr("/args", "[]"_json))); eval("console.log('hello');"); eval("console.clear();"); } TEST_P(ConsoleApiTest, testConsoleGroup) { InSequence s; - expectConsoleApiCall("startGroup", R"([{ - "type": "string", - "value": "group title" - }])"); - expectConsoleApiCall("log", R"([{ - "type": "string", - "value": "in group" - }])"); - expectConsoleApiCall("endGroup", "[]"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "startGroup"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "group title" + }])"_json))); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "log"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "in group" + }])"_json))); + expectConsoleApiCall( + AllOf(AtJsonPtr("/type", "endGroup"), AtJsonPtr("/args", "[]"_json))); eval("console.group('group title');"); eval("console.log('in group');"); eval("console.groupEnd();"); @@ -292,15 +335,24 @@ TEST_P(ConsoleApiTest, testConsoleGroup) { TEST_P(ConsoleApiTest, testConsoleGroupCollapsed) { InSequence s; - expectConsoleApiCall("startGroupCollapsed", R"([{ - "type": "string", - "value": "group collapsed title" - }])"); - expectConsoleApiCall("log", R"([{ - "type": "string", - "value": "in group collapsed" - }])"); - expectConsoleApiCall("endGroup", "[]"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "startGroupCollapsed"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "group collapsed title" + }])"_json))); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "log"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "in group collapsed" + }])"_json))); + expectConsoleApiCall( + AllOf(AtJsonPtr("/type", "endGroup"), AtJsonPtr("/args", "[]"_json))); eval("console.groupCollapsed('group collapsed title');"); eval("console.log('in group collapsed');"); eval("console.groupEnd();"); @@ -308,93 +360,149 @@ TEST_P(ConsoleApiTest, testConsoleGroupCollapsed) { TEST_P(ConsoleApiTest, testConsoleAssert) { InSequence s; - expectConsoleApiCall("assert", R"([{ - "type": "string", - "value": "Assertion failed: something is bad" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "assert"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "Assertion failed: something is bad" + }])"_json))); eval("console.assert(true, 'everything is good');"); eval("console.assert(false, 'something is bad');"); - expectConsoleApiCall("assert", R"([{ - "type": "string", - "value": "Assertion failed" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "assert"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "Assertion failed" + }])"_json))); eval("console.assert();"); } TEST_P(ConsoleApiTest, testConsoleCount) { InSequence s; - expectConsoleApiCall("count", R"([{ - "type": "string", - "value": "default: 1" - }])"); - expectConsoleApiCall("count", R"([{ - "type": "string", - "value": "default: 2" - }])"); - expectConsoleApiCall("count", R"([{ - "type": "string", - "value": "default: 3" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "count"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "default: 1" + }])"_json))); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "count"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "default: 2" + }])"_json))); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "count"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "default: 3" + }])"_json))); eval("console.count();"); eval("console.count('default');"); eval("console.count();"); eval("console.countReset();"); - expectConsoleApiCall("count", R"([{ - "type": "string", - "value": "default: 1" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "count"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "default: 1" + }])"_json))); eval("console.count();"); eval("console.countReset('default');"); - expectConsoleApiCall("count", R"([{ - "type": "string", - "value": "default: 1" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "count"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "default: 1" + }])"_json))); eval("console.count();"); } TEST_P(ConsoleApiTest, testConsoleCountLabel) { InSequence s; - expectConsoleApiCall("count", R"([{ - "type": "string", - "value": "foo: 1" - }])"); - expectConsoleApiCall("count", R"([{ - "type": "string", - "value": "foo: 2" - }])"); - expectConsoleApiCall("count", R"([{ - "type": "string", - "value": "foo: 3" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "count"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "foo: 1" + }])"_json))); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "count"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "foo: 2" + }])"_json))); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "count"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "foo: 3" + }])"_json))); eval("console.count('foo');"); eval("console.count('foo');"); eval("console.count('foo');"); eval("console.countReset('foo');"); - expectConsoleApiCall("count", R"([{ - "type": "string", - "value": "foo: 1" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "count"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "foo: 1" + }])"_json))); eval("console.count('foo');"); } TEST_P(ConsoleApiTest, testConsoleCountResetInvalidLabel) { InSequence s; - expectConsoleApiCall("warning", R"([{ - "type": "string", - "value": "Count for 'default' does not exist" - }])"); - expectConsoleApiCall("warning", R"([{ - "type": "string", - "value": "Count for 'default' does not exist" - }])"); - expectConsoleApiCall("warning", R"([{ - "type": "string", - "value": "Count for 'foo' does not exist" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "warning"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "Count for 'default' does not exist" + }])"_json))); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "warning"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "Count for 'default' does not exist" + }])"_json))); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "warning"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "Count for 'foo' does not exist" + }])"_json))); eval("console.countReset();"); eval("console.countReset('default');"); eval("console.countReset('foo');"); @@ -405,50 +513,82 @@ TEST_P(ConsoleApiTest, testConsoleCountResetInvalidLabel) { TEST_P(ConsoleApiTest, testConsoleTimeExistingLabel) { eval("console.time();"); - expectConsoleApiCall("warning", R"([{ - "type": "string", - "value": "Timer 'default' already exists" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "warning"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "Timer 'default' already exists" + }])"_json))); eval("console.time('default');"); eval("console.time('foo');"); - expectConsoleApiCall("warning", R"([{ - "type": "string", - "value": "Timer 'foo' already exists" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "warning"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "Timer 'foo' already exists" + }])"_json))); eval("console.time('foo');"); } TEST_P(ConsoleApiTest, testConsoleTimeInvalidLabel) { InSequence s; - expectConsoleApiCall("warning", R"([{ - "type": "string", - "value": "Timer 'default' does not exist" - }])"); - expectConsoleApiCall("warning", R"([{ - "type": "string", - "value": "Timer 'default' does not exist" - }])"); - expectConsoleApiCall("warning", R"([{ - "type": "string", - "value": "Timer 'foo' does not exist" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "warning"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "Timer 'default' does not exist" + }])"_json))); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "warning"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "Timer 'default' does not exist" + }])"_json))); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "warning"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "Timer 'foo' does not exist" + }])"_json))); eval("console.timeEnd();"); eval("console.timeEnd('default');"); eval("console.timeEnd('foo');"); - expectConsoleApiCall("warning", R"([{ - "type": "string", - "value": "Timer 'default' does not exist" - }])"); - expectConsoleApiCall("warning", R"([{ - "type": "string", - "value": "Timer 'default' does not exist" - }])"); - expectConsoleApiCall("warning", R"([{ - "type": "string", - "value": "Timer 'foo' does not exist" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "warning"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "Timer 'default' does not exist" + }])"_json))); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "warning"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "Timer 'default' does not exist" + }])"_json))); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "warning"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "Timer 'foo' does not exist" + }])"_json))); eval("console.timeLog();"); eval("console.timeLog('default');"); eval("console.timeLog('foo');"); @@ -456,10 +596,14 @@ TEST_P(ConsoleApiTest, testConsoleTimeInvalidLabel) { TEST_P(ConsoleApiTest, testConsoleSilentlyClearedOnReload) { InSequence s; - expectConsoleApiCall("log", R"([{ - "type": "string", - "value": "hello" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "log"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "hello" + }])"_json))); eval("console.log('hello');"); // If there are any expectations we haven't checked yet, clear them @@ -475,27 +619,43 @@ TEST_P(ConsoleApiTest, testConsoleSilentlyClearedOnReload) { } reload(); - expectConsoleApiCall("log", R"([{ - "type": "string", - "value": "world" - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "log"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "world" + }])"_json))); eval("console.log('world');"); } TEST_P(ConsoleApiTestWithPreExistingConsole, testPreExistingConsoleObject) { InSequence s; - expectConsoleApiCall("log", R"([{ - "type": "string", - "value": "hello" - }])"); - expectConsoleApiCall("warning", R"([{ - "type": "string", - "value": "world" - }])"); - expectConsoleApiCall("table", R"([{ - "type": "number", - "value": 42 - }])"); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "log"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "hello" + }])"_json))); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "warning"), + AtJsonPtr( + "/args", + R"([{ + "type": "string", + "value": "world" + }])"_json))); + expectConsoleApiCall(AllOf( + AtJsonPtr("/type", "table"), + AtJsonPtr( + "/args", + R"([{ + "type": "number", + "value": 42 + }])"_json))); eval("console.log('hello');"); eval("console.warn('world');"); // NOTE: not present in the pre-existing console object diff --git a/packages/react-native/ReactCommon/jsinspector-modern/tests/FollyDynamicMatchers.h b/packages/react-native/ReactCommon/jsinspector-modern/tests/FollyDynamicMatchers.h index ddc290cfb36..1b0d74414d4 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/tests/FollyDynamicMatchers.h +++ b/packages/react-native/ReactCommon/jsinspector-modern/tests/FollyDynamicMatchers.h @@ -77,4 +77,13 @@ MATCHER_P2( return false; } +/** + * A user-defined literal for constructing a folly::dynamic from a JSON + * string. Not technically specific to GMock, but convenient to have in a test + * suite. + */ +inline folly::dynamic operator""_json(const char* s, size_t n) { + return folly::parseJson(std::string{s, n}); +} + } // namespace facebook