Slide 1

Slide 1 text

Jan Molak Lead Developer of Serenity/JS Contributor to the Screenplay Pattern Co-author of "BDD in Action, 2nd edition" Trainer, Consultant janmolak.com Blended Testing

Slide 2

Slide 2 text

Jan Molak | serenity-js.org Blended Testing Interacting with multiple interfaces of the system under test
 to improve their stability, reliability, and performance 
 without reducing their coverage.

Slide 3

Slide 3 text

Jan Molak | serenity-js.org Tool-centric E2E automation How picking "the best tool for the job" can get us in trouble

Slide 4

Slide 4 text

Jan Molak | serenity-js.org Tool-centric E2E automation • Scenarios focus on interacting with one interface at the time System
 Under Test Web UI System
 State

Slide 5

Slide 5 text

Jan Molak | serenity-js.org Tool-centric E2E automation • Scenarios focus on interacting with one interface at the time System
 Under Test Web UI System
 State Web Integration Tool

Slide 6

Slide 6 text

Jan Molak | serenity-js.org Tool-centric E2E automation • Scenarios focus on interacting with one interface at the time System
 Under Test Web Test Suite Web UI System
 State Web Integration Tool

Slide 7

Slide 7 text

Jan Molak | serenity-js.org Tool-centric E2E automation • Scenarios focus on interacting with one interface at the time • Test suites organised per-interface System
 Under Test Web Test Suite Web UI REST API System
 State Web Integration Tool

Slide 8

Slide 8 text

Jan Molak | serenity-js.org Tool-centric E2E automation • Scenarios focus on interacting with one interface at the time • Test suites organised per-interface System
 Under Test Web Test Suite Web UI REST API System
 State Web Integration Tool API Integration Tool

Slide 9

Slide 9 text

Jan Molak | serenity-js.org Tool-centric E2E automation • Scenarios focus on interacting with one interface at the time • Test suites organised per-interface System
 Under Test Web Test Suite Web UI REST API API Test Suite System
 State Web Integration Tool API Integration Tool

Slide 10

Slide 10 text

Jan Molak | serenity-js.org Tool-centric E2E automation • Scenarios focus on interacting with one interface at the time • Test suites organised per-interface • Little or no code reuse => high maintenance or poor coverage System
 Under Test Web Test Suite Web UI REST API API Test Suite System
 State Web Integration Tool API Integration Tool

Slide 11

Slide 11 text

Jan Molak | serenity-js.org Tool-centric E2E automation • Scenarios focus on interacting with one interface at the time • Test suites organised per-interface • Little or no code reuse => high maintenance or poor coverage System
 Under Test Web Test Suite Web UI Mobile App REST API API Test Suite System
 State Web Integration Tool API Integration Tool ?

Slide 12

Slide 12 text

Jan Molak | serenity-js.org Tool-centric E2E automation • Scenarios focus on interacting with one interface at the time • Test suites organised per-interface • Little or no code reuse => high maintenance or poor coverage System
 Under Test Web Test Suite Web UI Mobile App REST API API Test Suite System
 State Web Integration Tool API Integration Tool Messaging API ? ?

Slide 13

Slide 13 text

Jan Molak | serenity-js.org Tool-centric E2E automation • Scenarios focus on interacting with one interface at the time • Test suites organised per-interface • Little or no code reuse => high maintenance or poor coverage System
 Under Test Web Test Suite Web UI Mobile App REST API API Test Suite System
 State Web Integration Tool API Integration Tool Batch API Messaging API ? ? ?

Slide 14

Slide 14 text

Jan Molak | serenity-js.org Tool-centric E2E automation Pick "the best tool" for the job - too many jobs, too many tools

Slide 15

Slide 15 text

Jan Molak | serenity-js.org UI-centric E2E automation Pick "the best tool" for the job - too many jobs, too many tools Check the UI, like the user would

Slide 16

Slide 16 text

Jan Molak | serenity-js.org UI-centric E2E automation • Scenarios only ever interact with the web UI System
 Under Test Web UI Mobile App REST API System
 State Batch API Messaging API

Slide 17

Slide 17 text

Jan Molak | serenity-js.org UI-centric E2E automation • Scenarios only ever interact with the web UI System
 Under Test Web UI Mobile App REST API System
 State Web Integration Tool Batch API Messaging API

Slide 18

Slide 18 text

