Permalink
Browse files

fix(screenplay): corrected the return type expected by the Question i…

…nterface

affects: @serenity-js/core, serenity-js

To define a question returning a synchronous answer make it implement Question<type>, for example:
Question<string>.
An asynchronous one should implement Question<PromiseLike<type>>, for example:
Question<PromiseLike<string>>

ISSUES CLOSED: #57
  • Loading branch information...
jan-molak committed Jun 11, 2017
1 parent 21485e3 commit 58ed941dd860e4d929a4949b3a3cf60583cb0a99
View
@@ -76,7 +76,7 @@
"ts-node": "2.1.0",
"tslint": "4.4.2",
"tslint-microsoft-contrib": "4.0.0",
"typescript": "2.1.6"
"typescript": "2.3.4"
},
"repository": {
"type": "git",
@@ -9,9 +9,9 @@ describe('Abilities', () => {
let notepad: Notepad;
const include = (expected: string) => (actual: string[]) => expect(actual).to.eventually.include(expected),
includeAllOf = (expected: string[]) => (actual: string[]) => expect(actual).to.eventually.include.members(expected),
equals = <T>(expected: T) => (actual: T) => expect(actual).to.eventually.equal(expected);
const include = (expected: string) => (actual: PromiseLike<string[]>): PromiseLike<void> => expect(actual).to.eventually.include(expected),
includeAllOf = (expected: string[]) => (actual: PromiseLike<string[]>): PromiseLike<void> => expect(actual).to.eventually.include.members(expected),
equals = <T>(expected: T) => (actual: PromiseLike<T>): PromiseLike<void> => expect(actual).to.eventually.equal(expected);
beforeEach(() => notepad = {});
@@ -99,33 +99,33 @@ describe('Abilities', () => {
});
});
class MyVoucherCode implements Question<string> {
class MyVoucherCode implements Question<PromiseLike<string>> {
static shownAs = (someValue: string) => new MyVoucherCode(someValue);
answeredBy = (actor: UsesAbilities) => Promise.resolve(this.value);
toString = () => 'My voucher code';
constructor(private value: string) {
}
}
class MyVoucherCodes implements Question<string[]> {
class MyVoucherCodes implements Question<PromiseLike<string[]>> {
static shownAs = (...someValues: string[]) => new MyVoucherCodes(someValues);
answeredBy = (actor: UsesAbilities) => Promise.resolve(this.values);
toString = () => 'My voucher codes';
constructor(private values: string[]) {
}
}
class AvailableVoucher implements Question<string> {
class AvailableVoucher implements Question<PromiseLike<string>> {
static of = (someValue: string) => new AvailableVoucher(someValue);
answeredBy = (actor: UsesAbilities) => Promise.resolve(this.value);
toString = () => 'Available voucher';
constructor(private value: string) {
}
}
class AvailableVouchers implements Question<string[]> {
class AvailableVouchers implements Question<PromiseLike<string[]>> {
static of = (...someValues: string[]) => new AvailableVouchers(someValues);
answeredBy = (actor: UsesAbilities) => Promise.resolve(this.values);
answeredBy = (actor: UsesAbilities): PromiseLike<string[]> => Promise.resolve(this.values);
toString = () => 'Available vouchers';
constructor(private values: string[]) {
}
@@ -133,7 +133,7 @@ describe('Screenplay Pattern', () => {
return new PerformASong(musicSheet);
}
performAs(actor: PerformsTasks): Promise<void> {
performAs(actor: PerformsTasks): PromiseLike<void> {
return actor.attemptsTo.apply(actor, this.playThe(this.musicSheet.chords));
}
@@ -149,7 +149,7 @@ describe('Screenplay Pattern', () => {
return new PlayAChord(chord);
}
performAs(actor: UsesAbilities): Promise<void> {
performAs(actor: UsesAbilities): PromiseLike<void> {
return PlayAnInstrument.as(actor).play(this.chord);
}
@@ -163,17 +163,17 @@ describe('Screenplay Pattern', () => {
return new NumberOfGuitarStrings();
}
answeredBy(actor: UsesAbilities): Promise<number>|number {
answeredBy(actor: UsesAbilities): number {
return 6;
}
}
interface Instrument {
play(chord: Chord): Promise<any>;
play(chord: Chord): PromiseLike<any>;
}
class AcousticGuitar implements Instrument {
play(chord: Chord): Promise<any> {
play(chord: Chord): PromiseLike<any> {
// use some "guitar driver" to play the chord on the "real guitar"
return Promise.resolve();
}
@@ -208,7 +208,7 @@ describe('Screenplay Pattern', () => {
*
* @param chord
*/
play(chord: Chord): Promise<void> {
play(chord: Chord): PromiseLike<void> {
return this.instrument.play(chord);
}
@@ -70,7 +70,7 @@ export class Actor implements PerformsTasks, UsesAbilities, AnswersQuestions {
}, Promise.resolve(null));
}
toSee<T>(question: Question<T>): PromiseLike<T>|T {
toSee<T>(question: Question<T>): T {
return question.answeredBy(this);
}
@@ -1,2 +1,4 @@
export type Assertion<T> = (actual: T) => PromiseLike<void>;
export type Expectation<T> = (expected: T) => Assertion<T>;
import { OneOrMany } from './lists';
export type Assertion<A> = (actual: A) => PromiseLike<void>;
export type Expectation<E, A extends PromiseLike<OneOrMany<E>> | OneOrMany<E>> = (expected: OneOrMany<E>) => Assertion<A>;
@@ -5,9 +5,13 @@ import { Expectation } from '../expectations';
import { OneOrMany } from '../lists';
import { Question } from '../question';
export class CompareNotes<S> implements Interaction {
static toSeeIf<A>(actual: Question<OneOrMany<A>>, expectation: Expectation<OneOrMany<A>>, topic: { toString: () => string }) {
return new CompareNotes<A>(actual, expectation, topic.toString());
export class CompareNotes<Expected, Actual extends PromiseLike<OneOrMany<Expected>> | OneOrMany<Expected>> implements Interaction {
static toSeeIf<E, A extends PromiseLike<OneOrMany<E>> | OneOrMany<E>>(
question: Question<A>,
expectation: Expectation<E, A>,
topic: { toString: () => string },
) {
return new CompareNotes(question, expectation, topic.toString());
}
performAs(actor: UsesAbilities & AnswersQuestions): PromiseLike<void> {
@@ -17,7 +21,7 @@ export class CompareNotes<S> implements Interaction {
then(expected => this.expect(expected)(actor.toSee(this.actual)));
}
constructor(private actual: Question<OneOrMany<S>>, private expect: Expectation<OneOrMany<S>>, private topic: string) {
constructor(private actual: Question<Actual>, private expect: Expectation<Expected, Actual>, private topic: string) {
}
toString = () => `{0} compares notes on ${this.subject()}`;
@@ -1,5 +1,5 @@
import { UsesAbilities } from './actor';
export interface Question<T> {
answeredBy(actor: UsesAbilities): PromiseLike<T>|T;
answeredBy(actor: UsesAbilities): T;
}
@@ -8,8 +8,8 @@ describe('Tasks', () => {
describe('See', () => {
class SomeResult implements Question<string> {
answeredBy(actor: UsesAbilities): PromiseLike<string>|string {
class SomeResult implements Question<PromiseLike<string>> {
answeredBy(actor: UsesAbilities): PromiseLike<string> {
return Promise.resolve('some value');
}
}
@@ -6,11 +6,11 @@ import { Target } from '../ui/target';
export class Attribute {
static of = (target: Target) => ({
called: (name: string): Question<string> => new AttributeValue(target, name),
called: (name: string): Question<PromiseLike<string>> => new AttributeValue(target, name),
})
}
class AttributeValue implements Question<string> {
class AttributeValue implements Question<PromiseLike<string>> {
answeredBy(actor: UsesAbilities): PromiseLike<string> {
return BrowseTheWeb.as(actor).locate(this.target).getAttribute(this.attribute);
@@ -3,7 +3,7 @@ import { Question, UsesAbilities } from '@serenity-js/core/lib/screenplay';
import { BrowseTheWeb } from '../abilities/browse_the_web';
import { Target } from '../ui/target';
export class SelectedValue implements Question<string> {
export class SelectedValue implements Question<PromiseLike<string>> {
static of = (target: Target) => new SelectedValue(target);
answeredBy(actor: UsesAbilities): PromiseLike<string> {
@@ -16,7 +16,7 @@ export class SelectedValue implements Question<string> {
toString = () => `the selected value of ${ this.target }`;
}
export class SelectedValues implements Question<string> {
export class SelectedValues implements Question<PromiseLike<string>> {
static of(target: Target) {
return new SelectedValues(target);
}
@@ -4,11 +4,11 @@ import { BrowseTheWeb } from '../abilities/browse_the_web';
import { Target } from '../ui/target';
export class Text {
static of = (element: Target): Question<string> => new TextOf(element);
static ofAll = (elements: Target): Question<string[]> => new TextOfAll(elements);
static of = (element: Target): Question<PromiseLike<string>> => new TextOf(element);
static ofAll = (elements: Target): Question<PromiseLike<string[]>> => new TextOfAll(elements);
}
class TextOf implements Question<string> {
class TextOf implements Question<PromiseLike<string>> {
answeredBy(actor: UsesAbilities): PromiseLike<string> {
return BrowseTheWeb.as(actor).locate(this.target).getText();
@@ -20,7 +20,7 @@ class TextOf implements Question<string> {
toString = () => `the text of ${ this.target}`;
}
class TextOfAll implements Question<string[]> {
class TextOfAll implements Question<PromiseLike<string[]>> {
answeredBy(actor: UsesAbilities): PromiseLike<string[]> {
// protractor ignores type definitions for the ElementArrayFinder
@@ -3,7 +3,7 @@ import { Question, UsesAbilities } from '@serenity-js/core/lib/screenplay';
import { Target } from '../ui/target';
import { Attribute } from './attribute';
export class Value implements Question<string> {
export class Value implements Question<PromiseLike<string>> {
static of = (target: Target) => new Value(target);
@@ -2,10 +2,10 @@ import { Question, UsesAbilities } from '@serenity-js/core/lib/screenplay';
import { BrowseTheWeb } from '../abilities/browse_the_web';
export class Website {
static title = (): Question<string> => new WebsiteTitle();
static title = (): Question<PromiseLike<string>> => new WebsiteTitle();
}
class WebsiteTitle implements Question<string> {
class WebsiteTitle implements Question<PromiseLike<string>> {
answeredBy(actor: UsesAbilities): PromiseLike<string> {
return BrowseTheWeb.as(actor).getTitle();

0 comments on commit 58ed941

Please sign in to comment.