What is the test case format in gherkin language? - testcase

I have a mock up profile page of a gym and I'm to write test cases for editing that profile page in gherkin language. I don't the gherkin test case format. Can anyone please help me with this?

There is no hard and fast rule to write the gherkin tests. But it is highly advisable that you write them by following recommended procedures, to make it understandable. The main purpose of gherkin is for someone apart from your team, understand the whole testing process.
There are three primary, conditions that you will have to satisfy writing gherkin.
Start your tests with the pre-defined statements i.e Given Then and When. Your feature file should have steps that should look like these:
Given I land on homepage
When I click on the signup button
Then I see the error
There are also other keywords like:
And - Connect more than two steps
Please refer to this documentation for more details:
https://github.com/cucumber/cucumber/wiki/Given-When-Then

In my opinion, this question has no scope; however, I'll try to answer. Gherkin is a language with no technical barriers; it enforces an entire team to write unambiguous requirement-based test specifications based on creative collaboration rather technical specifics. The base components of Gherkin have been explained in the first answer. So, I'd rather try to give a working example as requested in the question to understand the use of Given, When, Then clearly.
The following test (called test specification) is written in Gherkin in the feature file:
Feature: Google Book Searching from https://www.googleapis.com/books/v1/volumes?q={ID}
Scenario Outline: Verify that the response status code is 200 and content type is JSON.
Given webService endpoint is up
When user sends a get request to webService endpoint using following details
| ID | <ID> |
Then verify <statusCode> and <contentType> from webService endpoint response
Examples:
| ID | statusCode | contentType |
| 1 | 200 | "application/json; charset=UTF-8" |
| 9546 | 200 | "application/json; charset=UTF-8" |
| 9 | 200 | "application/json; charset=UTF-8" |
Now here is the step definition for the above test specification:
// for **Given** - as it has to ensure that the required webservice end-point is up:
#Given("webService endpoint is up")
public void webserviceEndpointIsUp() {
requestSpecification = new RequestSpecBuilder().
setBaseUri(prop.getProperty(BASE_URL)).
build();
}
// for **When** - as this is for the part when user sends the request to the webservice end-point and receives the response
#When("user sends a get request to webService endpoint using following details")
public void userSendsAGetRequestToWebServiceEndpointUsingID(Map<String, String> data) {
String ID = data.get("ID");
System.out.println("The current ID is: " + ID);
String pathParameters = "?q" + "=" + ID;
response = given().
spec(requestSpecification).
when().
get(pathParameters);
}
// for **Then** - finally, here is the then part. When we're verifying the actual stuff mentioned in the Scenario
#Then("verify {int} and {string} from webService endpoint response")
public void verifyResponseStatusCodeAndContentTypeFromWebServiceEndpointResponse(int statusCode, String contentType) {
Assert.assertEquals(statusCode, response.getStatusCode());
Assert.assertEquals(contentType, response.getContentType());
}
This is just one example that how tests are written in Gherkin, there is a lot more to learn to be able to write such scripts. So, I'll recommend to start off with the following links:
Writing Good Gherkin
Cucumeber-JVM Free Course

Related

Prevent NFC Service app from opening when reading empty tag with enableReaderMode

Moving from the enableForgroundDispatch (I don't seem to get it working on api 32) intent based way of reading NFC-tags to enableReaderMode. The latter one works well, but every now and then the NFC Service app is opening, showing 'emtpy tag' message. Is there a way to disable this, in code? It's true that the tags are empty, only reading and using the tag Id. Code look like the following;
Bundle opts = new Bundle();
opts.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 250);
getNfcAdapter().enableReaderMode(this, tag -> {
// passing tag to get tag.getId()
myViewModel.setTag(tag);
}, NfcAdapter.FLAG_READER_NFC_A |
NfcAdapter.FLAG_READER_NFC_B |
NfcAdapter.FLAG_READER_NFC_F |
NfcAdapter.FLAG_READER_NFC_V |
NfcAdapter.FLAG_READER_NFC_BARCODE |
NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK |
NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS
, opts);

MockMvc perform, array response assertion fail

