SFCC Cartridge
Testing
Native Mobile App Tests
7 min
native mobile app testing app testing overview if you have native applications for ios or android, we recommend integrating our mobile sdks in order to ensure accurate decisions for this order segment we have dedicated sections outlining the recommended integrations for ios https //docs forter com/mobile sdks/ios sdk overview and android https //docs forter com/mobile sdks/android sdk overview step 1 retrieve the fortermobileuid once you've installed the relevant forter mobile sdks, make sure that the sdk is generating a unique device identifier this identifier should be specific to the device (such as the idfv https //developer apple com/documentation/uikit/uidevice/1620059 identifierforvendor ) for ios and device identifier for android https //developer android com/training/articles/user data ids and it should persist across multiple user sessions when a customer makes a purchase from the mobile app, the unique identifier should also be included as the fortermobileuid value in the connectioninformation object of the order api https //docs forter com/reference/order v3 since the order api call is server to server, this value, along with the customer's ip address and useragent data should be retrieved from your https request headers and passed to the sfcc cartridge step 2 update ordertype make sure that the ordertype field in the forterorder ds file is updated to the "mobile" enum value step 2 2 mobile app order mapping the below code represents a mapped mobile app order for an sfra adyen integration please note that the following fields in the connectioninformation object have been updated ordertype this should always be "mobile" for transactions placed on an app fortermobileuid this should correspond to the id that is passed to the mobile sdk and included in the backend order request it replaces the fortertokencookie value for mobile orders customerip this should be the ip that corresponds to the end user's device not the ip of your server below is an example of how the connectioninformation object should appear for a native mobile app order { "orderid" "example order fdse0rr489", "ordertype" "mobile", "timesenttoforter" 1415287568000, "checkouttime" 1415273168, "connectioninformation" { "customerip" "107 57 208 5", "useragent" "teststore 18 4 1 rv 184100001 (iphone; ios 12 4 1; en us; iphone10,3)", "fortermobileuid" "6a9798ag16ff41f7b6b9878dd488add5", // pass unique identifier here "mobileappversion" "18 4 1" }, "totalamount" { "amountusd" "99 95" } } sample mobile order var forterlogger = require("int forter/cartridge/scripts/lib/forter/forterlogger ds"); / forterorder class is the dto object for request to include this script use var forterorder = require("int forter/cartridge/scripts/lib/forter/dto/forterorder ds"); / function forterorder(args) { var log = new forterlogger("forterorder ds"), order = args order, site = dw\ system site getcurrent(), paymentinstruments = order getpaymentinstruments(), a = null, authresponse = null, shipment = null; for each (var paymentinstrument in paymentinstruments) { if (paymentinstrument paymentmethod == 'credit card') { a = paymentinstrument; authresponse = args creditcardauthresponse; } else if (paymentinstrument paymentmethod == 'paypal' || paymentinstrument paymentmethod == 'applepay') { a = paymentinstrument; authresponse = {}; // not necessary as this info can be retreived from a instrument } else if (paymentinstrument paymentmethod == 'gift certificate') { // optional if this is an accepted a method in your store a = paymentinstrument; authresponse = args gcredemptiontransaction; } } forterordertype = function { for each (var type in ordertype) { if (ordertype type == 'sfcc storefront web') { return "web"; } else if (ordertype type == 'ios version mobile' || ordertype type == 'android linux mobile') { return "mobile" } } // general parameters this orderid = order originalorderno; // required this ordertype = order forterordertype; // "mobile" for app and "web" for web orders, this timesenttoforter = (new date()) gettime(); // required this checkouttime = new number((order creationdate gettime()/1000) tofixed()); // required //must be seconds, not milliseconds this connectioninformation = new forterconnectioninformation(order); // required // calculate totals this totalamount = {}; // required this totalamount amountlocalcurrency = order totalgrossprice value tofixed(2); this totalamount currency = order totalgrossprice currencycode; this amountusd = order totalgrossprice value //calculate totals for discounts var ordertotal = order getmerchandizetotalprice(), adjordertotal = order getadjustedmerchandizetotalprice(), shiptotal = order getshippingtotalprice(), adjshiptotal = order getadjustedshippingtotalprice(), total = ordertotal add(shiptotal), adjtotal = adjordertotal add(adjshiptotal); // discounts var discountprice = 0; var couponname = ''; var coupontype = ''; if (!order getcouponlineitems() isempty()) { var coupons = order getcouponlineitems(); var couponnames = \[]; for each (let coup in coupons) { couponnames push(coup getcouponcode()); if (!coup getpriceadjustments() isempty()) { var coupadjustments = coup getpriceadjustments(); for each (let coupadj in coupadjustments) { discountprice += coupadj pricevalue; } } } couponname = couponnames join(","); discountprice = discountprice ( 1); if (discountprice > 0) { this totaldiscount = {}; // optional this totaldiscount couponcodeused = couponname substring(0,20); // required this totaldiscount coupondiscountamount = {}; // required this totaldiscount coupondiscountamount amountlocalcurrency = discountprice tofixed(2); this totaldiscount coupondiscountamount currency = order currencycode; this totaldiscount discounttype = "coupon"; // required } } // customer's details this accountowner = new fortercustomer(order); // cart items (regular product) this cartitems = \[]; // required for each (var pli in order productlineitems) { this cartitems push(new fortercartitem(pli)); } // cart items (gift certificate) for each (var gcli in order giftcertificatelineitems) { this cartitems push(new fortercartitem(gcli)); } // payments this a = \[]; // required this a push(new forterpayment(order, authresponse, a , log)); // delivery and recipient (shipping information) if (order shipments length > 0) { shipment = order shipments\[0]; this primarydeliverydetails = {}; this primarydeliverydetails deliveryprice = {}; this primarydeliverydetails deliverymethod = (!empty(shipment getshippingmethod()) && !empty(shipment getshippingmethod() getdisplayname())) ? shipment getshippingmethod() getdisplayname() ""; //"by air"; var deliverytype = "physical"; //default value if (order productlineitems size() > 0 && order giftcertificatelineitems size() == 0) { deliverytype = "physical"; //if real products only } else if (order productlineitems size() == 0 && order giftcertificatelineitems size() > 0) { deliverytype = "digital"; //if gift certificates only this primarydeliverydetails deliverymethod = "email"; } else if (order productlineitems size() > 0 && order giftcertificatelineitems size() > 0) { deliverytype = "hybrid"; //if gift certificates and real products } this primarydeliverydetails deliverytype = deliverytype; this primarydeliverydetails deliveryprice amountlocalcurrency = shipment adjustedshippingtotalprice value tofixed(2); this primarydeliverydetails deliveryprice currency = shipment adjustedshippingtotalprice currencycode tostring(); if (shipment productlineitems size() > 0) { this primaryrecipient = {}; // optional this primaryrecipient personaldetails = {}; this primaryrecipient personaldetails firstname = shipment shippingaddress firstname; //from the shipping address this primaryrecipient personaldetails lastname = shipment shippingaddress lastname; //from the shipping address this primaryrecipient address = {}; this primaryrecipient address address1 = shipment shippingaddress address1; this primaryrecipient address address2 = !empty(shipment shippingaddress address2) ? shipment shippingaddress address2 ""; this primaryrecipient address zip = shipment shippingaddress postalcode; this primaryrecipient address city = shipment shippingaddress city; this primaryrecipient address region = shipment shippingaddress statecode; this primaryrecipient address country = shipment shippingaddress countrycode value touppercase(); this primaryrecipient phone = \[]; if (!empty(shipment shippingaddress phone)){ this primaryrecipient phone push(new forterphone(shipment shippingaddress phone)); } } else if (shipment giftcertificatelineitems size() > 0) { this primaryrecipient = {}; // optional this primaryrecipient personaldetails = {}; this primaryrecipient personaldetails fullname = shipment giftcertificatelineitems\[0] recipientname; //from the gift form this primaryrecipient personaldetails email = shipment giftcertificatelineitems\[0] recipientemail; //from the gift form } if (shipment gift == true) { this primaryrecipient comments = {}; this primaryrecipient comments messagetobeneficiary = shipment giftmessage ? shipment giftmessage ""; } } function forterconnectioninformation(order) { this customerip = request httpremoteaddress; // required this useragent = request httpuseragent; var ordertype = order ordertyperawrequest; if request httpcookies { // if web or mobile browser order for (var i = 0; i < request httpcookies cookiecount; i++) { if (request httpcookies\[i] name == "fortertoken") { this fortertokencookie = request httpcookies\[i] value; } else { this fortertokencookie = ""; } } } else if (ordertype type == 'ios version mobile' || ordertype type == 'android linux mobile') { // if app order if (request http muid) { this fortermobileuid = request http muid; } else { this fortermobileuid = ""; } this mobileappversion = request http versionheaders } this useragent = request httpuseragent; // required this fortertokencookie = ""; // conditional for (var i = 0; i < request httpcookies cookiecount; i++) { if (request httpcookies\[i] name == "fortertoken") { this fortertokencookie = request httpcookies\[i] value; } } } } function fortercustomer(order) { if (order customer profile != null) { this firstname = order customer profile firstname; this lastname = order customer profile lastname; this email = order customer profile email; this accountid = order customer id; this created = new number((order customer profile getcreationdate() gettime()/1000) tofixed()); var query = "customerno = {0} and paymentstatus = {1}"; var allorders seekableiterator = dw\ order ordermgr searchorders(query, "creationdate desc", order customer profile customerno, 2); this pastorderscount = new number(allorders count); } else { this firstname = order billingaddress firstname; this lastname = order billingaddress lastname; this email = order customeremail; } } function forterapplepay(auth, ap) { // where var ap is the raw applepay response data from your payment gateway var processorresponsecode = "", processorresponsetext = ""; // format the expiration month from 1 to 01, etc if (ap creditcardexpirationmonth tostring() length == 1) { var creditcardexpmonth = "0" + cc creditcardexpirationmonth tostring(); } else { var creditcardexpmonth = cc creditcardexpirationmonth tostring(); } this nameoncard = ap creditcardholder; this cardbrand = ap creditcardtype; this token = ap token; this lastfourdigits = ap creditcardnumberlastdigits; //optional this expirationmonth = creditcardexpmonth; this expirationyear = cc creditcardexpirationyear tostring(); this verificationresults = {}; this verificationresults avsfullresult = auth avs tostring(); // optional this verificationresults cvvresult = auth cvd code tostring(); // optional this verificationresults authorizationcode = auth authorization num tostring(); processorresponsecode = auth exact resp code tostring(); processorresponsetext = auth exact message tostring(); this verificationresults processorresponsecode = processorresponsecode; this verificationresults processorresponsetext = processorresponsetext; } function fortercartitem(item) { this basicitemdata = {}; if (item instanceof dw\ order productlineitem) { this basicitemdata productid = item productid; //optional this basicitemdata name = item productname; //required this basicitemdata quantity = item quantityvalue; //required var product = item getproduct(); if (product getcategories() isempty() && !empty(product getvariationmodel())) { product = product getvariationmodel() getmaster(); } this basicitemdata category = empty(product) ? "" product getcategories()\[0] getdisplayname(); this basicitemdata type = "tangible"; // add if type is available change according to the actual item type //if any adjustements this basicitemdata price = {}; this basicitemdata price amountlocalcurrency = item adjustedprice value tofixed(2); this basicitemdata price currency = item adjustedprice currencycode tostring(); } if (item instanceof dw\ order giftcertificatelineitem) { this basicitemdata name = item lineitemtext; //required this basicitemdata quantity = 1; //required (set 1 by default for a gift cert?) this basicitemdata type = "non tangible"; // add if type is available change according to the actual item type this deliverydetails = {}; this deliverydetails deliverytype = "digital"; this deliverydetails deliverymethod = "email"; this basicitemdata price = {}; this basicitemdata price amountlocalcurrency = item price value tofixed(2); this basicitemdata price currency = item price currencycode tostring(); this beneficiaries = \[]; this beneficiaries push(new forterbeneficiarydetailsfromgiftcard(item)); } } module exports = forterorder; step 3 testing normal qa email address place a phone order in your sandbox environment using any valid test email address the transaction should show in the portal transactions tab https //portal forter com/transactions and include a mobile phone icon next to the order number declined by forter place a purchase with email address decline\@forter com using a valid test card credit card or payment method this email address will always generate a "decline" decision in forter's sandbox environment and will enable you to test your sfcc cartridge flow for a declined mobile transaction once you've placed this declined order, please check your cartridge business manager and review and (potentially update) your processorresponse json file to either void funds and cancel declined mobile app orders approved by forter create an order using approve\@forter com and a valid test card for the transaction this will generate an "approve" decision and the transaction should show in the portal transactions tab https //portal forter com/transactions and include a mobile icon next to the order number make sure to review and update your processorresponse json file to capture the funds and proceed with this order in your oms