Skip to content

[BUG] TypeError in updatedDeliveryForm when carrier extra content is not the immediate next sibling #214

Description

@ShaiMagal

Prerequisites

  • I understand and accept the project's code of conduct.
  • I have already searched in existing issues and found no previous report of this bug.

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.

  1. Install PrestaShop 8.2.1 or later with the Classic theme.
  2. 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).
  3. Go to the checkout, reach the shipping step and open the browser console.
  4. Run $('.delivery-option').first().after('<div></div>'); to place an element between the delivery option and its extra content.
  5. Select another carrier.
  6. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Waiting for QA

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions