Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Creating Faster and More Reliable Web Tests with Blended Testing

Creating Faster and More Reliable Web Tests with Blended Testing

Automated acceptance tests are often implemented to exercise a fully-assembled and deployed system through its web interface. This approach makes them slow and flaky and reduces the value they could bring to your organisation.

Blended Testing is a technique that can improve the speed and stability of web-based test scenarios by making them take shortcuts through other interfaces of the system under test.
To use it effectively, though, we need to know when it's safe to take shortcuts and how to take them - this is where Task Analysis and the Screenplay Pattern can help.

In this talk, Jan Molak - Lead Developer of Serenity/JS and co-author of "BDD in Action, Second Edtion", will show you how to apply Task Analysis, Screenplay Pattern and use Serenity/JS 3.0 to design and develop blended test scenarios that exercise multiple interfaces of the system under test to improve execution speed and stability.

---

Video recording: https://www.youtube.com/@serenity-js
Serenity/JS website: https://serenity-js.org/

Jan Molak

April 04, 2023
Tweet

Other Decks in Programming

Transcript

  1. 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

    View Slide

  2. 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.

    View Slide

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

    View Slide

  4. 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

    View Slide

  5. 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

    View Slide

  6. 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

    View Slide

  7. 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

    View Slide

  8. 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

    View Slide

  9. 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

    View Slide

  10. 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

    View Slide

  11. 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
    ?

    View Slide

  12. 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
    ?
    ?

    View Slide

  13. 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
    ?
    ?
    ?

    View Slide

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

    View Slide

  15. 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

    View Slide

  16. 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

    View Slide

  17. 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

    View Slide

  18. 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

    View Slide

  19. 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

    View Slide

  20. 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

    View Slide

  21. 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
    ?
    ?

    View Slide

  22. 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
    ?
    ?

    View Slide

  23. 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

    View Slide

  24. 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

    View Slide

  25. 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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  29. 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

    View Slide

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

    View Slide

  31. 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

    View Slide

  32. 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
    ?

    View Slide

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

    View Slide

  34. 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.

    View Slide

  35. 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

    View Slide

  36. 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

    View Slide

  37. 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

    View Slide

  38. 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

    View Slide

  39. 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

    View Slide

  40. 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

    View Slide

  41. 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

    View Slide

  42. 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

    View Slide

  43. 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

    View Slide

  44. 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

    View Slide

  45. 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

    View Slide

  46. 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

    View Slide

  47. 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

    View Slide

  48. 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

    View Slide

  49. 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

    View Slide

  50. 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

    View Slide

  51. 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))


    )


    View Slide

  52. 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

    View Slide

  53. 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

    View Slide

  54. 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

    View Slide

  55. 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

    View Slide

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

    View Slide

  57. 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([ ]),


    )

    View Slide

  58. 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

    View Slide

  59. 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

    View Slide

  60. 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

    View Slide

  61. 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

    View Slide

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

    View Slide