Skip to content
Permalink
Browse files
feat(assertions): Pick allows to filter the answers to a Question
  • Loading branch information
jan-molak committed Feb 20, 2019
1 parent 1e4ac7d commit 4307966be395b5427e89d3f2c6001de37393280c
@@ -0,0 +1,203 @@
import 'mocha';

import { Actor, Question } from '@serenity-js/core';

import { expect } from '@integration/testing-tools';
import { given } from 'mocha-testdata';
import { equals, NoAnswerFound, Pick, startsWith } from '../src';

describe('Pick', () => {

const Alexandra = Actor.named('Alexandra');

interface Animal {
name: string;
sound: string;
}

const animals = [
{
name: 'bird',
sound: 'tweet',
},
{
name: 'dog',
sound: 'woof',
},
{
name: 'tiger',
sound: 'roar',
},
{
name: 'dinosaur',
sound: 'roar',
},
];

const Sound = {
of: (animal: Animal) => Question.about<string>(`the sound a ${ animal.name } makes`, actor => animal.sound),
};

const Name = {
of: (animal: Animal) => Question.about<string>(`the name of an animal`, actor => animal.name),
};

const AsyncName = {
of: (animal: Animal) => Question.about<Promise<string>>(`the name of a ${ animal.name }`, actor => Promise.resolve(animal.name)),
};

describe('when no filters are applied', () => {

const picked = Pick.from(q(p(animals)));

it('knows how many answers there are in the list', () =>
expect(picked.count().answeredBy(Alexandra)).to.eventually.equal(animals.length));

it('picks all answers from the list', () =>
expect(picked.all().answeredBy(Alexandra)).to.eventually.deep.equal(animals));

it('picks the first answer from the list', () =>
expect(picked.first().answeredBy(Alexandra)).to.eventually.deep.equal(animals[ 0 ]));

it('picks the last answer from the list', () =>
expect(picked.last().answeredBy(Alexandra)).to.eventually.deep.equal(animals[ animals.length - 1 ]));

it('picks the nth answer from the list', () =>
expect(picked.get(1).answeredBy(Alexandra)).to.eventually.deep.equal(animals[ 1 ]));
});

describe('when a filter is applied', () => {

const
picked = Pick.from(q(p(animals))).where(Sound.of, equals('roar')),
expected = animals.filter(a => a.sound === 'roar');

it('knows how many answers there are in the list', () =>
expect(picked.count().answeredBy(Alexandra)).to.eventually.equal(expected.length));

it('picks all answers from the list', () =>
expect(picked.all().answeredBy(Alexandra)).to.eventually.deep.equal(expected));

it('picks the first answer from the list', () =>
expect(picked.first().answeredBy(Alexandra)).to.eventually.deep.equal(expected[ 0 ]));

it('picks the last answer from the list', () =>
expect(picked.last().answeredBy(Alexandra)).to.eventually.deep.equal(expected[ expected.length - 1 ]));

it('picks the nth answer from the list', () =>
expect(picked.get(1).answeredBy(Alexandra)).to.eventually.deep.equal(expected[ 1 ]));
});

describe('when multiple filters are applied', () => {

const
picked = Pick.from(q(p(animals))).where(Sound.of, equals('roar')).where(Name.of, startsWith('tig')),
expected = [ { name: 'tiger', sound: 'roar' } ];

it('knows how many answers there are in the list', () =>
expect(picked.count().answeredBy(Alexandra)).to.eventually.equal(expected.length));

it('picks all answers from the list', () =>
expect(picked.all().answeredBy(Alexandra)).to.eventually.deep.equal(expected));

it('picks the first answer from the list', () =>
expect(picked.first().answeredBy(Alexandra)).to.eventually.deep.equal(expected[ 0 ]));

it('picks the last answer from the list', () =>
expect(picked.last().answeredBy(Alexandra)).to.eventually.deep.equal(expected[ expected.length - 1 ]));

it('picks the nth answer from the list', () =>
expect(picked.get(0).answeredBy(Alexandra)).to.eventually.deep.equal(expected[ 0 ]));
});

describe('when both sync and async filters are applied', () => {

const
picked = Pick.from(q(p(animals))).where(Sound.of, equals('roar')).where(AsyncName.of, startsWith('tig')),
expected = [ { name: 'tiger', sound: 'roar' } ];

it('knows how many answers there are in the list', () =>
expect(picked.count().answeredBy(Alexandra)).to.eventually.equal(expected.length));

it('picks all answers from the list', () =>
expect(picked.all().answeredBy(Alexandra)).to.eventually.deep.equal(expected));

it('picks the first answer from the list', () =>
expect(picked.first().answeredBy(Alexandra)).to.eventually.deep.equal(expected[ 0 ]));

it('picks the last answer from the list', () =>
expect(picked.last().answeredBy(Alexandra)).to.eventually.deep.equal(expected[ expected.length - 1 ]));

it('picks the nth answer from the list', () =>
expect(picked.get(0).answeredBy(Alexandra)).to.eventually.deep.equal(expected[ 0 ]));
});

describe('provides a sensible description', () => {

describe('when no filters are applied and Pick', () => {

const picked = Pick.from(q(p(animals)));

it('returns the number of answers', () =>
expect(picked.count().toString()).to.equal('number of the animals'));

it('picks all the items', () =>
expect(picked.all().toString()).to.equal('all of the animals'));

it('picks the first item', () =>
expect(picked.first().toString()).to.equal('first of the animals'));

it('picks the last item', () =>
expect(picked.last().toString()).to.equal('last of the animals'));

given([
{ description: '1st', index: 0 },
{ description: '2nd', index: 1 },
{ description: '3rd', index: 2 },
{ description: '4th', index: 3 },
{ description: '5th', index: 4 },
{ description: '10th', index: 9 },
{ description: '11th', index: 10 },
{ description: '20th', index: 19 },
{ description: '42nd', index: 41 },
{ description: '115th', index: 114 },
{ description: '1522nd', index: 1521 },

]).
it('picks the nth item', ({ description, index }) => {

const question = Question.about<string[]>('the alphabet letters', actor => 'abcdefghijklmnopqrstuvwxyz'.split(''));

expect(Pick.from(question).get(index).toString()).to.equal(`${ description } of the alphabet letters`);
});
});
});

describe('when there are no answers', () => {

const picked = Pick.from(q([]));

it('complains when you try to access the first one', () =>
expect(picked.first().answeredBy(Alexandra)).to.eventually.be.rejectedWith(NoAnswerFound, `There's no first of the animals`));

it('complains when you try to access the last one', () =>
expect(picked.last().answeredBy(Alexandra)).to.eventually.be.rejectedWith(NoAnswerFound, `There's no last of the animals`));

it('complains when you try to access the nth one', () =>
expect(picked.get(1).answeredBy(Alexandra)).to.eventually.be.rejectedWith(NoAnswerFound, `There's no 2nd of the animals`));

it('returns a count of 0', () =>
expect(picked.count().answeredBy(Alexandra)).to.eventually.equal(0));

it('returns an empty list when asked for all the answers', () =>
expect(picked.all().answeredBy(Alexandra)).to.eventually.deep.equal([]));
});

function p<T>(value: T) {
return Promise.resolve(value);
}

function q<T>(value: T): Question<T> {
return Question.about(`the animals`, actor => value);
}
});
@@ -1,8 +1,7 @@
import { Activity, AnswersQuestions, KnowableUnknown, PerformsTasks, Task } from '@serenity-js/core';
import { formatted } from '@serenity-js/core/lib/io';
import { match } from 'tiny-types';
import { Expectation } from './Expectation';
import { ExpectationMet, ExpectationNotMet, Outcome } from './outcomes';
import { ExpectationMet } from './outcomes';

export class Check<Actual> implements Task {
static whether<A>(actual: KnowableUnknown<A>, expectation: Expectation<any, A>) {
@@ -29,10 +28,9 @@ export class Check<Actual> implements Task {
actor.answer(this.expectation),
]).then(([actual, expectation]) =>
expectation(actual).then(outcome =>
match<Outcome<any, Actual>, void>(outcome)
.when(ExpectationMet, o => actor.attemptsTo(...this.activities))
.when(ExpectationNotMet, o => actor.attemptsTo(...this.alternativeActivities))
.else(_ => void 0),
outcome instanceof ExpectationMet
? actor.attemptsTo(...this.activities)
: actor.attemptsTo(...this.alternativeActivities),
),
);
}

0 comments on commit 4307966

Please sign in to comment.