Docs: https://serenity-js.org | Issues: https://github.com/serenity-js/serenity-js/issues | Backlog: https://github.com/orgs/serenity-js/projects
renovate[bot] on configure
Add renovate.json (compare)
dependabot[bot] on npm_and_yarn
chore(deps): bump chai from 4.3… (compare)
dependabot[bot] on npm_and_yarn
chore(deps-dev): bump lerna fro… (compare)
jan-molak on gh-pages
Updates (compare)
jan-molak on master
Update the-trouble-with-test-sc… Merge pull request #743 from ma… (compare)
Error: Error: Cannot find module 'unicode-13.0.0/Binary_Property/ID_Start/code-points.js'
- Is this somehow connected to the serenityJS framework?
Hey folks! Serenity/JS 2.19 adds two new interfaces to Abilities: Initialisable and Discardable.
Any custom Abilities you create that implement those interfaces will be initialised by Serenity/JS before the actor starts to perform their activities, and discarded when the scenario finishes (if the actor was instantiated in scenario scope), or when the entire test run finishes (if the actor was initialised in beforeAll
-style hook).
Here's an example of using those new features to make a Serenity/JS test interact with a PostgreSQL DB - https://serenity-js.org/modules/core/class/src/screenplay/Ability.ts~Ability.html
Take this new version for a spin and let me know what you think :-) I can't wait to see what you integrate your tests with!
Hi folks - new supporter here migrating over from the Java world of Serenity BDD. Very thankful this project exists - I've just started incorporating it as my REST integration test step in a Kubernetes microservice build pipeline.
I wanted to ask what do you find is the best approach to pass in the base URL for REST tests in this kind of scenario where the URL is not known ahead of time? For now I'm going to extract it from an environment variable and default to localhost:8080 but wondered if there was more sophisticated handling for REST defaults, etc. Thanks!
CallAnApi
ability.
const ScenarioName = (scenario: HookScenarioResult) =>
Question.about('The name of the scenario', actor => scenario.pickle.name);
Before( scenario => actorCalled('User').attemptsTo(
MaximizeBrowser.start(),
TakeNote.of(ScenarioName(scenario)).as('scenarioName'),
));
// code in an async interaction gets the name to use
const scenarioName: string = await actorCalled('User').answer(Note.of('scenarioName'));
Hey folks! I've added a neat little Question
in version 2.19.5, it's called q
and works just like string templates, but with other Serenity/JS questions:
import { q, actorCalled } from '@serenity-js/core';
import { Send, DeleteRequest } from '@serenity-js/rest';
actorCalled('Alice').attemptsTo(
Send.a(DeleteRequest.to(
q `/articles/${ Text.of(Article.id()) }`
))
)
Thoughts and feedback welcome!
Hi, is there a #result or something that can be used in the question string to display value of the question? i can only see #actor... i am trying to write a question that can be chained like tasks
class DateText extends Question {
static of(target) {
return new DateText(target);
}
as(dateFormat) {
this.dateFormat = dateFormat;
return this;
}
constructor(target) {
super();
this.target = target;
}
async performAs(actor) {
/*more fancy stuff here*/
const result = '2020/12/15';
return result;
}
}
but without toString method this throws and exception in formatter. If i return const string then it is being used in the calling Ensure as value...
Serenity/JS 2.20 has arrived with support for Cucumber 7 (including the new Rule/Example syntax) and the latest Serenity BDD reporting CLI.
There's also a brand new reporting guide on the website, and updates to the integration guide around integrating Serenity/JS with Cucumber, Jasmine, Mocha and Protractor
Take it all for a spin and let me know what you think!
Hi, how to get the parent of a Target with Serenity/JS?
Imagine two dialogs on a page, and I want to close the one with title "Awesome Title 2" it by clicking the X.
<div>
<div class="dialog">
<div class="dialog-title">Awesome Title 1</div>
<div class="dialog-content">Some information in here.</div>
<div class="close">X</div>
</div>
<div class="dialog">
<div class="dialog-title">Awesome Title 2</div>
<div class="dialog-content">Some other information in here.</div>
<div class="close">X</div>
</div>
</div>
I can target both dialogs:
const Dialogs = () => Target.all('dialogs').located(by.css('dialog'));
But I can just distinguish both dialogs by their titles.
const DialogTitle = (title: string) => Target.the(`dialog title ${title}`).located(by.cssContainingText('.dialog-title', title));
I won't use Pick
with get(index)
because the positions may change.
'Target of' won't work either because I'm not searching the child, but the parent.
I could try to use a located(by.xpath(''))
but this will be a mess in my specific case.
In Protractor there is the possibility the getDriver()
method to get the parent of an element: Protracor API
This seems not to be implemented in Serenity/JS.
I tried some things, but nothing worked out.
How to solve this? Am I missing something?
Thanks, Jan
Pick
would be an appropriate choice in your case; you could say:const DialogTitle = () => Target.the(`dialog title`).located(by.css('.dialog-title'))
const CloseButton = () => Target.the(`close button`).located(by.css('.close'))
CloseButton.of(Pick.from(Dialogs()).where(Text.of(DialogTitle()), includes('Awesome Title 1')).first())
Hi @jan-molak !
I'm having some problems with a post
method which needs an authentication token.
One previous post was suggesting to create a question in order to access the token, so I prepared my own version:
const Authorization = {
from: (
responseBody: Answerable<any> // you might want to introduce an interface to describe the response rather than `any`
) =>
Question.about(
`session token`,
actor =>
actor
.answer(responseBody)
.then(body => 'Bearer '.concat(body.access_token)) // or wherever the token is on the response body
),
}
I have a task that obtains the token:
export const RequestAuthentication = (): Task =>
Task.where(
`#actor requests auth token`,
Send.a(PostRequest.to('yyyy').with(formData)),
Log.the(LastResponse.status()),
Ensure.that(LastResponse.status(), equals(200)),
TakeNote.of(Authorization.from(LastResponse.body()))
)
And, finally, a task that performs a GET using the authorization previously obtained:
export const Search = (): Task => {
return Task.where(
`#actor searches for a case`,
Log.the(Note.of(Authorization.from(LastResponse.body()))),
Send.a(
GetRequest.to('https://xxxx').using({
headers: {
Authorization: Note.of(Authorization.from(LastResponse.body())),
},
})
),
Log.the(LastResponse.body()),
Ensure.that(LastResponse.status(), equals(200))
)
}
Since I have logged the token in a note, I can see that it is a valid one but it is not working (401 error). Maybe I need my question to return a whole AxiosRequestConfig and inject it to the using method?