Jan Molak | serenity-js.org UI-centric E2E automation • Scenarios only ever interact with the web UI System
 Under Test Web Test Suite Web UI Mobile App REST API System
 State Web Integration Tool Batch API Messaging API

Slide 19

Slide 19 text

Jan Molak | serenity-js.org UI-centric E2E automation • Scenarios only ever interact with the web UI • Interactions with other interfaces accidental, ad-hoc, or missed System
 Under Test Web Test Suite Web UI Mobile App REST API System
 State Web Integration Tool Batch API Messaging API

Slide 20

Slide 20 text

Jan Molak | serenity-js.org UI-centric E2E automation • Scenarios only ever interact with the web UI • Interactions with other interfaces accidental, ad-hoc, or missed System
 Under Test Web Test Suite Web UI Mobile App REST API System
 State Web Integration Tool Batch API Messaging API

Slide 21

Slide 21 text

Jan Molak | serenity-js.org UI-centric E2E automation • Scenarios only ever interact with the web UI • Interactions with other interfaces accidental, ad-hoc, or missed System
 Under Test Web Test Suite Web UI Mobile App REST API System
 State Web Integration Tool Batch API Messaging API ? ?

Slide 22

Slide 22 text

Jan Molak | serenity-js.org UI-centric E2E automation • Scenarios only ever interact with the web UI • Interactions with other interfaces accidental, ad-hoc, or missed • Slow and unreliable tests => high failure diagnosis costs System
 Under Test Web Test Suite Web UI Mobile App REST API System
 State Web Integration Tool Batch API Messaging API ? ?

Slide 23

Slide 23 text

Jan Molak | serenity-js.org UI-centric E2E automation • Scenarios only ever interact with the web UI • Interactions with other interfaces accidental, ad-hoc, or missed • Slow and unreliable tests => high failure diagnosis costs System
 Under Test Web Test Suite Web UI Mobile App REST API System
 State Web Integration Tool Batch API Messaging API ? ? API Test Suite API Integration Tool

Slide 24

Slide 24 text

Jan Molak | serenity-js.org UI-centric E2E automation Pick "the best tool" for the job - too many jobs, too many tools Check the UI, like the user would - users don't care about the UI

Slide 25

Slide 25 text

Jan Molak | serenity-js.org Blended testing Pick "the best tool" for the job - too many jobs, too many tools Check the UI, like the user would - users don't care about the UI Focus on actors, blend interfaces and tools

Slide 26

Slide 26 text

Jan Molak | serenity-js.org UCD mental model for Blended Testing Roles - Who?

Slide 27

Slide 27 text

Jan Molak | serenity-js.org UCD mental model for Blended Testing Roles - Who? ↳ Goals - Why?

Slide 28

Slide 28 text

Jan Molak | serenity-js.org UCD mental model for Blended Testing Roles - Who? ↳ Goals - Why? ↳ Tasks - What?

Slide 29

Slide 29 text

Jan Molak | serenity-js.org UCD mental model for Blended Testing Roles - Who? ↳ Goals - Why? ↳ Tasks - What? ↳ Interactions - How? Mental model inspired by:
 - "In praise of abstraction" by Kevin Lawrence, 2007 - "A bit of UCD for BDD and ATDD" by Antony Marcano, 2011

Slide 30

Slide 30 text

Jan Molak | serenity-js.org UCD mental model for Blended Testing Roles - Who? ↳ Goals - Why? ↳ Tasks - What? ↳ Interactions - How? ↳ Integration tools ↳ Interfaces - Implementation detail

Slide 31

Slide 31 text

Jan Molak | serenity-js.org Blended testing • Acceptance tests focus on actors, goals, and tasks • Use only interfaces necessary to do a meaningful test System
 Under Test Acceptance Test Suite System
 State Integration Tools Interfaces Test Automation Framework

Slide 32

Slide 32 text

Jan Molak | serenity-js.org Blended testing • Acceptance tests focus on actors, goals, and tasks • Use only interfaces necessary to do a meaningful test • Building multimodal automation frameworks is really hard System
 Under Test Acceptance Test Suite System
 State Integration Tools Interfaces Test Automation Framework ?

Slide 33

Slide 33 text

Jan Molak | serenity-js.org Actor-centred blended testing How to blend with Serenity/JS Screenplay Pattern

Slide 34

Slide 34 text

Jan Molak | serenity-js.org Screenplay Pattern Using your domain language to implement test scenarios
 that model what tasks the actors need to perform 
 in order to accomplish their goals 
 when interacting with the system under test.

