Prerequisites
Describe the bug and add attachments
In _dev/js/checkout.js, the updatedDeliveryForm handler assumes that the carrier extra content is always the immediate next sibling of the delivery option:
const carrierExtraContent = params.deliveryOption.next(prestashop.themeSelectors.checkout.carrierExtraContent);
if (carrierExtraContent.html().trim() !== '') {
carrierExtraContent.slideDown();
}
When .next() matches nothing, jQuery returns an empty collection and .html() returns undefined, so .trim() throws TypeError: Cannot read properties of undefined (reading 'trim') on every carrier change.
This happens as soon as any element sits between .delivery-option and .carrier-extra-content. Nothing in the markup guarantees that they stay adjacent, and it is a common pattern for pickup point / parcel shop modules to insert their selector right after the carrier row.
There is a second, related problem that makes this much harder to diagnose. jQuery 3 turns the exception into a rejection, so the .fail() branch in themes/_core/js/checkout-delivery.js runs:
.fail((resp) => {
prestashop.trigger('handleError', { eventType: 'updateDeliveryOptions', resp });
});
prestashop is an event emitter that exposes emit, not trigger. The .fail() handler therefore throws as well, and the only message that reaches the console is the secondary one:
Uncaught TypeError: r(...).trigger is not a function
at theme.js
at c (theme.js)
at Object.fireWith [as rejectWith] (theme.js)
The original error is completely hidden. That prestashop.trigger call is also present in develop, so it is worth fixing independently of this report.
Side effect worth noting: the exception aborts the updatedDeliveryForm emit loop, so any listener registered after the theme's own listener is silently skipped.
Steps to reproduce
No third-party module is required, the last step only simulates what a module does.
- Install PrestaShop 8.2.1 or later with the Classic theme.
- Have at least two carriers available in the checkout, one of them provided by a module so that a
.carrier-extra-content block is rendered (any module implementing displayCarrierExtraContent).
- Go to the checkout, reach the shipping step and open the browser console.
- Run
$('.delivery-option').first().after('<div></div>'); to place an element between the delivery option and its extra content.
- Select another carrier.
- See the error in the console.
Expected behavior
Selecting a carrier does not throw, and the extra content of the selected carrier is shown when it exists.
Actual Result
Uncaught TypeError on every carrier change, and the real cause is masked by a second TypeError coming from the .fail() branch.
PrestaShop version where the bug happens
8.2.1 to 8.2.6 (Classic theme 2.2.x). Reproduced on 8.2.3.
Additional information
Not reproducible on 1.7.8.x, nor on 9.0/9.1: the develop branch of this repository calls slideDown() directly on the collection, and jQuery silently ignores an empty set there.
The guard was introduced in 2.1.x by commit acd52d3 (PR #157, fix for PrestaShop/PrestaShop#37194) and never ported to 3.x.
Suggested fix, keeping the intent of #37194:
if (carrierExtraContent.length && carrierExtraContent.html().trim() !== '') {
carrierExtraContent.slideDown();
}
I am opening a pull request against 2.2.x with this change.
Prerequisites
Describe the bug and add attachments
In
_dev/js/checkout.js, theupdatedDeliveryFormhandler assumes that the carrier extra content is always the immediate next sibling of the delivery option:When
.next()matches nothing, jQuery returns an empty collection and.html()returnsundefined, so.trim()throwsTypeError: Cannot read properties of undefined (reading 'trim')on every carrier change.This happens as soon as any element sits between
.delivery-optionand.carrier-extra-content. Nothing in the markup guarantees that they stay adjacent, and it is a common pattern for pickup point / parcel shop modules to insert their selector right after the carrier row.There is a second, related problem that makes this much harder to diagnose. jQuery 3 turns the exception into a rejection, so the
.fail()branch inthemes/_core/js/checkout-delivery.jsruns:prestashopis an event emitter that exposesemit, nottrigger. The.fail()handler therefore throws as well, and the only message that reaches the console is the secondary one:The original error is completely hidden. That
prestashop.triggercall is also present indevelop, so it is worth fixing independently of this report.Side effect worth noting: the exception aborts the
updatedDeliveryFormemit loop, so any listener registered after the theme's own listener is silently skipped.Steps to reproduce
No third-party module is required, the last step only simulates what a module does.
.carrier-extra-contentblock is rendered (any module implementingdisplayCarrierExtraContent).$('.delivery-option').first().after('<div></div>');to place an element between the delivery option and its extra content.Expected behavior
Selecting a carrier does not throw, and the extra content of the selected carrier is shown when it exists.
Actual Result
Uncaught TypeErroron every carrier change, and the real cause is masked by a secondTypeErrorcoming from the.fail()branch.PrestaShop version where the bug happens
8.2.1 to 8.2.6 (Classic theme 2.2.x). Reproduced on 8.2.3.
Additional information
Not reproducible on 1.7.8.x, nor on 9.0/9.1: the
developbranch of this repository callsslideDown()directly on the collection, and jQuery silently ignores an empty set there.The guard was introduced in 2.1.x by commit acd52d3 (PR #157, fix for PrestaShop/PrestaShop#37194) and never ported to 3.x.
Suggested fix, keeping the intent of #37194:
I am opening a pull request against
2.2.xwith this change.