From 6937926f1f17c5c1d8696690e31bb7fa6b6c114a Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 9 Mar 2024 16:10:02 -0300 Subject: [PATCH 1/3] Implement jq expression Signed-off-by: Vitor Mattos --- README.md | 21 ++++++++++- composer.json | 3 +- features/bootstrap/FeatureContext.php | 10 ++++++ features/test.feature | 52 +++++++++++++++++++++------ src/NextcloudApiContext.php | 21 +++++++++-- 5 files changed, 91 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 3de9a88..32b2ca7 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,26 @@ When sending "post" to ocs "/apps/libresign/api/v1/request-signature" | file | {"base64":""} | ``` -By this way you will receive on your controller method 2 values, status as integer and file as array. +## Parse response using jq + +You can use [jq](https://jqlang.github.io/jq/manual/) expression casting to check a value in a json response body of a request. To do this you will need to install the jq command. + +Example: + +```gherkin +When set the response to: + """ + { + "Foo": { + "Bar": "33" + } + } + """ +And sending "POST" to "/" +Then the response should be a JSON array with the following mandatory values + | key | value | + | Foo | (jq).Bar == "33" | +``` ## Parse initial state If you need to parse the initial state to use placeholder or get any value from current initial state, implement a method `parseText` like this: diff --git a/composer.json b/composer.json index 151f27d..fa94a93 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,8 @@ "guzzlehttp/guzzle": "^7.8", "phpunit/phpunit": "^9.6", "behat/behat": "^3.13", - "libresign/behat-builtin-extension": "^0.6.1" + "libresign/behat-builtin-extension": "^0.6.1", + "estahn/json-query-wrapper": "*" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8", diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index d0b541e..f983f25 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -77,6 +77,16 @@ public function sendRequest(string $verb, string $url, $body = null, array $head } } + /** + * @when set the response to: + */ + public function setTheResponseTo(PyStringNode $response): void { + // Mock response to be equal to body of request + $this->mockServer->setDefaultResponse(new MockWebServerResponse( + (string) $response + )); + } + /** * @inheritDoc */ diff --git a/features/test.feature b/features/test.feature index 04a7ff3..f13ed6b 100644 --- a/features/test.feature +++ b/features/test.feature @@ -8,29 +8,59 @@ Feature: Test this extension | status | 1 | Scenario: Test response of POST is numeric - When sending "POST" to "/" - | status | 1 | + When set the response to: + """ + {"status":1} + """ + And sending "POST" to "/" Then the response should be a JSON array with the following mandatory values - | status | 1 | + | key | value | + | status | 1 | Scenario: Test response of POST is string - When sending "POST" to "/" - | status | "string" | + When set the response to: + """ + {"status":"string"} + """ + And sending "POST" to "/" Then the response should be a JSON array with the following mandatory values - | status | "string" | + | key | value | + | status | string | Scenario: Test response of POST is boolean - When sending "POST" to "/" - | status | true | + When set the response to: + """ + {"status":true} + """ + And sending "POST" to "/" Then the response should be a JSON array with the following mandatory values - | status | true | + | key | value | + | status | true | Scenario: Test response of POST is json - When sending "POST" to "/" - | status | (string){"string": "test"} | + When set the response to: + """ + {"status":{"string": "test"}} + """ + And sending "POST" to "/" Then the response should be a JSON array with the following mandatory values + | key | value | | status | {"string": "test"} | + Scenario: Test response of POST is json that match using jq + When set the response to: + """ + { + "Foo": { + "Bar": "33" + } + } + """ + And sending "POST" to "/" + Then the response should be a JSON array with the following mandatory values + | key | value | + | Foo | (jq).Bar == "33" | + Scenario: Test initial state with string Then the response should contain the initial state "appid-string" with the following values: """ diff --git a/src/NextcloudApiContext.php b/src/NextcloudApiContext.php index 04c82dd..cdbc94f 100644 --- a/src/NextcloudApiContext.php +++ b/src/NextcloudApiContext.php @@ -254,20 +254,35 @@ public function theResponseShouldBeAJsonArrayWithTheFollowingMandatoryValues(Tab $realResponseArray, 'Not found: "' . $value['key'] . '" at array: ' . json_encode($realResponseArray) ); + $actual = $realResponseArray[$value['key']]; + if (str_starts_with($value['value'], '(jq)')) { + $expected = substr($value['value'], 4); + $this->validateAsJsonQuery($expected, json_encode($actual)); + continue; + } if (is_bool($realResponseArray[$value['key']]) || is_iterable($realResponseArray[$value['key']]) || is_numeric($realResponseArray[$value['key']]) || (is_string($realResponseArray[$value['key']]) && $this->isJson($realResponseArray[$value['key']])) ) { - $actualJson = json_encode($realResponseArray[$value['key']]); - Assert::assertJsonStringEqualsJsonString($value['value'], $actualJson, 'Key: ' . $value['key']); + $actual = json_encode($actual); + Assert::assertJsonStringEqualsJsonString($value['value'], $actual, 'Key: ' . $value['key']); continue; } - $actual = $realResponseArray[$value['key']]; Assert::assertEquals($value['value'], $actual, 'Key: ' . $value['key']); } } + private function validateAsJsonQuery(string $expected, $actual) { + $return = shell_exec('which jq'); + if (empty($return)) { + throw new \InvalidArgumentException('Is necessary install the jq command to use jq'); + } + $jq = \JsonQueryWrapper\JsonQueryFactory::createWith($actual); + $result = $jq->run($expected); + Assert::assertTrue($result, 'The jq "' . $expected . '" do not match with: ' . $actual); + } + /** * @When the response should contain the initial state :name with the following values: */ From 83179fa52d357d18baf18fb65dc046307065c4be Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 9 Mar 2024 16:27:49 -0300 Subject: [PATCH 2/3] Use response overwrite to tests of initial state Signed-off-by: Vitor Mattos --- features/bootstrap/FeatureContext.php | 31 ------------- features/test.feature | 63 +++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 31 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index f983f25..c782772 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -98,35 +98,4 @@ public function theResponseShouldBeAJsonArrayWithTheFollowingMandatoryValues(Tab )); parent::theResponseShouldBeAJsonArrayWithTheFollowingMandatoryValues($table); } - - /** - * @inheritDoc - */ - public function theResponseShouldContainTheInitialStateWithTheFollowingValues(string $name, PyStringNode $expected): void { - switch ($name) { - case 'appid-string': - $value = base64_encode((string) $expected); - break; - case 'appid-json-object': - $value = base64_encode(json_encode(['fruit' => 'orange'])); - break; - case 'appid-json-array': - $value = base64_encode(json_encode(['orange'])); - break; - default: - $value = ''; - } - $this->response = new Response( - 200, - [], - << - - - - - HTML - ); - parent::theResponseShouldContainTheInitialStateWithTheFollowingValues($name, $expected); - } } diff --git a/features/test.feature b/features/test.feature index f13ed6b..2ee0645 100644 --- a/features/test.feature +++ b/features/test.feature @@ -62,35 +62,89 @@ Feature: Test this extension | Foo | (jq).Bar == "33" | Scenario: Test initial state with string + When set the response to: + """ + + + + + + """ + And sending "POST" to "/" Then the response should contain the initial state "appid-string" with the following values: """ default """ Scenario: Test initial state with string + When set the response to: + """ + + + + + + """ + And sending "POST" to "/" Then the response should contain the initial state "appid-string" with the following values: """ "text as json string" """ Scenario: Test initial state with boolean + When set the response to: + """ + + + + + + """ + And sending "POST" to "/" Then the response should contain the initial state "appid-string" with the following values: """ true """ Scenario: Test initial state with null + When set the response to: + """ + + + + + + """ + And sending "POST" to "/" Then the response should contain the initial state "appid-string" with the following values: """ null """ Scenario: Test initial state with empty + When set the response to: + """ + + + + + + """ + And sending "POST" to "/" Then the response should contain the initial state "appid-string" with the following values: """ """ Scenario: Test initial state with json + When set the response to: + """ + + + + + + """ + And sending "POST" to "/" Then the response should contain the initial state "appid-json-object" with the following values: """ { @@ -99,6 +153,15 @@ Feature: Test this extension """ Scenario: Test initial state with array + When set the response to: + """ + + + + + + """ + And sending "POST" to "/" Then the response should contain the initial state "appid-json-array" with the following values: """ [ From d5098d10fdeb1eccf3a4c0bc15b241d111f046b6 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Sat, 9 Mar 2024 16:40:42 -0300 Subject: [PATCH 3/3] Fix psalm and phpcs issues Signed-off-by: Vitor Mattos --- composer.json | 2 +- psalm-baseline.xml | 8 ++++++++ psalm.xml | 1 + src/NextcloudApiContext.php | 5 ++--- 4 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 psalm-baseline.xml diff --git a/composer.json b/composer.json index fa94a93..fc0382b 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "cs:check": "php-cs-fixer fix --dry-run --diff", "cs:fix": "php-cs-fixer fix", "psalm": "psalm --threads=1", - "psalm:update-baseline": "psalm --threads=1 --update-baseline --set-baseline=tests/psalm-baseline.xml", + "psalm:update-baseline": "psalm --threads=1 --update-baseline --set-baseline=psalm-baseline.xml", "psalm:clear": "psalm --clear-cache && psalm --clear-global-cache", "post-install-cmd": [ "@composer bin all install --ansi", diff --git a/psalm-baseline.xml b/psalm-baseline.xml new file mode 100644 index 0000000..2a9059c --- /dev/null +++ b/psalm-baseline.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/psalm.xml b/psalm.xml index 01b01a1..2f70544 100644 --- a/psalm.xml +++ b/psalm.xml @@ -7,6 +7,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://getpsalm.org/schema/config" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" + errorBaseline="psalm-baseline.xml" > diff --git a/src/NextcloudApiContext.php b/src/NextcloudApiContext.php index cdbc94f..25309e4 100644 --- a/src/NextcloudApiContext.php +++ b/src/NextcloudApiContext.php @@ -273,9 +273,8 @@ public function theResponseShouldBeAJsonArrayWithTheFollowingMandatoryValues(Tab } } - private function validateAsJsonQuery(string $expected, $actual) { - $return = shell_exec('which jq'); - if (empty($return)) { + private function validateAsJsonQuery(string $expected, string $actual): void { + if (!`which jq`) { throw new \InvalidArgumentException('Is necessary install the jq command to use jq'); } $jq = \JsonQueryWrapper\JsonQueryFactory::createWith($actual);