Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Expose cart errors as notices #8162

Merged
merged 22 commits into from
Jan 19, 2023
Merged

Conversation

mikejolley
Copy link
Member

@mikejolley mikejolley commented Jan 11, 2023

We identified an issue that API responses that returned errors were being stored to the data stores, but not converted to notices.

To resolve this, I've converted receiveError to a thunk that creates error notices, following the pattern of receiveCart/notifyQuantityChanges that @opr implemented.

When detangling this problem I converted a few files to Typescript and merged some hooks. Ill add notes in the diff.

Fixes #7721

Other Checks

  • This PR adds/removes a feature flag & I've updated this doc.
  • This PR adds/removes an experimental interfaces and I've updated this doc.
  • I tagged two reviewers because this PR makes queries to the database or I think it might have some security impact.

Testing

Automated Tests

  • Changes in this PR are covered by Automated Tests.
    • Unit tests
    • E2E tests

User Facing Testing

We need to test this by throwing errors from the API. Add some error code here:

You can try:

  • die( 1 ); to test a generic error
  • throw new RouteException( 'test-error', 'Test', 400 ); to test a named error
  1. With the above in place, on both cart and checkout, select a shipping rate
  2. You should see the error notice appear at the top of the cart/checkout

There is no other error handling or retry mechanism beyond this (out of scope).

Since this revises the changes in #7363, repeat these testing steps also:

  1. Add two items to your cart, item A and item B.
  2. Go to the Cart block, and ensure you see no errors.
  3. Open a new tab, and edit product A. Set it to be out of stock.
  4. Without reloading the page return to the Cart block, and increase the quantity of any product. Ensure an error appears.
  5. Edit product A again, and set it to be in stock.
  6. Without reloading the page return to the Cart block, and increase the quantity of any product. Ensure the previous error is removed.
  7. In separate tabs, edit product A and B. Set them both to be out of stock.
  8. Without reloading the page return to the Cart block, and increase the quantity of any product. Ensure an error appears showing both products are out of stock.
  9. Edit only one product, set it back to in stock.
  10. Without reloading the page return to the Cart block, and increase the quantity of any product. Ensure the error stays, but that it only shows that one of the products is out of stock.
  • Do not include in the Testing Notes

WooCommerce Visibility

  • WooCommerce Core
  • Feature plugin
  • Experimental

@mikejolley mikejolley added the skip-changelog PRs that you don't want to appear in the changelog. label Jan 11, 2023
@mikejolley mikejolley self-assigned this Jan 11, 2023
@mikejolley mikejolley added the block: checkout Issues related to the checkout block. label Jan 11, 2023
@woocommercebot woocommercebot requested review from a team and tarhi-saad and removed request for a team January 11, 2023 16:04
@@ -82,6 +82,7 @@
top: 0;
text-align: center;
transform: translateX(-50%);
white-space: nowrap;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small fix for to stop these periods wrapping
Screenshot 2023-01-11 at 16 04 42

@github-actions
Copy link
Contributor

github-actions bot commented Jan 11, 2023

The release ZIP for this PR is accessible via:

https://wcblocks.wpcomstaging.com/wp-content/uploads/woocommerce-gutenberg-products-block-8162.zip

Script Dependencies Report

There is no changed script dependency between this branch and trunk.

This comment was automatically generated by the ./github/compare-assets action.

TypeScript Errors Report

  • Files with errors: 496
  • Total errors: 2250

⚠️ ⚠️ This PR introduces new TS errors on 7 files:

assets/js/base/components/cart-checkout/shipping-rates-control/index.tsx

assets/js/base/context/hooks/payment-methods/use-payment-method-interface.ts

assets/js/base/context/hooks/shipping/use-shipping-data.ts

assets/js/base/context/providers/cart-checkout/shipping/index.tsx

assets/js/base/context/providers/cart-checkout/shipping/reducers.js

assets/js/blocks/checkout/inner-blocks/checkout-pickup-options-block/block.tsx

packages/checkout/components/store-notices-container/test/index.tsx

