SlideShare uma empresa Scribd logo
1 de 97
serenity-js.org#SerenityJS @JanMolak
Testing Angular apps.

At scale.
serenity-js.org#SerenityJS @JanMolak
Jan Molakconsultant, trainer, lead developer of Serenity/JS
serenity-js.org#SerenityJS @JanMolak
serenity-js.org#SerenityJS @JanMolak
serenity-js.org#SerenityJS @JanMolak
We ❤ E2E
serenity-js.org#SerenityJS @JanMolak
We 💔 E2E
(said no one ever)
serenity-js.org#SerenityJS @JanMolak
Execution time: minutes → hours
serenity-js.org#SerenityJS @JanMolak
Execution time: minutes → hours
Writing: hours → days
serenity-js.org#SerenityJS @JanMolak
Execution time: minutes → hours
Writing: hours → days
Analysis and reporting: hours → days
serenity-js.org#SerenityJS @JanMolak
Execution time: minutes → hours
Writing: hours → days
Analysis and reporting: hours → days
Maintenance: days → weeks
serenity-js.org#SerenityJS @JanMolak
The difference between

scalable tests 

and a world of pain

is design.
serenity-js.org#SerenityJS @JanMolak
Testing the Journey Planner
serenity-js.org#SerenityJS @JanMolak
serenity-js.org#SerenityJS @JanMolak
When a commuter wants to travel 

from Waterloo to Canary Wharf 

around 9:00 AM they should be told 

about the 8:59 AM Jubilee Line train.
serenity-js.org#SerenityJS @JanMolak
Open the Journey Planner
serenity-js.org#SerenityJS @JanMolak
Open the Journey Planner

Choose origin: Waterloo
serenity-js.org#SerenityJS @JanMolak
Open the Journey Planner

Choose origin: Waterloo
Enter “Waterloo”
serenity-js.org#SerenityJS @JanMolak
Open the Journey Planner

Choose origin: Waterloo
Enter “Waterloo”
Pick the first suggestion
serenity-js.org#SerenityJS @JanMolak
Open the Journey Planner

Choose origin: Waterloo
Enter “Waterloo”
Pick the first suggestion
Wait for the suggestions
serenity-js.org#SerenityJS @JanMolak
Open the Journey Planner

Choose origin: Waterloo
Enter “Waterloo”
Pick the first suggestion
Wait for the suggestions
Press ▼
serenity-js.org#SerenityJS @JanMolak
Open the Journey Planner

Choose origin: Waterloo
Enter “Waterloo”
Pick the first suggestion
Wait for the suggestions
Press ▼

Press ↩
serenity-js.org#SerenityJS @JanMolak
Open the Journey Planner

Choose origin: Waterloo
Enter “Waterloo”
Pick the first suggestion
Wait for the suggestions
Press ▼

Press ↩
serenity-js.org#SerenityJS @JanMolak
Open the Journey Planner

Choose origin: Waterloo
serenity-js.org#SerenityJS @JanMolak
Open the Journey Planner

Choose origin: Waterloo
Choose destination: Canary Wharf
serenity-js.org#SerenityJS @JanMolak
Open the Journey Planner

Choose origin: Waterloo
Choose destination: Canary Wharf
serenity-js.org#SerenityJS @JanMolak
Open the Journey Planner

Choose origin: Waterloo
Choose destination: Canary Wharf
Choose time of departure: 9:00 AM
serenity-js.org#SerenityJS @JanMolak
Open the Journey Planner

Choose origin: Waterloo
Choose destination: Canary Wharf
Choose time of departure: 9:00 AM
Click on the “change time” link
serenity-js.org#SerenityJS @JanMolak
Open the Journey Planner

Choose origin: Waterloo
Choose destination: Canary Wharf
Choose time of departure: 9:00 AM
Click on the “change time” link
Click on the “Leaving” button
serenity-js.org#SerenityJS @JanMolak
Open the Journey Planner

Choose origin: Waterloo
Choose destination: Canary Wharf
Choose time of departure: 9:00 AM
Click on the “change time” link
Click on the “Leaving” button
Select “09:00”
serenity-js.org#SerenityJS @JanMolak
Open the Journey Planner

Choose origin: Waterloo
Choose destination: Canary Wharf
Choose time of departure: 9:00 AM
serenity-js.org#SerenityJS @JanMolak
Open the Journey Planner

Choose origin: Waterloo
Choose destination: Canary Wharf
Choose time of departure: 9:00 AM
Confirm selection
serenity-js.org#SerenityJS @JanMolak
Open the Journey Planner

Choose origin: Waterloo
Choose destination: Canary Wharf
Choose time of departure: 9:00 AM
Confirm selection
Click on the “Plan my journey”
serenity-js.org#SerenityJS @JanMolak
Open the Journey Planner

Choose origin: Waterloo
Choose destination: Canary Wharf
Choose time of departure: 9:00 AM
Confirm selection
Click on the “Plan my journey”
Wait for the results to load
serenity-js.org#SerenityJS @JanMolak
Open the Journey Planner

Choose origin: Waterloo
Choose destination: Canary Wharf
Choose time of departure: 9:00 AM
Confirm selection
serenity-js.org#SerenityJS @JanMolak
Open the Journey Planner

Choose origin: Waterloo
Choose destination: Canary Wharf
Choose time of departure: 9:00 AM
Confirm selection
See a Jubilee Line train at 08:59
serenity-js.org#SerenityJS @JanMolak
At a high level,
it’s just 6 tasks
serenity-js.org#SerenityJS @JanMolak
Scripting the flow
serenity-js.org#SerenityJS @JanMolak
“Use Protractor to write and run the e2e tests.

End-to-end tests explore the application

as users experience it.
Protractor makes your scenario tests run
faster and in a stable manner. 
- Angular website
serenity-js.org#SerenityJS @JanMolak
const	
		origin																	=	element(by.id(‘…’)),	
		originSuggestions						=	element(by.xpath(‘…’)),	
		destination												=	element(by.id(‘…’)),	
		destinationSuggestions	=	element(by.xpath(‘…’)),	
		changeTimeLink									=	element(by.linkText(‘…’)),	
		leavingButton										=	element(by.css(‘…’)),	
		timeSelector											=	element(by.id(‘…’)),	
		planMyJourneyButton				=	element(by.buttonText(‘…’)),	
		journeyResults									=	element(by.css(‘…’)),	
		fastestJourney									=	element(by.css(‘…’));
serenity-js.org#SerenityJS @JanMolak
browser.get('https://tfl.gov.uk/');
serenity-js.org#SerenityJS @JanMolak
browser.get('https://tfl.gov.uk/');	
origin.sendKeys('Waterloo');
serenity-js.org#SerenityJS @JanMolak
browser.get('https://tfl.gov.uk/');	
origin.sendKeys('Waterloo');	
browser.wait(

	EC.visibilityOf(originSuggestions),	5000);
serenity-js.org#SerenityJS @JanMolak
browser.get('https://tfl.gov.uk/');	
origin.sendKeys('Waterloo');	
browser.wait(

	EC.visibilityOf(originSuggestions),	5000);	
origin.sendKeys(protractor.Key.ARROW_DOWN);	
origin.sendKeys(protractor.Key.ENTER);
serenity-js.org#SerenityJS @JanMolak
browser.get('https://tfl.gov.uk/');	
origin.sendKeys('Waterloo');	
browser.wait(

	EC.visibilityOf(originSuggestions),	5000);	
origin.sendKeys(protractor.Key.ARROW_DOWN);	
origin.sendKeys(protractor.Key.ENTER);	
destination.sendKeys('Canary	Wharf');	
browser.wait(

	EC.visibilityOf(destinationSuggestions),	5000);	