I am implementing integration tests for Spring Boot. One of my endpoint gives back all the users, even the deleted ones. Here deleted means the deleted boolean attribute is set to true on AppUser Entity (~soft delete).
The endpoint works perfectly, I have manual tested with Postman (you can see below the response). The code:
#Test
void testGetAllAppUsers_whenAuthorizedOnlyActiveFalse_gotDeletedUser() throws Exception {
String token = jwtProvider.generateToken(TestUtils.ACCOUNT_MANAGER_USERNAME);
String url = "/api/account/user";
mvc.perform(get(url)
.header("Authorization", token)
.param("only-active", "false"))
.andExpect(status().isOk())
.andExpect(jsonPath("$[*].deleted").value(Matchers.arrayContaining(true)));
}
the response:
...
Body = [{"id":7,"username":"ablabadmin#account.com","fullName":"Alpha Beta Lab Admin","deleted":false,"labsAsUser":[],"labsAsAdmin":[],"roles":[],"managedLabs":[]},{"id":11,"username":"ablabdeleteduser#account.com","fullName":"Alpha Beta Lab Deleted User","deleted":true,"labsAsUser":[],"labsAsAdmin":[],"roles":[],"managedLabs":[]},{"id":4,"username":"ablabman#account.com","fullName":"Alpha Beta Lab Manager","deleted":false,"labsAsUser":[],"labsAsAdmin":[],"roles":[],"managedLabs":[{"id":1,"key":"alab","name":"Alpha Lab","deleted":false,"createdAt":"2021-06-09","updatedAt":null,"labManagerUsernames":["alabman#account.com","ablabman#account.com"]},{"id":2,"key":"blab","name":"Beta Lab","deleted":false,"createdAt":"2021-06-09","updatedAt":null,"labManagerUsernames":["blabman#account.com","ablabman#account.com"]}]},{"id":10,"username":"ablabuser#account.com","fullName":"Alpha Beta Lab User","deleted":false,"labsAsUser":[],"labsAsAdmin":[],"roles":[],"managedLabs":[]},{"id":5,"username":"alabadmin#account.com","fullName":"Alpha Lab Admin","deleted":false,"labsAsUser":[],"labsAsAdmin":[],"roles":[],"managedLabs":[]},{"id":2,"username":"alabman#account.com","fullName":"Alpha Lab Manager","deleted":false,"labsAsUser":[],"labsAsAdmin":[],"roles":[],"managedLabs":[{"id":1,"key":"alab","name":"Alpha Lab","deleted":false,"createdAt":"2021-06-09","updatedAt":null,"labManagerUsernames":["alabman#account.com","ablabman#account.com"]}]},{"id":8,"username":"alabuser#account.com","fullName":"Alpha Lab User","deleted":false,"labsAsUser":[],"labsAsAdmin":[],"roles":[],"managedLabs":[]},{"id":1,"username":"aman#account.com","fullName":"Account Manager","deleted":false,"labsAsUser":[],"labsAsAdmin":[],"roles":[{"id":1,"role":"ACCOUNT_MANAGER"}],"managedLabs":[]},{"id":6,"username":"blabadmin#account.com","fullName":"Beta Lab Admin","deleted":false,"labsAsUser":[],"labsAsAdmin":[],"roles":[],"managedLabs":[]},{"id":3,"username":"blabman#account.com","fullName":"Beta Lab Manager","deleted":false,"labsAsUser":[],"labsAsAdmin":[],"roles":[],"managedLabs":[{"id":2,"key":"blab","name":"Beta Lab","deleted":false,"createdAt":"2021-06-09","updatedAt":null,"labManagerUsernames":["blabman#account.com","ablabman#account.com"]}]},{"id":9,"username":"blabuser#account.com","fullName":"Beta Lab User","deleted":false,"labsAsUser":[],"labsAsAdmin":[],"roles":[],"managedLabs":[]}]
Forwarded URL = null
Redirected URL = null
Cookies = []
java.lang.AssertionError: JSON path "$[*].deleted"
Expected: [<true>]
but: was a net.minidev.json.JSONArray (<[false,true,false,false,false,false,false,false,false,false,false]>)
Expected :[<true>]
Actual :a net.minidev.json.JSONArray (<[false,true,false,false,false,false,false,false,false,false,false]>)
...
I have tried out many other arguments: "true", false I have tried out contains method, and I ave tried out with "$[*].username" regex with an existing username, but every time I got AssertionError.
Can you please help me? There is definitely something I am missing. Also any advice is welcomed, since I am relatively new in Spring integration testing. Thanks in advance!
arrayContainingInAnyOrder(true,false) should work in this case.
But,
The test case would not have any value, even if it works with arrayContainingInAnyOrder(true,false).
As you can see, that [*].deleted returns value of deleted for all objects present in the response. The test must verify specific value.
For Example, If you are expecting that first user should have true then assert that $.[?(#.id ==1)].deleted is true.

Why does the first response takes more time in GAS web app?

Edit: I am using clasp. Updated the code to the actual GAS!
I have a GAS deployed as a web app. We send POST requests from Slack via a slash command and it needs a response in less than 3000ms because GAS can't handle asynchronous code.
At the first request, it takes more than 3000ms to send a response but on the following requests, it is around 1500ms.
The doPost function looks like the following.
var exports = exports || {};
var module = module || { exports: exports };
Logger = BetterLog.useSpreadsheet('spreadsheetId');
function doPost(request) {
var startExecutionDate = new Date();
var path = request.parameter.path;
Logger.log("Request received with path: " + path);
var response = Responses.Error;
var token = request.parameter.token;
if (path.startsWith('/slack')) {
Logger.log("Slack request");
var slackRouter = new SlackRouter();
response = slackRouter.post(request);
// ...
}
// ...
}
And this is the code for the Slack Router.
var exports = exports || {};
var module = module || { exports: exports };
var SlackRouter = (function () {
function SlackRouter() {
}
SlackRouter.prototype.post = function (request) {
var path = request.parameter.path;
switch (path) {
case Routes.Team:
Logger.log("For team");
// ...
}
};
return SlackRouter;
}());
exports.SlackRouter = SlackRouter;
I have the timestamps for each log.
First attempt
| Timestamp | Delta in ms | Log Message |
|--------------|-------------|---------------|
| 11:22:34:164 | 0 | Path: ... |
| 11:22:35:354 | 1190 | Slack request |
| 11:22:35:462 | 108 | For team |
Second attempt
| Timestamp | Delta in ms | Log Message |
|--------------|-------------|---------------|
| 11:22:45:047 | 0 | Path: ... |
| 11:22:45:164 | 117 | Slack request |
| 11:22:45:350 | 186 | For team |
I had several ideas already like the web app goes to a sleep state but since we calculate delta from the first log message it doesn't make sense.
So what is going on behind the scenes? Are you aware of any easy workarounds? If possible I don't want to build a microservice to send a response to Slack in time and later send the actual response.
The Apps Script servers don't keep every script ever written or deployed loaded in memory, and so scripts that haven't been run in a while need to be loaded from disk first. This is usually referred to as a "cold start time" in Cloud providers.
Answered by Eric Koleda on Google Apps Script Community forum
The most glaring issue is your use of ES6 syntax in your doPost() method.
Google Apps Script does not support ES6 template string syntax and only partially supports destructuring assignments. So that might be your issue. Your doPost() probably fails to return a value as a result so Slack likely repeats the request until it times out.
Try removing the BetterLog library. That may be causing the initial first-time delay.
https://developers.google.com/apps-script/guides/libraries
Warning: A script that uses a library does not run as quickly as it would if all the code were contained within a single script project. Although libraries can make development and maintenance more convenient, you should use them sparingly in projects where speed is critical. Because of this issue, library use should be limited in add-ons.

Simulate session using WithServer

I am trying to port tests from using FakeRequest to using WithServer.
In order to simulate a session with FakeRequest, it is possible to use WithSession("key", "value") as suggested in this post: Testing controller with fake session
However when using WithServer, the test now looks like:
"render the users page" in WithServer {
val users = await(WS.url("http://localhost:" + port + "/users").get)
users.status must equalTo(OK)
users.body must contain("Users")
}
Since there is no WithSession(..) method available, I tried instead WithHeaders(..) (does that even make sense?), to no avail.
Any ideas?
Thanks
So I found this question, which is relatively old:
Add values to Session during testing (FakeRequest, FakeApplication)
The first answer to that question seems to have been a pull request to add .WithSession(...) to FakeRequest, but it was not applicable to WS.url
The second answer seems to give me what I need:
Create cookie:
val sessionCookie = Session.encodeAsCookie(Session(Map("key" -> "value")))
Create and execute request:
val users = await(WS.url("http://localhost:" + port + "/users")
.withHeaders(play.api.http.HeaderNames.COOKIE -> Cookies.encodeCookieHeader(Seq(sessionCookie))).get())
users.status must equalTo(OK)
users.body must contain("Users")
Finally, the assertions will pass properly, instead of redirecting me to the login page
Note: I am using Play 2.4, so I use Cookies.encodeCookieHeader, because Cookies.encode is deprecated

Sending An HTTP Request using Intersystems Cache

I have the following Business Process defined within a Production on an Intersystems Cache Installation
/// Makes a call to Merlin based on the message sent to it from the pre-processor
Class sgh.Process.MerlinProcessor Extends Ens.BusinessProcess [ ClassType = persistent, ProcedureBlock ]
{
Property WorkingDirectory As %String;
Property WebServer As %String;
Property CacheServer As %String;
Property Port As %String;
Property Location As %String;
Parameter SETTINGS = "WorkingDirectory,WebServer,Location,Port,CacheServer";
Method OnRequest(pRequest As sgh.Message.MerlinTransmissionRequest, Output pResponse As Ens.Response) As %Status
{
Set tSC=$$$OK
Do ##class(sgh.Utils.Debug).LogDebugMsg("Packaging an HTTP request for Saved form "_pRequest.DateTimeSaved)
Set dateTimeSaved = pRequest.DateTimeSaved
Set patientId = pRequest.PatientId
Set latestDateTimeSaved = pRequest.LatestDateTimeSaved
Set formName = pRequest.FormName
Set formId = pRequest.FormId
Set episodeNumber = pRequest.EpisodeNumber
Set sentElectronically = pRequest.SentElectronically
Set styleSheet = pRequest.PrintName
Do ##class(sgh.Utils.Debug).LogDebugMsg("Creating HTTP Request Class")
set HTTPReq = ##class(%Net.HttpRequest).%New()
Set HTTPReq.Server = ..WebServer
Set HTTPReq.Port = ..Port
do HTTPReq.InsertParam("DateTimeSaved",dateTimeSaved)
do HTTPReq.InsertParam("HospitalNumber",patientId)
do HTTPReq.InsertParam("Episode",episodeNumber)
do HTTPReq.InsertParam("Stylesheet",styleSheet)
do HTTPReq.InsertParam("Server",..CacheServer)
Set Status = HTTPReq.Post(..Location,0) Quit:$$$ISERR(tSC)
Do ##class(sgh.Utils.Debug).LogDebugMsg("Sent the following request: "_Status)
Quit tSC
}
}
The thing is when I check the debug value (which is defined as a global) all I get is the number '1' - I have no idea therefore if the request has succeeded or even what is wrong (if it has not)
What do I need to do to find out
A) What is the actual web call being made?
B) What the response is?
There is a really slick way to get the answer the two questions you've asked, regardless of where you're using the code. Check the documentation out on the %Net.HttpRequest object here: http://docs.intersystems.com/ens20102/csp/docbook/DocBook.UI.Page.cls?KEY=GNET_http and the class reference here: http://docs.intersystems.com/ens20102/csp/documatic/%25CSP.Documatic.cls?APP=1&LIBRARY=ENSLIB&CLASSNAME=%25Net.HttpRequest
The class reference for the Post method has a parameter called test, that will do what you're looking for. Here's the excerpt:
method Post(location As %String = "", test As %Integer = 0, reset As %Boolean = 1) as %Status
Issue the Http 'post' request, this is used to send data to the web server such as the results of a form, or upload a file. If this completes correctly the response to this request will be in the HttpResponse. The location is the url to request, e.g. '/test.html'. This can contain parameters which are assumed to be already URL escaped, e.g. '/test.html?PARAM=%25VALUE' sets PARAM to %VALUE. If test is 1 then instead of connecting to a remote machine it will just output what it would have send to the web server to the current device, if test is 2 then it will output the response to the current device after the Post. This can be used to check that it will send what you are expecting. This calls Reset automatically after reading the response, except in test=1 mode or if reset=0.
I recommend moving this code to a test routine to view the output properly in terminal. It would look something like this:
// To view the REQUEST you are sending
Set sc = request.Post("/someserver/servlet/webmethod",1)
// To view the RESPONSE you are receiving
Set sc = request.Post("/someserver/servlet/webmethod",2)
// You could also do something like this to parse your RESPONSE stream
Write request.HttpResponse.Data.Read()
I believe the answer you want to A) is in the Server and Location properties of your %Net.HttpRequest object (e.g., HTTPReq.Server and HTTPReq.Location).
For B), the response information should be in the %Net.HttpResponse object stored in the HttpResponse property (e.g. HTTPReq.HttpResponse) after your call is completed.
I hope this helps!
-Derek
(edited for formatting)
From that code sample it looks like you're using Ensemble, not straight-up Cache.
In that case you should be doing this HTTP call in a Business Operation that uses the HTTP Outbound Adapter, not in your Business Process.
See this link for more info on HTTP Adapters:
http://docs.intersystems.com/ens20102/csp/docbook/DocBook.UI.Page.cls?KEY=EHTP
You should also look into how to use the Ensemble Message Browser. That should help with your logging needs.

Resources