Slide 35

Slide 35 text

Jan Molak | serenity-js.org Screenplay Pattern: Actors and roles Feature: Deals on apples Scenario: 3-for-2 on apples Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 3 packs of apples Then they should be requested to pay $5.00 Scenario: 3-for-2 deal reminder Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 2 packs of apples Then they should be requested to pay $5.00 But they should be reminded about the 3-for-2 deal

Slide 36

Slide 36 text

Jan Molak | serenity-js.org Screenplay Pattern: Actors and roles Feature: Deals on apples Scenario: 3-for-2 on apples Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 3 packs of apples Then they should be requested to pay $5.00 Scenario: 3-for-2 deal reminder Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 2 packs of apples Then they should be requested to pay $5.00 But they should be reminded about the 3-for-2 deal

Slide 37

Slide 37 text

Feature: Deals on apples Scenario: 3-for-2 on apples Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 3 packs of apples Then they should be requested to pay $5.00 Scenario: 3-for-2 deal reminder Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 2 packs of apples Then they should be requested to pay $5.00 But they should be reminded about the 3-for-2 deal import {actorCalled} from '@serenity-js/core' actorCalled('Shopper') Jan Molak | serenity-js.org Screenplay Pattern: Actors and roles

Slide 38

Slide 38 text

Feature: Deals on apples Scenario: 3-for-2 on apples Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 3 packs of apples Then they should be requested to pay $5.00 Scenario: 3-for-2 deal reminder Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 2 packs of apples Then they should be requested to pay $5.00 But they should be reminded about the 3-for-2 deal import {actorCalled} from '@serenity-js/core' // Shopper role: // - finds products of interest // - manages basket // - makes payments actorCalled('Shopper') Jan Molak | serenity-js.org Screenplay Pattern: Actors and roles

Slide 39

Slide 39 text

Feature: Deals on apples Scenario: 3-for-2 on apples Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 3 packs of apples Then they should be requested to pay $5.00 Scenario: 3-for-2 deal reminder Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 2 packs of apples Then they should be requested to pay $5.00 But they should be reminded about the 3-for-2 deal import {actorCalled} from '@serenity-js/core' // TODO: who's managing the shop? // Shopper role: // - finds products of interest // - manages basket // - makes payments actorCalled('Shopper') Jan Molak | serenity-js.org Screenplay Pattern: Actors and roles

Slide 40

Slide 40 text

Feature: Deals on apples Scenario: 3-for-2 on apples Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 3 packs of apples Then they should be requested to pay $5.00 Scenario: 3-for-2 deal reminder Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 2 packs of apples Then they should be requested to pay $5.00 But they should be reminded about the 3-for-2 deal import {actorCalled} from '@serenity-js/core' // Shopkeeper role: // - manages stock // - manages prices // - manages deals actorCalled('Shopkeeper') // Shopper role: // - finds products of interest // - manages basket // - makes payments actorCalled('Shopper') Jan Molak | serenity-js.org Screenplay Pattern: Actors and roles

Slide 41

Slide 41 text

Feature: Deals on apples Scenario: 3-for-2 on apples Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 3 packs of apples Then they should be requested to pay $5.00 Scenario: 3-for-2 deal reminder Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 2 packs of apples Then they should be requested to pay $5.00 But they should be reminded about the 3-for-2 deal import {actorCalled} from '@serenity-js/core' // Shopkeeper role: // - manages stock // - manages prices // - manages deals actorCalled('Shopkeeper') // Shopper role: // - finds products of interest // - manages basket // - makes payments actorCalled('Shopper') Jan Molak | serenity-js.org Screenplay Pattern: Actors and roles

Slide 42

Slide 42 text

Feature: Deals on apples Scenario: 3-for-2 on apples Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 3 packs of apples Then they should be requested to pay $5.00 Scenario: 3-for-2 deal reminder Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 2 packs of apples Then they should be requested to pay $5.00 But they should be reminded about the 3-for-2 deal import {actorCalled} from '@serenity-js/core' // Shopkeeper goals? actorCalled('Shopkeeper') // Shopper goals? actorCalled('Shopper') Jan Molak | serenity-js.org Screenplay Pattern: Goals

Slide 43

Slide 43 text

