Skip to content
Discussions/App Development/Meaningful error message in the given-when-then tests of the Shop exampleForum ↗

Meaningful error message in the given-when-then tests of the Shop example

App Development3 posts311 views2 likesLast activity Jul 2022
GY
gyorgybalazsiOP
Jun 2022

I am using the given-when-then test structure which can be found in the Shop reference application, because in this way the test cases can be mapped directly to the standard formulation of user story acceptance criteria.

The only problem with this structure is that in the case of a failing test, it doesn’t return any meaningful error message, just an “Assertion failed” message from the assert function.

This is my attempt to improve it. It does the job, but maybe there is a more idiomatic / elegant solution.

I was thinking about assertMsg, but as far as i can see it, it cannot be used, because the message is created in the then_ function, and the assertMsg would be in the run function.

module Test where

import DA.Optional (isSome)
import Daml.Script

import Asset
import Shop

data Fixture = Fixture with
  issuer : Party
  producer : Party
  owner : Party
  vendor : Party
  user : Party
  shopId : ShopId
  itemId : ItemId
  iouId : IouId
  vendorId : VendorRelationshipId
  userId : UserRelationshipId 

data TestResult = Ok | Error Text
  deriving Eq

data Test a b = Test with
  given : Script a
  when : a -> Script b
  then_ : a -> b -> Script TestResult

run : Test a b -> Script ()
run t = do
  fixture <- t.given
  result <- t.when fixture
  check <- t.then_ fixture result
  case check of
    Error msg -> abort msg
    Ok -> return ()

given_a_shop : Script Fixture
given_a_shop = do
  issuer <- allocateParty "Issuer"
  producer <- allocateParty "Producer"
  owner <- allocateParty "Owner"
  vendor <- allocateParty "Vendor"
  user <- allocateParty "User"

  itemId <- submit producer do createCmd Item with producer; owner = producer; label = "Apple"; quantity = 1.0; unit = "kg"; observers = []
  itemId <- submit producer do exerciseCmd itemId TransferItem with newOwner = vendor
  iouId <- submit issuer do createCmd Iou with issuer; owner = issuer; amount = 3.0; currency = "USD"
  iouId <- submit issuer do exerciseCmd iouId TransferIou with newOwner = user

  shopId <- submit owner do createCmd Shop with owner; vendors = []; users = []; offerIds = []
  (shopId, inviteId) <- submit owner do exerciseCmd shopId InviteVendor with vendor
  vendorId <- submit vendor do exerciseCmd inviteId AcceptVendorInvite
  (shopId, inviteId) <- submit owner do exerciseCmd shopId InviteUser with user
  userId <- submit user do exerciseCmd inviteId AcceptUserInvite
  pure Fixture with ..

when_the_vendor_offers_an_item : Fixture -> Script (ShopId, OfferId)
when_the_vendor_offers_an_item f = do
  submit f.vendor do exerciseCmd f.vendorId OfferItem with shopId = f.shopId; itemId = f.itemId; price = 1.0; currency = "USD"

then_the_offer_is_added_to_the_shop : Fixture -> (ShopId, OfferId) -> Script TestResult
then_the_offer_is_added_to_the_shop f (shopId, offerId) = do
  shopOpt <- queryContractId f.owner shopId
  if let Some shop = shopOpt in offerId `elem` shop.offerIds
  then return Ok 
  else return $ Error "Error: Offer is not added to the shop"

then_the_offer_is_visible_to_the_user : Fixture -> (ShopId, OfferId) -> Script TestResult
then_the_offer_is_visible_to_the_user f (shopId, offerId) = do
  offerOpt <- queryContractId f.user offerId 
  if isSome offerOpt 
  then return Ok
  else return $ Error "Error: Offer is not visible to the user"

when_an_item_is_bought : Fixture -> Script (ShopId, ItemId, IouId)
when_an_item_is_bought f = do
  let Fixture{..} = f
  (shopId, offerId) <- submit vendor do exerciseCmd vendorId OfferItem with price = 3.0; currency = "USD"; ..
  submit user do exerciseCmd userId BuyItem with ..

then_the_item_and_iou_exchange_hands : Fixture -> (ShopId, ItemId, IouId) -> Script TestResult
then_the_item_and_iou_exchange_hands f (shopId, itemId, iouId) = do
  itemOpt <- queryContractId f.user itemId
  iouOpt <- queryContractId f.vendor iouId 
  if let Some item = itemOpt in item.owner == f.user && let Some iou = iouOpt in iou.owner == f.vendor
  then return Ok
  else return $ Error "Error: Item and iou don't exchange hands"

gwt = script do
  let offer_added = Test with
        given = given_a_shop
        when = when_the_vendor_offers_an_item
        then_ = then_the_offer_is_added_to_the_shop
  let offer_user_visible = offer_added with
        then_ = then_the_offer_is_visible_to_the_user
  let asset_exchange = Test with
        given = given_a_shop
        when = when_an_item_is_bought
        then_ = then_the_item_and_iou_exchange_hands
  run offer_added
  run offer_user_visible
  run asset_exchange
NE
nemanja
Jul 2022

Hi @gyorgybalazsi :wave:

Is there anything specific you’d like feedback on?

GY
gyorgybalazsi
Jul 2022

Thanks, @nemanja I just put my thinking out there, to see if maybe somebody else also finds it useful.

← Back to Discussions