Hey,
a site that I have to write tests for does not use any helpful ids or attributes that stay the same after each build process. I have no control over this so I am kind of forced to come up with a solution.
Is there a way to chain selectors because at least I could search for the text on the site and then go down the tree. The problem is that by having
static InsurangeBegin = Target.the('Insurance begin').located(by.cssContainingText('Insurance begin', 'label'));
I can only get to the input label and not the input itself.
Does anyone know what I could do without changing too much of all my tasks that I build prior to this website redesign?
It would really help to just being able to write
static InsurangeBegin = Target.the('Insurance begin').located(by.cssContainingText('Insurance begin', 'label').css('+ div > label'));
Or maybe something like this is already possible.
Hi @Ijee!
Chaining selectors might make the tests quite fragile (as you know), so I'd always start with trying to influence the people developing the app to make it more testable before resorting to that.
So now that we have the "word of warning" out of the way... you can do that with Serenity/JS v2 (available on NPM in alpha).
Here's how you'd do it:
import { Target } from '@serenity-js/protractor';
import { by } from 'protractor';
export class IncuranceWidget {
static InsuranceBegin = Target.the('insurance begin component').located(by.cssContainingText('label', 'Insurance begin');
static InsuranceBeginLabel = Target.the('label').of(IncuranceWidget.InsuranceBegin).located(by.css('+ div > label'));
}
The .of method receives the "parent" Target and creates a nested selector.
You can find an example project using Serenity/JS v2 on the 2.0 branch
Does this help?
Thank you for the quick reply.
Yeah, I still hope for them to change at least some part of the site but I kind of doubt it is going to happen anytime soon which is why I asked here.
I'll try out the new version as I had that planned for some time anyway. 馃憤
I'd still love to have a by.cssContainingText(text: string, locator | css-selector)
have the locator use the first specified html element so I could do
by.cssContainingText('insurance begin', 'label + div > span').
So it would try to find a label with the text 'insurance begin' inside + the specified css-selector that gets appended.
But I guess I'd have to go to the protractor repository to suggest that. Either way I can probably work around my problem.
Well... so there's this experimental Pick feature I've been working on, and by experimental I mean that it might change its API (or class name) to avoid a name conflict with TypeScript's Pick.
import { Pick, Target } from '@serenity-js/protractor';
import { by } from 'protractor';
export class IncuranceWidget {
// target all the labels
static InsuranceBeginLabels = Target.all('insurance begin component').located(by.cssContainingText('label', 'Insurance begin'));
// pick the first one
static FirstInsuranceBegin = Pick.from(IncuranceWidget.InsuranceBeginLabels).first();
// selector relative to the first label
static InsuranceBeginLabel = Target.the('label').of(IncuranceWidget.InsuranceBegin).located(by.css('+ div > label'));
}
Serenity/JS TodoApp demonstrates how to use Pick and relative Targets.
Let me know what you think!
Most helpful comment
Well... so there's this experimental
Pickfeature I've been working on, and by experimental I mean that it might change its API (or class name) to avoid a name conflict with TypeScript's Pick.