Feature: Deals on apples Scenario: 3-for-2 on apples Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 3 packs of apples Then they should be requested to pay $5.00 Scenario: 3-for-2 deal reminder Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 2 packs of apples Then they should be requested to pay $5.00 But they should be reminded about the 3-for-2 deal import {actorCalled} from '@serenity-js/core' // Shopkeeper goals: // - price apples at $2.50 // - enable 3-for-2 deal on apples actorCalled('Shopkeeper') // Shopper goals: // - find apples // - check price // - check missed deal suggestions actorCalled('Shopper') Jan Molak | serenity-js.org Screenplay Pattern: Goals

Slide 44

Slide 44 text

Feature: Deals on apples Scenario: 3-for-2 on apples Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 3 packs of apples Then they should be requested to pay $5.00 Scenario: 3-for-2 deal reminder Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 2 packs of apples Then they should be requested to pay $5.00 But they should be reminded about the 3-for-2 deal import {actorCalled} from '@serenity-js/core' actorCalled('Shopkeeper').attemptsTo( 
 setProductPrice('apples', '$2.50'), enableDeal('3-for-2', 'apples'), 
 ) actorCalled('Shopper').attemptsTo( findProduct('apples'), addProductToBasket('apples', 3), verifyBasketTotal('$5.00'), verifyMissedDeals([ ]), ) Jan Molak | serenity-js.org Screenplay Pattern: Tasks

Slide 45

Slide 45 text

Feature: Deals on apples Scenario: 3-for-2 on apples Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 3 packs of apples Then they should be requested to pay $5.00 Scenario: 3-for-2 deal reminder Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 2 packs of apples Then they should be requested to pay $5.00 But they should be reminded about the 3-for-2 deal import {actorCalled} from '@serenity-js/core' actorCalled('Shopkeeper').attemptsTo( 
 setProductPrice('apples', '$2.50'), enableDeal('3-for-2', 'apples'), 
 ) actorCalled('Shopper').attemptsTo( findProduct('apples'), addProductToBasket('apples', 3), verifyBasketTotal('$5.00'), verifyMissedDeals([ ]), ) Jan Molak | serenity-js.org Screenplay Pattern: Tasks Task names based on your domain

Slide 46

Slide 46 text

Feature: Deals on apples Scenario: 3-for-2 on apples Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 3 packs of apples Then they should be requested to pay $5.00 Scenario: 3-for-2 deal reminder Given a pack of apples costs $2.50 And there’s a 3-for-2 deal on apples When the shopper wants to buy 2 packs of apples Then they should be requested to pay $5.00 But they should be reminded about the 3-for-2 deal import {actorCalled} from '@serenity-js/core' actorCalled('Shopkeeper').attemptsTo( 
 setProductPrice('apples', '$2.50'), enableDeal('3-for-2', 'apples'), 
 ) actorCalled('Shopper').attemptsTo( findProduct('apples'), addProductToBasket('apples', 3), verifyBasketTotal('$5.00'), verifyMissedDeals([ ]), ) Jan Molak | serenity-js.org Screenplay Pattern: Tasks High-level tasks
 unconstrained by
 interface implementation

Slide 47

Slide 47 text

actorCalled('Shopkeeper').attemptsTo( 
 setProductPrice('apples', '$2.50'), enableDeal('3-for-2', 'apples'), 
 ) actorCalled('Shopper').attemptsTo( findProduct('apples'), addProductToBasket('apples', 3), verifyBasketTotal('$5.00'), verifyMissedDeals([ ]), ) Jan Molak | serenity-js.org Implementing Tasks import {Task} from '@serenity-js/core' const setProductPrice = (name, price) => Task.where(`#actor sets price of ${ name } at ${ price }`, 
 // …sub-tasks 
 ) Tasks are composites
 of activities

Slide 48

Slide 48 text

