Published on
·
Time to read
3 minute read

Fighting FedEx with DevTools

Blog post image
Authors

It's the age-old story: software engineer tries to use a buggy website, spends way more time than they should debugging it. This was me trying to set my vacation hold for a recent family trip, but little did I know, this was just the beginning of my boxing match with FedEx and the eventual rare victory I was about to claim!

Logging in to FedEx Delivery Manager, I attempted to use the Vacation Hold feature, but was greeted with a blank UI.

screenshot of missing UI

"No problem," I thought, "I'll just check the Developer Console." But what did I find there? A classic JavaScript error: "undefined is not a function."

Uncaught TypeError: undefined is not a function
    at h (eval at <anonymous> (jquery-1.8.3.min.js:2:14136), <anonymous>:48:158)
    at f (eval at <anonymous> (jquery-1.8.3.min.js:2:14136), <anonymous>:50:300)
    at eval (eval at <anonymous> (jquery-1.8.3.min.js:2:14136), <anonymous>:9:216)
    at c.checkAndLoadScripts (eval at <anonymous> (jquery-1.8.3.min.js:2:14136), <anonymous>:12:94)
    at c.init (eval at <anonymous> (jquery-1.8.3.min.js:2:14136), <anonymous>:9:185)
    at HTMLDivElement.eval (eval at <anonymous> (jquery-1.8.3.min.js:2:14136), <anonymous>:5:3)
    at Function.each (jquery-1.8.3.min.js:2:14440)
    at init.each (jquery-1.8.3.min.js:2:11217)
    at Object.complete (jquery-1.8.3.min.js:2:79370)
    at l (jquery-1.8.3.min.js:2:16996)
    at Object.fireWith (jquery-1.8.3.min.js:2:17783)
    at T (jquery-1.8.3.min.js:2:81117)
    at XMLHttpRequest.r (jquery-1.8.3.min.js:2:86563)
    at Object.g [as apply] (77371e2372ae5cd0a0e5f981ba0cc5db9001192124f:24:474)
    at XMLHttpRequest.<anonymous> (adrum-4.5.17.2890.js:29:163)
    at Object.g [as apply] (77371e2372ae5cd0a0e5f981ba0cc5db9001192124f:24:474)

Feeling nerd sniped now, I clicked on the stack trace, hoping for some answers. But what did I get instead? A generic rethrow of the error, completely unhelpful. So, I did what any self-respecting, deeply stereotyped software engineer would do. I enabled "Pause on Caught Exceptions", grabbed a Mountain Dew, and refreshed that sucker.

screenshot of unhelpful original stack and enabling more info

Huzzah! Finally, the real source of the error was revealed: a missing jQuery plugin named "dateinput."

screenshot of actual stack trace

Being the resourceful, desperate-for-excitement engineer-on-paternity-leave that I am, I explored the jQuery object a bit and noticed a similarly named datepicker plugin was available. I decided to monkeypatch dateinput with it and give it another try.

$.prototype.dateinput = $.prototype.datepicker

And, to my joy, it worked! Sort of. The UI loaded, but I was still getting errors when trying to save the vacation hold.

screenshot of UI loading succesfully

Undeterred, I popped open the network panel to see what was up. I found the culprit: Date validation errors! Sure enough the datepicker was setting the year incorrectly despite displaying 2023 in the UI.

screenshot of network request failing

Feeling the light at the end of the tunnel now, I quickly copied the network request as a curl command, modified the date to match my desired format, ran in in my shell, and...

curl 'https://api.fedex.com/deliverymanager/v3/addresses/ID_GOES_HERE/vacationholds' \
 -H 'authority: api.fedex.com' \
 -H 'authorization: Bearer TOKEN_GOES_HERE' \
 -H 'content-type: application/json' \
 -H 'origin: https://www.fedex.com' \
 -H 'referer: https://www.fedex.com/apps/myprofile/deliverymanager/?locale=en_US&cntry_code=us&wpro=true' \
 --data-raw '{"saveVacationHoldControlParameters":{"actionType":"ADD"},"vacationHolds":[{"vacationHoldDetail":{"beginDate":"Jan-24-2023","endDate":"Jan-31-2023"}}]}' \
 --compressed

Eureka! It worked!

screenshot of it working

So, the moral of the story is: when dealing with buggy websites, JavaScript errors, and frustration with the failures of a multi-billion dollar corporation in your hometown, never give up! With a bit of determination, a healthy dose of jQuery monkeypatching, and some spare paternity leave on your hands, anything is possible.