Permalink
Browse files

fix(protractor): a Target's name can use the "{0}" token, same as the…

… locator

affects: serenity-js
  • Loading branch information...
jan-molak committed May 13, 2017
1 parent 8d7edbd commit 6a0329100baf934f6f4762f85d033ea8ee1c929d
@@ -32,6 +32,12 @@ describe ('Target', () => {
expect(target.called('"Sign Up" button').toString()).to.equal('the "Sign Up" button');
});
it ('can have its name resolved at a later stage', () => {
const target = Target.the('"{0}" button').located(byLocator);
expect(target.of('Sign Up').toString()).to.equal('the "Sign Up" button');
});
it ('can have a CSS locator defined using tokens to be resolved at a later stage', () => {
const
byLocatorTemplate = webdriver.By.css('{0}#sign-up.{1}'),
@@ -86,12 +92,4 @@ describe ('Target', () => {
target.of('some-replacement');
}).to.throw('by.model("checkbox") is not a webdriver-compatible locator so you won\'t be able to use token replacement with it');
});
describe ('TargetBuilder', () => {
it ('is easy to identify', () => {
const target = Target.the('sign up form');
expect(target.toString()).to.equal('TargetBuilder for the sign up form');
});
});
});
@@ -1,14 +1,15 @@
import { ElementArrayFinder, ElementFinder } from 'protractor';
import { Locator } from 'protractor/built/locators';
import { describeAs } from '../../../serenity/recording/activity_description';
export class Target {
static the(name: string) {
return new TargetBuilder(name);
}
static the = (name: string) => ({
located: (byLocator: Locator): Target => new Target(name, byLocator),
})
of(...tokenReplacements: string[]): Target {
return new Target(this.name, new Interpolated(this.locator).with(tokenReplacements));
return new Target(describeAs(this.name, ...tokenReplacements), new Interpolated(this.locator).with(tokenReplacements));
}
called(newName: string): Target {
@@ -38,6 +39,9 @@ class Interpolated {
public with(tokenReplacements: string[]) {
const unescaped = template => template.replace(/\\{(\d+)\\}/, '{$1}');
const asString = (locator: Locator): string => unescaped(`${(locator as any).value}`);
// note: ProtractorBy is not compatible with WebdriverBy https://github.com/angular/protractor/issues/3508
if (! this.canBeInterpolated()) {
throw new Error(this.locator.toString() +
@@ -46,34 +50,10 @@ class Interpolated {
const cloned: any = Object.assign({}, this.locator);
cloned.__proto__ = Object.getPrototypeOf(this.locator);
cloned.value = this.interpolated((this.locator as any).value, tokenReplacements);
cloned.value = describeAs(asString(this.locator), ...tokenReplacements);
return cloned;
}
private canBeInterpolated(): boolean {
return !! (this.locator as any).value;
}
private interpolated(template: string, replacements: string[]) {
const
argToken = /\\?\{(\d+)\\?\}/g,
interpolator = (token: string, field: number) => replacements[ field ];
return template.replace(argToken, interpolator);
}
}
export class TargetBuilder {
constructor(private name: string) {
}
located(byLocator: Locator): Target {
return new Target(this.name, byLocator);
}
toString(): string {
return `TargetBuilder for the ${ this.name }`;
}
private canBeInterpolated = (): boolean => !! (this.locator as any).value;
}
@@ -13,9 +13,14 @@ export function describeAs(template: string, ...parameters: any[]): string {
const first: any = parameters[0];
switch (true) {
case parameters.length > 1: return interpolateArguments(template, parameters);
case isActor(first): return includeActorName(interpolateArguments(template, parameters), first);
default: return interpolateFields(template, first);
case parameters.length > 1 || typeof first !== 'object':
return interpolateArguments(template, parameters);
case isActor(first):
return includeActorName(interpolateArguments(template, parameters), first);
default:
return interpolateFields(template, first);
}
}

0 comments on commit 6a03291

Please sign in to comment.