actorCalled('Shopkeeper').attemptsTo( 
 setProductPrice('apples', '$2.50'), enableDeal('3-for-2', 'apples'), 
 ) Jan Molak | serenity-js.org Implementing API Tasks import {Task} from '@serenity-js/core' import {Send, PostRequest} from '@serenity-js/rest' const setProductPrice = (name, price) => Task.where(`#actor sets price of ${ name } at ${ price }`, 
 Send.a(PostRequest.to('/products').with({ name: name, 
 price: price, }), ) Interacting with
 REST APIs

Slide 49

Slide 49 text

actorCalled('Shopkeeper').attemptsTo( 
 setProductPrice('apples', '$2.50'), enableDeal('3-for-2', 'apples'), 
 ) Jan Molak | serenity-js.org Implementing API Tasks import {Task} from '@serenity-js/core' import {Send, LastResponse, PostRequest} from '@serenity-js/rest' import {Ensure, equals} from '@serenity-js/assertions' const setProductPrice = (name, price) => Task.where(`#actor sets price of ${ name } at ${ price }`, 
 Send.a(PostRequest.to('/products').with({ name: name, 
 price: price, }), Ensure.that(LastResponse.status(), equals(200)) ) Composing assertions
 into tasks

Slide 50

Slide 50 text

import { CallAnApi } from '@serenity-sj/rest' actorCalled('Shopkeeper') .whoCan( CallAnApi.using(axios) ) .attemptsTo( 
 setProductPrice('apples','$2.50'), enableDeal('3-for-2', 'apples'), 
 ) Jan Molak | serenity-js.org Implementing API Tasks import {Task} from '@serenity-js/core' import {Send, LastResponse, PostRequest} from '@serenity-js/rest' import {Ensure, equals} from '@serenity-js/assertions' const setProductPrice = (name, price) => Task.where(`#actor sets price of ${ name } at ${ price }`, 
 Send.a(PostRequest.to('/products').with({ name: name, 
 price: price, }), Ensure.that(LastResponse.status(), equals(200)) ) Abilities enable interactions

Slide 51

Slide 51 text

import { CallAnApi } from '@serenity-sj/rest' actorCalled('Shopkeeper') .whoCan( CallAnApi.using(axios) ) .attemptsTo( 
 setProductPrice('apples','$2.50'), enableDeal('3-for-2', 'apples'), 
 ) Jan Molak | serenity-js.org Implementing API Tasks import {Task} from '@serenity-js/core' import {Send, LastResponse, PostRequest} from '@serenity-js/rest' import {Ensure, equals} from '@serenity-js/assertions' const setProductPrice = (name, price) => setProductPriceViaAdminApi(name, price) const setProductPriceViaAdminApi = (name, price) => Task.where(`#actor sets price of ${ name } at ${ price }`, 
 Send.a(PostRequest.to('/products').with({ name: name, 
 price: price, }), Ensure.that(LastResponse.status(), equals(200)) )

Slide 52

Slide 52 text

import { CallAnApi } from '@serenity-sj/rest' actorCalled('Shopkeeper') .whoCan( CallAnApi.using(axios) ) .attemptsTo( 
 setProductPrice('apples','$2.50'), enableDeal('3-for-2', 'apples'), 
 ) Jan Molak | serenity-js.org Alternative implementations import {Task} from '@serenity-js/core' import {Send, LastResponse, PostRequest} from '@serenity-js/rest' import {Ensure, equals} from '@serenity-js/assertions' const setProductPrice = (name, price) => setProductPriceViaAdminApi(name, price) const setProductPriceViaAdminApi = (name, price) => // … const setProductPriceViaAdminUI = (name, price) => Task.where(`#actor sets price of ${ name } at ${ price }`, authenticateWithStoreAdminPanel(adminCredentials()), openProductCatalog(), findProductByName(name), changeProductPrice(price), 
 ) Alternative implementations of the same task

Slide 53

Slide 53 text

import { BrowseTheWebWithWebdriverIO } from '@serenity-sj/webdriverio' actorCalled('Shopkeeper') .whoCan( CallAnApi.using(axios), BrowseTheWebWithWebdriverIO 
 .using(browser) ) .attemptsTo( 
 setProductPrice('apples','$2.50'), enableDeal('3-for-2', 'apples'), 
 ) Jan Molak | serenity-js.org Alternative implementations import {Task} from '@serenity-js/core' import {Send, LastResponse, PostRequest} from '@serenity-js/rest' import {Ensure, equals} from '@serenity-js/assertions' const setProductPrice = (name, price) => setProductPriceViaAdminUI(name, price) const setProductPriceViaAdminApi = (name, price) => // … const setProductPriceViaAdminUI = (name, price) => Task.where(`#actor sets price of ${ name } at ${ price }`, authenticateWithStoreAdminPanel(adminCredentials()), openProductCatalog(), findProductByName(name), changeProductPrice(price), 
 ) The same test scenario, interacting through the web UI

Slide 54

Slide 54 text

import { BrowseTheWebWithWebdriverIO } from '@serenity-sj/webdriverio' actorCalled('Shopkeeper') .whoCan( CallAnApi.using(axios), BrowseTheWebWithWebdriverIO 
 .using(browser) ) .attemptsTo( 
 setProductPrice('apples','$2.50'), enableDeal('3-for-2', 'apples'), 
 ) Jan Molak | serenity-js.org Implementing web UI tasks import {Task} from '@serenity-js/core' import {Enter, Click, Text} from '@serenity-js/web' import {Ensure, equals} from '@serenity-js/assertions' const authenticateWithStoreAdminPanel = ({username, password}) => Task.where(`#actor authenticates with StoreAdmin`, Enter.theValue(username).into(LoginForm.usernameField()), Enter.theValue(password).into(LoginForm.passwordField()), Click.on(LoginForm.submitButton()), Ensure.that(Text.of(AdminPanel.user()), equals(username)) ) Web interactions

Slide 55

Slide 55 text

import { BrowseTheWebWithWebdriverIO } from '@serenity-sj/webdriverio' actorCalled('Shopkeeper') .whoCan( CallAnApi.using(axios), BrowseTheWebWithWebdriverIO 
 .using(browser) ) .attemptsTo( 
 setProductPrice('apples','$2.50'), enableDeal('3-for-2', 'apples'), 
 ) Jan Molak | serenity-js.org Implementing web UI tasks import {Task} from '@serenity-js/core' import {Enter,Click,Text,PageElement,By} from '@serenity-js/web' import {Ensure, equals} from '@serenity-js/assertions' const authenticateWithStoreAdminPanel = ({username, password}) => Task.where(`#actor authenticates with StoreAdmin`, Enter.theValue(username).into(LoginForm.usernameField()), Enter.theValue(password).into(LoginForm.passwordField()), Click.on(LoginForm.submitButton()), Ensure.that(Text.of(AdminPanel.user()), equals(username)) ) const LoginForm = { usernameField: () => PageElement.located(By.css('input.username')) .describedAs('username field) passwordField: // … } Locating page elements

Slide 56

Slide 56 text

Jan Molak | serenity-js.org Blending like a pro with Serenity/JS

Slide 57

Slide 57 text

Jan Molak | serenity-js.org Blended testing like a pro • Acceptance tests focus on actors, goals, and tasks import {actorCalled} from '@serenity-js/core' await actorCalled('Shopkeeper').attemptsTo( 
 setProductPrice('apples', '$2.50'), enableDeal('3-for-2', 'apples'), 
 ) await actorCalled('Shopper').attemptsTo( findProduct('apples'), addProductToBasket('apples', 3), verifyBasketTotal('$5.00'), verifyMissedDeals([ ]), )

Slide 58

Slide 58 text

Jan Molak | serenity-js.org Blended testing like a pro • Acceptance tests focus on actors, goals, and tasks • Tasks provide alternative implementations and enable code reuse import {actorCalled} from '@serenity-js/core' await actorCalled('Shopkeeper').attemptsTo( 
 setProductPrice('apples', '$2.50'), enableDeal('3-for-2', 'apples'), 
 ) await actorCalled('Shopper').attemptsTo( findProduct('apples'), addProductToBasket('apples', 3), verifyBasketTotal('$5.00'), verifyMissedDeals([ ]), ) Serenity/JS Custom
 task libraries findProduct 
 setProductPrice 
 enableDeal Tasks

Slide 59

Slide 59 text

Jan Molak | serenity-js.org Blended testing like a pro • Acceptance tests focus on actors, goals, and tasks • Tasks provide alternative implementations and enable code reuse System
 Under Test Acceptance
 Tests System
 State Serenity/JS
 Modules Custom
 task libraries Targeted
 Tests

Slide 60

Slide 60 text

Jan Molak | serenity-js.org Blended testing like a pro • Acceptance tests focus on actors, goals, and tasks • Tasks provide alternative implementations and enable code reuse • Standardised patterns System
 Under Test Acceptance
 Tests System
 State Serenity/JS
 Modules Custom Integrations Custom
 task libraries Targeted
 Tests

Slide 61

Slide 61 text

Jan Molak | serenity-js.org Blended testing like a pro • Acceptance tests focus on actors, goals, and tasks • Tasks provide alternative implementations and enable code reuse • Standardised patterns mean consistent reporting

Slide 62

Slide 62 text

Jan Molak | serenity-js.org Start automating with Serenity/JS in 15 minutes 🚀 serenity-js.org