Skip to content

Commit

Permalink
Features for v1.5 (#22)
Browse files Browse the repository at this point in the history
Added lots of stuff for v1.5
  • Loading branch information
hgiesenow committed Oct 4, 2023
1 parent 0b28401 commit 1461d28
Show file tree
Hide file tree
Showing 68 changed files with 3,148 additions and 2,069 deletions.
2 changes: 2 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jobs:
- image: 'hgiesenow/php:<< parameters.php_version >>'
steps:
- checkout
- run: 'apk add --no-cache --virtual .build-deps $PHPIZE_DEPS && pecl install uopz-7.1.1 && apk del .build-deps && docker-php-ext-enable uopz'
- run: 'composer require -W symfony/dom-crawler:"^<< parameters.symfony_version >>" symfony/property-access:"^<< parameters.symfony_version >>"; rm composer.lock'
- run: 'composer require --dev -W symfony/framework-bundle:"^<< parameters.symfony_version >>"; rm composer.lock'
- run: 'composer require --dev -W monolog/monolog:"^<< parameters.monolog_version >>"; rm composer.lock'
Expand All @@ -34,6 +35,7 @@ jobs:
- image: 'hgiesenow/php:<< parameters.php_version >>'
steps:
- checkout
- run: 'apk add --no-cache --virtual .build-deps $PHPIZE_DEPS && pecl install uopz-7.1.1 && apk del .build-deps && docker-php-ext-enable uopz'
- attach_workspace:
at: '.'
- run: 'phpdbg -qrr -d memory_limit=4G vendor/bin/phpunit --testsuite unit'
Expand Down
42 changes: 34 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,16 @@ This bundle provides reusable behat contexts for symfony applications.
All steps are written in present tense, as suggested on https://automationpanda.com/2021/05/11/should-gherkin-steps-use-past-present-or-future-tense/

## Features
* BrowserContext for simple HTTP/DOM/Form interactions
* CommandContext to test symfony commands
* LoggingContext to verify correct logging
* [CommandContext](doc/context/CommandContext.md) to test symfony commands.
* [DateContext](doc/context/DateContext.md) to mock the current date.
* [FormContext](doc/context/FormContext.md) to test/manipulate/fill html forms.
* [HtmlContext](doc/context/HtmlContext.md) to check the DOM/plain HTTP response.
* [HttpContext](doc/context/HttpContext.md) for simple HTTP interactions.
* [JsonContext](doc/context/JsonContext.md) to send or check json data in request/response.
* [LoggingContext](doc/context/LoggingContext.md) to verify correct logging.
* [MailerContext](doc/context/MailerContext.md) to check if mails were triggered.
* [AbstractApiContext](doc/context/AbstractApiContext.md) to help implementing custom context for external API interaction.
* [AbstractDatabaseContext](doc/context/AbstractDatabaseContext.md) to help implementing custom context with database interaction.

## Installation

Expand Down Expand Up @@ -33,11 +40,32 @@ default:
suites:
default:
contexts:
- Elbformat\SymfonyBehatBundle\Context\BrowserContext
- Elbformat\SymfonyBehatBundle\Context\CommandContext
- Elbformat\SymfonyBehatBundle\Context\DateContext
- Elbformat\SymfonyBehatBundle\Context\FormContext
- Elbformat\SymfonyBehatBundle\Context\HtmlContext
- Elbformat\SymfonyBehatBundle\Context\HttpContext
- Elbformat\SymfonyBehatBundle\Context\JsonContext
- Elbformat\SymfonyBehatBundle\Context\LoggingContext
- Elbformat\SymfonyBehatBundle\Context\SwiftmailerContext
- Elbformat\SymfonyBehatBundle\Context\MailerContext
```
### Mailer
To make the Test-Mailer work, you need to set the mailer dsn in `config/packages/framework.yaml`
```
when@test:
framework:
mailer:
dsn: 'test://test'
```
### API
To not send requests to a real api, you should configure the MockClient to be used in `config/packages/framework.yaml`
```
when@test:
framework:
http_client:
mock_response_factory: App\Tests\Mock\MockClientCallback
```

## Examples
Examples can be found in [dock/examples.md](doc/examples.md).
Expand All @@ -46,9 +74,7 @@ Examples can be found in [dock/examples.md](doc/examples.md).
When updating from a previous version, see the [changelog](doc/changelog.md) for changes.

## What's next?
The next release will likely contain more contexts like
* AbstractApiContext - to build your own API-Mock contexts
* MailerContext - For newer applications and symfony 6.x compatibility
The next release should likely contain more tests/stability improvements.

## Development
If you want to develop on the bundle you will find useful information in [doc/development.md](doc/development.md)
11 changes: 7 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,19 @@
"symfony/property-access": "^5.4|^6.2"
},
"require-dev": {
"doctrine/orm": "^2.12",
"friendsofphp/php-cs-fixer": "^3.3",
"phpunit/phpunit": "^9.5",
"vimeo/psalm": "^4.13",
"monolog/monolog": "^2.6",
"slope-it/clock-mock": "^0.4.0",
"symfony/framework-bundle": "^5.4|^6.2",
"doctrine/orm": "^2.12"
"symfony/http-client": "^5.4|^6.2",
"symfony/mailer": "^5.4|^6.2",
"vimeo/psalm": "^4.13"
},
"config": {
"allow-plugins": {
"composer/package-versions-deprecated": true
}
},
"sort-packages": true
}
}
63 changes: 63 additions & 0 deletions doc/changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,68 @@
# Changelog

## v1.5.0

### Restructuring BrowserContext
As the BrowserContext was getting more and more complex, it is now split into 4 Contexts, sharing the state:
* HttpContext - Basic request/response operations, including headers and redirects
* HtmlContext - Querying the DOM for Text/HTML
* FromContext - Testing, manipulating and submitting forms
* JsonContext - Json response checks for custom APIs

### Switching LoggingContext
The LoggingContext was formerly bound to monolog, which is not required in newer symfony applications.
Instead, we now have a PSR-compatible TestLogger that catches the logs and can be queried in behat.

### Improvements to HttpContext
* Allow adding HTTP headers to `When I send ... request to ...`
* Allow non-rfc conform redirects with path instead of URL
* Allow testing for path only in redirect check

### Improvements to HtmlContext
* `When I remove attribute ... from ...` to unhide elements
* `Then I see ... before ...` to check sortings.
* TODO: Not found tags are not shown with full content, but only the tag

### Improvements to FormContext
* `When I submit the form with button ...` to distinguish the submit button
* `When I clear field ...` to remove data from a field
* `When I check ... checkbox with value ...` to distinguish between multi-options
* `When I uncheck ... checkbox` to revert checking
* `When I add an input field ...` to add dynamic collection fields
* `When I remove an input field ...` to remove dynamic collection fields
* `When I remove a select field ...` to remove dynamic collection fields
* `Then the form contains a select` to check for options in selects
* `Then select ... contains option` to check for options in selects
* `Then select ... does not contain option` to check for options in selects
* TODO: file upload

### Improvements in AbstractDatabaseContext
* `assertObject` returns the found object to allow steps to be built upon the results.
* Support for constructor arguments, including defaults defined in the context.
* `assertCollectionDoesNotContain` helps negation of collection check
* Support creating m:n relations by adding a `$reverseRelationName` parameter.

### Added DateContext
Based on [ClockMock](https://packagist.org/packages/slope-it/clock-mock) and the uopz extension, the context allows you to change the current date inside your tests.

### Added MailerContext in favour of SwiftmailerContext
As Swiftmailer is deprecated in favour of the symfony mailer, we adapted the context as well.

### Added AbstractApiContext
This context will help you build your own API context, like the AbstractDatabaseContext

## v1.4.2

* Fix: Comparing a string to a tag with inner html that contains spaces.

## v1.4.1

* Fix: Error, when a monolog handler is tagged.

## v1.4.0

* Support for PHP 8.2 and Symfony 6.2

## v1.3.0
### Added support for multiselect
`<select multiple>` form fields can now be selected with
Expand Down
30 changes: 30 additions & 0 deletions doc/context/AbstractApiContext.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# AbstractApiContext
This context has no steps by itself, but helper to mock away external APIs in tests and check if they are called correctly, or how the app behaves with different responses.
For example if you want to test your connection to an API for users

## Given
### `Given a call to the user api <url> will return`
```
"""
{"some":"json response"}
"""
```
or
```
"""
HTTP/1.0 OK
Content-Type: application/json
{"some":"json response with http headers"}
"""
```
Will mock the response, the next request to his api will get.
Backed by using the `addResponse` method.

## Then
### `the user api <url> has been called`
Check if the api call was performed right, by the application.
Can also contain payload or methods.
Backed by using the `assertApiCall` method.
### `the user api <url> has not been called`
The opposite, by using `assertNoApiCall` method.
31 changes: 31 additions & 0 deletions doc/context/AbstractDatabaseContext.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# AbstractDatabaseContext
This context has no steps by itself, but helper to create an own context by extending it.
For example if you want to create users and assign them to groups this could look like.

## Given
### `Given there is a user`
```
| firstname | Test |
| lastname | User |
```
Create the entity by mapping attributes from the table.
Uses `createObject` under the hood.
### `Given the user <userId> is assigned to group <groupId>`
Create a relation between two entities. Uses `createRelation` under the hood.

## Then
**NOTE:** You need to name the `Thens` a bit differently from the `Givens`, as behat will not distinguish the keywords.
Otherwise, you would create objects/relations instead of checking if they exist.
Usually we do this by adding things like "*exists*" or "*now*".

### `Then there exists a user`
```
| firstname | Test |
| lastname | User |
```
Check if the entity with the given attributes can be found.
### `Then there exists no user`
The opposite.
### `Then user<userId> is now assigned to group <groupId>`
Check if the relation exists.

14 changes: 14 additions & 0 deletions doc/context/CommandContext.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# CommandContext
This context contains steps to test symfony commands

## When
### `When I run command <command>`
Execute the given symfony command, including parsing of arguments.

## Then
### `Then the command has a return value of <code>`
Check the return code. 0 indicates a success, everything else an error.
### `Then the command outputs <text>`
Check if the text is contained somewhere in the command's output.
### `Then the command does not output <text>`
Make sure, that the given text is not in the command's output.
7 changes: 7 additions & 0 deletions doc/context/DateContext.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# DateContext
This context manipulates the time. It uses the uopz extension and [ClockMock](https://packagist.org/packages/slope-it/clock-mock).

## Given
### `Given the current date is <date>`
Modify the date, that is returned by `date()` or `new DateTime()`.
Will automatically be reset to the current date before each scenario.
47 changes: 47 additions & 0 deletions doc/context/FormContext.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# FormContext
Although it's technically and logically close to the HtmlContext, the form thing have an extra context.
This is because of the high complexity and huge amount of steps it contains.

## When
### `When I use form <name>`
Bind all following steps to this named form.
### `When I fill <value> into <fieldName>`
Fill an input field.
### `When I select <fieldName> radio button with value <value>`
Select a radio button.
### `When I clear field <fieldName>`
Reset the value of an input field.
### `When I check <fieldName> checkbox`
Check a single checkbox
### `When I check <fieldName> checkbox with value <value>`
Check an array checkbox
### `When I uncheck <fieldName> checkbox`
Uncheck a single checkbox.
### `When I uncheck <fieldName> checkbox with value <value>`
Uncheck an array checkbox
### `When I select <value> from <fieldName>`
Select from a dropdown.
### `When I select <fixture> upload at <fieldName>`
Select a file upload.
### `When I add an input field <fieldName>`
Add a new field to the form.
### `When I remove an input field <fieldName>`
Remove a field from the form.
### `When I remove a select field <fieldName>`
Remove a dropdown from the form.
### `When I submit the form`
Submit the form without a button.
### `When I submit the form with button <buttonName>`
Submit the form with a specific button.

## Then
### `Then the page contains a form named <name>`
Check existence of the form.
### `Then the form contains an input field`
Check existence of the field (and it's attributes).
### `Then the form contains a select`
Check existence of the dropdown.
### `Then select <fieldName> contains option <label>`
Check existence of a dropdown option.
### `Then select <fieldName> does not contain option`
Check absence of a dropdown option.
18 changes: 18 additions & 0 deletions doc/context/HtmlContext.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# HtmlContext
Performs checks on the plain response or DOM.

## When
### `When I remove attribute <attr> from <xpath>`
Modify the DOM to remove attributes like "disabled".

## Then
### `Then I see <text>`
Check if the string is contained somewhere in the plain text response.
### `Then I don't see <text>`
Check if the string is not contained somewhere in the plain text response.
### `Then I see :text1 before :text2`
Check if the string comes before the other string. Useful to test sorting.
### `Then I see a(n) :tag tag <text>`
Check for a specific html tag. Attributes can be defined in a table. Text is optional and matched against the strip_tags content.
### `Then I don\'t see a(n) :tag tag :content`
The opposite.
22 changes: 22 additions & 0 deletions doc/context/HttpContext.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# HttpContext
Performs HTTP Operations (Request/Response).

## When
### `When I visit <url>`
Open a page.
### `When I navigate to <url> with http headers`
Open a page but add some headers (from table) in the request.
### `When I make a <method> request to <url>`
Perform a request with a different method and optional json data.
### `When I follow the redirect`
Visit the page that is set in the location header of the previous response.

## Then
### `Then the response status code is <code>`
Check the HTTP Status code.
### `Then the page shows up`
Alias for status code 200.
### `Then the response has http headers`
Check for the existence of certain HTTP Headers.
### `Then I am being redirected to <url>`
Check if the status code and location header are set.
14 changes: 14 additions & 0 deletions doc/context/JsonContext.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# JsonContext
HTTP Operations with json payload in request/response.

## When
### `When I make a :method request with json data to :url`
Perform a request with json payload

## Then
### `Then the response json matches`
Check if the JSON response is equivalent to the given json (ignores formatting).
### `Then the response json contains`
Check if the given JSON is contained in the response (ignoring extra keys).
### `Then the response json does not contain`
Check that the response does not contain the given object.
9 changes: 9 additions & 0 deletions doc/context/LoggingContext.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# LoggingContext
Checks if logging works as expected.
Uses a MockLogger under the hood.
Is independent of monolog as it's using the PSR Logger.

## Then
### `Then the log contains a(n) <level> entry <text>`
Check if the given message wit the given severity exists.
Can optionally also check for the logging context via table.

0 comments on commit 1461d28

Please sign in to comment.