workarea 3.4.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (571) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +326 -0
  3. data/CHANGELOG.md +20501 -0
  4. data/README.md +163 -0
  5. data/docker-compose.yml +27 -0
  6. data/docs/Gemfile +8 -0
  7. data/docs/bin/middleman +29 -0
  8. data/docs/config.rb +87 -0
  9. data/docs/config.ru +7 -0
  10. data/docs/data/articles.yml +157 -0
  11. data/docs/package.json +15 -0
  12. data/docs/source/404.html.erb +13 -0
  13. data/docs/source/articles/access-routes-in-javascript.html.md +33 -0
  14. data/docs/source/articles/add-a-content-area.html.md +169 -0
  15. data/docs/source/articles/add-a-content-block-type.html.md +334 -0
  16. data/docs/source/articles/add-a-report.html.md +202 -0
  17. data/docs/source/articles/add-css-through-the-admin-ui.html.md +30 -0
  18. data/docs/source/articles/add-javascript-through-a-manifest.html.md +367 -0
  19. data/docs/source/articles/add-javascript-through-a-view.html.md +80 -0
  20. data/docs/source/articles/add-javascript-through-the-admin-ui.html.md +30 -0
  21. data/docs/source/articles/add-metrics.html.md +58 -0
  22. data/docs/source/articles/add-or-replace-a-pricing-calculator.html.md +150 -0
  23. data/docs/source/articles/add-remove-or-change-a-mongoid-validation.html.md +147 -0
  24. data/docs/source/articles/add-remove-or-change-a-product-template.html.md +142 -0
  25. data/docs/source/articles/add-remove-sort-and-group-storefront-search-filters.html.md +483 -0
  26. data/docs/source/articles/add-stylesheets-through-a-manifest.html.md +276 -0
  27. data/docs/source/articles/add-system-content.html.md +138 -0
  28. data/docs/source/articles/analytics-overview.html.md +51 -0
  29. data/docs/source/articles/analyze-storefront-search-results.html.md +261 -0
  30. data/docs/source/articles/api-overview.html.md +35 -0
  31. data/docs/source/articles/appending.html.md +506 -0
  32. data/docs/source/articles/application-document.html.md +88 -0
  33. data/docs/source/articles/automated-javascript-testing.html.md +162 -0
  34. data/docs/source/articles/b2b-overview.html.md +64 -0
  35. data/docs/source/articles/browser-and-device-support.html.md +47 -0
  36. data/docs/source/articles/change-product-placeholder-image.html.md +39 -0
  37. data/docs/source/articles/change-storefront-search-results.html.md +283 -0
  38. data/docs/source/articles/change-the-storefront-product-pricing-ui.html.md +348 -0
  39. data/docs/source/articles/change-the-storefront-search-filters-ui.html.md +103 -0
  40. data/docs/source/articles/checkout.html.md +479 -0
  41. data/docs/source/articles/commerce-model.html.md +164 -0
  42. data/docs/source/articles/configuration-for-hosting.html.md +106 -0
  43. data/docs/source/articles/configuration.html.md +406 -0
  44. data/docs/source/articles/configure-a-payment-gateway.html.md +58 -0
  45. data/docs/source/articles/configure-asset-storage.html.md +29 -0
  46. data/docs/source/articles/configure-asset-types.html.md +18 -0
  47. data/docs/source/articles/configure-contact-form-subjects-list.html.md +24 -0
  48. data/docs/source/articles/configure-imageoptim.html.md +23 -0
  49. data/docs/source/articles/configure-locales.html.md +45 -0
  50. data/docs/source/articles/configure-logins-and-authentication.html.md +42 -0
  51. data/docs/source/articles/configure-low-inventory-threshold.html.md +26 -0
  52. data/docs/source/articles/configure-product-image-sizes-and-processing.html.md +28 -0
  53. data/docs/source/articles/content.html.md +554 -0
  54. data/docs/source/articles/contentable.html.md +41 -0
  55. data/docs/source/articles/contribute-code.html.md +69 -0
  56. data/docs/source/articles/contribute-documentation.html.md +60 -0
  57. data/docs/source/articles/create-a-custom-discount.html.md +234 -0
  58. data/docs/source/articles/create-a-new-app.html.md +131 -0
  59. data/docs/source/articles/create-a-plugin.html.md +19 -0
  60. data/docs/source/articles/create-a-style-guide.html.md +71 -0
  61. data/docs/source/articles/create-a-theme.html.md +134 -0
  62. data/docs/source/articles/css-architectural-overview.html.md +89 -0
  63. data/docs/source/articles/customize-a-helper.html.md +91 -0
  64. data/docs/source/articles/decoration.html.md +415 -0
  65. data/docs/source/articles/define-and-configure-inventory-policies.html.md +107 -0
  66. data/docs/source/articles/documentation-style-guide.html.md +48 -0
  67. data/docs/source/articles/documentation.html.md +54 -0
  68. data/docs/source/articles/domain-modeling.html.md +82 -0
  69. data/docs/source/articles/error-pages.html.md.erb +95 -0
  70. data/docs/source/articles/extension-overview.html.md +152 -0
  71. data/docs/source/articles/favicon-support.html.md +112 -0
  72. data/docs/source/articles/feature-spec-helper-stylesheet.html.md +25 -0
  73. data/docs/source/articles/featurejs-and-feature-spec-helper.html.md +20 -0
  74. data/docs/source/articles/help-and-support.html.md +34 -0
  75. data/docs/source/articles/html-fragment-caching.html.md +46 -0
  76. data/docs/source/articles/http-caching.html.md +43 -0
  77. data/docs/source/articles/i18n.html.md +35 -0
  78. data/docs/source/articles/images-flow.html.md +10 -0
  79. data/docs/source/articles/index-storefront-search-documents.html.md +104 -0
  80. data/docs/source/articles/infrastructure.html.md +46 -0
  81. data/docs/source/articles/installing.html.md +61 -0
  82. data/docs/source/articles/integrate-a-payment-gateway.html.md +124 -0
  83. data/docs/source/articles/integrate-a-web-analytics-provider.html.md +35 -0
  84. data/docs/source/articles/integrate-an-inventory-management-system.html.md +88 -0
  85. data/docs/source/articles/integrating-with-other-software.html.md +59 -0
  86. data/docs/source/articles/inventory.html.md +352 -0
  87. data/docs/source/articles/javascript-coding-standards.html.md +30 -0
  88. data/docs/source/articles/javascript-modules.html.md +174 -0
  89. data/docs/source/articles/javascript-overview.html.md +62 -0
  90. data/docs/source/articles/javascript-reference-documentation.html.md +51 -0
  91. data/docs/source/articles/javascript-templates.html.md +52 -0
  92. data/docs/source/articles/low-level-caching.html.md +25 -0
  93. data/docs/source/articles/maintain-a-plugin.html.md +12 -0
  94. data/docs/source/articles/maintenance-policy.html.md +79 -0
  95. data/docs/source/articles/navigable.html.md +51 -0
  96. data/docs/source/articles/navigating-the-code.html.md +149 -0
  97. data/docs/source/articles/navigation.html.md +386 -0
  98. data/docs/source/articles/order-life-cycle.html.md +546 -0
  99. data/docs/source/articles/order-pricing.html.md +389 -0
  100. data/docs/source/articles/orders-and-items.html.md +210 -0
  101. data/docs/source/articles/orders.html.md +66 -0
  102. data/docs/source/articles/overriding.html.md +155 -0
  103. data/docs/source/articles/overview.html.md +43 -0
  104. data/docs/source/articles/plugins-overview.html.md +12 -0
  105. data/docs/source/articles/prerequisites-and-dependencies.html.md +202 -0
  106. data/docs/source/articles/products.html.md.erb +1270 -0
  107. data/docs/source/articles/progressive-web-application-support.html.md +148 -0
  108. data/docs/source/articles/rails-asset-manifests.html.md +33 -0
  109. data/docs/source/articles/rails-asset-view-helpers.html.md +25 -0
  110. data/docs/source/articles/reading-data.html.md +10 -0
  111. data/docs/source/articles/releasable.html.md +37 -0
  112. data/docs/source/articles/report-a-bug.html.md +75 -0
  113. data/docs/source/articles/ruby-coding-standards.html.md +10 -0
  114. data/docs/source/articles/run-sidekiq-in-a-local-environment.html.md +40 -0
  115. data/docs/source/articles/searching.html.md +1005 -0
  116. data/docs/source/articles/security-policy.html.md +42 -0
  117. data/docs/source/articles/seeds.html.md +345 -0
  118. data/docs/source/articles/shipping.html.md +756 -0
  119. data/docs/source/articles/sort-and-exclude-product-options.html.md +47 -0
  120. data/docs/source/articles/storefront-search-features.html.md +568 -0
  121. data/docs/source/articles/storefront-searches.html.md +126 -0
  122. data/docs/source/articles/style-guides.html.md +21 -0
  123. data/docs/source/articles/stylesheet-coding-standards.html.md +24 -0
  124. data/docs/source/articles/stylesheets-overview.html.md +67 -0
  125. data/docs/source/articles/swappable-list-data-structure.html.md +81 -0
  126. data/docs/source/articles/system-emails.html.md +102 -0
  127. data/docs/source/articles/taggable.html.md +8 -0
  128. data/docs/source/articles/test-a-credit-card-transaction.html.md +16 -0
  129. data/docs/source/articles/test-if-a-plugin-is-installed.html.md +34 -0
  130. data/docs/source/articles/testing.html.md +914 -0
  131. data/docs/source/articles/themes-overview.html.md +155 -0
  132. data/docs/source/articles/translate-administrable-content.html.md +14 -0
  133. data/docs/source/articles/translate-javascript-content.html.md +16 -0
  134. data/docs/source/articles/translate-or-customize-message-content.html.md +29 -0
  135. data/docs/source/articles/translate-or-customize-static-content.html.md +30 -0
  136. data/docs/source/articles/use-an-existing-workarea-app.html.md +108 -0
  137. data/docs/source/articles/view-models.html.md +509 -0
  138. data/docs/source/articles/views.html.md +14 -0
  139. data/docs/source/articles/workers.html.md +613 -0
  140. data/docs/source/articles/writing-data.html.md +10 -0
  141. data/docs/source/cli.html.md +163 -0
  142. data/docs/source/favicon.ico +0 -0
  143. data/docs/source/images/3-variants-1-option.png +0 -0
  144. data/docs/source/images/3-variants-3-options.png +0 -0
  145. data/docs/source/images/3-years-primary-image.png +0 -0
  146. data/docs/source/images/404-storefront-error-page.png +0 -0
  147. data/docs/source/images/404-system-content-admin.png +0 -0
  148. data/docs/source/images/404.jpg +0 -0
  149. data/docs/source/images/5-years-primary-image.png +0 -0
  150. data/docs/source/images/activity-dashboard.png +0 -0
  151. data/docs/source/images/activity-for-object.png +0 -0
  152. data/docs/source/images/activity-ui.png +0 -0
  153. data/docs/source/images/adding-captioned-image-block-custom-icon.png +0 -0
  154. data/docs/source/images/adding-captioned-image-block-default-icon.png +0 -0
  155. data/docs/source/images/admin-alerts-ui.png +0 -0
  156. data/docs/source/images/admin-category-range-filters.png +0 -0
  157. data/docs/source/images/admin-for-3-column-hero.png +0 -0
  158. data/docs/source/images/admin-help-index.png +0 -0
  159. data/docs/source/images/admin-help-ui.png +0 -0
  160. data/docs/source/images/admin-javascript.png +0 -0
  161. data/docs/source/images/admin-notification-for-deactivated-discount.png +0 -0
  162. data/docs/source/images/admin-notifications-ui.png +0 -0
  163. data/docs/source/images/admin-product-show-page.png +0 -0
  164. data/docs/source/images/admin-products-index-page.png +0 -0
  165. data/docs/source/images/admin-range-filters.png +0 -0
  166. data/docs/source/images/admin-style-guides-navigation.png +0 -0
  167. data/docs/source/images/after-re-seeding.png +0 -0
  168. data/docs/source/images/after-seeding-localhost-3000.png +0 -0
  169. data/docs/source/images/after-seeding.png +0 -0
  170. data/docs/source/images/arrow.svg +1 -0
  171. data/docs/source/images/arrow_white.svg +1 -0
  172. data/docs/source/images/aws-resource-map.png +0 -0
  173. data/docs/source/images/backordered-until-output-on-inventory-sku-card.png +0 -0
  174. data/docs/source/images/before-seeding-localhost-3000.png +0 -0
  175. data/docs/source/images/before-seeding.png +0 -0
  176. data/docs/source/images/browsing-workarea-versions-on-the-web.png +0 -0
  177. data/docs/source/images/bulk-asset-upload-on-assets-index-page.png +0 -0
  178. data/docs/source/images/bulk-asset-upload-while-editing-content.png +0 -0
  179. data/docs/source/images/bundle-show-workarea-core.png +0 -0
  180. data/docs/source/images/bundle-show-workarea.png +0 -0
  181. data/docs/source/images/calendar-for-backordered-until-field.png +0 -0
  182. data/docs/source/images/captioned-image-block-in-storefront.png +0 -0
  183. data/docs/source/images/captioned-image-content-block-storefront-component-style-guide.png +0 -0
  184. data/docs/source/images/cart-system-content-in-admin.png +0 -0
  185. data/docs/source/images/cart-system-content-in-storefront.png +0 -0
  186. data/docs/source/images/checkout-addresses-guest.png +0 -0
  187. data/docs/source/images/checkout-addresses-user.png +0 -0
  188. data/docs/source/images/checkout-confirmation.png +0 -0
  189. data/docs/source/images/checkout-flow-0.png +0 -0
  190. data/docs/source/images/checkout-flow-1.png +0 -0
  191. data/docs/source/images/checkout-flow-2.png +0 -0
  192. data/docs/source/images/checkout-flow-3.png +0 -0
  193. data/docs/source/images/checkout-flow-4.png +0 -0
  194. data/docs/source/images/checkout-payment-guest.png +0 -0
  195. data/docs/source/images/checkout-payment-user.png +0 -0
  196. data/docs/source/images/checkout-shipping.png +0 -0
  197. data/docs/source/images/color-picker-component-admin-style-guide.png +0 -0
  198. data/docs/source/images/color-picker-component-on-content-editing-screen.png +0 -0
  199. data/docs/source/images/commerce-model-carts-orders.png +0 -0
  200. data/docs/source/images/commerce-model-order-pricing.png +0 -0
  201. data/docs/source/images/commerce-model.png +0 -0
  202. data/docs/source/images/configuring-an-index-pattern-in-kibana.png +0 -0
  203. data/docs/source/images/content-block-presets.png +0 -0
  204. data/docs/source/images/content-search-customization.png +0 -0
  205. data/docs/source/images/country-with-region-data-in-address-form.png +0 -0
  206. data/docs/source/images/country-without-region-data-in-address-form.png +0 -0
  207. data/docs/source/images/create-content-block-preset-ui.png +0 -0
  208. data/docs/source/images/credit-card-icons.png +0 -0
  209. data/docs/source/images/css-added-through-admin.png +0 -0
  210. data/docs/source/images/css-admin-ui.png +0 -0
  211. data/docs/source/images/current-configuration-shown-in-admin-settings.png +0 -0
  212. data/docs/source/images/customer-impersonation-in-admin.png +0 -0
  213. data/docs/source/images/customer-impersonation-in-store-front.png +0 -0
  214. data/docs/source/images/date-filter-same-day.png +0 -0
  215. data/docs/source/images/developer-toolbar-in-store-front.png +0 -0
  216. data/docs/source/images/discounts-sorted-by-most-redeemed.png +0 -0
  217. data/docs/source/images/edit-help-article.png +0 -0
  218. data/docs/source/images/editing-content-for-search-customization.png +0 -0
  219. data/docs/source/images/editing-dynamic-captioned-image-block.png +0 -0
  220. data/docs/source/images/editing-product-fields-in-the-admin.png +0 -0
  221. data/docs/source/images/editing-search-system-content.png +0 -0
  222. data/docs/source/images/editing-static-captioned-image-block-custom-icon.png +0 -0
  223. data/docs/source/images/editing-static-captioned-image-block-default-icon.png +0 -0
  224. data/docs/source/images/external.svg +1 -0
  225. data/docs/source/images/favicon_16.png +0 -0
  226. data/docs/source/images/favicon_180.png +0 -0
  227. data/docs/source/images/favicon_32.png +0 -0
  228. data/docs/source/images/filters-all.png +0 -0
  229. data/docs/source/images/filters-control.png +0 -0
  230. data/docs/source/images/filters-custom.png +0 -0
  231. data/docs/source/images/filters-groups.png +0 -0
  232. data/docs/source/images/filters-material.png +0 -0
  233. data/docs/source/images/filters-omitted.png +0 -0
  234. data/docs/source/images/filters-pinned.png +0 -0
  235. data/docs/source/images/filters-range.png +0 -0
  236. data/docs/source/images/filters-sorted.png +0 -0
  237. data/docs/source/images/filters-wrapping-to-second-line-in-admin.png +0 -0
  238. data/docs/source/images/generic-product-template-images-no-options-selected.png +0 -0
  239. data/docs/source/images/generic-product-template-images-options-selected.png +0 -0
  240. data/docs/source/images/generic-template.png +0 -0
  241. data/docs/source/images/hosting.svg +1 -0
  242. data/docs/source/images/image-group-content-block-in-storefront.png +0 -0
  243. data/docs/source/images/images.svg +1 -0
  244. data/docs/source/images/import-export-screenshot.png +0 -0
  245. data/docs/source/images/invalid-display.png +0 -0
  246. data/docs/source/images/itcss.png +0 -0
  247. data/docs/source/images/kibana-dev-tools-console.png +0 -0
  248. data/docs/source/images/layout-content-admin-with-2-areas.png +0 -0
  249. data/docs/source/images/layout-content-admin-with-3-areas.png +0 -0
  250. data/docs/source/images/link-to-search-system-content.png +0 -0
  251. data/docs/source/images/logo.svg +1 -0
  252. data/docs/source/images/menu.svg +2 -0
  253. data/docs/source/images/mongo-replica-set.svg +1 -0
  254. data/docs/source/images/multi-column-hero-blocks.png +0 -0
  255. data/docs/source/images/option-selects-product-template-images-options-selected.png +0 -0
  256. data/docs/source/images/option-selects-template.png +0 -0
  257. data/docs/source/images/option-thumbnails-template.png +0 -0
  258. data/docs/source/images/order-item-total-price-diagram.png +0 -0
  259. data/docs/source/images/order-pricing-cart-example.png +0 -0
  260. data/docs/source/images/order-pricing-example-adjustments.png +0 -0
  261. data/docs/source/images/order-pricing-example-totals.png +0 -0
  262. data/docs/source/images/order-pricing-placed-order-example.png +0 -0
  263. data/docs/source/images/order-shipping-total-diagram.png +0 -0
  264. data/docs/source/images/order-show-with-multiple-tenders.png +0 -0
  265. data/docs/source/images/order-subtotal-price-diagram.png +0 -0
  266. data/docs/source/images/order-tax-total-diagram.png +0 -0
  267. data/docs/source/images/order-total-price-diagram.png +0 -0
  268. data/docs/source/images/order-total-value-diagram.png +0 -0
  269. data/docs/source/images/orders-dashboard-links.png +0 -0
  270. data/docs/source/images/oval.svg +1 -0
  271. data/docs/source/images/payment-icon-storefront-style-guide.png +0 -0
  272. data/docs/source/images/people-dashboard-links.png +0 -0
  273. data/docs/source/images/price-adjustments-diagram.png +0 -0
  274. data/docs/source/images/price-display-no-options.png +0 -0
  275. data/docs/source/images/price-display-options-selected.png +0 -0
  276. data/docs/source/images/pricing-calculators-diagram.png +0 -0
  277. data/docs/source/images/product-list-content-block-admin.png +0 -0
  278. data/docs/source/images/product-list-content-block-in-store-front.png +0 -0
  279. data/docs/source/images/promo-products-excluded-autocomplete-results-after.png +0 -0
  280. data/docs/source/images/promo-products-excluded-featured-category-results-after.png +0 -0
  281. data/docs/source/images/promo-products-excluded-recommendations-results-after.png +0 -0
  282. data/docs/source/images/promo-products-excluded-search-category-results-after.png +0 -0
  283. data/docs/source/images/promo-products-excluded-search-results-after.png +0 -0
  284. data/docs/source/images/promo-products-included-autocomplete-results-before.png +0 -0
  285. data/docs/source/images/promo-products-included-featured-category-results-before.png +0 -0
  286. data/docs/source/images/promo-products-included-recommendations-results-before.png +0 -0
  287. data/docs/source/images/promo-products-included-search-category-results-before.png +0 -0
  288. data/docs/source/images/promo-products-included-search-results-before.png +0 -0
  289. data/docs/source/images/rails-version-constraint.png +0 -0
  290. data/docs/source/images/re-enable-discount.png +0 -0
  291. data/docs/source/images/reading-data.svg +1 -0
  292. data/docs/source/images/readme-hero.png +0 -0
  293. data/docs/source/images/redesigned-customized-sort-for-search-results.png +0 -0
  294. data/docs/source/images/reviews-summary-above-share-buttons.png +0 -0
  295. data/docs/source/images/reviews-summary-below-product-name.png +0 -0
  296. data/docs/source/images/reviews-summary-below-share-buttons.png +0 -0
  297. data/docs/source/images/reviews-summary-removed.png +0 -0
  298. data/docs/source/images/rsa-fingerprint-for-stash.png +0 -0
  299. data/docs/source/images/ruby-version-constraint.png +0 -0
  300. data/docs/source/images/script-tag-added-through-admin.png +0 -0
  301. data/docs/source/images/search-analysis-admin-alternate-rendering.png +0 -0
  302. data/docs/source/images/search-analysis-admin.png +0 -0
  303. data/docs/source/images/search-quality-report.png +0 -0
  304. data/docs/source/images/search.svg +1 -0
  305. data/docs/source/images/searching-for-cart-system-content-in-admin.png +0 -0
  306. data/docs/source/images/searching-for-layout-system-content-in-admin.png +0 -0
  307. data/docs/source/images/seeded-admin.png +0 -0
  308. data/docs/source/images/seeds-from-plugins.png +0 -0
  309. data/docs/source/images/seo-metadata-automation-ui.png +0 -0
  310. data/docs/source/images/show-password-button.png +0 -0
  311. data/docs/source/images/storefront-autocomplete.png +0 -0
  312. data/docs/source/images/storefront-category-summary-content-block.png +0 -0
  313. data/docs/source/images/storefront-category.png +0 -0
  314. data/docs/source/images/storefront-product-after-overriding.png +0 -0
  315. data/docs/source/images/storefront-product-before-overriding.png +0 -0
  316. data/docs/source/images/storefront-product-browse-page.png +0 -0
  317. data/docs/source/images/storefront-product-recommendations.png +0 -0
  318. data/docs/source/images/storefront-product-show-page.png +0 -0
  319. data/docs/source/images/storefront-requests-and-search-requests.png +0 -0
  320. data/docs/source/images/storefront-search-request-handling.png +0 -0
  321. data/docs/source/images/storefront-search-response-creation.png +0 -0
  322. data/docs/source/images/storefront-search.png +0 -0
  323. data/docs/source/images/storefront-style-guides-navigation.png +0 -0
  324. data/docs/source/images/styles.css +3 -0
  325. data/docs/source/images/tax-categories-ui.png +0 -0
  326. data/docs/source/images/tax-rates-ui.png +0 -0
  327. data/docs/source/images/unpurchasable-product.png +0 -0
  328. data/docs/source/images/url-redirects-filtering.png +0 -0
  329. data/docs/source/images/utility-nav-area-in-admin.png +0 -0
  330. data/docs/source/images/utility-nav-area-in-storefront.png +0 -0
  331. data/docs/source/images/validation-message-in-storefront.png +0 -0
  332. data/docs/source/images/view-model-interface.png +0 -0
  333. data/docs/source/images/viewing-workarea-version-in-source.png +0 -0
  334. data/docs/source/images/workarea.svg +1 -0
  335. data/docs/source/images/worst-performing-searches-on-results-customization-page.png +0 -0
  336. data/docs/source/images/writing-data.svg +1 -0
  337. data/docs/source/index.html.erb +167 -0
  338. data/docs/source/javascripts/jquery.js +2 -0
  339. data/docs/source/javascripts/lunr.js +7 -0
  340. data/docs/source/javascripts/site.js +299 -0
  341. data/docs/source/javascripts/vendor/highlight.pack.js +2 -0
  342. data/docs/source/layouts/article.erb +106 -0
  343. data/docs/source/layouts/bare.erb +46 -0
  344. data/docs/source/layouts/layout.erb +43 -0
  345. data/docs/source/release-notes.html.md +258 -0
  346. data/docs/source/release-notes/workarea-3-0-0.html.md +146 -0
  347. data/docs/source/release-notes/workarea-3-0-1.html.md +161 -0
  348. data/docs/source/release-notes/workarea-3-0-10.html.md +39 -0
  349. data/docs/source/release-notes/workarea-3-0-11.html.md +277 -0
  350. data/docs/source/release-notes/workarea-3-0-12.html.md +14 -0
  351. data/docs/source/release-notes/workarea-3-0-13.html.md +153 -0
  352. data/docs/source/release-notes/workarea-3-0-14.html.md +93 -0
  353. data/docs/source/release-notes/workarea-3-0-15.html.md +107 -0
  354. data/docs/source/release-notes/workarea-3-0-16.html.md +36 -0
  355. data/docs/source/release-notes/workarea-3-0-17.html.md +141 -0
  356. data/docs/source/release-notes/workarea-3-0-18.html.md +123 -0
  357. data/docs/source/release-notes/workarea-3-0-19.html.md +160 -0
  358. data/docs/source/release-notes/workarea-3-0-2.html.md +222 -0
  359. data/docs/source/release-notes/workarea-3-0-20.html.md +95 -0
  360. data/docs/source/release-notes/workarea-3-0-21.html.md +168 -0
  361. data/docs/source/release-notes/workarea-3-0-22.html.md +268 -0
  362. data/docs/source/release-notes/workarea-3-0-23.html.md +173 -0
  363. data/docs/source/release-notes/workarea-3-0-24.html.md +19 -0
  364. data/docs/source/release-notes/workarea-3-0-25.html.md +26 -0
  365. data/docs/source/release-notes/workarea-3-0-26.html.md +199 -0
  366. data/docs/source/release-notes/workarea-3-0-27.html.md +113 -0
  367. data/docs/source/release-notes/workarea-3-0-28.html.md +39 -0
  368. data/docs/source/release-notes/workarea-3-0-29.html.md +73 -0
  369. data/docs/source/release-notes/workarea-3-0-3.html.md +35 -0
  370. data/docs/source/release-notes/workarea-3-0-30.html.md +186 -0
  371. data/docs/source/release-notes/workarea-3-0-31.html.md +125 -0
  372. data/docs/source/release-notes/workarea-3-0-32.html.md +73 -0
  373. data/docs/source/release-notes/workarea-3-0-33.html.md +137 -0
  374. data/docs/source/release-notes/workarea-3-0-34.html.md +203 -0
  375. data/docs/source/release-notes/workarea-3-0-35.html.md +205 -0
  376. data/docs/source/release-notes/workarea-3-0-36.html.md +105 -0
  377. data/docs/source/release-notes/workarea-3-0-37.html.md +144 -0
  378. data/docs/source/release-notes/workarea-3-0-38.html.md +73 -0
  379. data/docs/source/release-notes/workarea-3-0-39.html.md +77 -0
  380. data/docs/source/release-notes/workarea-3-0-4.html.md +14 -0
  381. data/docs/source/release-notes/workarea-3-0-40.html.md +130 -0
  382. data/docs/source/release-notes/workarea-3-0-41.html.md +70 -0
  383. data/docs/source/release-notes/workarea-3-0-42.html.md +52 -0
  384. data/docs/source/release-notes/workarea-3-0-43.html.md +72 -0
  385. data/docs/source/release-notes/workarea-3-0-44.html.md +93 -0
  386. data/docs/source/release-notes/workarea-3-0-45.html.md +61 -0
  387. data/docs/source/release-notes/workarea-3-0-46.html.md +171 -0
  388. data/docs/source/release-notes/workarea-3-0-47.html.md +130 -0
  389. data/docs/source/release-notes/workarea-3-0-48.html.md +160 -0
  390. data/docs/source/release-notes/workarea-3-0-49.html.md +28 -0
  391. data/docs/source/release-notes/workarea-3-0-5.html.md +225 -0
  392. data/docs/source/release-notes/workarea-3-0-50.html.md +74 -0
  393. data/docs/source/release-notes/workarea-3-0-51.html.md +61 -0
  394. data/docs/source/release-notes/workarea-3-0-52.html.md +76 -0
  395. data/docs/source/release-notes/workarea-3-0-53.html.md +126 -0
  396. data/docs/source/release-notes/workarea-3-0-54.html.md +112 -0
  397. data/docs/source/release-notes/workarea-3-0-55.html.md +105 -0
  398. data/docs/source/release-notes/workarea-3-0-56.html.md +56 -0
  399. data/docs/source/release-notes/workarea-3-0-57.html.md +82 -0
  400. data/docs/source/release-notes/workarea-3-0-58.html.md +153 -0
  401. data/docs/source/release-notes/workarea-3-0-59.html.md +78 -0
  402. data/docs/source/release-notes/workarea-3-0-6.html.md +165 -0
  403. data/docs/source/release-notes/workarea-3-0-60.html.md +43 -0
  404. data/docs/source/release-notes/workarea-3-0-61.html.md +46 -0
  405. data/docs/source/release-notes/workarea-3-0-62.html.md +23 -0
  406. data/docs/source/release-notes/workarea-3-0-63.html.md +25 -0
  407. data/docs/source/release-notes/workarea-3-0-64.html.md +25 -0
  408. data/docs/source/release-notes/workarea-3-0-65.html.md +37 -0
  409. data/docs/source/release-notes/workarea-3-0-7.html.md +207 -0
  410. data/docs/source/release-notes/workarea-3-0-8.html.md +337 -0
  411. data/docs/source/release-notes/workarea-3-0-9.html.md +196 -0
  412. data/docs/source/release-notes/workarea-3-1-0.html.md +414 -0
  413. data/docs/source/release-notes/workarea-3-1-1.html.md +139 -0
  414. data/docs/source/release-notes/workarea-3-1-10.html.md +19 -0
  415. data/docs/source/release-notes/workarea-3-1-11.html.md +27 -0
  416. data/docs/source/release-notes/workarea-3-1-12.html.md +216 -0
  417. data/docs/source/release-notes/workarea-3-1-13.html.md +113 -0
  418. data/docs/source/release-notes/workarea-3-1-14.html.md +39 -0
  419. data/docs/source/release-notes/workarea-3-1-15.html.md +107 -0
  420. data/docs/source/release-notes/workarea-3-1-16.html.md +188 -0
  421. data/docs/source/release-notes/workarea-3-1-17.html.md +141 -0
  422. data/docs/source/release-notes/workarea-3-1-18.html.md +73 -0
  423. data/docs/source/release-notes/workarea-3-1-19.html.md +137 -0
  424. data/docs/source/release-notes/workarea-3-1-2.html.md +55 -0
  425. data/docs/source/release-notes/workarea-3-1-20.html.md +203 -0
  426. data/docs/source/release-notes/workarea-3-1-21.html.md +205 -0
  427. data/docs/source/release-notes/workarea-3-1-22.html.md +121 -0
  428. data/docs/source/release-notes/workarea-3-1-23.html.md +144 -0
  429. data/docs/source/release-notes/workarea-3-1-24.html.md +94 -0
  430. data/docs/source/release-notes/workarea-3-1-25.html.md +77 -0
  431. data/docs/source/release-notes/workarea-3-1-26.html.md +130 -0
  432. data/docs/source/release-notes/workarea-3-1-27.html.md +70 -0
  433. data/docs/source/release-notes/workarea-3-1-28.html.md +52 -0
  434. data/docs/source/release-notes/workarea-3-1-29.html.md +44 -0
  435. data/docs/source/release-notes/workarea-3-1-3.html.md +185 -0
  436. data/docs/source/release-notes/workarea-3-1-30.html.md +72 -0
  437. data/docs/source/release-notes/workarea-3-1-31.html.md +93 -0
  438. data/docs/source/release-notes/workarea-3-1-32.html.md +61 -0
  439. data/docs/source/release-notes/workarea-3-1-33.html.md +171 -0
  440. data/docs/source/release-notes/workarea-3-1-34.html.md +130 -0
  441. data/docs/source/release-notes/workarea-3-1-35.html.md +179 -0
  442. data/docs/source/release-notes/workarea-3-1-36.html.md +28 -0
  443. data/docs/source/release-notes/workarea-3-1-37.html.md +74 -0
  444. data/docs/source/release-notes/workarea-3-1-38.html.md +61 -0
  445. data/docs/source/release-notes/workarea-3-1-39.html.md +96 -0
  446. data/docs/source/release-notes/workarea-3-1-4.html.md +148 -0
  447. data/docs/source/release-notes/workarea-3-1-40.html.md +126 -0
  448. data/docs/source/release-notes/workarea-3-1-41.html.md +128 -0
  449. data/docs/source/release-notes/workarea-3-1-42.html.md +105 -0
  450. data/docs/source/release-notes/workarea-3-1-43.html.md +37 -0
  451. data/docs/source/release-notes/workarea-3-1-44.html.md +82 -0
  452. data/docs/source/release-notes/workarea-3-1-45.html.md +153 -0
  453. data/docs/source/release-notes/workarea-3-1-46.html.md +91 -0
  454. data/docs/source/release-notes/workarea-3-1-47.html.md +65 -0
  455. data/docs/source/release-notes/workarea-3-1-48.html.md +46 -0
  456. data/docs/source/release-notes/workarea-3-1-49.html.md +23 -0
  457. data/docs/source/release-notes/workarea-3-1-5.html.md +169 -0
  458. data/docs/source/release-notes/workarea-3-1-50.html.md +42 -0
  459. data/docs/source/release-notes/workarea-3-1-51.html.md +25 -0
  460. data/docs/source/release-notes/workarea-3-1-52.html.md +57 -0
  461. data/docs/source/release-notes/workarea-3-1-6.html.md +117 -0
  462. data/docs/source/release-notes/workarea-3-1-7.html.md +176 -0
  463. data/docs/source/release-notes/workarea-3-1-8.html.md +283 -0
  464. data/docs/source/release-notes/workarea-3-1-9.html.md +212 -0
  465. data/docs/source/release-notes/workarea-3-2-0.html.md +1705 -0
  466. data/docs/source/release-notes/workarea-3-2-1.html.md +216 -0
  467. data/docs/source/release-notes/workarea-3-2-10.html.md +237 -0
  468. data/docs/source/release-notes/workarea-3-2-11.html.md +121 -0
  469. data/docs/source/release-notes/workarea-3-2-12.html.md +145 -0
  470. data/docs/source/release-notes/workarea-3-2-13.html.md +138 -0
  471. data/docs/source/release-notes/workarea-3-2-14.html.md +77 -0
  472. data/docs/source/release-notes/workarea-3-2-15.html.md +130 -0
  473. data/docs/source/release-notes/workarea-3-2-16.html.md +111 -0
  474. data/docs/source/release-notes/workarea-3-2-17.html.md +52 -0
  475. data/docs/source/release-notes/workarea-3-2-18.html.md +44 -0
  476. data/docs/source/release-notes/workarea-3-2-19.html.md +72 -0
  477. data/docs/source/release-notes/workarea-3-2-2.html.md +145 -0
  478. data/docs/source/release-notes/workarea-3-2-20.html.md +93 -0
  479. data/docs/source/release-notes/workarea-3-2-21.html.md +61 -0
  480. data/docs/source/release-notes/workarea-3-2-22.html.md +154 -0
  481. data/docs/source/release-notes/workarea-3-2-23.html.md +130 -0
  482. data/docs/source/release-notes/workarea-3-2-24.html.md +200 -0
  483. data/docs/source/release-notes/workarea-3-2-25.html.md +28 -0
  484. data/docs/source/release-notes/workarea-3-2-26.html.md +94 -0
  485. data/docs/source/release-notes/workarea-3-2-27.html.md +61 -0
  486. data/docs/source/release-notes/workarea-3-2-28.html.md +96 -0
  487. data/docs/source/release-notes/workarea-3-2-29.html.md +126 -0
  488. data/docs/source/release-notes/workarea-3-2-30.html.md +112 -0
  489. data/docs/source/release-notes/workarea-3-2-31.html.md +105 -0
  490. data/docs/source/release-notes/workarea-3-2-32.html.md +56 -0
  491. data/docs/source/release-notes/workarea-3-2-33.html.md +82 -0
  492. data/docs/source/release-notes/workarea-3-2-34.html.md +153 -0
  493. data/docs/source/release-notes/workarea-3-2-35.html.md +91 -0
  494. data/docs/source/release-notes/workarea-3-2-36.html.md +118 -0
  495. data/docs/source/release-notes/workarea-3-2-37.html.md +46 -0
  496. data/docs/source/release-notes/workarea-3-2-38.html.md +23 -0
  497. data/docs/source/release-notes/workarea-3-2-39.html.md +42 -0
  498. data/docs/source/release-notes/workarea-3-2-4.html.md +109 -0
  499. data/docs/source/release-notes/workarea-3-2-40.html.md +25 -0
  500. data/docs/source/release-notes/workarea-3-2-41.html.md +90 -0
  501. data/docs/source/release-notes/workarea-3-2-5.html.md +186 -0
  502. data/docs/source/release-notes/workarea-3-2-6.html.md +173 -0
  503. data/docs/source/release-notes/workarea-3-2-7.html.md +89 -0
  504. data/docs/source/release-notes/workarea-3-2-8.html.md +137 -0
  505. data/docs/source/release-notes/workarea-3-2-9.html.md +219 -0
  506. data/docs/source/release-notes/workarea-3-3-0.html.md +1272 -0
  507. data/docs/source/release-notes/workarea-3-3-1.html.md +324 -0
  508. data/docs/source/release-notes/workarea-3-3-10.html.md +69 -0
  509. data/docs/source/release-notes/workarea-3-3-11.html.md +72 -0
  510. data/docs/source/release-notes/workarea-3-3-12.html.md +136 -0
  511. data/docs/source/release-notes/workarea-3-3-13.html.md +61 -0
  512. data/docs/source/release-notes/workarea-3-3-14.html.md +196 -0
  513. data/docs/source/release-notes/workarea-3-3-15.html.md +167 -0
  514. data/docs/source/release-notes/workarea-3-3-16.html.md +234 -0
  515. data/docs/source/release-notes/workarea-3-3-17.html.md +82 -0
  516. data/docs/source/release-notes/workarea-3-3-18.html.md +165 -0
  517. data/docs/source/release-notes/workarea-3-3-19.html.md +106 -0
  518. data/docs/source/release-notes/workarea-3-3-2.html.md +72 -0
  519. data/docs/source/release-notes/workarea-3-3-20.html.md +116 -0
  520. data/docs/source/release-notes/workarea-3-3-21.html.md +228 -0
  521. data/docs/source/release-notes/workarea-3-3-22.html.md +125 -0
  522. data/docs/source/release-notes/workarea-3-3-23.html.md +154 -0
  523. data/docs/source/release-notes/workarea-3-3-24.html.md +70 -0
  524. data/docs/source/release-notes/workarea-3-3-25.html.md +114 -0
  525. data/docs/source/release-notes/workarea-3-3-26.html.md +260 -0
  526. data/docs/source/release-notes/workarea-3-3-27.html.md +138 -0
  527. data/docs/source/release-notes/workarea-3-3-28.html.md +147 -0
  528. data/docs/source/release-notes/workarea-3-3-29.html.md +63 -0
  529. data/docs/source/release-notes/workarea-3-3-3.html.md +153 -0
  530. data/docs/source/release-notes/workarea-3-3-30.html.md +102 -0
  531. data/docs/source/release-notes/workarea-3-3-31.html.md +57 -0
  532. data/docs/source/release-notes/workarea-3-3-32.html.md +44 -0
  533. data/docs/source/release-notes/workarea-3-3-33.html.md +114 -0
  534. data/docs/source/release-notes/workarea-3-3-4.html.md +332 -0
  535. data/docs/source/release-notes/workarea-3-3-5.html.md +242 -0
  536. data/docs/source/release-notes/workarea-3-3-6.html.md +100 -0
  537. data/docs/source/release-notes/workarea-3-3-7.html.md +148 -0
  538. data/docs/source/release-notes/workarea-3-3-8.html.md +163 -0
  539. data/docs/source/release-notes/workarea-3-3-9.html.md +93 -0
  540. data/docs/source/release-notes/workarea-3-4-0.html.md +580 -0
  541. data/docs/source/release-notes/workarea-3-4-1.html.md +150 -0
  542. data/docs/source/release-notes/workarea-3-4-10.html.md +72 -0
  543. data/docs/source/release-notes/workarea-3-4-11.html.md +60 -0
  544. data/docs/source/release-notes/workarea-3-4-12.html.md +155 -0
  545. data/docs/source/release-notes/workarea-3-4-2.html.md +188 -0
  546. data/docs/source/release-notes/workarea-3-4-3.html.md +136 -0
  547. data/docs/source/release-notes/workarea-3-4-4.html.md +114 -0
  548. data/docs/source/release-notes/workarea-3-4-5.html.md +275 -0
  549. data/docs/source/release-notes/workarea-3-4-6.html.md +169 -0
  550. data/docs/source/release-notes/workarea-3-4-7.html.md +162 -0
  551. data/docs/source/release-notes/workarea-3-4-8.html.md +95 -0
  552. data/docs/source/release-notes/workarea-3-4-9.html.md +135 -0
  553. data/docs/source/search.html.erb +34 -0
  554. data/docs/source/shared/_header.erb +61 -0
  555. data/docs/source/shared/_svgs.erb +17 -0
  556. data/docs/source/style_guide/index.html.erb +382 -0
  557. data/docs/source/stylesheets/_base.scss +125 -0
  558. data/docs/source/stylesheets/_components.scss +669 -0
  559. data/docs/source/stylesheets/_helpers.scss +10 -0
  560. data/docs/source/stylesheets/_opinions.scss +42 -0
  561. data/docs/source/stylesheets/_settings.scss +56 -0
  562. data/docs/source/stylesheets/_typography.scss +119 -0
  563. data/docs/source/stylesheets/site.css.scss +14 -0
  564. data/docs/source/stylesheets/vendor/_avalanche.scss +328 -0
  565. data/docs/source/stylesheets/vendor/_normalize.scss +341 -0
  566. data/docs/source/stylesheets/vendor/highlight/_tomorrow_night_blue.scss +75 -0
  567. data/docs/source/upgrade-guides.html.md +18 -0
  568. data/docs/source/upgrade-guides/workarea-3-4-0.html.md +152 -0
  569. data/docs/workarea_renderer.rb +8 -0
  570. data/docs/yarn.lock +2522 -0
  571. metadata +669 -0
