diff --git a/docs/commands/overview.md b/docs/commands/overview.md index ecb10f3..f85cb33 100644 --- a/docs/commands/overview.md +++ b/docs/commands/overview.md @@ -1,5 +1,7 @@ # Overview of Commands +... better docs will come ;-) + ## Requirements You need to install following package to use the code generation feature diff --git a/docs/testing.md b/docs/testing.md new file mode 100644 index 0000000..ddce1f1 --- /dev/null +++ b/docs/testing.md @@ -0,0 +1,242 @@ +# :fontawesome-solid-journal-whills: **Testing** + +Many Laravel services provide functionality to help you easily and expressively write tests, and this SOAP wrapper is no exception. + +## :fontawesome-brands-jedi-order: **Faking** + +The `Soap` facade's `fake` method allows you to instruct the SOAP client to return stubbed / dummy responses when requests are made. + +### Simple Fake +For example, to instruct the SOAP client to return empty, `200` status code responses for every request, you may call the `fake` method with no arguments: + + use CodeDredd\Soap\Facades\Soap; + + Soap::fake(); + + $response = Soap::baseWsdl(...)->call(...); + +### Faking Specific URLs + +Alternatively, you may pass an array to the `fake` method. The array's keys should represent ACTION patterns that you wish to fake and their associated responses. The `*` character may be used as a wildcard character. You may use the `response` method to construct stub / fake responses for these endpoints: +The difference between Laravels HTTP wrapper is the fact that actions which are not defined in fake are also faked with a default 200 response! +Also a faked response status code is always 200 if you define it in the range between 200 and 400. Status codes 400 and greater are correct responded. + + Soap::fake([ + // Stub a JSON response for all Get_ actions... + 'Get_*' => Soap::response(['foo' => 'bar'], 200, ['Headers']), + + // Stub a string response for Submit_User action + 'Submit_User' => Soap::response('Hello World', 200, ['Headers']), + ]); + +If you would like to overwrite the fallback ACTION pattern that will stub all unmatched URLs, you may use a single `*` character: + + Soap::fake([ + // Stub a JSON response for all Get_ actions... + 'Get_*' => Soap::response(['foo' => 'bar'], 200, ['Headers']), + + // Stub a string response for all other actions + '*' => Soap::response('Hello World', 200, ['Headers']), + ]); + +One important notice. Because a SOAP API doesn't return only string every response with only a string in the body will be formatted to an array: + + //For above example + [ + 'response' => 'Hello World' + ] + +### Faking Response Sequences + +Sometimes you may need to specify that a single ACTION should return a series of fake responses in a specific order. You may accomplish this by using the `Soap::sequence` method to build the responses: + + Soap::fake([ + // Stub a series of responses for Get_* actions... + 'Get_*' => Soap::sequence() + ->push('Hello World') + ->push(['foo' => 'bar']) + ->pushStatus(404) + ]); + +When all of the responses in a response sequence have been consumed, any further requests will cause the response sequence to throw an exception. If you would like to specify a default response that should be returned when a sequence is empty, you may use the `whenEmpty` method: + + Soap::fake([ + // Stub a series of responses for Get_* actions... + 'Get_*' => Soap::sequence() + ->push('Hello World') + ->push(['foo' => 'bar']) + ->whenEmpty(Soap::response()) + ]); + +If you would like to fake a sequence of responses but do not need to specify a specific ACTION pattern that should be faked, you may use the `Soap::fakeSequence` method: + + Soap::fakeSequence() + ->push('Hello World') + ->whenEmpty(Soap::response()); + +### Fake Callback + +If you require more complicated logic to determine what responses to return for certain endpoints, you may pass a callback to the `fake` method. This callback will receive an instance of `CodeDredd\Soap\Client\Request` and should return a response instance: + + Soap::fake(function ($request) { + return Soap::response('Hello World', 200); + }); + +------------------------ + +## :fontawesome-brands-jedi-order: **Asserts** + +When faking responses, you may occasionally wish to inspect the requests the client receives in order to make sure your application is sending the correct data or headers. + +### :fontawesome-solid-jedi: ***assertSent*** + +> Assert that a request / response pair was recorded matching a given truth test. + +!!! info "" + - **`Method`** : `#!php-inline function assertSent(callable $callback)` + - **`Return`** : `#!php-inline void` + +!!! example "Examples" + === "simple" + ``` php-inline + Soap::assertSent(function($request){ + return $request->action() === 'YourAction' + }); + ``` + === "with arguments" + ``` php-inline + Soap::assertSent(function($request){ + return $request->action() === 'YourAction' && + $request->arguments() === ['argument' => 'value'] + }); + ``` + === "full" + ``` php-inline + Soap::fake(); + + Soap::baseWsdl('https://test/v1?wsdl')->call('YourAction', ['argument' => 'value']); + + Soap::assertSent(function($request){ + return $request->action() === 'YourAction' && + $request->arguments() === ['argument' => 'value'] + }); + ``` + +### :fontawesome-solid-jedi: ***assertNotSent*** + +> Assert that a request / response pair was not recorded matching a given truth test. + +!!! info "" + - **`Method`** : `#!php-inline function assertNotSent(callable $callback)` + - **`Return`** : `#!php-inline void` + +!!! example "Examples" + === "simple" + ``` php-inline + Soap::assertNotSent(function($request){ + return $request->action() === 'YourAction' + }); + ``` + === "with arguments" + ``` php-inline + Soap::assertNotSent(function($request){ + return $request->action() === 'YourAction' && + $request->arguments() === ['argument' => 'value'] + }); + ``` + === "full" + ``` php-inline + Soap::fake(); + + Soap::baseWsdl('https://test/v1?wsdl')->call('YourAction', ['argument' => 'value']); + + Soap::assertNotSent(function($request){ + return $request->action() === 'YourAction' && + $request->arguments() === ['argument' => 'NotThisValue'] + }); + ``` + +### :fontawesome-solid-jedi: ***assertActionCalled*** + +> Assert that a given soap action is called with optional arguments. + +!!! info "" + - **`Method`** : `#!php-inline function assertActionCalled(string $action)` + - **`Return`** : `#!php-inline void` + +!!! example "Examples" + === "simple" + ``` php-inline + Soap::assertActionCalled('YourAction'); + ``` + === "full" + ``` php-inline + Soap::fake(); + + Soap::baseWsdl('https://test/v1?wsdl')->call('YourAction'); + + Soap::assertActionCalled('YourAction'); + ``` +### :fontawesome-solid-jedi: ***assertNothingSent*** + +> Assert that no request / response pair was recorded. + +!!! info "" + - **`Method`** : `#!php-inline function assertNothingSent()` + - **`Return`** : `#!php-inline void` + +!!! example "Examples" + === "simple" + ``` php-inline + Soap::assertNothingSent(); + ``` + === "full" + ``` php-inline + Soap::fake(); + + Soap::assertNothingSent(); + ``` + +### :fontawesome-solid-jedi: ***assertSequencesAreEmpty*** + +> Assert that every created response sequence is empty. + +!!! info "" + - **`Method`** : `#!php-inline function assertSequencesAreEmpty()` + - **`Return`** : `#!php-inline void` + +!!! example "Examples" + === "simple" + ``` php-inline + Soap::assertSequencesAreEmpty(); + ``` + === "full" + ``` php-inline + Soap::fake(); + + Soap::assertSequencesAreEmpty(); + ``` + +### :fontawesome-solid-jedi: ***assertSentCount*** + +> Assert how many requests have been recorded. + +!!! info "" + - **`Method`** : `#!php-inline function assertSentCount(int $count)` + - **`Return`** : `#!php-inline void` + +!!! example "Examples" + === "simple" + ``` php-inline + Soap::assertSentCount(3); + ``` + === "full" + ``` php-inline + Soap::fake(); + + $client = Soap::buildClient('laravlel_soap'); + $response = $client->call('YourAction'); + $response2 = $client->call('YourOtherAction'); + + Soap::assertSentCount(2); + ``` diff --git a/docs/testing/asserts.md b/docs/testing/asserts.md index 77ae86d..96d7f86 100644 --- a/docs/testing/asserts.md +++ b/docs/testing/asserts.md @@ -1,5 +1,32 @@ +# Asserts + When faking responses, you may occasionally wish to inspect the requests the client receives in order to make sure your application is sending the correct data or headers. You may accomplish this by calling the `Soap::assertSent` method after calling `Soap::fake`. +## Overview + +### assertSent + +!!! info "" + - **`Method`** : `#!php-inline function assertSent(callable $callback)` + - **`Return`** : `#!php-inline void` + +!!! example "Examples" + === "simple" + ``` php-inline + Soap::assertSent(function($request){ + return $request->action() === 'YourAction' + }); + ``` + === "with arguments" + ``` php-inline + Soap::assertSent(function($request){ + return $request->action() === 'YourAction' && + $request->arguments() === ['argument' => 'value'] + }); + ``` + + +## Examples The `assertSent` method accepts a callback which will be given an `CodeDredd\Soap\Client\Request` instance and should return a boolean value indicating if the request matches your expectations. In order for the test to pass, at least one request must have been issued matching the given expectations: Soap::fake(); diff --git a/mkdocs.yml b/mkdocs.yml index 81f69fd..77417d0 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -4,6 +4,10 @@ site_author: 'Gregor Becker' docs_dir: docs/ repo_name: 'codedredd/laravel-soap' repo_url: 'https://github.com/codedredd/laravel-soap' + +# Copyright +copyright: Copyright © 2020 - 2020 Gregor Becker + nav: - Introduction: 'index.md' - Installation: 'installation.md' @@ -16,8 +20,26 @@ nav: - Overview: 'commands/overview.md' - 'Make Client': 'commands/make-client.md' - 'Make Validation': 'commands/make-validation.md' - - Testing: - - Faking: 'testing/faking.md' - - Asserts: 'testing/asserts.md' + - Testing: 'testing.md' theme: name: 'material' +markdown_extensions: + - admonition + - codehilite: + guess_lang: false + - toc: + permalink: true + - pymdownx.betterem: + smart_enable: all + - pymdownx.superfences + - pymdownx.inlinehilite + - pymdownx.tabbed + - pymdownx.emoji: + emoji_index: !!python/name:materialx.emoji.twemoji + emoji_generator: !!python/name:materialx.emoji.to_svg + - pymdownx.highlight: + extend_pygments_lang: + - name: php-inline + lang: php + options: + startinline: true diff --git a/src/Client/Request.php b/src/Client/Request.php index 86de110..b029c30 100644 --- a/src/Client/Request.php +++ b/src/Client/Request.php @@ -63,7 +63,8 @@ public function xmlContent() public function arguments(): array { $xml = SoapXml::fromString($this->xmlContent()); + $arguments = Arr::first(XMLSerializer::domNodeToArray($xml->getBody())); - return Arr::first(XMLSerializer::domNodeToArray($xml->getBody())); + return $arguments ?? []; } } diff --git a/src/Facades/Soap.php b/src/Facades/Soap.php index 1fc817d..299150a 100644 --- a/src/Facades/Soap.php +++ b/src/Facades/Soap.php @@ -28,6 +28,7 @@ * @method static assertActionCalled(string $action) * @method static assertNothingSent() * @method static assertSequencesAreEmpty() + * @method static assertSentCount($count) */ class Soap extends Facade { diff --git a/src/SoapFactory.php b/src/SoapFactory.php index 47f2161..24c88d4 100644 --- a/src/SoapFactory.php +++ b/src/SoapFactory.php @@ -9,7 +9,6 @@ use GuzzleHttp\Psr7\Response as Psr7Response; use Illuminate\Support\Str; use Illuminate\Support\Traits\Macroable; -use PHPUnit\Framework\Assert as PHPUnit; class SoapFactory { @@ -71,6 +70,10 @@ public function __call($method, $parameters) return $this->macroCall($method, $parameters); } + if (Str::contains($method, 'assert')) { + return (new SoapTesting($this))->{$method}(...$parameters); + } + return tap(new SoapClient($this), function ($request) { $request->stub($this->stubCallbacks); })->{$method}(...$parameters); @@ -81,6 +84,16 @@ public function isRecording() return $this->recording; } + public function getResponseSequences() + { + return $this->responseSequences; + } + + public function getRecorded() + { + return $this->recorded; + } + /** * Record a request response pair. * @@ -219,33 +232,6 @@ public function stubMethod($method, $callback) }); } - /** - * Assert that a request / response pair was recorded matching a given truth test. - * - * @param string $action - * @return void - */ - public function assertActionCalled(string $action) - { - $this->assertSent(function (Request $request) use ($action) { - return $request->action() === $action; - }); - } - - /** - * Assert that a request / response pair was recorded matching a given truth test. - * - * @param callable $callback - * @return void - */ - public function assertSent($callback) - { - PHPUnit::assertTrue( - $this->recorded($callback)->count() > 0, - 'An expected request was not recorded.' - ); - } - /** * Get a collection of the request / response pairs matching the given truth test. * @@ -266,46 +252,4 @@ public function recorded($callback) return $callback($pair[0], $pair[1]); }); } - - /** - * Assert that a request / response pair was not recorded matching a given truth test. - * - * @param callable $callback - * @return void - */ - public function assertNotSent($callback) - { - PHPUnit::assertFalse( - $this->recorded($callback)->count() > 0, - 'Unexpected request was recorded.' - ); - } - - /** - * Assert that no request / response pair was recorded. - * - * @return void - */ - public function assertNothingSent() - { - PHPUnit::assertEmpty( - $this->recorded, - 'Requests were recorded.' - ); - } - - /** - * Assert that every created response sequence is empty. - * - * @return void - */ - public function assertSequencesAreEmpty() - { - foreach ($this->responseSequences as $responseSequence) { - PHPUnit::assertTrue( - $responseSequence->isEmpty(), - 'Not all response sequences are empty.' - ); - } - } } diff --git a/src/SoapTesting.php b/src/SoapTesting.php new file mode 100644 index 0000000..75b8e57 --- /dev/null +++ b/src/SoapTesting.php @@ -0,0 +1,105 @@ +factory = $factory; + } + + /** + * Assert that a request / response pair was not recorded matching a given truth test. + * + * @param callable $callback + * @return void + */ + public function assertNotSent($callback) + { + PHPUnit::assertFalse( + $this->factory->recorded($callback)->count() > 0, + 'Unexpected request was recorded.' + ); + } + + /** + * Assert that no request / response pair was recorded. + * + * @return void + */ + public function assertNothingSent() + { + PHPUnit::assertEmpty( + $this->factory->getRecorded(), + 'Requests were recorded.' + ); + } + + /** + * Assert that every created response sequence is empty. + * + * @return void + */ + public function assertSequencesAreEmpty() + { + foreach ($this->factory->getResponseSequences() as $responseSequence) { + PHPUnit::assertTrue( + $responseSequence->isEmpty(), + 'Not all response sequences are empty.' + ); + } + } + + /** + * Assert that a given soap action is called with optional arguments. + * + * @param string $action + * @return void + */ + public function assertActionCalled(string $action) + { + $this->assertSent(function (Request $request) use ($action) { + return $request->action() === $action; + }); + } + + /** + * Assert that a request / response pair was recorded matching a given truth test. + * + * @param callable $callback + * @return void + */ + public function assertSent($callback) + { + PHPUnit::assertTrue( + $this->factory->recorded($callback)->count() > 0, + 'An expected request was not recorded.' + ); + } + + /** + * Assert how many requests have been recorded. + * + * @param $count + * @return void + */ + public function assertSentCount($count) + { + PHPUnit::assertCount($count, $this->factory->getRecorded()); + } +} diff --git a/tests/Unit/SoapClientTest.php b/tests/Unit/SoapClientTest.php index ed9aacb..06b5719 100644 --- a/tests/Unit/SoapClientTest.php +++ b/tests/Unit/SoapClientTest.php @@ -78,6 +78,8 @@ public function testSequenceFake() self::assertEquals($responseFake, $response->json()); self::assertEquals($responseFake2, $response2->json()); self::assertEquals($responseFake2, $response3->json()); + + Soap::assertSentCount(3); } /**