-
Notifications
You must be signed in to change notification settings - Fork 20
Playwright refactoring + api project #134
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 6 commits
252cb6b
0acf917
31232f5
6422349
18212b8
5a277f3
f723d47
a3e47d9
35d3b14
fce89dd
9a9efea
d43a536
af758a8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| { | ||
| "API_HOST": "https://reqres.in/" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <TargetFramework>net6.0</TargetFramework> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| <Nullable>enable</Nullable> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> | ||
| <PackageReference Include="SpecFlow" Version="3.9.74" /> | ||
| <PackageReference Include="SpecFlow.NUnit" Version="3.9.69" /> | ||
| <PackageReference Include="SpecFlow.Tools.MsBuild.Generation" Version="3.9.69" /> | ||
| <PackageReference Include="NUnit3TestAdapter" Version="4.2.1" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup> | ||
| <ProjectReference Include="..\Behavioral.Automation.API\Behavioral.Automation.API.csproj" /> | ||
| <ProjectReference Include="..\Behavioral.Automation.Transformations\Behavioral.Automation.Transformations.csproj" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup> | ||
| <None Update="specflow.json"> | ||
| <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||
| </None> | ||
| <None Update="AutomationConfig.json"> | ||
| <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||
| </None> | ||
| </ItemGroup> | ||
|
|
||
| </Project> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| Feature: reqres test | ||
|
|
||
| Scenario: Get all users | ||
| When user sends a "GET" request to "api/users" url | ||
| Then response json path "$..data[?(@.email == 'george.bluth@reqres.in')].first_name" value should be "["George"]" | ||
|
|
||
| Scenario: Get second page | ||
| When user sends a "GET" request to "api/users" url with the following parameters: | ||
| | Name | Value | Kind | | ||
| | page | 2 | Param | | ||
| | CustomHeader | test | Header | | ||
|
|
||
| Scenario: Complex request | ||
| Given user creates a "POST" request to "api/users" url with the json: | ||
| """ | ||
| { | ||
| "name": "morpheus", | ||
| "job": "leader" | ||
| } | ||
| """ | ||
| When user adds parameters and send request: | ||
| | Name | Value | Kind | | ||
| | CustomHeader | test | Header | |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| { | ||
| "bindingCulture": { | ||
| "language": "en-us" | ||
| }, | ||
| "language": { | ||
| "feature": "en-us" | ||
| }, | ||
| "runtime": { | ||
| "missingOrPendingStepsOutcome": "Error" | ||
| }, | ||
| "stepAssemblies": [ | ||
| { | ||
| "assembly": "Behavioral.Automation.API" | ||
| }, | ||
| { | ||
| "assembly": "Behavioral.Automation.Transformations" | ||
| } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <TargetFramework>net6.0</TargetFramework> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| <Nullable>enable</Nullable> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <PackageReference Include="FluentAssertions" Version="6.5.1" /> | ||
| <PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" /> | ||
| <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" /> | ||
| <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" /> | ||
| <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="6.0.1" /> | ||
| <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" /> | ||
| <PackageReference Include="NUnit" Version="3.13.2" /> | ||
| <PackageReference Include="Polly" Version="7.2.3" /> | ||
| <PackageReference Include="SpecFlow" Version="3.9.74" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup> | ||
| <ProjectReference Include="..\Behavioral.Automation.Configs\Behavioral.Automation.Configs.csproj" /> | ||
| </ItemGroup> | ||
|
|
||
| </Project> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,226 @@ | ||
| using System.Text; | ||
| using System.Web; | ||
| using Behavioral.Automation.API.Configs; | ||
| using Behavioral.Automation.API.Context; | ||
| using Behavioral.Automation.API.Models; | ||
| using Behavioral.Automation.API.Services; | ||
| using Behavioral.Automation.Configs; | ||
| using TechTalk.SpecFlow; | ||
| using TechTalk.SpecFlow.Assist; | ||
|
|
||
| namespace Behavioral.Automation.API.Bindings; | ||
|
|
||
| [Binding] | ||
| public class HttpRequestSteps | ||
| { | ||
| private readonly ApiContext _apiContext; | ||
| private readonly HttpService _httpService; | ||
|
|
||
| public HttpRequestSteps(ApiContext apiContext, HttpService httpService) | ||
| { | ||
| _apiContext = apiContext; | ||
| _httpService = httpService; | ||
| } | ||
|
|
||
| [When("user sends a \"(.*)\" request to \"(.*)\" url")] | ||
| public HttpResponseMessage UserSendsHttpRequest(string httpMethod, string url) | ||
| { | ||
| var method = new HttpMethod(httpMethod.ToUpper()); | ||
|
|
||
| if (!IsAbsoluteUrl(url)) | ||
| { | ||
| url = ConfigManager.GetConfig<Config>().ApiHost + url; | ||
| } | ||
|
|
||
| _apiContext.Request = new HttpRequestMessage(method, url); | ||
| _httpService.SendContextRequest(); | ||
|
|
||
| return _apiContext.Response; | ||
| } | ||
|
|
||
| [When("user sends a \"(.*)\" request to \"(.*)\" url with the following parameters:")] | ||
| public HttpResponseMessage UserSendsHttpRequestWithParameters(string httpMethod, string url, Table tableParameters) | ||
| { | ||
| UserCreatesHttpRequestWithParameters(httpMethod, url, tableParameters); | ||
| _httpService.SendContextRequest(); | ||
|
|
||
| return _apiContext.Response; | ||
| } | ||
|
|
||
| [When("user sends a \"(.*)\" request to \"(.*)\" url with the json:")] | ||
| public HttpResponseMessage UserSendsHttpRequestWithParameters(string httpMethod, string url, string jsonToSend) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm sure it's a bad idea to write
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If JSON is not very long it looks fine for me. I've added a step and an example using a file as a JSON source. |
||
| { | ||
| //TODO: body can be: | ||
| // form-data | ||
| // x-www-form-urlencoded | ||
| // raw (Text, JavaScript, JSON, HTML, XML) | ||
| // binary | ||
| // GraphQL | ||
| // Consider adding other types | ||
| var method = new HttpMethod(httpMethod.ToUpper()); | ||
| if (!IsAbsoluteUrl(url)) | ||
| { | ||
| url = ConfigManager.GetConfig<Config>().ApiHost + url; | ||
| } | ||
|
|
||
| var uriBuilder = new UriBuilder(url); | ||
|
|
||
| _apiContext.Request = new HttpRequestMessage(method, uriBuilder.Uri); | ||
| _apiContext.Request.Content = new StringContent(jsonToSend, Encoding.UTF8, "application/json"); | ||
|
|
||
| _httpService.SendContextRequest(); | ||
|
|
||
| return _apiContext.Response; | ||
| } | ||
|
|
||
|
|
||
| [When("user sends a \"(.*)\" request to \"(.*)\" url with the application/x-www-form-urlencoded:")] | ||
| public HttpResponseMessage UserSendsHttpRequestWithFormUrlEncodedContent(string httpMethod, string url, Table parameters) | ||
| { | ||
| var method = new HttpMethod(httpMethod.ToUpper()); | ||
| if (!IsAbsoluteUrl(url)) | ||
| { | ||
| url = ConfigManager.GetConfig<Config>().ApiHost + url; | ||
| } | ||
|
|
||
| var uriBuilder = new UriBuilder(url); | ||
|
|
||
| _apiContext.Request = new HttpRequestMessage(method, uriBuilder.Uri); | ||
|
|
||
| var body = parameters.Rows.Select(row => new KeyValuePair<string, string>(row[0], row[1])); | ||
|
|
||
| _apiContext.Request.Content = new FormUrlEncodedContent(body); | ||
|
|
||
| _httpService.SendContextRequest(); | ||
|
|
||
| return _apiContext.Response; | ||
| } | ||
|
|
||
| [Given("user creates a \"(.*)\" request to \"(.*)\" url with the json:")] | ||
| public HttpRequestMessage UserCreatesHttpRequestWithJson(string httpMethod, string url, string jsonToSend) | ||
| { | ||
| var method = new HttpMethod(httpMethod.ToUpper()); | ||
| if (!IsAbsoluteUrl(url)) | ||
| { | ||
| url = ConfigManager.GetConfig<Config>().ApiHost + url; | ||
| } | ||
|
|
||
| var uriBuilder = new UriBuilder(url); | ||
|
|
||
| _apiContext.Request = new HttpRequestMessage(method, uriBuilder.Uri); | ||
| _apiContext.Request.Content = new StringContent(jsonToSend, Encoding.UTF8, "application/json"); | ||
| return _apiContext.Request; | ||
| } | ||
|
|
||
| [Given("user creates a \"(.*)\" request to \"(.*)\" url")] | ||
| public HttpRequestMessage GivenUserCreatesARequestToUrl(string httpMethod, string url) | ||
| { | ||
| var method = new HttpMethod(httpMethod.ToUpper()); | ||
| if (!IsAbsoluteUrl(url)) | ||
| { | ||
| url = ConfigManager.GetConfig<Config>().ApiHost + url; | ||
| } | ||
|
|
||
| var uriBuilder = new UriBuilder(url); | ||
|
|
||
| _apiContext.Request = new HttpRequestMessage(method, uriBuilder.Uri); | ||
| return _apiContext.Request; | ||
| } | ||
|
|
||
| [Given("user creates a \"(.*)\" request to \"(.*)\" url with the following parameters:")] | ||
| public HttpRequestMessage UserCreatesHttpRequestWithParameters(string httpMethod, string url, Table tableParameters) | ||
| { | ||
| var method = new HttpMethod(httpMethod.ToUpper()); | ||
| if (!IsAbsoluteUrl(url)) | ||
| { | ||
| url = ConfigManager.GetConfig<Config>().ApiHost + url; | ||
| } | ||
|
|
||
| _apiContext.Request = new HttpRequestMessage(method, url); | ||
| AddParametersToRequest(_apiContext.Request, tableParameters); | ||
| return _apiContext.Request; | ||
| } | ||
|
|
||
| [When("user adds a JSON body and send the request:")] | ||
| public HttpResponseMessage WhenUserAddsJsonBodyAndSendRequest(string jsonToSend) | ||
| { | ||
| _apiContext.Request.Content = new StringContent(jsonToSend, Encoding.UTF8, "application/json"); | ||
|
|
||
| _httpService.SendContextRequest(); | ||
|
|
||
| return _apiContext.Response; | ||
| } | ||
|
|
||
| [When("user adds parameters and send request:")] | ||
| public HttpResponseMessage WhenUserAddsParametersAndSendRequest(Table tableParameters) | ||
| { | ||
| AddParametersToRequest(_apiContext.Request, tableParameters); | ||
| _httpService.SendContextRequest(); | ||
|
|
||
| return _apiContext.Response; | ||
| } | ||
|
|
||
| [When("user sends request")] | ||
| public HttpResponseMessage WhenUserSendsRequest() | ||
| { | ||
| _httpService.SendContextRequest(); | ||
| return _apiContext.Response; | ||
| } | ||
|
|
||
| [Given("the response status code should be \"(\\d*)\"")] | ||
| public void ChangeResponseStatusCode(int statusCode) | ||
| { | ||
| _apiContext.ExpectedStatusCode = statusCode; | ||
| } | ||
|
|
||
| private static bool IsAbsoluteUrl(string url) | ||
| { | ||
| return Uri.IsWellFormedUriString(url, UriKind.Absolute); | ||
| } | ||
|
|
||
| private static void AddParametersToRequest(HttpRequestMessage request, Table tableParameters) | ||
| { | ||
| var uriBuilder = new UriBuilder(request.RequestUri); | ||
|
|
||
| var parameters = tableParameters.CreateSet<HttpParameters>(); | ||
|
|
||
| var headers = new List<KeyValuePair<string, IEnumerable<string>>>(); | ||
| if (parameters is not null) | ||
| { | ||
| var query = HttpUtility.ParseQueryString(uriBuilder.Query); | ||
| foreach (var parameter in parameters) | ||
| { | ||
| var parameterKind = Enum.Parse<RequestParameterKind>(parameter.Kind); | ||
|
|
||
| if (parameterKind is RequestParameterKind.Param) | ||
| { | ||
| query.Add(parameter.Name, parameter.Value); | ||
| } | ||
|
|
||
| if (parameterKind is RequestParameterKind.Header) | ||
| { | ||
| var headerValue = parameter.Value.Trim().Split(","); | ||
| headers.Add(new KeyValuePair<string, IEnumerable<string>>(parameter.Name, headerValue)); | ||
| } | ||
| } | ||
|
|
||
| uriBuilder.Query = query.ToString(); | ||
| } | ||
|
|
||
| request.RequestUri = uriBuilder.Uri; | ||
|
|
||
| if (headers.Any()) | ||
| { | ||
| foreach (var header in headers) | ||
| { | ||
| if (header.Key.Equals("Content-Type", StringComparison.InvariantCultureIgnoreCase)) | ||
| { | ||
| throw new Exception( | ||
| "Remove the Content-Type header, please. The Content-Type header is automatically added with request step bindings."); | ||
| } | ||
|
|
||
| request.Headers.Add(header.Key, header.Value); | ||
| } | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It makes sense to rewrite
IsAbsoluteUrlto something likeGetAbsoluteUrlsince it's use throughout the code. Additionally, you can return Uri from this method that will be well-formed and wouldn't require using string concatenationThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done