destination.sendKeys(protractor.Key.ARROW_DOWN);	
destination.sendKeys(protractor.Key.ENTER);
serenity-js.org#SerenityJS @JanMolak
changeTimeLink.click();	
leavingButton.click();	
timeSelector.element(

		by.cssContainingText('option',	'09:00')

).click();
serenity-js.org#SerenityJS @JanMolak
changeTimeLink.click();	
leavingButton.click();	
timeSelector.element(

		by.cssContainingText('option',	'09:00')

).click();	
planMyJourneyButton.click();	
browser.wait(EC.visibilityOf(journeyResults),	5000);
serenity-js.org#SerenityJS @JanMolak
fastestJourney.getText()	
				.then(journeyDetailsFromText)	
				.then(option	=>	{	
								expect(option).to.deep.equal({	
												line:							'Jubilee',	
												departs_at:	'08:59',	
								});	
			});
serenity-js.org#SerenityJS @JanMolak
cost	
		origin																	=	element(by.id(‘…’)),	
		originSuggestions						=	element(by.xpath(‘…’)),	
		destination												=	element(by.id(‘…’)),	
		destinationSuggestions	=	element(by.xpath(‘…’)),	
		changeTimeLink									=	element(by.linkText(‘…’)),	
		leavingButton										=	element(by.css(‘…’)),	
		timeSelector											=	element(by.id(‘…’)),	
		planMyJourneyButton				=	element(by.buttonText(‘…’)),	
		journeyResults									=	element(by.css(‘…’)),	
		fastestJourney									=	element(by.css(‘…’));	


browser.get('https://tfl.gov.uk/');	
origin.sendKeys('Waterloo');	
browser.wait(

	EC.visibilityOf(originSuggestions),	5000);	
origin.sendKeys(protractor.Key.ARROW_DOWN);	
origin.sendKeys(protractor.Key.ENTER);	
destination.sendKeys('Canary	Wharf');	
browser.wait(

	EC.visibilityOf(destinationSuggestions),	5000);	
