| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/renderer/cart/commerce_hint_agent.h" |
| |
| #include "base/cfi_buildflags.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "build/build_config.h" |
| #include "components/commerce/core/commerce_heuristics_data.h" |
| #include "components/commerce/core/commerce_heuristics_data_metrics_helper.h" |
| #if BUILDFLAG(IS_ANDROID) |
| #include "components/commerce/core/commerce_feature_list.h" |
| #else |
| #include "components/search/ntp_features.h" |
| #endif |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/gurl.h" |
| |
| namespace { |
| |
| constexpr int kTestIterations = 1000; |
| |
| // clang-format off |
| const char* kAddToCart[] = { |
| "submit.add-to-cart: Submit", |
| "gp/add-to-cart/json/", |
| "-addtocart&", |
| "?add-to-cart=1", |
| "action: peake_add_to_basket", |
| "action: woosea_addtocart_details", |
| "ajax=add_to_cart", |
| "action: woocommerce_add_to_cart", |
| "add-to-cart: 123", |
| "queryString=submit.addToCart", |
| "queryString=submit.AddToCart", |
| "&link=Add%20to%20Cart", |
| "api_call:shopping_bag_add_to_bag", // nordstrom.com |
| "\"cart_type\":\"REGULAR\"", // target.com |
| "cnc/checkout/cartItems/addItemToCart", // kohls.com |
| "\"event\":\"product_added_to_cart\"", // staples.com |
| "checkout/basket/add_and_show", // wayfair.com |
| "isQuickAddToCartButton=true", // costco.com |
| }; |
| |
| const char* kAddToCartWithDOMBasedHeuristics[] = { |
| "{\"productId\":\"123\",\"quantity\":14}", |
| "{\"productId\":\"123\",\"quantity\":\"151\"}", |
| "{\"Quantity\":\"2\"}", |
| "{\"cart_quantity\":\"23\"}", |
| "{\"product_quantity\":76}", |
| }; |
| |
| const char* kNotAddToCart[] = { |
| "misadd-to-cart", |
| "add_to_cartoon", |
| "_add_to_basketball", |
| "cart/address", |
| "golfcart/add", |
| }; |
| |
| const char* kNotAddToCartWithDOMBasedHeuristics[] = { |
| "{\"productName\":\"quantity_calculator\"}", |
| "quantity=1", |
| "{\"product_quantity\":ab}", |
| "{\"quality\":\"2\"}", |
| }; |
| |
| const char* kVisitCart[] = { |
| // Real cart URLs. |
| "https://www.brownells.com/aspx/Store/Cart.aspx", |
| "https://www.carid.com/cart.php", |
| "https://www.chegg.com/shoppingcart", |
| "https://www.target.com/co-cart", |
| "https://beastacademy.com/checkout/cart", |
| "https://cart.ebay.com/", |
| "https://cart.ebay.com/sc/view", |
| "https://cart.godaddy.com/", |
| "https://cart.godaddy.com/Basket.aspx", |
| "https://cart.godaddy.com/basket.aspx", |
| "https://cart.godaddy.com/go/checkout", |
| "https://cart.godaddy.com/upp/vcart", |
| "https://cart.payments.ebay.com/sc/add", |
| "https://es-store.usps.com/store/cart/cart.jsp", |
| "https://poshmark.com/bundles/shop", |
| "https://secure-athleta.gap.com/shopping-bag", |
| "https://secure-bananarepublic.gap.com/shopping-bag", |
| "https://secure-oldnavy.gap.com/buy/shopping_bag.do", |
| "https://secure-oldnavy.gap.com/shopping-bag", |
| "https://secure-www.gap.com/shopping-bag", |
| "https://secure.newegg.com/Shop/Cart", |
| "https://secure.newegg.com/shop/cart", |
| "https://secure2.homedepot.com/mycart/home", |
| "https://shop.advanceautoparts.com/web/OrderItemDisplay", |
| "https://shop.lululemon.com/shop/mybag", |
| "https://smile.amazon.co.uk/gp/cart/view.html", |
| "https://smile.amazon.com/gp/aw/c?ref_=navm_hdr_cart", |
| "https://smile.amazon.com/gp/cart/view.html", |
| "https://store.bricklink.com/v2/globalcart.page", |
| "https://store.steampowered.com/cart", |
| "https://store.steampowered.com/cart/", |
| "https://store.usps.com/store/cart/cart.jsp", |
| "https://training.atlassian.com/auth/cart", |
| "https://www.abebooks.com/servlet/ShopBasketPL", |
| "https://www.abebooks.com/servlet/ShoppingBasket", |
| "https://www.academy.com/shop/cart", |
| "https://www.acehardware.com/cart", |
| "https://www.adorama.com/Als.Mvc/CartView", |
| "https://www.adorama.com/als.mvc/cartview", |
| "https://www.ae.com/us/en/cart", |
| "https://www.altardstate.com/cart/", |
| "https://www.amazon.co.uk/gp/aws/cart/add.html", |
| "https://www.amazon.co.uk/gp/cart/view.html", |
| "https://www.amazon.co.uk/gp/cart/view.html/ref=chk_logo_return_to_cart", |
| "https://www.amazon.co.uk/gp/cart/view.html/ref=lh_cart", |
| "https://www.amazon.com/-/es/gp/cart/view.html", |
| "https://www.amazon.com/gp/aw/c?ref_=navm_hdr_cart", |
| "https://www.amazon.com/gp/aws/cart/add.html", |
| "https://www.amazon.com/gp/cart/view.html", |
| "https://www.amazon.com/gp/cart/view.html/ref=lh_cart", |
| "https://www.amazon.com/gp/cart/view.html/ref=lh_cart_vc_btn", |
| "https://www.anthropologie.com/cart", |
| "https://www.apple.com/shop/bag", |
| "https://www.apple.com/us-hed/shop/bag", |
| "https://www.apple.com/us/shop/goto/bag", |
| "https://www.apple.com/us_epp_805199/shop/bag", |
| "https://www.atlassian.com/purchase/cart", |
| "https://www.att.com/buy/cart", |
| "https://www.att.com/buy/checkout/cartview", |
| "https://www.backcountry.com/Store/cart/cart.jsp", |
| "https://www.basspro.com/shop/AjaxOrderItemDisplayView", |
| "https://www.bathandbodyworks.com/cart", |
| "https://www.bedbathandbeyond.com/store/cart", |
| "https://www.belk.com/shopping-bag/", |
| "https://www.bestbuy.com/cart", |
| "https://www.bhphotovideo.com/c/find/cart.jsp", |
| "https://www.bhphotovideo.com/find/cart.jsp", |
| "https://www.bhphotovideo.com/find/cart.jsp/mode/edu", |
| "https://www.bloomingdales.com/my-bag", |
| "https://www.boostmobile.com/cart.html", |
| "https://www.bricklink.com/v2/globalcart.page", |
| "https://www.brownells.com/aspx/Store/Cart.aspx", |
| "https://www.brownells.com/aspx/store/cart.aspx", |
| "https://www.buybuybaby.com/store/cart", |
| "https://www.carid.com/cart.php", |
| "https://www.chegg.com/shoppingcart", |
| "https://www.chegg.com/shoppingcart/", |
| "https://www.containerstore.com/cart/list.htm", |
| "https://www.costco.com/CheckoutCartDisplayView", |
| "https://www.costco.com/CheckoutCartView", |
| "https://www.crateandbarrel.com/Checkout/Cart", |
| "https://www.crateandbarrel.com/checkout/cart", |
| "https://www.dickssportinggoods.com/OrderItemDisplay", |
| "https://www.dillards.com/webapp/wcs/stores/servlet/OrderItemDisplay", |
| "https://www.dsw.com/en/us/shopping-bag", |
| "https://www.electronicexpress.com/cart", |
| "https://www.etsy.com/cart", |
| "https://www.etsy.com/cart/", |
| "https://www.etsy.com/cart/listing.php", |
| "https://www.etsy.com/cart/listing.php", |
| "https://www.eyebuydirect.com/cart", |
| "https://www.fingerhut.com/cart/index", |
| "https://www.finishline.com/store/cart/cart.jsp", |
| "https://www.freepeople.com/cart", |
| "https://www.freepeople.com/cart/", |
| "https://www.gamestop.com/cart", |
| "https://www.gamestop.com/cart/", |
| "https://www.groupon.com/cart", |
| "https://www.groupon.com/checkout/cart", |
| "https://www.harborfreight.com/checkout/cart", |
| "https://www.hmhco.com/hmhstorefront/cart", |
| "https://www.homedepot.com/mycart/home", |
| "https://www.homesquare.com/Checkout/Cart.aspx", |
| "https://www.hottopic.com/cart", |
| "https://www.hsn.com/checkout/bag", |
| "https://www.ikea.com/us/en/shoppingcart/", |
| "https://www.jcpenney.com/cart", |
| "https://www.jcrew.com/checkout/cart", |
| "https://www.joann.com/cart", |
| "https://www.kohls.com/checkout/shopping_cart.jsp", |
| "https://www.landsend.com/shopping-bag", |
| "https://www.landsend.com/shopping-bag/", |
| "https://www.llbean.com/webapp/wcs/stores/servlet/LLBShoppingCartDisplay", |
| "https://www.lowes.com/cart", |
| "https://www.lulus.com/checkout/bag", |
| "https://www.macys.com/my-bag", |
| "https://www.microsoft.com/en-US/store/cart", |
| "https://www.microsoft.com/en-us/store/buy/cart", |
| "https://www.microsoft.com/en-us/store/cart", |
| "https://www.midwayusa.com/cart", |
| "https://www.midwayusa.com/cart/", |
| "https://www.neimanmarcus.com/checkout/cart.jsp", |
| "https://www.nike.com/cart", |
| "https://www.nordstrom.com/shopping-bag", |
| "https://www.officedepot.com/cart/shoppingCart.do", |
| "https://www.opticsplanet.com/checkout/cart", |
| "https://www.overstock.com/cart", |
| ("https://www.pacsun.com/on/demandware.store/Sites-pacsun-Site/default/" |
| "Cart-Show"), |
| "https://www.petsmart.com/cart/", |
| "https://www.pier1.com/cart", |
| "https://www.pokemoncenter.com/cart", |
| "https://www.potterybarn.com/shoppingcart/", |
| "https://www.qvc.com/checkout/cart.html", |
| "https://www.redbubble.com/cart", |
| "https://www.rei.com/ShoppingCart", |
| "https://www.revolve.com/r/ShoppingBag.jsp", |
| "https://www.rockauto.com/en/cart", |
| "https://www.rockauto.com/en/cart/", |
| "https://www.rockauto.com/en/cart/checkout", |
| "https://www.saksfifthavenue.com/cart", |
| "https://www.samsclub.com/cart", |
| "https://www.samsclub.com/sams/cart/cart.jsp", |
| "https://www.sephora.com/basket", |
| "https://www.shutterfly.com/cart", |
| "https://www.shutterfly.com/cart/", |
| "https://www.staples.com/cc/mmx/cart", |
| "https://www.sweetwater.com/store/cart.php", |
| "https://www.talbots.com/cart", |
| "https://www.target.com/co-cart", |
| "https://www.target.com/co-cart", |
| "https://www.teacherspayteachers.com/Cart", |
| "https://www.teacherspayteachers.com/Cart/Checkout", |
| "https://www.therealreal.com/cart", |
| "https://www.tractorsupply.com/TSCShoppingCartView", |
| "https://www.ulta.com/bag", |
| "https://www.ulta.com/bag/empty", |
| "https://www.ulta.com/bag/login", |
| "https://www.underarmour.com/en-us/cart", |
| "https://www.urbanoutfitters.com/cart", |
| "https://www.vitalsource.com/cart", |
| "https://www.walgreens.com/cart/view-ui", |
| "https://www.walmart.com/cart", |
| "https://www.walmart.com/cart/", |
| "https://www.wayfair.com/session/public/basket.php", |
| "https://www.wayfair.com/v/checkout/basket/add_and_show", |
| "https://www.wayfair.com/v/checkout/basket/show", |
| "https://www.webstaurantstore.com/viewcart.cfm", |
| "https://www.weightwatchers.com/us/shop/checkout/cart", |
| "https://www.westelm.com/shoppingcart/", |
| "https://www.wiley.com/en-us/cart", |
| "https://www.wish.com/cart" |
| "https://www.williams-sonoma.com/shoppingcart/", |
| "https://www.zappos.com/cart", |
| "https://www.zazzle.com/co/cart", |
| "https://www.zennioptical.com/shoppingCart", |
| "https://www2.hm.com/en_gb/cart", |
| "https://www2.hm.com/en_us/cart", |
| // Example cart URLs. |
| "http://example.com/us/cart/", |
| "http://example.com/cart/", |
| "https://example.com/cart", |
| "http://example.com/cart", |
| "http://example.com/cart?param", |
| "http://example.com/cart#anchor", |
| "http://example.com/cart?param=value#anchor", |
| "https://www.example.com/cart/list.htm", |
| "https://cart.example.com", |
| "https://www.example.com/my-cart", |
| "https://www.example.com/CartView/", |
| "https://www.example.com/checkout/cart", |
| "https://www.example.com/CheckoutCartView/", |
| "https://example.com/bundles/shop", |
| "https://www.example.com/AjaxOrderItemDisplay", |
| "https://www.example.com/OrderItemDisplayView.jsp", |
| "https://www.example.com/cart-show", |
| }; |
| |
| const char* kNotVisitCart[] = { |
| // Real non-cart URLs. |
| "https://www.rockauto.com/xx/cart/", |
| "https://api.bestbuy.com/click/-/6429440/cart", |
| "https://api.bestbuy.com/click/-/6429442/cart", |
| "https://business.landsend.com/checkout/cart", |
| "https://business.officedepot.com/cart/checkout.do", |
| "https://business.officedepot.com/cart/shoppingCart.do", |
| "https://business.officedepot.com/cart/updateRouter.do", |
| "https://cart.ebay.com/api/xo", |
| "https://cns.usps.com/shippingCart", |
| "https://cns.usps.com/shippingCart.shtml", |
| "https://ecommerce2.apple.com/asb2bstorefront/asb2b/en/USD/cart", |
| "https://factory.jcrew.com/checkout/cart", |
| "https://m.llbean.com/webapp/wcs/stores/servlet/LLBShoppingCartDisplay", |
| "https://photo.samsclub.com/cart/items", |
| "https://photo.walgreens.com/cart/confirmation", |
| "https://photo.walgreens.com/cart/review", |
| "https://photo.walgreens.com/cart/shipping", |
| "https://photo.walgreens.com/cart/shoppingcart", |
| "https://photos3.walmart.com/shoppingcart", |
| "https://poshmark.com/bundles/sell", |
| "https://poshmark.com/category/Women-Bags", |
| "https://poshmark.com/category/Women-Bags-Crossbody_Bags", |
| "https://poshmark.com/showroom/" |
| "Louis-Vuitton-Handbags-1b6f536521bf8d6e0a155371", |
| "https://secure.newegg.com/Shopping/AddToCart.aspx", |
| "https://secure.newegg.com/Shopping/AddtoCart.aspx", |
| "https://secure.newegg.com/Shopping/EmailCart.aspx", |
| "https://shop.lululemon.com/c/bags/_/N-1z0xcuuZ8rd", |
| "https://shop.lululemon.com/c/bags/_/N-8rd", |
| "https://shop.lululemon.com/p/bags/All-Night-Festival-Bag-Micro/_/" |
| "prod9960617", |
| "https://shop.lululemon.com/p/bags/Everywhere-Belt-Bag/_/prod8900747", |
| "https://store.steampowered.com/app/1220140/Cartel_Tycoon/", |
| "https://store.steampowered.com/itemcart/checkout/", |
| "https://store.steampowered.com/points/shop/c/itembundles", |
| "https://store.usps.com/store/product/shipping-supplies/" |
| "readypost-15l-x-12w-x-10h-mailing-cartons-P_843061", |
| "https://www.academy.com/shop/browse/camping--outdoors/" |
| "sleeping-bags-and-bedding/airbeds--sleeping-pads", |
| "https://www.academy.com/shop/browse/outdoors/camping--outdoors/" |
| "sleeping-bags-airbeds-cots/airbeds--sleeping-pads", |
| "https://www.academy.com/shop/browse/sports/basketball/basketball-hoops", |
| "https://www.academy.com/shop/browse/sports/boxing--mma/" |
| "boxing-mma-punching-bags/heavy-bags", |
| "https://www.acehardware.com/cart/checkout", |
| "https://www.acehardware.com/departments/home-and-decor/" |
| "trash-and-recycling/garbage-cans-and-recycling-bins", |
| "https://www.acehardware.com/departments/lawn-and-garden/gardening-tools/" |
| "wheelbarrows-carts-and-hand-trucks", |
| "https://www.acehardware.com/departments/lawn-and-garden/gardening-tools/" |
| "wheelbarrows-carts-and-hand-trucks/7331739", |
| "https://www.adorama.com/l/Photography/Photography-Bags-and-Cases", |
| "https://www.ae.com/us/en/c/aerie/accessories-shoes/bags/cat6460064", |
| "https://www.ae.com/us/en/c/women/accessories-socks/belts-bags/cat1070004", |
| "https://www.ae.com/us/en/p/women/high-waisted-shorts/mom-shorts/" |
| "ae-paperbag-denim-mom-shorts/0338_6267_489", |
| "https://www.ae.com/us/en/p/women/jogger-pants/jogger-pants/" |
| "ae-paperbag-jogger-pant/0322_4413_309", |
| "https://www.altardstate.com/as/all-accessories/bags-keychains/", |
| "https://www.anthropologie.com/bags", |
| "https://www.anthropologie.com/shop/julien-leather-tote-bag", |
| "https://www.anthropologie.com/shop/liberty-crossbody-bag", |
| "https://www.anthropologie.com/shop/luna-slouchy-crossbody-bag", |
| "https://www.att.com/buy/bundles", |
| "https://www.att.com/buy/bundles/", |
| "https://www.att.com/buy/bundles/hsiaplans", |
| "https://www.backcountry.com/backcountry-double-ski-snowboard-rolling-bag", |
| "https://www.backcountry.com/down-sleeping-bags", |
| "https://www.backcountry.com/patagonia-baggies-shorts-mens", |
| "https://www.backcountry.com/sleeping-bags", |
| "https://www.basspro.com/shop/en/sleeping-bags", |
| "https://www.basspro.com/shop/en/" |
| "spring-fishing-classic-sale-tackle-boxes-and-bags", |
| "https://www.basspro.com/shop/en/tackle-bags", |
| "https://www.basspro.com/shop/en/tackle-boxes-bags", |
| "https://www.bathandbodyworks.com/c/gifts/gift-basket-stuffers", |
| "https://www.bathandbodyworks.com/on/demandware.store/" |
| "Sites-BathAndBodyWorks-Site/en_US/Cart-AddProduct", |
| "https://www.bathandbodyworks.com/on/demandware.store/" |
| "Sites-BathAndBodyWorks-Site/en_US/Cart-AddToWishlist", |
| "https://www.bathandbodyworks.com/on/demandware.store/" |
| "Sites-BathAndBodyWorks-Site/en_US/Cart-ContinueShopping", |
| "https://www.bedbathandbeyond.com/store/category/bedding/bed-in-a-bag/" |
| "16078/", |
| "https://www.bedbathandbeyond.com/store/category/bedding/bed-in-a-bag/" |
| "16078/_full-queen_queen/" |
| "dmlzdWFsVmFyaWFudC5ub252aXN1YWxWYXJpYW50LlNLVV9GT1JfU1dBVENILlNLVV9TSVpFOi" |
| "JmdWxsL3F1ZWVuInwicXVlZW4i", |
| "https://www.bedbathandbeyond.com/store/category/storage-cleaning/" |
| "storage-organization/drawers-carts/12642/", |
| "https://www.bedbathandbeyond.com/store/category/storage-cleaning/" |
| "storage-organization/storage-bins-baskets/12208/", |
| "https://www.belk.com/bed-bath/bedding/bed-in-a-bag/", |
| "https://www.belk.com/handbags/", |
| "https://www.belk.com/handbags/purses-handbags/", |
| "https://www.belk.com/handbags/purses-handbags/crossbody-bags/", |
| "https://www.bestbuy.com/site/combo/washer-dryer-bundles/" |
| "af7c2f64-5faa-4a9e-a079-7246f70db472", |
| "https://www.bestbuy.com/site/washers-dryers/washer-dryer-bundles/" |
| "pcmcat303000050004.c", |
| "https://www.bhphotovideo.com/c/browse/Bags-Cases-Carrying-Equipment/ci/" |
| "167/N/4075788798", |
| "https://www.bhphotovideo.com/c/buy/Shoulder-Gadget-Bags/ci/174", |
| "https://www.bloomingdales.com/shop/handbags", |
| "https://www.bloomingdales.com/shop/handbags/clutches-evening-bags", |
| "https://www.bloomingdales.com/shop/sale/handbags-purses", |
| "https://www.bloomingdales.com/shop/tory-burch/handbags-wallets", |
| "https://www.boostmobile.com/cart", |
| "https://www.buybuybaby.com/store/category/gear-travel/diaper-bags/30507/", |
| "https://www.buybuybaby.com/store/category/gear-travel/diaper-bags/" |
| "diaper-backpacks/32034/", |
| "https://www.buybuybaby.com/store/product/" |
| "carter-39-s-by-davinci-adrian-swivel-glider-with-ottoman-in-performance-" |
| "fabric/5354803", |
| "https://www.buybuybaby.com/store/registry/FreeGoodyBag", |
| "https://www.chegg.com/homework-help/" |
| "mauro-products-distributes-single-product-woven-basket-whose-chapter-6-" |
| "problem-7be-solution-9780077386214-exc", |
| "https://www.chegg.com/homework-help/questions-and-answers/" |
| "example-1010-p-252-suppose-mountain-climber-instead-drags-bag-supplies-" |
| "slope-increasing-sp-q31806760", |
| "https://www.containerstore.com/s/laundry-cleaning/hampers-baskets/12", |
| "https://www.containerstore.com/s/storage/decorative-bins-baskets/12", |
| "https://www.containerstore.com/s/storage/plastic-bins-baskets/12", |
| "https://www.containerstore.com/s/storage/plastic-bins-baskets/" |
| "white-nordic-storage-baskets-with-handles/12d", |
| "https://www.costco.com/ManageShoppingCartCmd", |
| "https://www.costco.com/handbags-wallets.html", |
| "https://www.costco.com/logon-instacart", |
| "https://www.crateandbarrel.com/decorating-and-accessories/baskets/1", |
| "https://www.crateandbarrel.com/furniture/bar-cabinets-and-carts/1", |
| "https://www.crateandbarrel.com/furniture/filing-cabinets-and-carts/1", |
| "https://www.dickssportinggoods.com/c/basketball-gear", |
| "https://www.dickssportinggoods.com/f/basketball-shoes-for-men", |
| "https://www.dickssportinggoods.com/f/golf-bags-accessories-1", |
| "https://www.dickssportinggoods.com/p/" |
| "jordan-air-jordan-1-mid-basketball-shoes-19nikmrjrdn1mdblknke/" |
| "19nikmrjrdn1mdblknke", |
| "https://www.dillards.com/brand/Michael+Kors/handbags", |
| "https://www.dillards.com/c/handbags", |
| "https://www.dillards.com/c/handbags-cross-body-bags", |
| "https://www.dillards.com/c/sale-clearance/handbags", |
| "https://www.dsw.com/en/us/category/womens-clearance-handbags/" |
| "N-1z141jrZ1z141ilZ1z141cp", |
| "https://www.dsw.com/en/us/category/womens-crossbody-handbags/" |
| "N-1z141jrZ1z128u1Z1z141cp", |
| "https://www.dsw.com/en/us/category/womens-handbags/N-1z141jrZ1z141cp", |
| "https://www.dsw.com/en/us/category/womens-leather-and-nubuck-handbags/" |
| "N-1z141jrZ1z12bixZ1z12b4gZ1z12b7gZ1z141cp", |
| "https://www.etsy.com/c/bags-and-purses/handbags", |
| "https://www.etsy.com/c/bags-and-purses/handbags/shoulder-bags", |
| "https://www.eyebuydirect.com/sunglasses/frames/cartel-tortoise-m-19614", |
| "https://www.fingerhut.com/cart/justAdded", |
| "https://www.fingerhut.com/search/Clothing/Handbags", |
| "https://www.fingerhut.com/search/Clothing/Handbags/2126.uts", |
| "https://www.fingerhut.com/search/Clothing/Luggage%20&%20Travel%20Bags", |
| "https://www.finishline.com/store/cart/cartSlide.jsp", |
| "https://www.finishline.com/store/men/shoes/basketball/_/N-3z3fil", |
| "https://www.finishline.com/store/product/" |
| "mens-air-jordan-6-rings-basketball-shoes/prod739613", |
| "https://www.finishline.com/store/product/" |
| "nike-zoom-freak-2-basketball-shoes/prod2800331", |
| "https://www.freepeople.com/bags/", |
| "https://www.freepeople.com/shop/carter-sweater-set/", |
| "https://www.freepeople.com/shop/hudson-sling-bag/", |
| "https://www.gamestop.com/clothing/bags-travel/backpacks", |
| "https://www.gamestop.com/toys-collectibles/toys/blind-bags", |
| "https://www.gamestop.com/toys-collectibles/toys/plush/products/" |
| "squishmallows-plush-bag-clip-assortment/11108921.html", |
| "https://www.groupon.com/coupons/carters", |
| "https://www.groupon.com/coupons/instacart", |
| "https://www.groupon.com/deals/" |
| "gg-mp-oled-fingertip-pulse-oximeter-finger-blood-oxygen-spo2-pr-heart-" |
| "rate-monitor-bag", |
| "https://www.harborfreight.com/material-handling/" |
| "hand-trucks-carts-dollies.html", |
| "https://www.harborfreight.com/tool-storage-organization/" |
| "tool-boxes-bags-belts.html", |
| "https://www.harborfreight.com/tool-storage-organization/tool-storage/" |
| "tool-carts.html", |
| "https://www.harborfreight.com/tool-storage-organization/" |
| "yukon-tool-storage/tool-carts-cabinets.html", |
| "https://www.homedepot.com/b/Appliances-Garbage-Disposals/N-5yc1vZc3no", |
| "https://www.homedepot.com/p/" |
| "GE-4-2-cu-ft-White-Top-Load-Washing-Machine-with-Stainless-Steel-Basket-" |
| "GTW335ASNWW/308653937", |
| "https://www.homedepot.com/p/" |
| "GE-4-5-cu-ft-High-Efficiency-White-Top-Load-Washing-Machine-with-" |
| "Stainless-Steel-Basket-GTW465ASNWW/308653940", |
| "https://www.homedepot.com/p/Vigoro-2-cu-ft-Bagged-Brown-Mulch-52050196/" |
| "205606287", |
| "https://www.hottopic.com/accessories/bags/", |
| "https://www.hottopic.com/accessories/bags/backpacks/", |
| "https://www.hottopic.com/accessories/bags/wallets/", |
| "https://www.hottopic.com/on/demandware.store/Sites-hottopic-Site/default/" |
| "Cart-AddToWishlist", |
| "https://www.hsn.com/shop/clearance-handbags-and-wallets-for-women/" |
| "fa0402-4525", |
| "https://www.hsn.com/shop/handbags-and-wallets-for-women/fa0402", |
| "https://www.hsn.com/shop/hands-free-handbags/20986", |
| "https://www.hsn.com/shop/patricia-nash-handbags-and-wallets-for-women/" |
| "fa0402-16311", |
| "https://www.ikea.com/us/en/cat/baskets-16201/", |
| "https://www.ikea.com/us/en/cat/kitchen-islands-carts-10471/", |
| "https://www.ikea.com/us/en/cat/kitchen-islands-carts-fu005/", |
| "https://www.ikea.com/us/en/cat/storage-boxes-baskets-10550/", |
| "https://www.jcpenney.com/cart/signin", |
| "https://www.jcpenney.com/g/purses-accessories/crossbody-bags", |
| "https://www.jcpenney.com/g/purses-accessories/view-all-handbags-wallets", |
| "https://www.jcpenney.com/jsp/cart/viewShoppingBag.jsp", |
| "https://www.jcrew.com/c/mens_category/bags", |
| "https://www.jcrew.com/c/womens_category/handbags", |
| "https://www.jcrew.com/checkout2/shoppingbag.jsp", |
| "https://www.joann.com/home-decor-and-holiday/" |
| "storage-and-organization-decor/baskets/", |
| "https://www.joann.com/iris-usa-6-drawer-medium-cart/7226947.html", |
| "https://www.joann.com/sewing/sewing-baskets-and-pin-cushions/", |
| "https://www.joann.com/we-r-memory-keepers-a-la-cart/zprd_18086751a.html", |
| "https://www.kohls.com/catalog/" |
| "womens-totes-handbags-purses-accessories.jsp", |
| "https://www.kohls.com/ecom/kohls-smartcart-kcash.html", |
| "https://www.kohls.com/product/prd-1369234/" |
| "shark-navigator-lift-away-deluxe-professional-bagless-vacuum.jsp", |
| "https://www.kohls.com/product/prd-3698449/" |
| "mens-nike-dri-fit-icon-basketball-shorts.jsp", |
| "https://www.landsend.com/products/open-or-zip-top-natural-canvas-tote-bag/" |
| "id_299717", |
| "https://www.landsend.com/shop/bags-travel-sale/S-xfd-ytq-xec", |
| "https://www.llbean.com/llb/shop/webapp/wcs/stores/servlet/" |
| "LLBShoppingCartDisplay", |
| "https://www.lowes.com/pl/Bagged-mulch-Mulch-Landscaping-Lawn-garden/" |
| "4294612786", |
| "https://www.lowes.com/pl/" |
| "Kitchen-islands-carts-Dining-kitchen-furniture-Furniture-Home-decor/" |
| "1323549633", |
| "https://www.lowes.com/pl/" |
| "Plastic-storage-totes-Baskets-storage-containers-Storage-organization/" |
| "4294713243", |
| "https://www.lowes.com/pl/" |
| "Wheelbarrows-Wheelbarrows-yard-carts-Outdoor-tools-equipment-Outdoors/" |
| "3394587996", |
| "https://www.lulus.com/categories/39_598/vegan-handbags-and-purses.html", |
| "https://www.lulus.com/categories/99_39/handbags-and-purses.html", |
| "https://www.lulus.com/products/weekend-traveler-black-and-cognac-tote-bag/" |
| "1029302.html", |
| "https://www.lulus.com/products/weekend-traveler-cognac-tote-bag/" |
| "1029322.html", |
| "https://www.macys.com/shop/bed-bath/bed-in-a-bag", |
| "https://www.macys.com/shop/featured/michael-kors-handbags", |
| "https://www.macys.com/shop/handbags-accessories", |
| "https://www.macys.com/shop/sale/Business_category/" |
| "Handbags%20%26%20Accessories%7CWomen%7CWomen%27s%20Shoes", |
| "https://www.microsoft.com/en-us/store/collections/surfacebagsandsleeves/" |
| "pc", |
| "https://www.microsoft.com/en-us/store/collections/surfacebundles", |
| "https://www.midwayusa.com/backpacks-and-bags/br", |
| "https://www.midwayusa.com/range-bags/br", |
| "https://www.midwayusa.com/shooting-rests-and-bags/br", |
| "https://www.neimanmarcus.com/c/handbags-all-handbags-cat46860739", |
| "https://www.neimanmarcus.com/c/handbags-cat13030735", |
| "https://www.neimanmarcus.com/c/sale-all-sale-women-handbags-cat74120753", |
| "https://www.neimanmarcus.com/c/sale-women-handbags-cat46520737", |
| "https://www.nike.com/w/mens-bags-and-backpacks-9xy71znik1", |
| "https://www.nike.com/w/mens-basketball-shoes-3glsmznik1zy7ok", |
| "https://www.nike.com/w/" |
| "mens-nike-by-you-basketball-shoes-3glsmz6ealhznik1zy7ok", |
| "https://www.nike.com/w/womens-basketball-shoes-3glsmz5e1x6zy7ok", |
| "https://www.nordstrom.com/browse/designer/women/handbags", |
| "https://www.nordstrom.com/browse/sale/women/handbags", |
| "https://www.nordstrom.com/browse/women/handbags", |
| "https://www.nordstrom.com/browse/women/handbags/crossbody", |
| "https://www.officedepot.com/cart/checkout.do", |
| "https://www.opticsplanet.com/cart-empty", |
| "https://www.overstock.com/Bedding-Bath/Bed-in-a-Bag/29942/cat.html", |
| "https://www.overstock.com/Home-Garden/Kitchen-Carts/1996/subcat.html", |
| "https://www.overstock.com/Home-Garden/" |
| "Malia-Outdoor-Standing-Wicker-Basket-Chair-with-Cushion-by-Christopher-" |
| "Knight-Home/29874486/product.html", |
| "https://www.overstock.com/Home-Garden/Simple-Living-Georgia-Kitchen-Cart/" |
| "30992405/product.html", |
| "https://www.pacsun.com/mens/backpacks-bags/", |
| "https://www.pacsun.com/on/demandware.store/Sites-pacsun-Site/default/" |
| "Cart-ContinueShopping", |
| "https://www.pacsun.com/womens/accessories/handbags/", |
| "https://www.pacsun.com/womens/jeans/baggy/", |
| "https://www.petsmart.com/cart-checkout/", |
| "https://www.petsmart.com/fish/filters-and-pumps/filter-media/" |
| "top-fin-ef-s-element-aquarium-filter-cartridges---12pk-57278.html", |
| "https://www.petsmart.com/on/demandware.store/Sites-PetSmart-Site/default/" |
| "Cart-ContinueShopping", |
| "https://www.petsmart.com/on/demandware.store/Sites-PetSmart-Site/default/" |
| "Paypal-StartExpressCheckoutFromCartFlow", |
| "https://www.pier1.com/cart/add", |
| "https://www.pier1.com/cart/change", |
| "https://www.pier1.com/products/sisal-bunny-girl-with-basket-15h", |
| "https://www.pier1.com/products/twig-basket-with-bunny", |
| "https://www.pokemoncenter.com/category/bags-and-totes", |
| "https://www.potterybarn.com/products/beachcomber-basket-collection/", |
| "https://www.potterybarn.com/products/seagrass-basket-collection-havana/", |
| "https://www.potterybarn.com/products/seagrass-basket-collection-savannah/", |
| "https://www.potterybarn.com/shop/organization/baskets-organization/", |
| "https://www.qvc.com/handbags-&-luggage/_/N-uoq0/c.html", |
| "https://www.qvc.com/handbags-&-luggage/dooney-&-bourke/_/N-uoq0Z1z141jd/" |
| "c.html", |
| "https://www.qvc.com/handbags-&-luggage/handbags/_/N-2a0k5/c.html", |
| "https://www.qvc.com/handbags-&-luggage/luggage/_/N-1cjuv/c.html", |
| "https://www.redbubble.com/shop/drawstring-bags", |
| "https://www.redbubble.com/shop/duffle-bags", |
| "https://www.redbubble.com/shop/makeup+bags", |
| "https://www.redbubble.com/shop/tote-bags", |
| "https://www.rei.com/c/mens-sleeping-bags", |
| "https://www.rei.com/c/womens-sleeping-bags", |
| "https://www.rei.com/product/126821/patagonia-baggies-shorts-womens", |
| "https://www.rei.com/rei-garage/c/sleeping-bags-and-accessories", |
| "https://www.revolve.com/bags-clutches/br/cc5b36/", |
| "https://www.revolve.com/bags-crossbody-bags/br/f8c179/", |
| "https://www.revolve.com/bags-totes/br/317dcf/", |
| "https://www.revolve.com/bags/br/2df9df/", |
| "https://www.rockauto.com/es/cart/", |
| "https://www.saksfifthavenue.com/c/handbags", |
| "https://www.saksfifthavenue.com/c/handbags/handbags/crossbody-bags", |
| "https://www.saksfifthavenue.com/c/handbags/handbags/totes", |
| "https://www.saksfifthavenue.com/c/handbags/saint-laurent", |
| "https://www.samsclub.com/b/gourmet-gift-baskets-and-food/1261", |
| "https://www.samsclub.com/sams/controller/SamsInstaCartZipcodeController", |
| "https://www.sephora.com/beauty-sample-bag", |
| "https://www.sephora.com/beauty/beauty-sample-bag", |
| "https://www.sephora.com/product/baggage-claim-gold-eye-masks-P428668", |
| "https://www.sephora.com/shop/makeup-bags-cosmetic-bags", |
| "https://www.shutterfly.com/maincart/start.sfly", |
| "https://www.shutterfly.com/personalized-gifts/cotton-tote-bags", |
| "https://www.shutterfly.com/signout/itemsInCart.sfly", |
| "https://www.staples.com/hp-ink-cartridges/cat_CG812", |
| "https://www.staples.com/services/printing/Cart", |
| "https://www.staples.com/services/printing/CartCheckout", |
| "https://www.staples.com/services/printing/cart", |
| "https://www.sweetwater.com/c933--Electric_Guitar_Gig_Bags", |
| "https://www.sweetwater.com/c982--Drum_Microphone_Bundles", |
| "https://www.sweetwater.com/shop/drums-percussion/drum-cases-bags/", |
| "https://www.sweetwater.com/store/detail/" |
| "PS9339--prs-private-stock-number-9339-mccarty-594-hollowbody-ii-namm-2021-" |
| "tiger-eye-glow", |
| "https://www.talbots.com/accessories/handbags", |
| "https://www.talbots.com/basket-weave-sweater---solid/P211121070.html", |
| "https://www.talbots.com/nappa-havana-turnlock-camera-bag/P211061420.html", |
| "https://www.talbots.com/on/demandware.store/Sites-talbotsus-Site/default/" |
| "Cart-SubmitForm", |
| "https://www.target.com/c/easter-basket-candy/-/N-4pa5f", |
| "https://www.target.com/c/easter-basket-fillers/-/N-w48b8", |
| "https://www.target.com/c/easter-baskets/-/N-4uswf", |
| "https://www.teacherspayteachers.com/Product/" |
| "Free-Easter-and-Spring-Craft-Chicks-in-a-Basket-1165442", |
| "https://www.teacherspayteachers.com/Product/" |
| "March-Madness-Basketball-Tournament-Math-Project-PBL-Digital-Google-" |
| "Slides-326537", |
| "https://www.teacherspayteachers.com/Store/Not-So-Wimpy-Teacher/Category/" |
| "Writing-Bundles-509675", |
| "https://www.therealreal.com/designers/chanel/women/handbags", |
| "https://www.therealreal.com/shop/women/handbags", |
| "https://www.therealreal.com/shop/women/handbags/crossbody-bags", |
| "https://www.therealreal.com/shop/women/handbags/totes", |
| "https://www.tractorsupply.com/tsc/catalog/egg-cartons", |
| "https://www.tractorsupply.com/tsc/catalog/garden-carts", |
| "https://www.tractorsupply.com/tsc/catalog/wheelbarrows-garden-carts", |
| "https://www.tractorsupply.com/tsc/product/" |
| "ohio-steel-15-cu-ft-poly-swivel-dump-cart", |
| "https://www.ulta.com/" |
| "free-dry-shampoo-9-piece-beauty-bag-with-50-hair-care-purchase", |
| "https://www.ulta.com/makeup-bags-organizers", |
| "https://www.underarmour.com/en-us/c/mens/accessories/bags/", |
| "https://www.underarmour.com/en-us/c/mens/shoes/basketball/", |
| "https://www.underarmour.com/en-us/c/mens/sports/basketball/", |
| "https://www.underarmour.com/en-us/c/shoes/basketball/", |
| "https://www.urbanoutfitters.com/bags-wallets-for-women", |
| "https://www.urbanoutfitters.com/shop/" |
| "bdg-bubble-corduroy-high-waisted-baggy-pant", |
| "https://www.urbanoutfitters.com/shop/" |
| "bdg-high-waisted-baggy-jean-medium-wash", |
| "https://www.urbanoutfitters.com/shop/carter-triangle-bracket-wall-shelf", |
| "https://www.vans.com/shop/mens-accessories-backpacks-bags", |
| "https://www.vans.com/shop/womens-accessories-backpacks-bags", |
| "https://www.walmart.com/browse/build-your-easter-basket/0/0/", |
| "https://www.walmart.com/browse/home/bed-in-a-bag-sets/" |
| "4044_539103_9474113_3388004", |
| "https://www.wayfair.com/furniture/sb0/kitchen-islands-carts-c415182.html", |
| "https://www.wayfair.com/storage-organization/sb0/" |
| "hampers-laundry-baskets-c215044.html", |
| "https://www.weightwatchers.com/us/recipe/" |
| "2-ingredient-dough-everything-bagels/5fbd830687a4600722b90e01", |
| "https://www.weightwatchers.com/us/recipe/" |
| "corned-beef-and-cabbage-fried-rice/601c5ce2a1ceeb43bfb53608", |
| "https://www.weightwatchers.com/us/recipe/" |
| "corned-beef-and-cabbage-red-potatoes-1/5626a5f34236657004995b4d", |
| "https://www.weightwatchers.com/us/recipe/" |
| "spinach-bagels-herbed-cream-cheese/5e596fb716a786036659fb09", |
| "https://www.westelm.com/products/hilo-basket-planters-d10517/", |
| "https://www.westelm.com/products/" |
| "mid-century-heathered-basketweave-wool-rug-steel-t1811/", |
| "https://www.westelm.com/products/parker-mid-century-bar-cart-h415/", |
| "https://www.westelm.com/shop/storage-organization/storage-baskets-bins/", |
| "https://www.williams-sonoma.com/shop/easter/easter-feature-build-basket/", |
| "https://www.williams-sonoma.com/shop/home-furniture/bar-carts-cabinets/", |
| "https://www.williams-sonoma.com/shop/home-furniture/kitchen-island-cart/", |
| "https://www.williams-sonoma.com/shop/tabletop-glassware-bar/" |
| "serving-trays-platters-baskets/", |
| "https://www.zappos.com/brooks-women-sneakers-athletic-shoes/" |
| "CK_XARC81wFSARpaARrAAQHiAgUBAgsYCg.zso", |
| "https://www.zappos.com/filters/women-sneakers-athletic-shoes/" |
| "CK_XARC81wFaByTcA4Ql5AfAAQHiAgQBAgsY.zso", |
| "https://www.zappos.com/sandals/CK_XARC51wHiAgIBAg.zso", |
| "https://www.zappos.com/sneakers-athletic-shoes/CK_XARC81wHiAgIBAg.zso", |
| "https://www2.hm.com/en_us/women/products/accessories/purses-bags.html", |
| "https://www2.hm.com/en_us/women/products/pants/paperbag-pants.html", |
| // Example non-cart URLs. |
| "https://example.com/gp/aw/c?ref_=navm_hdr_cart", |
| "https://example.com/cartoon", |
| "https://example.com/checkout", |
| "https://example.com/moving-cart", |
| "https://example.com/shoulder_bag", |
| }; |
| |
| const char* kVisitCheckout[] = { |
| "https://www.amazon.com/gp/buy/spc/handlers/display.html?", |
| "https://smile.amazon.com/gp/buy/spc/handlers/display.html?", |
| "https://pay.ebay.com/rgxo?action=view&sessionid=1111111111", |
| "https://www.example.com/chkout/rc", |
| "https://www.example.com/final-checkout", |
| "https://www.example.com/Secure-Checkout", |
| "https://www.example.com/Checkout-Begin", |
| "https://www.example.com/checkout-start", |
| "http://example.com/us/checkout/", |
| "http://example.com/checkout/", |
| "https://example.com/checkout?param#anchor", |
| "https://example.com/checkout#anchor", |
| "https://example.com/123/checkouts/456", |
| "http://example.com/123/checkouts/456", |
| "http://example.com/123/SPcheckouts", |
| "https://www.example.com/intlcheckout" |
| }; |
| |
| const char* kNotVisitCheckout[] = { |
| "https://www.amazon.com/gp/spc/handlers/display.html?", |
| "https://www.amazon.com/gp/aw/c?ref_=navm_hdr_cart", |
| "https://cart.ebay.com/rgxo", |
| "https://pay.ebay.com/api/xo", |
| "https://example.com/gp/cart/mobile/go-to-checkout.html/ref=ox_sc_proceed?proceedToCheckout=1", |
| "http://example.com/checkoutput", |
| "http://example.com/us/checkoutside/", |
| }; |
| |
| const char* kPurchaseURL[] = { |
| "https://www.amazon.com/gp/buy/spc/handlers/static-submit-decoupled.html/ref=ox_spc_place_order?ie=UTF8", |
| }; |
| |
| const char* kNotPurchaseURL[] = { |
| "https://example.com/gp/buy/spc/handlers/static-submit-decoupled.html/ref=ox_spc_place_order?ie=UTF8", |
| }; |
| |
| const char* kPurchaseText[] = { |
| "Place order", |
| "PAY NOW", |
| "PLACE ORDER", |
| "Pay now", |
| "pay $24", |
| "pay $24.35", |
| "pay USD 24.35", |
| "make payment", |
| "confirm & pay", |
| "PURCHASE", |
| "MAKE THIS PURCHASE", |
| }; |
| |
| const char* kNotPurchaseText[] = { |
| "I'd like to pay now", |
| "replace order", |
| "Pay nowadays", |
| "make payment later", |
| "confirm and continue" |
| "submit", |
| "Continue to Review Order", |
| "next step: review order" |
| "Process Order", |
| "", |
| }; |
| |
| const char* kSkipText[] = { |
| "Skipped", |
| "A skipped product", |
| "萬國碼", |
| "一個萬國碼產品", |
| }; |
| |
| const char* kNotSkipText[] = { |
| "", |
| "A normal product", |
| }; |
| // clang-format on |
| |
| // Cannot use \b, or non-alphabetical words would fail. |
| const char kSkipPattern[] = "(^|\\W)(?i)(skipped|萬國碼)(\\W|$)"; |
| std::map<std::string, std::string> kSkipParams = { |
| {"product-skip-pattern", kSkipPattern}}; |
| |
| std::map<std::string, std::string> kSkipAddToCartRequests = { |
| {"https://www.electronicexpress.com", "https://www.electronicexpress.com"}, |
| {"https://www.electronicexpress.com", "https://www.google.com"}, |
| {"https://www.costco.com", "https://www.clicktale.net"}, |
| {"https://www.hsn.com", "https://www.granify.com"}, |
| {"https://www.lululemon.com", "https://www.launchdarkly.com"}, |
| {"https://www.qvc.com", "https://www.qvc.com"}, |
| {"https://www.qvc.com", "https://www.google.com"}, |
| }; |
| |
| std::map<std::string, std::string> kNotSkipAddToCartRequests = { |
| {"https://www.costco.com", "https://www.granify.com"}, |
| {"https://www.hsn.com", "https://www.launchdarkly.com"}, |
| {"https://www.lululemon.com", "https://www.clicktale.net"}, |
| }; |
| } // namespace |
| |
| using cart::CommerceHintAgent; |
| |
| class CommerceHintAgentUnitTest : public testing::Test { |
| public: |
| void TearDown() override { |
| // Clear out heuristics data that is set up during testing. |
| commerce_heuristics::CommerceHeuristicsData::GetInstance() |
| .PopulateDataFromComponent( |
| /*hint_json_data=*/"{}", /*global_json_data=*/"{}", |
| /*product_id_json_data=*/"{}", /*cart_extraction_script=*/""); |
| } |
| |
| protected: |
| base::HistogramTester histogram_tester_; |
| }; |
| |
| TEST_F(CommerceHintAgentUnitTest, IsAddToCart) { |
| // Heuristics from feature param default value. |
| for (auto* str : kAddToCart) { |
| EXPECT_TRUE(CommerceHintAgent::IsAddToCart(str)) << str; |
| } |
| for (auto* str : kNotAddToCart) { |
| EXPECT_FALSE(CommerceHintAgent::IsAddToCart(str)) << str; |
| } |
| |
| // Heuristics from component. |
| const std::string& component_pattern = R"###( |
| { |
| "add_to_cart_request_regex": "bar" |
| } |
| )###"; |
| EXPECT_TRUE(commerce_heuristics::CommerceHeuristicsData::GetInstance() |
| .PopulateDataFromComponent("{}", component_pattern, "", "")); |
| EXPECT_TRUE(CommerceHintAgent::IsAddToCart("request_bar")); |
| for (auto* str : kAddToCart) { |
| EXPECT_FALSE(CommerceHintAgent::IsAddToCart(str)) << str; |
| } |
| |
| // Feature param has a higher priority. |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeatureWithParameters( |
| #if !BUILDFLAG(IS_ANDROID) |
| ntp_features::kNtpChromeCartModule, |
| #else |
| commerce::kCommerceHintAndroid, |
| #endif |
| {{"add-to-cart-pattern", "foo"}}); |
| EXPECT_FALSE(CommerceHintAgent::IsAddToCart("request_bar")); |
| } |
| |
| TEST_F(CommerceHintAgentUnitTest, IsAddToCartForDomBasedHeuristics) { |
| for (auto* str : kAddToCartWithDOMBasedHeuristics) { |
| EXPECT_TRUE(CommerceHintAgent::IsAddToCartForDomBasedHeuristics(str)) |
| << str; |
| } |
| for (auto* str : kNotAddToCartWithDOMBasedHeuristics) { |
| EXPECT_FALSE(CommerceHintAgent::IsAddToCartForDomBasedHeuristics(str)) |
| << str; |
| } |
| } |
| |
| TEST_F(CommerceHintAgentUnitTest, IsAddToCart_SkipLengthLimit) { |
| std::string str = "a"; |
| for (int i = 0; i < 12; ++i) { |
| str += str; |
| } |
| // This is equal to length limit in CommerceHintAgent. |
| EXPECT_EQ(str.size(), 4096U); |
| |
| str += "/add-to-cart"; |
| EXPECT_FALSE(CommerceHintAgent::IsAddToCart(str)); |
| EXPECT_TRUE(CommerceHintAgent::IsAddToCart(str, true)); |
| } |
| |
| TEST_F(CommerceHintAgentUnitTest, IsVisitCart) { |
| // Heuristics from feature param default value. |
| for (auto* str : kVisitCart) { |
| EXPECT_TRUE(CommerceHintAgent::IsVisitCart(GURL(str))) << str; |
| } |
| for (auto* str : kNotVisitCart) { |
| EXPECT_FALSE(CommerceHintAgent::IsVisitCart(GURL(str))) << str; |
| } |
| |
| // General heuristics from component. |
| const std::string& component_pattern = R"###( |
| { |
| "cart_page_url_regex": "bar" |
| } |
| )###"; |
| EXPECT_TRUE(commerce_heuristics::CommerceHeuristicsData::GetInstance() |
| .PopulateDataFromComponent("{}", component_pattern, "", "")); |
| EXPECT_TRUE(CommerceHintAgent::IsVisitCart(GURL("https://wwww.foo.com/bar"))); |
| |
| // Per-domain heuristics from component which has a higher priority than |
| // general heuristics. |
| EXPECT_TRUE(commerce_heuristics::CommerceHeuristicsData::GetInstance() |
| .PopulateDataFromComponent(R"###( |
| { |
| "foo.com": { |
| "cart_url_regex" : "foo.com/([^/]+/)?trac" |
| } |
| } |
| )###", |
| "{}", "", "")); |
| EXPECT_TRUE( |
| CommerceHintAgent::IsVisitCart(GURL("https://wwww.foo.com/test/trac"))); |
| EXPECT_FALSE( |
| CommerceHintAgent::IsVisitCart(GURL("https://wwww.foo.com/bar"))); |
| |
| // Feature param has a higher priority than component. |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeatureWithParameters( |
| #if !BUILDFLAG(IS_ANDROID) |
| ntp_features::kNtpChromeCartModule, |
| #else |
| commerce::kCommerceHintAndroid, |
| #endif |
| {{"cart-pattern", "baz"}, {"cart-pattern-mapping", R"###( |
| { |
| "foo.com": "foo.com/cart" |
| } |
| )###"}}); |
| EXPECT_FALSE( |
| CommerceHintAgent::IsVisitCart(GURL("https://wwww.foo.com/bar"))); |
| EXPECT_FALSE( |
| CommerceHintAgent::IsVisitCart(GURL("https://wwww.foo.com/test/trac"))); |
| } |
| |
| TEST_F(CommerceHintAgentUnitTest, IsVisitCheckout) { |
| // Heuristics from feature param default value. |
| for (auto* str : kVisitCheckout) { |
| EXPECT_TRUE(CommerceHintAgent::IsVisitCheckout(GURL(str))) << str; |
| } |
| for (auto* str : kNotVisitCheckout) { |
| EXPECT_FALSE(CommerceHintAgent::IsVisitCheckout(GURL(str))) << str; |
| } |
| histogram_tester_.ExpectBucketCount( |
| "Commerce.Heuristics.CheckoutURLGeneralPatternSource", |
| CommerceHeuristicsDataMetricsHelper::HeuristicsSource::FROM_COMPONENT, 0); |
| EXPECT_GT(histogram_tester_.GetBucketCount( |
| "Commerce.Heuristics.CheckoutURLGeneralPatternSource", |
| CommerceHeuristicsDataMetricsHelper::HeuristicsSource:: |
| FROM_FEATURE_PARAMETER), |
| 0); |
| |
| // General heuristics from component. |
| const std::string& component_pattern = R"###( |
| { |
| "checkout_page_url_regex": "bar" |
| } |
| )###"; |
| EXPECT_TRUE(commerce_heuristics::CommerceHeuristicsData::GetInstance() |
| .PopulateDataFromComponent("{}", component_pattern, "", "")); |
| EXPECT_TRUE( |
| CommerceHintAgent::IsVisitCheckout(GURL("https://wwww.foo.com/bar"))); |
| histogram_tester_.ExpectBucketCount( |
| "Commerce.Heuristics.CheckoutURLGeneralPatternSource", |
| CommerceHeuristicsDataMetricsHelper::HeuristicsSource::FROM_COMPONENT, 1); |
| // Per-domain heuristics from component which has a higher priority than |
| // general heuristics. |
| EXPECT_TRUE(commerce_heuristics::CommerceHeuristicsData::GetInstance() |
| .PopulateDataFromComponent(R"###( |
| { |
| "foo.com": { |
| "checkout_url_regex" : "foo.com/([^/]+/)?tuokcehc" |
| } |
| } |
| )###", |
| "{}", "", "")); |
| EXPECT_TRUE(CommerceHintAgent::IsVisitCheckout( |
| GURL("https://wwww.foo.com/test/tuokcehc"))); |
| EXPECT_FALSE( |
| CommerceHintAgent::IsVisitCheckout(GURL("https://wwww.foo.com/bar"))); |
| |
| // Feature param has a higher priority than component. |
| int prev_count = histogram_tester_.GetBucketCount( |
| "Commerce.Heuristics.CheckoutURLGeneralPatternSource", |
| CommerceHeuristicsDataMetricsHelper::HeuristicsSource:: |
| FROM_FEATURE_PARAMETER); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeatureWithParameters( |
| #if !BUILDFLAG(IS_ANDROID) |
| ntp_features::kNtpChromeCartModule, |
| #else |
| commerce::kCommerceHintAndroid, |
| #endif |
| {{"checkout-pattern", "foo"}, {"checkout-pattern-mapping", R"###( |
| { |
| "foo.com": "foo.com/checkout" |
| } |
| )###"}}); |
| EXPECT_FALSE( |
| CommerceHintAgent::IsVisitCheckout(GURL("https://wwww.foo.com/bar"))); |
| EXPECT_FALSE(CommerceHintAgent::IsVisitCheckout( |
| GURL("https://wwww.foo.com/test/tuokcehc"))); |
| EXPECT_EQ(2, histogram_tester_.GetBucketCount( |
| "Commerce.Heuristics.CheckoutURLGeneralPatternSource", |
| CommerceHeuristicsDataMetricsHelper::HeuristicsSource:: |
| FROM_FEATURE_PARAMETER) - |
| prev_count); |
| } |
| |
| TEST_F(CommerceHintAgentUnitTest, IsPurchaseByURL) { |
| // Heuristics from feature param default value. |
| for (auto* str : kPurchaseURL) { |
| EXPECT_TRUE(CommerceHintAgent::IsPurchase(GURL(str))) << str; |
| } |
| for (auto* str : kNotPurchaseURL) { |
| EXPECT_FALSE(CommerceHintAgent::IsPurchase(GURL(str))) << str; |
| } |
| |
| // Per-domain heuristics from component has a higher priority than default |
| // value. |
| EXPECT_TRUE(commerce_heuristics::CommerceHeuristicsData::GetInstance() |
| .PopulateDataFromComponent(R"###( |
| { |
| "foo.com": { |
| "purchase_url_regex" : "foo.com/([^/]+/)?esahcrup" |
| } |
| } |
| )###", |
| "{}", "", "")); |
| EXPECT_TRUE(CommerceHintAgent::IsPurchase( |
| GURL("https://wwww.foo.com/test/esahcrup"))); |
| |
| // Feature param has a higher priority than component. |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeatureWithParameters( |
| #if !BUILDFLAG(IS_ANDROID) |
| ntp_features::kNtpChromeCartModule, |
| #else |
| commerce::kCommerceHintAndroid, |
| #endif |
| {{"purchase-url-pattern-mapping", R"###( |
| { |
| "foo.com": "foo.com/purchase" |
| } |
| )###"}}); |
| EXPECT_FALSE(CommerceHintAgent::IsPurchase( |
| GURL("https://wwww.foo.com/test/esahcrup"))); |
| } |
| |
| TEST_F(CommerceHintAgentUnitTest, IsPurchaseByForm) { |
| // Heuristics from feature param default value. |
| for (auto* str : kPurchaseText) { |
| EXPECT_TRUE(CommerceHintAgent::IsPurchase(GURL(), str)) << str; |
| } |
| for (auto* str : kNotPurchaseText) { |
| EXPECT_FALSE(CommerceHintAgent::IsPurchase(GURL(), str)) << str; |
| } |
| |
| // Heuristics from component. |
| const std::string& component_pattern = R"###( |
| { |
| "purchase_button_text_regex": "bar" |
| } |
| )###"; |
| EXPECT_TRUE(commerce_heuristics::CommerceHeuristicsData::GetInstance() |
| .PopulateDataFromComponent("{}", component_pattern, "", "")); |
| EXPECT_TRUE(CommerceHintAgent::IsPurchase(GURL(), "bar")); |
| for (auto* str : kPurchaseText) { |
| EXPECT_FALSE(CommerceHintAgent::IsPurchase(GURL(), str)) << str; |
| } |
| |
| // Feature param has a higher priority. |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeatureWithParameters( |
| #if !BUILDFLAG(IS_ANDROID) |
| ntp_features::kNtpChromeCartModule, |
| #else |
| commerce::kCommerceHintAndroid, |
| #endif |
| {{"purchase-button-pattern", "foo"}}); |
| EXPECT_FALSE(CommerceHintAgent::IsPurchase(GURL(), "bar")); |
| } |
| |
| TEST_F(CommerceHintAgentUnitTest, ShouldSkipFromFeatureParam) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeatureWithParameters( |
| #if !BUILDFLAG(IS_ANDROID) |
| ntp_features::kNtpChromeCartModule, |
| #else |
| commerce::kCommerceHintAndroid, |
| #endif |
| kSkipParams); |
| |
| for (auto* str : kSkipText) { |
| EXPECT_TRUE(CommerceHintAgent::ShouldSkip(str)) << str; |
| } |
| for (auto* str : kNotSkipText) { |
| EXPECT_FALSE(CommerceHintAgent::ShouldSkip(str)) << str; |
| } |
| int match_times = (sizeof(kSkipText) / sizeof(*kSkipText)) + |
| (sizeof(kNotSkipText) / sizeof(*kNotSkipText)); |
| ASSERT_EQ(histogram_tester_.GetBucketCount( |
| "Commerce.Heuristics.SkipProductPatternSource", |
| CommerceHeuristicsDataMetricsHelper::HeuristicsSource:: |
| FROM_FEATURE_PARAMETER), |
| match_times); |
| ASSERT_EQ(histogram_tester_.GetBucketCount( |
| "Commerce.Heuristics.SkipProductPatternSource", |
| CommerceHeuristicsDataMetricsHelper::HeuristicsSource:: |
| FROM_COMPONENT), |
| 0); |
| } |
| |
| TEST_F(CommerceHintAgentUnitTest, ShouldSkipFromComponent) { |
| const std::string& component_pattern = R"###( |
| { |
| "sensitive_product_regex": "(^|\\W)(?i)(skipped|萬國碼)(\\W|$)" |
| } |
| )###"; |
| EXPECT_TRUE(commerce_heuristics::CommerceHeuristicsData::GetInstance() |
| .PopulateDataFromComponent("{}", component_pattern, "", "")); |
| |
| for (auto* str : kSkipText) { |
| EXPECT_TRUE(CommerceHintAgent::ShouldSkip(str)) << str; |
| } |
| for (auto* str : kNotSkipText) { |
| EXPECT_FALSE(CommerceHintAgent::ShouldSkip(str)) << str; |
| } |
| int match_times = (sizeof(kSkipText) / sizeof(*kSkipText)) + |
| (sizeof(kNotSkipText) / sizeof(*kNotSkipText)); |
| ASSERT_EQ(histogram_tester_.GetBucketCount( |
| "Commerce.Heuristics.SkipProductPatternSource", |
| CommerceHeuristicsDataMetricsHelper::HeuristicsSource:: |
| FROM_FEATURE_PARAMETER), |
| 0); |
| ASSERT_EQ(histogram_tester_.GetBucketCount( |
| "Commerce.Heuristics.SkipProductPatternSource", |
| CommerceHeuristicsDataMetricsHelper::HeuristicsSource:: |
| FROM_COMPONENT), |
| match_times); |
| } |
| |
| TEST_F(CommerceHintAgentUnitTest, ShouldSkip_Priority) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeatureWithParameters( |
| #if !BUILDFLAG(IS_ANDROID) |
| ntp_features::kNtpChromeCartModule, |
| #else |
| commerce::kCommerceHintAndroid, |
| #endif |
| kSkipParams); |
| // Initiate component skip pattern so that nothing is skipped. |
| const std::string& empty_pattern = R"###( |
| { |
| "sensitive_product_regex": "\\b\\B" |
| } |
| )###"; |
| EXPECT_TRUE(commerce_heuristics::CommerceHeuristicsData::GetInstance() |
| .PopulateDataFromComponent("{}", empty_pattern, "", "")); |
| |
| // Honor the skip pattern from feature parameter as it has higher priority. |
| for (auto* str : kSkipText) { |
| EXPECT_TRUE(CommerceHintAgent::ShouldSkip(str)) << str; |
| } |
| for (auto* str : kNotSkipText) { |
| EXPECT_FALSE(CommerceHintAgent::ShouldSkip(str)) << str; |
| } |
| } |
| |
| TEST_F(CommerceHintAgentUnitTest, ShouldSkipAddToCartFromResource) { |
| for (auto const& entry : kSkipAddToCartRequests) { |
| EXPECT_TRUE(CommerceHintAgent::ShouldSkipAddToCartRequest( |
| GURL(entry.first), GURL(entry.second))); |
| } |
| |
| for (auto const& entry : kNotSkipAddToCartRequests) { |
| EXPECT_FALSE(CommerceHintAgent::ShouldSkipAddToCartRequest( |
| GURL(entry.first), GURL(entry.second))); |
| } |
| } |
| |
| float BenchmarkIsAddToCart(base::StringPiece str) { |
| const base::TimeTicks now = base::TimeTicks::Now(); |
| for (int i = 0; i < kTestIterations; ++i) { |
| CommerceHintAgent::IsAddToCart(str); |
| } |
| const base::TimeTicks end = base::TimeTicks::Now(); |
| float elapsed_us = |
| static_cast<float>((end - now).InMicroseconds()) / kTestIterations; |
| LOG(INFO) << "IsAddToCart(" << str.size() << " chars) took: " << elapsed_us |
| << " µs"; |
| return elapsed_us; |
| } |
| |
| float BenchmarkIsVisitCart(const GURL& url) { |
| const base::TimeTicks now = base::TimeTicks::Now(); |
| for (int i = 0; i < kTestIterations; ++i) { |
| CommerceHintAgent::IsVisitCart(url); |
| } |
| const base::TimeTicks end = base::TimeTicks::Now(); |
| float elapsed_us = |
| static_cast<float>((end - now).InMicroseconds()) / kTestIterations; |
| LOG(INFO) << "IsVisitCart(" << url.spec().size() |
| << " chars) took: " << elapsed_us << " µs"; |
| return elapsed_us; |
| } |
| |
| float BenchmarkIsVisitCheckout(const GURL& url) { |
| const base::TimeTicks now = base::TimeTicks::Now(); |
| for (int i = 0; i < kTestIterations; ++i) { |
| CommerceHintAgent::IsVisitCheckout(url); |
| } |
| const base::TimeTicks end = base::TimeTicks::Now(); |
| float elapsed_us = |
| static_cast<float>((end - now).InMicroseconds()) / kTestIterations; |
| LOG(INFO) << "IsVisitCheckout(" << url.spec().size() |
| << " chars) took: " << elapsed_us << " µs"; |
| return elapsed_us; |
| } |
| |
| float BenchmarkIsPurchase(const GURL& url, base::StringPiece str) { |
| const base::TimeTicks now = base::TimeTicks::Now(); |
| for (int i = 0; i < kTestIterations; ++i) { |
| CommerceHintAgent::IsPurchase(url, str); |
| } |
| const base::TimeTicks end = base::TimeTicks::Now(); |
| float elapsed_us = |
| static_cast<float>((end - now).InMicroseconds()) / kTestIterations; |
| LOG(INFO) << "IsPurchase(" << str.size() << " chars) took: " << elapsed_us |
| << " µs"; |
| return elapsed_us; |
| } |
| |
| float BenchmarkShouldSkip(base::StringPiece str) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeatureWithParameters( |
| #if !BUILDFLAG(IS_ANDROID) |
| ntp_features::kNtpChromeCartModule, |
| #else |
| commerce::kCommerceHintAndroid, |
| #endif |
| kSkipParams); |
| |
| const base::TimeTicks now = base::TimeTicks::Now(); |
| for (int i = 0; i < kTestIterations; ++i) { |
| CommerceHintAgent::ShouldSkip(str); |
| } |
| const base::TimeTicks end = base::TimeTicks::Now(); |
| float elapsed_us = |
| static_cast<float>((end - now).InMicroseconds()) / kTestIterations; |
| LOG(INFO) << "ShouldSkip(" << str.size() << " chars) took: " << elapsed_us |
| << " µs"; |
| return elapsed_us; |
| } |
| |
| float BenchmarkShouldSkipAddToCart(const GURL& url) { |
| const base::TimeTicks now = base::TimeTicks::Now(); |
| for (int i = 0; i < kTestIterations; ++i) { |
| CommerceHintAgent::ShouldSkipAddToCartRequest(url, url); |
| } |
| const base::TimeTicks end = base::TimeTicks::Now(); |
| float elapsed_us = |
| static_cast<float>((end - now).InMicroseconds()) / kTestIterations; |
| LOG(INFO) << "ShouldSkipAddToCart(" << url.spec().size() |
| << " chars) took: " << elapsed_us << " µs"; |
| return elapsed_us; |
| } |
| |
| // TSAN builds are 20~50X slower than Release build. |
| #if defined(THREAD_SANITIZER) || defined(ADDRESS_SANITIZER) || \ |
| defined(MEMORY_SANITIZER) || BUILDFLAG(CFI_CAST_CHECK) || \ |
| BUILDFLAG(CFI_ICALL_CHECK) || BUILDFLAG(CFI_ENFORCEMENT_DIAGNOSTIC) || \ |
| BUILDFLAG(CFI_ENFORCEMENT_TRAP) |
| #define MAYBE_RegexBenchmark DISABLED_RegexBenchmark |
| #else |
| #define MAYBE_RegexBenchmark RegexBenchmark |
| #endif |
| |
| TEST_F(CommerceHintAgentUnitTest, MAYBE_RegexBenchmark) { |
| std::string str = "abcdefghijklmnop"; |
| const GURL basic_url = GURL("http://example.com/"); |
| // Compile regex before benchmark loop. |
| CommerceHintAgent::IsAddToCart(str); |
| CommerceHintAgent::IsVisitCart(basic_url); |
| CommerceHintAgent::IsVisitCheckout(basic_url); |
| CommerceHintAgent::IsPurchase(basic_url, str); |
| for (int length = 16; length <= (1L << 20); length *= 4) { |
| const GURL url("http://example.com/" + str); |
| |
| // With string copy, it would take at least 400us, assuming string length is |
| // 1M chars, and running x86-64 Release build on Linux workstation. x86-64 |
| // Debug build is ~4X slower, Debug build on Pixel 2 is 3~10X slower, and |
| // Release build on Nexus 5 is ~10X slower. |
| int slow_factor = 1; |
| #if !defined(NDEBUG) |
| slow_factor *= 4; |
| #endif |
| #if BUILDFLAG(IS_ANDROID) |
| slow_factor *= 10; |
| #endif |
| |
| float elapsed_us = BenchmarkIsAddToCart(str); |
| // Typical value is ~10us on x86-64 Release build. |
| // Without capping the length, it would take at least 2000us. |
| EXPECT_LT(elapsed_us, 50.0 * slow_factor); |
| |
| elapsed_us = BenchmarkIsVisitCart(url); |
| // Typical value is ~10us. |
| EXPECT_LT(elapsed_us, 50.0 * slow_factor); |
| |
| elapsed_us = BenchmarkIsVisitCheckout(url); |
| // Typical value is ~10us. |
| // Without capping the length, it would take at least 2000us. |
| EXPECT_LT(elapsed_us, 100.0 * slow_factor); |
| |
| elapsed_us = BenchmarkIsPurchase(basic_url, str); |
| // Typical value is ~0.1us. |
| EXPECT_LT(elapsed_us, 5.0 * slow_factor); |
| |
| elapsed_us = BenchmarkShouldSkip(str); |
| // Typical value is ~10us. |
| EXPECT_LT(elapsed_us, 50.0 * slow_factor); |
| |
| elapsed_us = BenchmarkShouldSkipAddToCart(url); |
| // Typical value is ~10us. |
| EXPECT_LT(elapsed_us, 50.0 * slow_factor); |
| |
| str += str; |
| str += str; |
| } |
| } |