npx serenity-js new
What are you testing?
- web
- apis
- mobile
Which integration tool would you like?
- playwright
- webdriverio
- protractor
- selenium 4
Would you like to use typescript?
- yes
- hell yes
;-)
@serenity-js/protractor
to @serenity-js/web
, but we'll need to check if those could work for Playwright?
Select
for you so it will land as part of 3.0.0
@nchursin - check out https://github.com/serenity-js/serenity-js/tree/features/web where I made a couple of changes you might be interested in in the context of your work on Playwright integration:
In particular:
@serenity-js/webdriverio
and @serenity-js/protractor
to @serenity-js/web
; there's still a couple left in protractor
, but I'll migrate them across within the next day or two - https://github.com/serenity-js/serenity-js/tree/features/web/packages/web/src/screenplay@integration/web
, which ensures that all the common interactions and questions work across the different web integration tools (similar to what @viper3400 proposed in the comment here https://github.com/serenity-js/serenity-js/issues/493#issuecomment-743732779)@integration/web
runs the exact same set of tests using the common interactions and questions against the different runners; here is the configuration for the tests - https://github.com/serenity-js/serenity-js/blob/features/web/integration/web/package.json#L30-L32There's a couple of things still missing, like support for switching tabs/windows, managing cookies and so on, but the core pattern is reasonably stable I think.
Any new integration module, like @serenity-js/playwright
, will need to provide an appropriate implementation of BrowseTheWeb
- example for WebdriverIO - https://github.com/serenity-js/serenity-js/blob/features/web/packages/webdriverio/src/screenplay/abilities/BrowseTheWebWithWebdriverIO.ts
as well as integration tool-specific implementations of:
UIElement
UIElementList
UIElementLocator
- see examples here https://github.com/serenity-js/serenity-js/tree/features/web/packages/webdriverio/src/uiAhh, sorry guys. I had to delete my last posts, as they were just half of the truth and became misleading.
With PR #987 some issues are fixed, but I still had have troubles in web-protractor-runner and web-webdriver-io. This is not about NodeJS version or numeric separators, as I thought yesterday. Turned out, that this is still about parallelism. @jan-molak turned this off for ci (https://github.com/serenity-js/serenity-js/blob/bce390d9c5e4658d53d6bccf8e396271ad398572/integration/web-protractor-runner/src/protractor.conf.ts#L13). But my local machine is not able to run the integration tests in parallel either. So turning of parallel executions brought me a step further.
Hey folks, I managed to optimise the main CI/CD pipeline on master so that it takes ~20 minutes in total instead of ~33 minutes.
The main difference is that it's now much more efficient with using lerna bootstrap
command, which turned out to be the slowest part, especially on Windows builds.
Here are the changes - https://github.com/serenity-js/serenity-js/pull/1006/files
The way it affects other contributors is that lerna bootstrap
is no longer linked from the postinstall
script in root package.json
, so when running the build locally instead of npm ci
please run make install
.
I've updated the contributing guide to reflect that.
@viper3400 -I'll get your fixes to timeouts merged tomorrow, thanks!
@nchursin - features/web
is ready for you to rebase against
If you spot any issues - please let me know
Hi all!
has anybody using serenity-protractor experienced StaleElementReferenceException
issues?
After trying different 'spells', the only thing that fixed the issue was to use https://www.npmjs.com/package/ts-retry-promise to retry problematic interactions. For instance, for getting text of an element I have the following method:
static async getTextWithRetry(webElement: ElementFinder): Promise<string> {
let text: string
await retry(
async () => {
text = await webElement.getText()
},
{ retries: 3 }
)
return text
}
Would it make sense to add this kind of retry thing to the protractor module? It could have a specific config where you set number of retries/timeout
@jan-molak is there any issue on the latest serenity-rest lib. I'm getting the following error upon setting the axiosInstance.
error TS2345: Argument of type 'import("/app/node_modules/axios/index").AxiosInstance' is not assignable to parameter of type 'import("/app/node_modules/@serenity-js/rest/node_modules/axios/index").AxiosInstance'.
The types of 'interceptors.response.use' are incompatible between these types.
Types of parameters 'onFulfilled' and 'onFulfilled' are incompatible.
Type 'T | Promise<T>' is not assignable to type 'AxiosResponse<any> | Promise<AxiosResponse<any>>'.
Type 'T' is not assignable to type 'AxiosResponse<any> | Promise<AxiosResponse<any>>'.
Type 'T' is not assignable to type 'Promise<AxiosResponse<any>>'.ts(2345)
Version details:
"@serenity-js/rest": {
"version": "2.32.2"
}
"axios": {
"version": "0.21.1"
}
Hi @jan-molak,
I got some minutes and updated my features/web branch. When I look at the current tests and at the GitHub actions, it looks like you have given up to run the integration-web tests at Windows at all? :D
Anyway, with your latest tweaks I'm able to run the tests now at Windows locally without the flakiness which was seeded by the parallelization.
But there is one thing left: I spotted this earlier (and probably each time when running the tests), but postponed to analyse it deeper, because of the other problems:
https://github.com/serenity-js/serenity-js/blob/b322acde4d5b7c0c4c8cb47f0f61aa2b5ee0d101/integration-web/web/spec/screenplay/interactions/Press.spec.ts#L50
This step won't run with Protractor in Windows for me. Seems like the SHIFT modifier key is not pressed any more when the Arrow Left keys are pressed. The input is not marked and then not deleted when the Backspace key is pressed.
Find the failing Protractor Press spec in this report: https://drive.google.com/file/d/18gGbDfT6tOh9hJ18QLNkhyJYZXo6mt05/view?usp=sharing
WDIO seems to handle this, but there are no screenshots attached in the report, so I can't control what is happening there.
I'm also not sure if you release pipelines are really "green" as there are still errors in the logs. Are you aware of this?
https://github.com/serenity-js/serenity-js/runs/3784611368?check_suite_focus=true
@jan-molak hey mate, I finally got to re-writing the playwright integration, and actually about half-way through it.
The new approach is amazing - much easier to add a new implementation than it was!
I have a couple of questions though:
BrowseTheWeb.sendKeys
supposed to work? Are there any tests for it I can look at? I want to understand the outcome of inputs like [ 'Shift', 'h', 'i' ]
or [ 'Ctrl', 'a' ]
- do I suppose to join the pairs like 'Shift+h'
or should I hold 'Shift'
, so it's like [ 'Shift+h', 'Shift+a' ]
? I'm trying to implement the executeScript
, but struggling with this error: '[arg: Unboxed<InnerArguments>]' is assignable to the constraint of y: any) => actualKeys.push({
295 type 'InnerArguments', but 'InnerArguments' could be instantiated with a d: 'down',
296 allPages(): Promise<SerenityPage[]> { different subtype of constraint 'any[]'.
Have you had anything like this for other implementation? I'm realy not sure this is coming from
Here's the method from pw i'm using: https://playwright.dev/docs/api/class-page#page-evaluate
here's the code:
async executeScript<Result, InnerArguments extends any[]>(
script: string | ((...parameters: InnerArguments) => Result),
...args: InnerArguments
): Promise<Result> {
const nativeArguments = await Promise.all(
args.map(
arg => arg instanceof PlaywrightPageElement ? arg.nativeElement() : arg
)
) as InnerArguments;
const page = await this.page();
return page.evaluate<Result, InnerArguments>(script, nativeArguments);
}
But we can make them actually generic on the BrowseTheWebLevel
, at least the close
methods. Also, we have other switchTo
kinda methods there, e.g. switchToFrame
, so it has some logic behind moving switchToPage
there.
I don't think it's a big deal BrowseTheWeb
has interactions with Page
- it's dependent on it anyway, cause needs to return pages (methods page
, allPages
). But closeOthers
on a page may be a trouble, cause we actually have to expose the whole browser context to a page... I don't like this, feels wrong
There's what i suggest
closePage(page: SerenityPage): Promise<void> {
// generic implementation stored in abstract BrowseTheWeb
// so no specifics need to be made for Pw/Wdio/Protractor
return page.close();
}
async closeOtherPages(page: SerenityPage): Promise<void> {
// generic implementation stored in abstract BrowseTheWeb
// so no specifics need to be made for Pw/Wdio/Protractor
const allPages = await this.allPages();
return Promise.all(allPages
.filter((pageToCheck) => page.handle === pageToCheck.handle)
.map((pageToClose) => pageToClose.close()));
}
switchToPage(page: SerenityPage): Promise<void> {
// new method in BrowseTheWeb
// Implementation specific logic goes here based on page.handle()
}
switchToFrame(targetOrIndex: string | number | PageElement<any, any>): Promise<void> {
// exsiting method in BrowseTheWeb
}
Hi @jan-molak
I went on with migration to Serenity/JS 3 but now I struggle with the following pattern I used in Serenity/JS 2:
const InputContainers = () =>
PageElements.located(By.css('.input-container')).describedAs('input containers');
const Labels = () =>
PageElements.located(By.css('label')).describedAs('label');
const InputContainerForLabelWithText = (text: string) =>
InputContainers().where(Text.ofAll(Labels()), contain(text)).first();
I have parent cotainers which contain labels. I want to locate the first container, where it's label contains the given text.
This pattern worked before, but now I assume it does not work with the Text.ofAll
within the .where()
?
Error message is:
Argument of type 'Question<Promise<string[]>> & Adapter<string[]>' is not assignable to parameter of type 'MetaQuestion<PageElement<unknown>, string[] | Promise<string[]>>'.
Property 'of' is missing in type 'Question<Promise<string[]>> & Adapter<string[]>' but required in type 'MetaQuestion<PageElement<unknown>, string[] | Promise<string[]>>'.ts(2345)
MetaQuestion.d.ts(29, 5): 'of' is declared here.
Do you have an idea?
@jan-molak, a strange thing while migrating to 3.0:
Though my test runs (login to app, navigate to some feautre a simple Wait.for(Duration.ofSeconds(10))
throws this error:
User in role administrator navigates to feature
User in role administrator navigates to the episode feature: xxx
User in role administrator checks whether <<feature link for xxx>>.of(<<feature navigation bar>>.of(<<selected page>>)) does become visible
User in role administrator hovers the mouse over <<arrow icon which reveals more features>>.of(<<feature navigation bar>>.of(<<selected page>>)) (206ms)
User in role administrator clicks on <<arrow icon which reveals more features>>.of(<<feature navigation bar>>.of(<<selected page>>)) (85ms)
User in role administrator hovers the mouse over <<expanded menu>>.of(<<feature navigation bar>>.of(<<selected page>>)) (191ms)
User in role administrator clicks on <<feature link for xxx>>.of(<<expanded menu>>.of(<<feature navigation bar>>.of(<<selected page>>))) (153ms)
User in role administrator waits for 10s (0ms)
ConfigurationError: User in role administrator can't BrowseTheWeb yet. Did you give them the ability to do so?
Execution failed with error (6s 908ms)
ConfigurationError: User in role administrator can't BrowseTheWeb yet. Did you give them the ability to do so?
at Actor.abilityTo (C:\dev\git\xxx\e2e-serenityjs\node_modules\@serenity-js\core\src\screenplay\actor\Actor.ts:47:19)
at Function.as (C:\dev\git\xxx\e2e-serenityjs\node_modules\@serenity-js\web\src\screenplay\abilities\BrowseTheWeb.ts:18:22)
at C:\dev\git\xxx\e2e-serenityjs\node_modules\@serenity-js\web\src\screenplay\interactions\Wait.ts:184:44
I think my actor has the ability, how else the rest of the test shall run?
page.on('dialog')
, otherwise it just hangs. Dialogs are dismissed by defaultHi @jan-molak, me again with some testing result of Serenity/JS 3.x and back with my 'dialog' pattern :D
Remember that?
class Targets {
Dialogs = () => PageElements.located(By.css('.ui-dialog')).describedAs('visible modal dialogs');
DialogTitle = () => PageElement.located(By.css('.ui-dialog-title')).describedAs(`dialog title`);
DialogWithTitle = (dialogTitle: string) =>
this.Dialogs()
.where(Text.of(this.DialogTitle()), includes(dialogTitle))
.first();
}
Now, I wan't to check, whether there is a dialog with a special title and if so, click a button.
Check.whether(DiaglogWithTitle('DISCARD'), isVisible())
.andIfSo( Click.on(...))
This worked perfect with Serenity/JS 2.x (with Jasmine & Protractor & the targets) but now in 3.x (using mocha, wdio, devtools & page elements) I get:
LogicError: Can't retrieve the first item from a list with 0 items: [ ]
Why it makes sense logicaly, it introduces more logic into my tests: As workaround I now first check, if there are any dialogs at all ...
Check.whether(this.Dialogs().count(), isGreaterThan(0)).andIfSo(
Check.whether(DiaglogWithTitle('DISCARD'), isVisible()).andIfSo(
Click.on(...)
)
)
It's okay for me and just wanted you to know, just another point on my migration list...
Photographer.whoWill(TakePhotosOfInteractions)
in my config all is fine. With this setting, there is a lot of visible "flickering" each time a screenshot is taken (when not running in headless) mode.
if (config[key] !== null && config[key] !== undefined )
for line 62. However, I have some issue when doing make install of the repo in local.