@@ -0,0 +1,88 @@
1
+ ---
2
+ title: Application Document
3
+ excerpt: An application document is a persistable model with a global id, timestamps, an audit log, and life cycle callbacks providing hooks for callbacks workers. An application document cleans some of its data before validation and before create.
4
+ ---
5
+
6
+ # Application Document
7
+
8
+ An <dfn>application document</dfn> is a persistable model with a global id, timestamps, an audit log, and life cycle callbacks providing hooks for [callbacks workers](workers.html#callbacks-worker). An application document cleans some of its data before validation and before create.
9
+
10
+ ## Mongoid
11
+
12
+ Workarea employs [Mongoid](https://rubygems.org/gems/mongoid) ([docs](https://docs.mongodb.com/ruby-driver/master/mongoid/), [source](https://github.com/mongodb/mongoid)), MongoDB's <abbr title="object document mapper">ODM</abbr> written in Ruby, to map between in-memory models and documents persisted to disk.
13
+
14
+ ### Document
15
+
16
+ An application document includes the `Mongoid::Document` module ([docs](https://docs.mongodb.com/ruby-driver/master/tutorials/6.1.0/mongoid-documents/), [docs](http://www.rubydoc.info/gems/mongoid/6.0.0/Mongoid/Document)), providing a large API for document persistence, queries, relations, callbacks, validations, indexes, and more.
17
+
18
+ ### Timestamps
19
+
20
+ An application document also includes Mongoid's `Mongoid::Timestamps` module ([docs](http://www.rubydoc.info/gems/mongoid/6.0.0/Mongoid/Timestamps)), which provides timestamp fields and accessor methods such as `ApplicationDocument#created_at` and `ApplicationDocument#updated_at`.
21
+
22
+ ### Audit Log
23
+
24
+ An application document additionally includes the `Mongoid::AuditLog` module ([docs](http://www.rubydoc.info/gems/mongoid-audit_log/0.4.0/Mongoid/AuditLog)) from the [mongoid-audit\_log](https://rubygems.org/gems/mongoid-audit_log) library ([docs](http://www.rubydoc.info/gems/mongoid-audit_log/0.4.0), [source](https://github.com/bencrouse/mongoid-audit_log)). This library provides basic audit logging for each application document. `ApplicationDocument#audit_log_entries` provides access to the audit log entries for an application document instance.
25
+
26
+ ## Global ID
27
+
28
+ An application document includes `GlobalID::Identification` ([docs](http://www.rubydoc.info/gems/globalid/0.3.7/GlobalID/Identification)), providing the model with a global id that is guaranteed to be unique within the application, independent of its type.
29
+
30
+ ## Callbacks Workers
31
+
32
+ An application document includes `Sidekiq::Callbacks`, providing `ApplicationDocument#run_callbacks`, an extension of `ActiveSupport::Callbacks#run_callbacks` ([docs](http://api.rubyonrails.org/classes/ActiveSupport/Callbacks.html#method-i-run_callbacks)) allowing [callbacks workers](workers.html#callbacks-worker) to run or enqueue in response to the document's life cycle callbacks, such as `after_save` and `after_destroy`.
33
+
34
+ ## Data Cleaning
35
+
36
+ An application document cleans array fields before validation and ensures default locale values before create.
37
+
38
+ ### Reject Blank Array Members
39
+
40
+ Before validation, each field value of type `Array` is cleaned to remove blank members.
41
+
42
+ ```
43
+ category = Workarea::Catalog::Category.new(terms_facets: ['color', '', nil, 'size'])
44
+
45
+ category.terms_facets
46
+ # => ["color", "", nil, "size"]
47
+
48
+ category.validate
49
+
50
+ category.terms_facets
51
+ # => ["color", "size"]
52
+ ```
53
+
54
+ ### Ensure Default Locale Values
55
+
56
+ Before create, for each localized field with a value, the value is copied to the default locale if that value is blank within the default locale. Ensuring a value for the default locale avoids a class of errors when locales switch or fall back.
57
+
58
+ ```
59
+ I18n.default_locale
60
+ # => :en
61
+
62
+ I18n.locale
63
+ # => :en
64
+
65
+ # change to non-default locale
66
+ I18n.locale = :fr
67
+
68
+ I18n.locale
69
+ # => :fr
70
+
71
+ # within this locale, create a product with a name (a localized field)
72
+ red_dress = Workarea::Catalog::Product.create!(name: 'Robe Rouge')
73
+
74
+ red_dress.name
75
+ # => "Robe Rouge"
76
+
77
+ # switch back to the default locale
78
+ I18n.locale = I18n.default_locale
79
+
80
+ # the 'name' value from the :fr locale has been copied to the :en locale to
81
+ # avoid errors when switching or falling back
82
+ red_dress.name
83
+ # => "Robe Rouge"
84
+
85
+ # red_dress.name_translations
86
+ # => {"fr"=>"Robe Rouge", "en"=>"Robe Rouge"}
87
+ ```
88
+
@@ -0,0 +1,162 @@
1
+ ---
2
+ title: Automated JavaScript Testing
3
+ excerpt: The Workarea platform uses Teaspoon to unit test JavaScript modules.
4
+ ---
5
+
6
+ # Automated JavaScript Testing
7
+
8
+ ## Overview
9
+
10
+ The Workarea platform uses [Teaspoon](https://github.com/modeset/teaspoon) to unit test JavaScript modules.
11
+
12
+ The tests themselves are written using the [Mocha](https://github.com/mochajs/mocha) test framework. [Chai](http://chaijs.com/) is the chosen assertion library. Specifically, [Chai's Expect style](http://chaijs.com/guide/styles/#expect) is used in an attempt to achieve parity with RSpec.
13
+
14
+ Lastly, Workarea uses [Sinon](http://sinonjs.org/) via [Sinon Chai](https://github.com/domenic/sinon-chai) which provides test spies, mocks, and stubs.
15
+
16
+ ## When should a Teaspoon test be written?
17
+
18
+ The platform's JavaScript modules are written using [The Revealing Module Pattern](https://carldanley.com/js-revealing-module-pattern/). If a module publicly exposes a method that method then becomes testable. The majority of the platform's modules, however, initialize only when an element with a specific selector is found within a given scope. These modules provide functionality for general use or for a specific feature are less straight forward to test.
19
+
20
+ ### Utility Modules
21
+
22
+ If a module is written with many useful public methods it becomes an ideal Teaspoon test candidate. An example of this is the `WORKAREA.dialog` module. This module is written to be almost entirely public facing, deferring a lot of the interactive functionality to other modules who make use of its API.
23
+
24
+ ### General Purpose Modules
25
+
26
+ If a general-use, DOM-based module is written then a fixture can be used as the method's scope. This way you are able to assert that the module functions properly within the vacuum that is the fixture. An example of this type of module would be the `WORKAREA.dialogButtons` module, which searches a given scope for an element with a `data-dialog-button` attribute before providing its functionality to said element.
27
+
28
+ ### Broken Code
29
+
30
+ If a JavaScript bug is uncovered during QA, a Teaspoon test should be written to prove that the bug exists before the code is updated. This ensures that the bug has actually been fixed and will not resurface again.
31
+
32
+ ## Feature Tests v. Unit Tests
33
+
34
+ For complex features, such as the content editing feature of the Admin, there is a large amount of JavaScript required to make the feature function properly. When writing Teaspoon tests for these types of modules keep in mind that you aren't using Teaspoon to test the feature itself, but how the methods provided by the module interact with the page.
35
+
36
+ It should be noted that feature tests require that the entire application be spun up each time the suite is run, so they should only be written to describe and verify high-level features. Unit tests do not require the entire application and are therefore much quicker. If you can provide adequate test coverage using unit tests, you should do so.
37
+
38
+ ## Examples
39
+
40
+ Let's look at a few samples directly from the Workarea source code.
41
+
42
+ ### The `WORKAREA.string` Utility Module
43
+
44
+ ```
45
+ WORKAREA.registerModule('string', (function () {
46
+ 'use strict';
47
+
48
+ var pluralize = function (count, string, pluralizedString) {
49
+ if (count > 1 && ! _.isUndefined(pluralizedString)) {
50
+ return pluralizedString;
51
+ } else if (count > 1) {
52
+ return string + 's';
53
+ } else {
54
+ return string;
55
+ }
56
+ },
57
+
58
+ titleize = function (string) {
59
+ if ( ! _.isString(string)) {
60
+ throw new Error('WORKAREA.string.titleize: expecting string');
61
+ }
62
+
63
+ return _.map(
64
+ $.trim(string).toLowerCase().split(' '),
65
+ function (subString) {
66
+ return subString.charAt(0).toUpperCase() +
67
+ subString.slice(1);
68
+ }
69
+ ).join(' ');
70
+ };
71
+
72
+ return {
73
+ titleize: titleize,
74
+ pluralize: pluralize
75
+ };
76
+ }()));
77
+ ```
78
+
79
+ As you can see, the `WORKAREA.string` module has two public methods, `titleize` and `pluralize`. Each one of these methods function as a utility for other modules to use and, therefore, should be tested to ensure they are working properly:
80
+
81
+ ```
82
+ describe('WORKAREA.string', function () {
83
+ describe('titleize', function () {
84
+ it('titleizes a given string', function () {
85
+ expect(WORKAREA.string.titleize('foo ')).to.equal('Foo');
86
+ expect(WORKAREA.string.titleize('BAR')).to.equal('Bar');
87
+ expect(WORKAREA.string.titleize('fOoBaR')).to.equal('Foobar');
88
+ });
89
+ });
90
+
91
+ describe('pluralize', function () {
92
+ it('returns a custom pluralized string', function () {
93
+ expect(WORKAREA.string.pluralize(2, 'baz', 'bazes')).to.equal('bazes');
94
+ });
95
+
96
+ it('returns a simple pluralized string', function () {
97
+ expect(WORKAREA.string.pluralize(2, 'bar')).to.equal('bars');
98
+ });
99
+
100
+ it('returns an unpluralized string', function () {
101
+ expect(WORKAREA.string.pluralize(1, 'foo')).to.equal('foo');
102
+ });
103
+ });
104
+ });
105
+ ```
106
+
107
+ ### The `WORKAREA.helpTooltips` Global Module
108
+
109
+ ```
110
+ WORKAREA.registerModule('helpTooltips', (function () {
111
+ 'use strict';
112
+
113
+ var initTooltip = function (init, link) {
114
+ var fragmentId = $(link).attr('href'),
115
+ options = $(link).data('helpTooltip') || {};
116
+
117
+ $(link).tooltipster(_.assign({ content: $(fragmentId) }, options));
118
+ },
119
+
120
+ init = function ($scope) {
121
+ $('[data-help-tooltip]', $scope).each(initTooltip);
122
+ };
123
+
124
+ return {
125
+ init: init
126
+ };
127
+ }()));
128
+ ```
129
+
130
+ This module is responsible for creating an instance of jQuery Tooltipster for each element within the given <coder>$scope that has a <code>data-help-tooltip</code> attribute.</coder>
131
+
132
+ Create the fixture that meets these requirements:
133
+
134
+ ```
135
+ = link_to 'Tooltip', '#help-tooltip', id: 'help-link', data: { help_tooltip: '' }
136
+ #help-tooltip.help-tooltip
137
+ %p Tooltip content.
138
+ ```
139
+
140
+ And use the fixture as the aforementioned `$scope` when testing the module:
141
+
142
+ ```
143
+ describe('WORKAREA.helpTooltips', function () {
144
+ describe('init', function () {
145
+ it('inits tooltipster on the link', function () {
146
+ this.fixtures = fixture.load('help_tooltip.html', true);
147
+
148
+ sinon.spy($.prototype, 'tooltipster');
149
+
150
+ WORKAREA.helpTooltips.init($(this.fixtures));
151
+
152
+ expect($.fn.tooltipster.calledOnce).to.equal(true);
153
+
154
+ $.fn.tooltipster.restore();
155
+ });
156
+ });
157
+ });
158
+ ```
159
+
160
+ Notice that there are no tests asserting that jQuery Tooltipster itself is working properly. Since the platform depends on this 3rd party plugin, and the plugin ships with it's own tests, we simply need to ensure that jQuery Tooltipster is being instantiated under the right conditions.
161
+
162
+
@@ -0,0 +1,64 @@
1
+ ---
2
+ title: B2B Overview
3
+ excerpt: An overview of Workarea B2B functionality
4
+ ---
5
+
6
+ # B2B Overview
7
+
8
+ Workarea offers a suite of B2B features to allow retailers to operate a B2B
9
+ Storefront. These features are packaged as a set of plugins as part of the
10
+ Workarea Commerce Cloud. See [workarea.com](https://www.workarea.com) for more
11
+ info.
12
+
13
+ Each plugin includes a readme which details the specific features and
14
+ functionality it provides.
15
+
16
+ * [B2B](https://stash.tools.weblinc.com/projects/WL/repos/workarea-b2b/browse)
17
+ * [Quotes](https://stash.tools.weblinc.com/projects/WL/repos/workarea-quotes/browse)
18
+ * [Variant List](https://stash.tools.weblinc.com/projects/WL/repos/workarea-variant-list/browse)
19
+ * [Quick Order](https://stash.tools.weblinc.com/projects/WL/repos/workarea-quick-order/browse)
20
+ * [Clifton Theme](https://stash.tools.weblinc.com/projects/WL/repos/workarea-clifton-theme/browse)
21
+
22
+ ## B2B Feature Summary
23
+
24
+ * Organizations, Accounts, and Memberships for customers.
25
+ * Account configuration - payment terms, price lists, credit limits, and order
26
+ restrictions.
27
+ * Membership roles - Administrator, Approver, and Shopper.
28
+ * Admin management of account credit limits and balances.
29
+ * Storefront organization account pages for customers to view and manage their
30
+ accounts
31
+ * Account customer checkout with configurable address and payment options.
32
+ * Configurable order approvals.
33
+ * Custom price lists.
34
+ * Reorder items from order history.
35
+
36
+ ## Quotes Feature Summary
37
+
38
+ * Quote request submission at the payment step of checkout.
39
+ * Customer quote management from the account page.
40
+ * Copy quote item and order details to a new cart.
41
+ * Admin management of quotes.
42
+ * B2B support - enabling organization account-based quotes and customer
43
+ management of quotes through their organization account pages
44
+
45
+ ## Variant List Feature Summary
46
+
47
+ * A new product template designed for products with many variants.
48
+ * Allow shoppers to add multiple variants to a cart at one time.
49
+
50
+ ## Quick Order Feature Summary
51
+
52
+ * Enable customers to quickly add items to their cart by entering a list of SKUs
53
+ and quantities or uploading a file.
54
+
55
+ ## Clifton Theme Feature Summary
56
+
57
+ * A B2B focused theme for the Workarea commerce platform.
58
+ * Designed with B2B in mind, supports the full B2B plugin suite.
59
+
60
+ ## Demo site
61
+
62
+ The complete Workarea B2B suite is installed for demonstration purposes only at
63
+ <https://b2b.demo.workarea.com> - for admin access or a full guided demo of
64
+ Workarea B2B functionality please contact [Workarea support](https://workarea.support.com).
@@ -0,0 +1,47 @@
1
+ ---
2
+ title: Browser & Device Support
3
+ excerpt: The Workarea platform is designed for compatibility with modern browsers and devices. The platform is explicitly tested with the browsers and devices that are most often used by end users, as reported by our systems integrators.
4
+ ---
5
+
6
+ # Browser & Device Support
7
+
8
+ The Workarea platform is designed for compatibility with modern browsers and devices. The platform is explicitly tested with the browsers and devices that are most often used by end users, as reported by our systems integrators.
9
+
10
+ ## Storefront
11
+
12
+ Responsive: YES
13
+
14
+ Environments manually tested:
15
+
16
+ - Latest Chrome on latest macOS
17
+ - Latest Safari on latest macOS
18
+ - Latest Firefox on latest macOS
19
+ - Latest Edge on latest Windows
20
+ - IE 11 on latest compatible Windows
21
+ - IE 10 on latest compatible Windows
22
+ - IE 9 on latest compatible Windows
23
+ - Safari on latest iPhone
24
+ - Safari on latest iPad
25
+ - Android Browser on latest GALAXY phone
26
+
27
+ ## Admin
28
+
29
+ Responsive: PARTIALLY, Tablet Supported
30
+
31
+ Environments manually tested:
32
+
33
+ - Latest Chrome on latest macOS
34
+ - Latest Safari on latest macOS
35
+ - Latest Firefox on latest macOS
36
+ - Latest Edge on latest Windows
37
+ - IE 11 on latest compatible Windows
38
+ - IE 10 on latest compatible Windows
39
+ - Safari on latest iPad
40
+
41
+ ## System Emails
42
+
43
+ Responsive: YES
44
+
45
+ Emails were adapted from a community-supported, responsive template called [Cerberus](http://tedgoas.github.io/Cerberus/), which has been tested in a variety of email clients. Before any system email is sent it is first processed by a gem called [Premailer](https://github.com/premailer/premailer), which helps to standardize the way emails are customized. Minor changes like colors, fonts, and image sources should require only minimal testing in a web browser. Changes to layouts, new layouts, or other significant changes should be tested through a 3rd-party email testing service.
46
+
47
+
@@ -0,0 +1,39 @@
1
+ ---
2
+ title: Change Product Placeholder Image
3
+ excerpt: Learn how to change the default placeholder image for catalog products.
4
+ ---
5
+
6
+ # Change Product Placeholder Image
7
+
8
+ Products can be associated with images, but this is by no means required. In the event that a product has no images associated with it, a default placeholder image is rendered. This may not be suitable for your Workarea application's look-and-feel, and this article explains how to change that default image. Placeholder images can be configured either from a Workarea application, or from a plugin (such as a theme). Plugins and themes typically change the placeholder image when the existing one does not match the proper dimensions for a PDP image.
9
+
10
+ ## Override the Image File
11
+
12
+ Save your new placeholder image file as `app/assets/images/workarea/core/product_placeholder.jpg`. This is, by default, the first file path that is looked up and cached into the database for use as a product image when no images have been uploaded for that product. File paths within the main Workarea component engines (Storefront, Admin, Core, etc.) are checked, as well as any plugins that you have installed. This gives plugins, especially themes, a chance to override the image as well. Workarea applications have the "final word", as always, and can override this path even if plugins have it overridden already.
13
+
14
+ To see the new placeholder image, you must first clear out the existing cached image. Run the following in `rails console` to do that:
15
+
16
+ ```ruby
17
+ Workarea::Catalog::ProductPlaceholderImage.cached.destroy!
18
+ ```
19
+
20
+ To generate a new placeholder image (and verify that your change succeeded), you can then run `rails console`:
21
+
22
+ ```ruby
23
+ Workarea::Catalog::ProductPlaceholderImage.cached
24
+ ```
25
+
26
+ If your new placeholder image was uploaded, the aformentioned method call will return a new record (as evidenced by a different `:_id` attribute), thus confirming that a new image has been uploaded. You can also visit a product detail page for a product that has no images and view the placeholder through the browser.
27
+
28
+ ## Configure Placeholder Image Filename
29
+
30
+ Although this is not common, it is possible to change the filename of the placeholder image that Workarea looks up in the asset pipeline. To do this, configure the `product_placeholder_image_name` setting like so:
31
+
32
+ ```ruby
33
+ # config/initializers/workarea.rb
34
+ Workarea.configure do |config|
35
+ config.product_placeholder_image_name = 'no_product_image.jpg'
36
+ end
37
+ ```
38
+
39
+ Your placeholder image will now be looked up at `app/assets/workarea/core/no_product_image.jpg`.
@@ -0,0 +1,283 @@
1
+ ---
2
+ title: Change Storefront Search Results
3
+ excerpt: This document provides a specific example of changing Storefront search results, as well as commentary on how to adapt these ideas to your own use cases.
4
+ ---
5
+
6
+ Change Storefront Search Results
7
+ ================================================================================
8
+
9
+ After familiarizing yourself with the [Storefront search features](storefront-search-features.html) and learning how to [analyze Storefront search results](analyze-storefront-search-results.html), you may want to go a step further and actually _change_ Storefront search results.
10
+ Specifically, you'll likely want to change _which_ documents match a given search query (matching) and/or _how well_ each document matches the query (relevance).
11
+
12
+ Search results are created by matching _search documents_, created by _search models_, to a _search request body_, created by a _search query object_. These are therefore your extension points.
13
+ To an extent, you can apply changes to these features via administration and configuration, particularly to manipulate a search request body.
14
+ (Review the documents linked above for coverage of these concepts and a list of relevant administration and configuration.)
15
+ However, many changes require deeper extension of these features through [decoration](decoration.html).
16
+
17
+ This document provides a specific example of such a change, as well as commentary on how to adapt these ideas to your own use cases.
18
+
19
+
20
+ Example
21
+ --------------------------------------------------------------------------------
22
+
23
+ For the sake of having a concrete example, we'll use the following:
24
+
25
+ You're developing an application, and the retailer has previously extended the platform to establish the concept of "promo" products.
26
+ These products are typically shared via email campaigns and other marketing and are not intended to be [merchandised](products.html#merchandising-amp-browsing-the-storefront_14) within the Storefront.
27
+ The retailer has therefore opened a change request for you to exclude promo products from _all_ Storefront search results, since most of Workarea's merchandising features are driven by search.
28
+
29
+
30
+ Setup
31
+ --------------------------------------------------------------------------------
32
+
33
+ In order to work on this change request, first set up some test data.
34
+ While you could do this entirely through automated tests, for the sake of this document we'll set up [seeds](seeds.html) and work in a development environment, which is more visual.
35
+
36
+ Let's assume that as part of a previous change request, another developer has already decorated the catalog product model to add a `:promo` field to all products.
37
+
38
+ ```ruby
39
+ # app/models/workarea/catalog/product.decorator
40
+ module Workarea
41
+ decorate Catalog::Product do
42
+ decorated do
43
+ field :promo, type: Boolean, default: false
44
+ end
45
+ end
46
+ end
47
+ ```
48
+
49
+ This developer also extended the Admin to allow administration of this field.
50
+ In production environments, a small number of products (usually 5-10 at any given time) will have this flag set to `true`.
51
+ These are the products that must be excluded from search results.
52
+
53
+ Start by creating some appropriate seed data to test within your development environment.
54
+ The following seeds create four products that will match a search for "promo", but only two of the products are actual promo products (i.e. `:promo` is `true`).
55
+ The seeds also create categories which merchandise all four of the test products.
56
+ One of the categories uses product rules to merchandise the products, while the other uses featured products.
57
+
58
+ ```ruby
59
+ # app/seeds/workarea/promo_products_seeds.rb
60
+ module Workarea
61
+ class PromoProductsSeeds
62
+ def perform
63
+ puts 'Adding promo products...'
64
+
65
+ promo_product_ids = []
66
+
67
+ # create 4 products that match the search query "promo"
68
+ # 2 of which are actual promo products that should not display
69
+ # in search results
70
+ 4.times do | i |
71
+ promo = i.even?
72
+ name = i.even? ? "Promo (do not merchandize)" : "Not Promo"
73
+ sku = "promo-test-#{i}"
74
+
75
+ product = Catalog::Product.create!(
76
+ name: name,
77
+ variants: [{ sku: sku }],
78
+ promo: promo
79
+ )
80
+ # collect the product IDs to create a category below
81
+ promo_product_ids << product.id
82
+
83
+ # create corresponding pricing to make products displayable
84
+ Pricing::Sku.create!(
85
+ id: sku,
86
+ prices: [{ regular: Faker::Commerce.price.to_m }]
87
+ )
88
+ end
89
+
90
+ # create 2 categories which both include all 4 "promo" products
91
+ # the first via product rules
92
+ # the second via product IDs (featured products)
93
+ Catalog::Category.create!(
94
+ name: 'Promo Search',
95
+ product_rules: [
96
+ { name: 'search', operator: 'equals', value: 'promo' }
97
+ ]
98
+ )
99
+ Catalog::Category.create!(
100
+ name: 'Promo Featured',
101
+ product_ids: promo_product_ids
102
+ )
103
+ end
104
+ end
105
+ end
106
+ ```
107
+
108
+ Add the new seeds to your application's configuration:
109
+
110
+ ```ruby
111
+ # config/initializers/seeds.rb
112
+ Workarea.config.seeds << 'Workarea::PromoProductsSeeds'
113
+ ```
114
+
115
+ And then run the seeds:
116
+
117
+ ```bash
118
+ $ bin/rails db:seed
119
+ ```
120
+
121
+ Now the setup is complete.
122
+ At this point, searching for "promo" returns all 4 test products.
123
+
124
+ ![Before: promo products included in search results](../images/promo-products-included-search-results-before.png)
125
+
126
+ To complete the change request, you must write the code necessary to exclude the promo products from these results.
127
+ However, the retailer wants to exclude these products from _all_ search results, which includes autocomplete, categories, and product recommendations as well.
128
+
129
+ You can see the products are currently included in autocomplete results:
130
+
131
+ ![Before: promo products included in autocomplete results](../images/promo-products-included-autocomplete-results-before.png)
132
+
133
+ And all four products are included in the "Promo Search" category, which merchandises the products using a product rule:
134
+
135
+ ![Before: promo products included in search-based category results](../images/promo-products-included-search-category-results-before.png)
136
+
137
+ Additionally, the products are all included in the results for the "Promo Featured" category, which merchandises the products using featured products:
138
+
139
+ ![Before: promo products included in featured-product-based category results](../images/promo-products-included-featured-category-results-before.png)
140
+
141
+ Finally, at least one promo product is returned in search results:
142
+
143
+ ![Before: promo products included in recommendations results](../images/promo-products-included-recommendations-results-before.png)
144
+
145
+ (In this doc we won't go into exactly how recommendations work; we'll only cover how to exclude the promo products from the search-based results.)
146
+
147
+
148
+ Changing Search Documents
149
+ --------------------------------------------------------------------------------
150
+
151
+ Most search extensions require changes to the _documents_ and the _query_.
152
+ In the case of our example, we need to add the "promo" flag to product search documents.
153
+ While another developer previously extended the catalog product model (for MongoDB documents), the `:promo` field does not yet exist within the search documents.
154
+
155
+ To add a field to search documents, identify and decorate the relevant [Storefront search model](storefront-search-features.html#search-models_13) and then [re-index](index-storefront-search-documents.html) the documents.
156
+
157
+ In the case of our example, the relevant search model is `Search::Storefront::Product`, to which you must add the `:promo` field from the catalog model.
158
+ An important consideration when adding a field to a search model is the field's mapping (data type).
159
+ The promo field in MongoDB is a boolean value.
160
+ Search models provide [field namespaces](storefront-search-features.html#field-namespaces_16) to map fields to their correct types.
161
+ Review the source for the search model you are decorating to see which namespaces are available.
162
+
163
+ Looking at the Storefront product search model, there is no boolean namespace, but the `keywords` namespace is a good choice for the promo field.
164
+ Adding the field as `keywords.promo` will allow you to filter on the field within your search queries and will ensure the field's values are stored as-is, without being analyzed.
165
+
166
+ ```ruby
167
+ # app/models/workarea/search/storefront/product.decorator
168
+ module Workarea
169
+ decorate Search::Storefront::Product do
170
+ def keywords
171
+ # add the 'promo' field within the 'keywords' namespace
172
+ super.merge(promo: model.promo.to_s)
173
+ end
174
+ end
175
+ end
176
+ ```
177
+
178
+ After applying the changes, re-index the relevant products in the Storefront.
179
+ In this case, since you're working in a development environment, it's safe to re-index the entire Storefront as a shortcut:
180
+
181
+ ```bash
182
+ $ bin/rails workarea:search_indexes:storefront
183
+ ```
184
+
185
+ In production environments, modifying the `:promo` field's value for a given MongoDB document (e.g. through the Admin) will cause the document to be re-indexed into the appropriate search indexes.
186
+
187
+
188
+ Changing Search Queries
189
+ --------------------------------------------------------------------------------
190
+
191
+ After changing the data within the search indexes, you can leverage these changes within your search queries.
192
+ First determine which search queries you need to change.
193
+ (Refer to the table in [Storefront Search Features, Initialization & Parameters](storefront-search-features.html#initialization-amp-parameters_9).)
194
+ Our fictional change request requires changing all queries used within the Storefront.
195
+
196
+ Ultimately, for each query, you want to change the hash returned by `#body`, which is the search request body that is sent to Elasticsearch.
197
+ Most queries decompose the implementation of `#body` into several methods, some of which are defined in modules that are shared across queries.
198
+ Review the sources for the queries you are changing, and identify the method(s) that represent the portion of the request body you want to change.
199
+ The specific methods you change will depend on your use case.
200
+
201
+ Returning to the promo products example, the goal is to "filter out" all search documents whose `keywords.promo` field contains the string `'true'`.
202
+ Three of the four search queries used within the Storefront share a method, `product_display_query_clauses`, which matches documents based on keyword and other non-analyzed fields.
203
+ You can decorate these three queries with a single decorator, modifying that method to include additional clauses to exclude "promo" documents.
204
+
205
+ ```ruby
206
+ # app/queries/workarea/search/product_display_rules.decorator
207
+ module Workarea
208
+ decorate Search::ProductSearch, Search::CategoryBrowse, Search::RelatedProducts do
209
+ def product_display_query_clauses(allow_displayable_when_out_of_stock: true)
210
+ result = super
211
+ # add a compound query clause to exclude promo products
212
+ result << {
213
+ bool: {
214
+ must_not: {
215
+ term: { 'keywords.promo' => true }
216
+ }
217
+ }
218
+ }
219
+ result
220
+ end
221
+ end
222
+ end
223
+ ```
224
+
225
+ The example uses the logic "keywords.promo must not contain true" rather than "keywords.promo must contain false" to avoid the need to re-index all search documents for this feature to work.
226
+ The chosen logic excludes only those product search documents that have a `keywords.promo` field and whose value contains `'true'`.
227
+ Existing search documents without a keywords.promo field will continue to match queries as expected.
228
+
229
+ The decorator above does not cover the autocomplete feature, which relies on a separate query.
230
+ So you must additionally decorate the `SearchSuggestions` query class, adding similar logic to this query's request body.
231
+ This query's body is implemented almost entirely within the `#query` method, so apply your changes there:
232
+
233
+ ```ruby
234
+ # app/queries/workarea/search/search_suggestions.decorator
235
+ module Workarea
236
+ decorate Search::SearchSuggestions do
237
+ def query
238
+ result = super
239
+ # add a compound query clause to exclude promo products
240
+ result[:bool][:must_not] = [
241
+ { term: { 'keywords.promo' => true } }
242
+ ]
243
+ result
244
+ end
245
+ end
246
+ end
247
+ ```
248
+
249
+
250
+ Result
251
+ --------------------------------------------------------------------------------
252
+
253
+ Changing the documents and queries as described above has the effect of excluding promo products from all Storefront search results.
254
+ To verify this manually, re-visit each of the search features, and confirm the two test promo products do not display in the results.
255
+ In each case, the "Not promo" products continue to match, but the promo products are excluded.
256
+
257
+ Search results:
258
+
259
+ ![After: promo products excluded from search results](../images/promo-products-excluded-search-results-after.png)
260
+
261
+ Autocomplete:
262
+
263
+ ![After: promo products excluded from autocomplete results](../images/promo-products-excluded-autocomplete-results-after.png)
264
+
265
+ Categories:
266
+
267
+ ![After: promo products excluded from search-based category results](../images/promo-products-excluded-search-category-results-after.png)
268
+
269
+ ![After: promo products excluded from featured-product-based category results](../images/promo-products-excluded-featured-category-results-after.png)
270
+
271
+ And recommendations:
272
+
273
+ ![After: promo products excluded from recommendations results](../images/promo-products-excluded-recommendations-results-after.png)
274
+
275
+
276
+ Automated Testing
277
+ --------------------------------------------------------------------------------
278
+
279
+ In this doc we used manual testing to confirm the results because it allowed a visual demonstration of the material.
280
+ However, to avoid regressions, take the time to write automated tests for your changes.
281
+ This particular example avoids the need to decorate any existing tests, but other use cases may break existing functionality and require test decoration.
282
+
283
+ See [Testing](testing.html) for coverage of this topic.