comments-aggregator

}
onSelectRate={ ( newShippingRateId ) => {
selectShippingRate( newShippingRateId, packageId );
dispatchCheckoutEvent( 'set-selected-shipping-rate', {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved here from useSelectShippingRate which I've merged with useShippingData. The 2 hooks did very similar things.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 11, 2023

Size Change: +519 B (0%)

Total Size: 1.08 MB

Filename Size Change
build/all-products-frontend.js 11.6 kB -1 B (0%)
build/all-products.js 33.4 kB +2 B (0%)
build/all-reviews.js 7.67 kB -2 B (0%)
build/attribute-filter-wrapper-frontend.js 7.68 kB -3 B (0%)
build/blocks-checkout.js 41 kB +724 B (+2%)
build/cart-blocks/cart-cross-sells-products-frontend.js 9.61 kB -2 B (0%)
build/cart-blocks/cart-express-payment--checkout-blocks/express-payment-frontend.js 5.08 kB +1 B (0%)
build/cart-blocks/cart-express-payment-frontend.js 722 B +4 B (+1%)
build/cart-blocks/cart-line-items--mini-cart-contents-block/products-table-frontend.js 5.33 kB +2 B (0%)
build/cart-blocks/empty-cart-frontend.js 345 B -1 B (0%)
build/cart-blocks/filled-cart-frontend.js 656 B -205 B (-24%) 🎉
build/cart-blocks/order-summary-coupon-form-frontend.js 1.69 kB +1 B (0%)
build/cart-blocks/order-summary-discount-frontend.js 2.12 kB -1 B (0%)
build/cart-blocks/order-summary-shipping-frontend.js 14.9 kB +39 B (0%)
build/cart-blocks/order-summary-taxes-frontend.js 435 B -1 B (0%)
build/cart-blocks/proceed-to-checkout-frontend.js 1.24 kB +1 B (0%)
build/cart-frontend.js 28.5 kB -44 B (0%)
build/cart.js 47.5 kB -11 B (0%)
build/checkout-blocks/actions-frontend.js 1.85 kB +1 B (0%)
build/checkout-blocks/billing-address--checkout-blocks/shipping-address-frontend.js 3.91 kB +1 B (0%)
build/checkout-blocks/billing-address-frontend.js 1.15 kB +2 B (0%)
build/checkout-blocks/contact-information-frontend.js 2.04 kB +1 B (0%)
build/checkout-blocks/express-payment-frontend.js 1.13 kB +1 B (0%)
build/checkout-blocks/order-summary-cart-items-frontend.js 3.67 kB +1 B (0%)
build/checkout-blocks/order-summary-coupon-form-frontend.js 1.85 kB -1 B (0%)
build/checkout-blocks/order-summary-discount-frontend.js 2.29 kB -2 B (0%)
build/checkout-blocks/order-summary-shipping-frontend.js 14.9 kB +38 B (0%)
build/checkout-blocks/payment-frontend.js 8.33 kB +1 B (0%)
build/checkout-blocks/pickup-options-frontend.js 2.78 kB -1 B (0%)
build/checkout-blocks/shipping-address-frontend.js 1.11 kB +2 B (0%)
build/checkout-blocks/shipping-method-frontend.js 2.26 kB +1 B (0%)
build/checkout-blocks/shipping-methods-frontend.js 4.83 kB +41 B (+1%)
build/checkout-frontend.js 30.1 kB -24 B (0%)
build/checkout.js 43.3 kB +54 B (0%)
build/filter-wrapper-frontend.js 14.1 kB +4 B (0%)
build/legacy-template.js 2.87 kB +1 B (0%)
build/mini-cart-component-frontend.js 27.7 kB -1 B (0%)
build/mini-cart-contents-block/filled-cart-frontend.js 268 B -200 B (-43%) 🎉
build/mini-cart-contents-block/products-table-frontend.js 590 B -1 B (0%)
build/mini-cart-contents-block/title-frontend.js 367 B -1 B (0%)
build/mini-cart-contents.js 16.9 kB +2 B (0%)
build/mini-cart.js 4.29 kB -1 B (0%)
build/price-filter-frontend.js 13.9 kB +3 B (0%)
build/price-filter-wrapper-frontend.js 7.01 kB +2 B (0%)
build/price-filter.js 8.4 kB -1 B (0%)
build/product-add-to-cart-frontend.js 6.71 kB -1 B (0%)
build/product-add-to-cart.js 8.47 kB +2 B (0%)
build/product-best-sellers.js 7.61 kB +2 B (0%)
build/product-button--product-category-list--product-image--product-price--product-rating--product-sale-b--e17c7c01.js 439 B -1 B (0%)
build/product-button--product-image--product-rating--product-sale-badge--product-title.js 257 B -1 B (0%)
build/product-button-frontend.js 2.14 kB -1 B (0%)
build/product-button.js 3.84 kB -1 B (0%)
build/product-categories.js 2.36 kB -1 B (0%)
build/product-category-list-frontend.js 1.14 kB -1 B (0%)
build/product-image-frontend.js 2.14 kB -1 B (0%)
build/product-image.js 3.94 kB -2 B (0%)
build/product-new.js 7.6 kB -2 B (0%)
build/product-on-sale.js 7.93 kB -1 B (0%)
build/product-price-frontend.js 2.18 kB -2 B (0%)
build/product-query.js 5.95 kB +1 B (0%)
build/product-rating-frontend.js 1.57 kB -1 B (0%)
build/product-sale-badge-frontend.js 1.37 kB -3 B (0%)
build/product-sale-badge.js 812 B -2 B (0%)
build/product-stock-indicator-frontend.js 1.26 kB -1 B (0%)
build/product-summary-frontend.js 1.53 kB +1 B (0%)
build/product-tag.js 8.08 kB -2 B (0%)
build/product-title-frontend.js 1.57 kB -1 B (0%)
build/product-title.js 3.31 kB -2 B (0%)
build/product-top-rated.js 7.84 kB +2 B (0%)
build/products-by-attribute.js 8.52 kB -1 B (0%)
build/rating-filter-frontend.js 21.4 kB -3 B (0%)
build/rating-filter.js 7.43 kB +1 B (0%)
build/reviews-by-category.js 11.2 kB -1 B (0%)
build/reviews-by-product.js 12.3 kB +1 B (0%)
build/reviews-frontend.js 7.14 kB +4 B (0%)
build/single-product-frontend.js 17.7 kB -3 B (0%)
build/single-product.js 9.99 kB +4 B (0%)
build/stock-filter-frontend.js 21.1 kB -1 B (0%)
build/stock-filter.js 8.17 kB +2 B (0%)
build/vendors--attribute-filter-wrapper--cart-blocks/cart-cross-sells-products--cart-blocks/order-summary--82e4ed06-frontend.js 6.86 kB +1 B (0%)
build/vendors--attribute-filter-wrapper--rating-filter-wrapper--stock-filter-wrapper-frontend.js 7.7 kB +2 B (0%)
build/vendors--cart-blocks/cart-cross-sells-products--cart-blocks/order-summary-shipping--checkout-blocks--18f9376a-frontend.js 19.4 kB +1 B (0%)
build/vendors--cart-blocks/order-summary-shipping--checkout-blocks/billing-address--checkout-blocks/order--5b8feb0b-frontend.js 4.83 kB -1 B (0%)
build/wc-blocks-data.js 21.6 kB +97 B (0%)
build/wc-blocks-middleware.js 933 B +1 B (0%)
build/wc-blocks-registry.js 3.16 kB +1 B (0%)
build/wc-blocks-shared-hocs.js 1.73 kB -1 B (0%)
build/wc-blocks-style-rtl.css 25.6 kB +3 B (0%)
build/wc-blocks-style.css 25.6 kB +3 B (0%)
build/wc-blocks-vendors.js 64.2 kB +2 B (0%)
ℹ️ View Unchanged
Filename Size
build/active-filters-frontend.js 7.99 kB
build/active-filters-wrapper-frontend.js 6.01 kB
build/active-filters.js 7.31 kB
build/attribute-filter-frontend.js 22.9 kB
build/attribute-filter.js 12.4 kB
build/cart-blocks/cart-accepted-payment-methods-frontend.js 1.38 kB
build/cart-blocks/cart-cross-sells-frontend.js 253 B
build/cart-blocks/cart-items-frontend.js 299 B
build/cart-blocks/cart-line-items-frontend.js 1.07 kB
build/cart-blocks/cart-order-summary-frontend.js 1.25 kB
build/cart-blocks/cart-totals-frontend.js 321 B
build/cart-blocks/order-summary-fee-frontend.js 274 B
build/cart-blocks/order-summary-heading-frontend.js 456 B
build/cart-blocks/order-summary-subtotal-frontend.js 274 B
build/catalog-sorting.js 1.71 kB
build/checkout-blocks/fields-frontend.js 344 B
build/checkout-blocks/order-note-frontend.js 1.14 kB
build/checkout-blocks/order-summary-fee-frontend.js 277 B
build/checkout-blocks/order-summary-frontend.js 1.25 kB
build/checkout-blocks/order-summary-subtotal-frontend.js 275 B
build/checkout-blocks/order-summary-taxes-frontend.js 435 B
build/checkout-blocks/terms-frontend.js 1.56 kB
build/checkout-blocks/totals-frontend.js 324 B
build/customer-account.js 3.08 kB
build/featured-category.js 13.1 kB
build/featured-product.js 13.4 kB
build/filter-wrapper.js 2.4 kB
build/general-style-rtl.css 1.31 kB
build/general-style.css 1.31 kB
build/handpicked-products.js 7.24 kB
build/mini-cart-contents-block/empty-cart-frontend.js 366 B
build/mini-cart-contents-block/footer-frontend.js 2.82 kB
build/mini-cart-contents-block/items-frontend.js 237 B
build/mini-cart-contents-block/shopping-button-frontend.js 313 B
build/mini-cart-frontend.js 1.88 kB
build/price-format.js 1.19 kB
build/product-add-to-cart--product-button--product-category-list--product-image--product-price--product-r--a0326d00.js 226 B
build/product-add-to-cart--product-button--product-image--product-rating--product-title.js 151 B
build/product-category-list.js 503 B
build/product-category.js 8.6 kB
build/product-price.js 1.54 kB
build/product-rating.js 920 B
build/product-results-count.js 1.68 kB
build/product-search.js 2.62 kB
build/product-sku-frontend.js 629 B
build/product-sku.js 377 B
build/product-stock-indicator.js 645 B
build/product-summary.js 920 B
build/product-tag-list-frontend.js 1.13 kB
build/product-tag-list.js 496 B
build/rating-filter-wrapper-frontend.js 6.21 kB
build/stock-filter-wrapper-frontend.js 5.87 kB
build/store-notices.js 1.64 kB
build/vendors--cart-blocks/cart-cross-sells-products--cart-blocks/cart-line-items--cart-blocks/cart-order--3c5fe802-frontend.js 5.26 kB
build/vendors--cart-blocks/cart-cross-sells-products--product-add-to-cart-frontend.js 7.53 kB
build/vendors--cart-blocks/cart-line-items--checkout-blocks/order-summary-cart-items--mini-cart-contents---233ab542-frontend.js 3.14 kB
build/vendors--checkout-blocks/shipping-method-frontend.js 12 kB
build/vendors--checkout-blocks/shipping-methods-frontend.js 9.48 kB
build/wc-blocks-editor-style-rtl.css 5.41 kB
build/wc-blocks-editor-style.css 5.41 kB
build/wc-blocks-google-analytics.js 1.56 kB
build/wc-blocks-shared-context.js 1.52 kB
build/wc-blocks-vendors-style-rtl.css 1.96 kB
build/wc-blocks-vendors-style.css 1.96 kB
build/wc-blocks.js 2.63 kB
build/wc-payment-method-bacs.js 816 B
build/wc-payment-method-cheque.js 811 B
build/wc-payment-method-cod.js 909 B
build/wc-payment-method-paypal.js 837 B
build/wc-settings.js 2.6 kB
build/wc-shipping-method-pickup-location.js 29.7 kB

compressed-size-action

@@ -21,10 +21,10 @@ export const hasStoreNoticesContainer = ( container: string ): boolean => {
};

const findParentContainer = ( container: string ): string => {
if ( container.includes( noticeContexts.CHECKOUT + '/' ) ) {
if ( container.includes( noticeContexts.CHECKOUT ) ) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the slash do that wc/cart errors surface in wc/checkout if the StoreNoticesContainer is not present.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain this a bit more, not sure I understand fully what the slash did and why removing it is needed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic was looking for a prefix of wc/cart/ and then selecting either the parent container, or switching to wc/checkout.

This worked for children of wc/cart/ but not for wc/cart itself. Removing the slash lets it change the container if the wc/cart container was passed in.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahhh right yes because we add errors to inner blocks. Nice one thanks!

}

// Re-throw the error.
throw error;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These did nothing. We cannot catch them because the function is async.

@@ -47,7 +47,8 @@ const StoreNotices = ( {

if (
activeElement &&
inputs.indexOf( activeElement.tagName.toLowerCase() ) !== -1
inputs.indexOf( activeElement.tagName.toLowerCase() ) !== -1 &&
activeElement.getAttribute( 'type' ) !== 'radio'
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small change allows us to scroll to errors after clicking a radio input.

@@ -0,0 +1,42 @@
/**
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These types were all moved from the old type-defs

@@ -269,14 +256,6 @@ export const removeCoupon =
dispatch.receiveCart( response );
} catch ( error ) {
dispatch.receiveError( error );

// If updated cart state was returned, also update that.
if ( error.data?.cart ) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this logic into receiveError thunk.

@@ -7,7 +7,7 @@ import type { CartResponse } from './cart-response';
export type ApiErrorResponse = {
code: string;
message: string;
data: ApiErrorResponseData;
data?: ApiErrorResponseData | undefined;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not all API errors have data - it's optional.

Copy link
Contributor

@opr opr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good, when testing with die( 1 ) it shows
image

Could we make this more user-friendly, like "Something went wrong, please contact us for assistance." instead?

I also noticed that when retrying on the same page, after causing the generic error, and then trying with the thrown named error, the generic error still remains. Is it possible to get around this? I think this is the same problem as we had with the quantity messages, vs auto-dismissed and persistent errors isn't it?

@@ -21,10 +21,10 @@ export const hasStoreNoticesContainer = ( container: string ): boolean => {
};

const findParentContainer = ( container: string ): string => {
if ( container.includes( noticeContexts.CHECKOUT + '/' ) ) {
if ( container.includes( noticeContexts.CHECKOUT ) ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain this a bit more, not sure I understand fully what the slash did and why removing it is needed

@mikejolley
Copy link
Member Author

I also noticed that when retrying on the same page, after causing the generic error, and then trying with the thrown named error, the generic error still remains. Is it possible to get around this? I think this is the same problem as we had with the quantity messages, vs auto-dismissed and persistent errors isn't it?

Similar issue @opr Will the PR you're working on which dismisses notices work here too?

@opr
Copy link
Contributor

opr commented Jan 12, 2023

Similar issue @opr Will the PR you're working on which dismisses notices work here too?

Yes, we can clear errors out before adding new ones. See #7363 for implementation if you want to copy it in here.

Update: #7363 is merged into trunk now.

@mikejolley mikejolley requested a review from opr January 12, 2023 15:21
@mikejolley mikejolley force-pushed the fix/expose-cart-errors-as-notices branch 4 times, most recently from 887b3fe to be006fa Compare January 17, 2023 16:59
Copy link
Contributor

@opr opr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functionality-wise this is working ok according to test instructions, but I added a few comments please take a look

assets/js/data/cart/notify-errors.ts Show resolved Hide resolved
assets/js/data/cart/notify-errors.ts Show resolved Hide resolved
assets/js/data/cart/notify-errors.ts Outdated Show resolved Hide resolved
assets/js/base/context/hooks/shipping/types.ts Outdated Show resolved Hide resolved
assets/js/base/utils/create-notice.ts Show resolved Hide resolved
@mikejolley mikejolley requested a review from opr January 18, 2023 16:15
Copy link
Contributor

@opr opr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good now, the test comment could maybe be updated to reflect that it's the number of elements containing matching text, rather than instances of the text occurring?

Besides that, nice one. Thanks for working on this!

@github-actions github-actions bot added this to the 9.5.0 milestone Jan 18, 2023
@mikejolley mikejolley force-pushed the fix/expose-cart-errors-as-notices branch from 6daf0cf to 1154fc2 Compare January 19, 2023 16:01
@mikejolley
Copy link
Member Author

e2e fails seem to be fse related. JS tests are passing here and for me locally, so merging.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
block: checkout Issues related to the checkout block. skip-changelog PRs that you don't want to appear in the changelog.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Checkout Block: Surface errors from Cart Routes/batch
2 participants