destination.sendKeys(protractor.Key.ARROW_DOWN);	
destination.sendKeys(protractor.Key.ENTER);	
changeTimeLink.click();	
leavingButton.click();	
timeSelector.element(

		by.cssContainingText('option',	'09:00')

).click();	
planMyJourneyButton.click();	
browser.wait(EC.visibilityOf(journeyResults),	5000);	
fastestJourney.getText()	
				.then(journeyDetailsFromText)	
				.then(option	=>	{	
								expect(option).to.deep.equal({	
												line:							‘Jubilee',	
												departs_at:	'08:59',	
								});	
6 tasks ?
serenity-js.org#SerenityJS @JanMolak
cost	
		origin																	=	element(by.id(‘…’)),	
		originSuggestions						=	element(by.xpath(‘…’)),	
		destination												=	element(by.id(‘…’)),	
		destinationSuggestions	=	element(by.xpath(‘…’)),	
		changeTimeLink									=	element(by.linkText(‘…’)),	
		leavingButton										=	element(by.css(‘…’)),	
		timeSelector											=	element(by.id(‘…’)),	
		planMyJourneyButton				=	element(by.buttonText(‘…’)),	
		journeyResults									=	element(by.css(‘…’)),	
		fastestJourney									=	element(by.css(‘…’));	


browser.get('https://tfl.gov.uk/');	
origin.sendKeys('Waterloo');	
browser.wait(

	EC.visibilityOf(originSuggestions),	5000);	
origin.sendKeys(protractor.Key.ARROW_DOWN);	
origin.sendKeys(protractor.Key.ENTER);	
destination.sendKeys('Canary	Wharf');	
browser.wait(

	EC.visibilityOf(destinationSuggestions),	5000);	
destination.sendKeys(protractor.Key.ARROW_DOWN);	
destination.sendKeys(protractor.Key.ENTER);	
changeTimeLink.click();	
leavingButton.click();	
timeSelector.element(

		by.cssContainingText('option',	'09:00')

).click();	
planMyJourneyButton.click();	
browser.wait(EC.visibilityOf(journeyResults),	5000);	
fastestJourney.getText()	
				.then(journeyDetailsFromText)	
				.then(option	=>	{	
								expect(option).to.deep.equal({	
												line:							‘Jubilee',	
												departs_at:	'08:59',	
								});	
6 tasks buried in
36 lines of noise
serenity-js.org#SerenityJS @JanMolak
“If you have WebDriver APIs
in your test methods,
You’re Doing It Wrong!
- Simon Stewart, creator of WebDriver
serenity-js.org#SerenityJS @JanMolak
A test system needs design
serenity-js.org#SerenityJS @JanMolak
Page Objects to the rescue?
serenity-js.org#SerenityJS @JanMolak
serenity-js.org#SerenityJS @JanMolak
class	JourneyPlanner	{	
		//	Locators	
		//	Actions	
}
serenity-js.org#SerenityJS @JanMolak
class	JourneyPlanner	{	


		//	Locators	
		private	originField												=	by.id('...');	
		private	originSuggestions						=	by.xpath('...');	
		private	destinationField							=	by.id('...');	
		private	destinationSuggestions	=	by.xpath('...');	
		private	changeTimeLink									=	by.linkText('...');	
		private	leavingButton										=	by.css('...');	
		private	timeSelector											=	by.id('...');	
		private	planMyJourneyButton				=	by.buttonText('...');
serenity-js.org#SerenityJS @JanMolak
class	JourneyPlanner	{	


		//	Actions	
		chooseOriginOf(origin:	string)	{	
				element(this.originField).sendKeys(origin);										

				browser.wait(…);

				element(this.originField).sendKeys(…);	
				element(this.originField).sendKeys(…);	
		}	
		chooseDestinationOf(destination:	string)	{	…	}

		chooseTimeOfDeparture(time:	string)	{	…	}	
		confirmSelection()	{	…	}
serenity-js.org#SerenityJS @JanMolak
const	journeyPlanner	=	new	JourneyPlanner();

serenity-js.org#SerenityJS @JanMolak
const	journeyPlanner	=	new	JourneyPlanner();

journeyPlanner.get();	
journeyPlanner.chooseOriginOf('Waterloo');	
journeyPlanner.chooseDestinationOf('Canary	Wharf');	
journeyPlanner.chooseTimeOfDeparture('09:00');	
journeyPlanner.confirmSelection();
serenity-js.org#SerenityJS @JanMolak
const	journeyPlanner	=	new	JourneyPlanner();

journeyPlanner.get();	
journeyPlanner.chooseOriginOf('Waterloo');	
journeyPlanner.chooseDestinationOf('Canary	Wharf');	
journeyPlanner.chooseTimeOfDeparture('09:00');	
journeyPlanner.confirmSelection();	
const	journeyResults	=	new	JourneyResults();
serenity-js.org#SerenityJS @JanMolak
const	journeyPlanner	=	new	JourneyPlanner();

journeyPlanner.get();	
journeyPlanner.chooseOriginOf('Waterloo');	
journeyPlanner.chooseDestinationOf('Canary	Wharf');	
journeyPlanner.chooseTimeOfDeparture('09:00');	
journeyPlanner.confirmSelection();	
const	journeyResults	=	new	JourneyResults();	
expect(journeyResults.fastestTrain())

		.to.eventually.deep.equal({	line:	‘Jubilee’,	…})
serenity-js.org#SerenityJS @JanMolak
const	journeyPlanner	=	new	JourneyPlanner();

journeyPlanner.get();	
journeyPlanner.chooseOriginOf('Waterloo');	
journeyPlanner.chooseDestinationOf('Canary	Wharf');	
journeyPlanner.chooseTimeOfDeparture('09:00');	
journeyPlanner.confirmSelection();	
const	journeyResults	=	new	JourneyResults();	
expect(journeyResults.fastestOption())

		.to.eventually.deep.equal({	line:	‘Jubilee’,	…})
not bad!
serenity-js.org#SerenityJS @JanMolak
const	journeyPlanner	=	new	JourneyPlanner();

journeyPlanner.get();	
journeyPlanner.chooseOriginOf('Waterloo');	
journeyPlanner.chooseDestinationOf('Canary	Wharf');	
journeyPlanner.chooseTimeOfDeparture('09:00');	
journeyPlanner.confirmSelection();	
const	journeyResults	=	new	JourneyResults();	
expect(journeyResults.fastestOption())

		.to.eventually.deep.equal({	line:	‘Jubilee’,	…})
not bad?
serenity-js.org#SerenityJS @JanMolak
class	JourneyPlanner	{	
		private	originField												=	by.id('...');	
		private	originSuggestions						=	by.xpath('...');	
		private	destinationField							=	by.id('...');	
		private	destinationSuggestions	=	by.xpath('...');	
		private	changeTimeLink									=	by.linkText('...');	
		private	leavingButton										=	by.css('...');	
		private	timeSelector											=	by.id('...');

		private	planMyJourneyButton				=	by.buttonText('...');

					
		get	=	()	=>	browser.get('https://tfl.gov.uk/');	
		chooseOriginOf(origin:	string)	{	
				element(this.originField).sendKeys(origin);										

				browser.wait(…);

				element(this.originField).sendKeys(…);	
				element(this.originField).sendKeys(…);	
		}	
		chooseDestinationOf(destination:	string)	{	
				element(this.destinationField).sendKeys(destination);	
				browser.wait(…);										

				element(this.destinationField).sendKeys(…);									

				element(this.destinationField).sendKeys(…);	
		}

		changeJourneyTime()	{	
				element(this.changeTimeLink).click();	
		}

		chooseTimeOfDeparture(time)	{	
				element(this.leavingButton).click();	
				element(this.timeSelector).element(…).click();	
		}	
		confirmSelection()	{	
				element(this.planMyJourneyButton).click();

		}

large classes
serenity-js.org#SerenityJS @JanMolak
class	JourneyPlanner	{	
		private	originField												=	by.id('...');	
		private	originSuggestions						=	by.xpath('...');	
		private	destinationField							=	by.id('...');	
		private	destinationSuggestions	=	by.xpath('...');	
		private	changeTimeLink									=	by.linkText('...');	
		private	leavingButton										=	by.css('...');	
		private	timeSelector											=	by.id('...');

		private	planMyJourneyButton				=	by.buttonText('...');

					
		get	=	()	=>	browser.get('https://tfl.gov.uk/');	
		chooseOriginOf(origin:	string)	{	
				element(this.originField).sendKeys(origin);										

				browser.wait(…);

				element(this.originField).sendKeys(…);	
				element(this.originField).sendKeys(…);	
		}	
		chooseDestinationOf(destination:	string)	{	
				element(this.destinationField).sendKeys(destination);	
				browser.wait(…);										

				element(this.destinationField).sendKeys(…);									

				element(this.destinationField).sendKeys(…);	
		}

		changeJourneyTime()	{	
				element(this.changeTimeLink).click();	
		}

		chooseTimeOfDeparture(time)	{	
				element(this.leavingButton).click();	
				element(this.timeSelector).element(…).click();	
		}	
		confirmSelection()	{	
				element(this.planMyJourneyButton).click();

		}

large classes
bloated methods
serenity-js.org#SerenityJS @JanMolak
class	JourneyPlanner	{	
		private	originField												=	by.id('...');	
		private	originSuggestions						=	by.xpath('...');	
		private	destinationField							=	by.id('...');	
		private	destinationSuggestions	=	by.xpath('...');	
		private	changeTimeLink									=	by.linkText('...');	
		private	leavingButton										=	by.css('...');	
		private	timeSelector											=	by.id('...');

		private	planMyJourneyButton				=	by.buttonText('...');

					
		get	=	()	=>	browser.get('https://tfl.gov.uk/');	
		chooseOriginOf(origin:	string)	{	
				element(this.originField).sendKeys(origin);										

				browser.wait(…);

				element(this.originField).sendKeys(…);	
				element(this.originField).sendKeys(…);	
		}	
		chooseDestinationOf(destination:	string)	{	
				element(this.destinationField).sendKeys(destination);	
				browser.wait(…);										

				element(this.destinationField).sendKeys(…);									

				element(this.destinationField).sendKeys(…);	
		}

		changeJourneyTime()	{	
				element(this.changeTimeLink).click();	
		}

		chooseTimeOfDeparture(time)	{	
				element(this.leavingButton).click();	
				element(this.timeSelector).element(…).click();	
		}	
		confirmSelection()	{	
				element(this.planMyJourneyButton).click();

		}

large classes
bloated methods
difficult to compose
serenity-js.org#SerenityJS @JanMolak
Serenity/JS and
the Screenplay Pattern
serenity-js.org#SerenityJS @JanMolak
“A good acceptance test

is user-centred.
It reflects a user’s journey

to accomplish their goal.
serenity-js.org#SerenityJS @JanMolak


Open the Journey Planner

Choose origin of Waterloo
Choose destination of Canary Wharf
Choose time of departure: 09:00
Confirm selection
See if the fastest train departs at 08:59
serenity-js.org#SerenityJS @JanMolak


				OpenJourneyPlanner(),	
				ChooseOriginOf(‘Waterloo’),	
				ChooseDestinationOf(‘Canary	Wharf’),	
				ChooseTimeOfDeparture(‘09:00’),	
				ConfirmSelection(),	
				See.if(FastestTrain(),	departsAt(‘08:59’)),
serenity-js.org#SerenityJS @JanMolak
“A task is a composition

of interactions with the
system, performed by an actor

to accomplish a certain goal.
serenity-js.org#SerenityJS @JanMolak
Designing a task
serenity-js.org#SerenityJS @JanMolak
						ChooseOriginOf(‘Waterloo’)
serenity-js.org#SerenityJS @JanMolak
const	ChooseOriginOf	=	(station:	string)	=>	Task
serenity-js.org#SerenityJS @JanMolak
import	{	Task	}	from	‘serenity-js/protractor’	
const	ChooseOriginOf	=	(station:	string)	=>	Task
serenity-js.org#SerenityJS @JanMolak
import	{	Task	}	from	‘serenity-js/protractor’	
const	ChooseOriginOf	=	(station:	string)	=>		
		Task.where(`#actor	selects	origin	of	${station}`,	
		);
serenity-js.org#SerenityJS @JanMolak
import	{	Enter,	Task	}	from	‘serenity-js/protractor’	
const	ChooseOriginOf	=	(station:	string)	=>		
		Task.where(`#actor	selects	origin	of	${station}`,	
				Enter.theValue(station).into(Planner.Origin),

		);
serenity-js.org#SerenityJS @JanMolak
import	{	Enter,	Task	}	from	‘serenity-js/protractor’	
const	ChooseOriginOf	=	(station:	string)	=>		
		Task.where(`#actor	selects	origin	of	${station}`,	
				Enter.theValue(station).into(Planner.Origin),	
				PickFirstSuggestionFrom(Planner.Origin_Suggestions),		
		);
serenity-js.org#SerenityJS @JanMolak
Actors perform tasks
serenity-js.org#SerenityJS @JanMolak
import	{	Actor	}	from	‘serenity-js/protractor’;	
const	Connie	=	Actor.named(‘Connie’);
serenity-js.org#SerenityJS @JanMolak
import	{	Actor	}	from	‘serenity-js/protractor’;	
const	Connie	=	Actor.named(‘Connie’);



Connie.attemptsTo(	
		//	...	

);
serenity-js.org#SerenityJS @JanMolak
const	Connie	=	Actor.named(‘Connie’);



Connie.attemptsTo(

				OpenJourneyPlanner(),	
				ChooseOriginOf(‘Waterloo’),	
				ChooseDestinationOf(‘Canary	Wharf’),	
				ChooseTimeOfDeparture(‘09:00’),	
				ConfirmSelection(),

);
serenity-js.org#SerenityJS @JanMolak
Actors have abilities 

that enable interactions
with the system
serenity-js.org#SerenityJS @JanMolak
import	{	protractor	}	from	‘protractor’;

import	{	Actor,	BrowseTheWeb	}	from	‘serenity-js/protractor’;



const	Connie	=	Actor

		.named(‘Connie’)	
		.whoCan(BrowseTheWeb.using(protractor.browser));
serenity-js.org#SerenityJS @JanMolak
Actors ask questions
and verify the answers
serenity-js.org#SerenityJS @JanMolak


actor.attemptsTo(	
		See.if(

				question:	Question<T>,		
				assertion:	Assertion<T>,

		)	
);
serenity-js.org#SerenityJS @JanMolak
import	{	Text	}	from	‘serenity-js/protractor’;	
actor.attemptsTo(	
		See.if(

				Text.of(Planner.Header),		
				equals(‘Plan	a	Journey’)

		)	
);
serenity-js.org#SerenityJS @JanMolak
import	{	SelectedValue	}	from	‘serenity-js/protractor’;	


actor.attemptsTo(	
		See.if(

				SelectedValue.of(Planner.Time_Selector),		
				equals(‘09:00’)

		)	
);
serenity-js.org#SerenityJS @JanMolak


actor.attemptsTo(	
		See.if(

				FastestTrain(),		
				departsAt(‘08:59’),

		)	
);
serenity-js.org#SerenityJS @JanMolak
The end result
serenity-js.org#SerenityJS @JanMolak
const	Connie	=	Actor.named(‘Connie’)	
		.whoCan(BrowseTheWeb.using(protractor.browser));	


Connie.attemptsTo(

				OpenJourneyPlanner(),	
				ChooseOriginOf(‘Waterloo’),	
				ChooseDestinationOf(‘Canary	Wharf’),	
				ChooseTimeOfDeparture(‘09:00’),	
				ConfirmSelection(),	
				See.if(FastestTrain(),	departsAt(‘08:59’))

);
serenity-js.org#SerenityJS @JanMolak
const	Connie	=	Actor.named(‘Connie’)	
		.whoCan(BrowseTheWeb.using(protractor.browser));	


Connie.attemptsTo(

				PlanAJourney.from(‘Waterloo’).to(‘Canary	Wharf’).

								departingAt(‘09:00’),	
				//	…

);
serenity-js.org#SerenityJS @JanMolak
Reporting
serenity-js.org#SerenityJS @JanMolak
serenity-js.org#SerenityJS @JanMolak
serenity-js.org#SerenityJS @JanMolak
Questions to ask:
- How much time do I spend maintaining the tests?
- Am I modelling user’s interactions with the system, 

or how the system is built?
- Can I share elements of my testing framework with others?
- How much duplication and dead code is there in my tests?
- How long would it take me to find the issue if a test fails?
- How long to change the tests when the system changes?
- Can I use my tests to drive the design of the system?
serenity-js.org#SerenityJS @JanMolak
Make your tests

scalable by design
serenity-js.org#SerenityJS @JanMolak
Thank you!
Learn more at serenity-js.org



janmolak.com

jan.molak@serenity.io

twitter.com/JanMolak
linkedin.com/in/janmolak
github.com/jan-molak

Mais conteúdo relacionado

Último

+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
masabamasaba
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
VictorSzoltysek
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
masabamasaba
 

Último (20)

Generic or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisions
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfThe Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
 
%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 

Destaque

How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
ThinkNow
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
Kurio // The Social Media Age(ncy)
 

Destaque (20)

Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage Engineerings
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
 
Skeleton Culture Code
Skeleton Culture CodeSkeleton Culture Code
Skeleton Culture Code
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
 
12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work
 

Angular connect. Testing angular apps. at scale.