Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Checkout error handling in JS #5202

Merged
merged 5 commits into from
Apr 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 22 additions & 9 deletions app/assets/javascripts/darkswarm/services/checkout.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,28 @@ Darkswarm.factory 'Checkout', ($injector, CurrentOrder, ShippingMethods, StripeE

submit: =>
Loading.message = t 'submitting_order'
$http.put('/checkout.json', {order: @preprocess()}).success (data, status)=>
Navigation.go data.path
.error (response, status)=>
if response.path
Navigation.go response.path
else
Loading.clear()
@errors = response.errors
RailsFlashLoader.loadFlash(response.flash)
$http.put('/checkout.json', {order: @preprocess()})
.then (response) =>
Navigation.go response.data.path
.catch (response) =>
try
@handle_checkout_error_response(response)
catch error
@loadFlash(error: t("checkout.failed")) # inform the user about the unexpected error
throw error # generate a BugsnagJS alert

handle_checkout_error_response: (response) =>
if response.data.path
Navigation.go response.data.path
else
throw response unless response.data.flash

@errors = response.data.errors
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I cannot find/understand what this @errors does but I dont want to remove it and break things...

@loadFlash(response.data.flash)

loadFlash: (flash) =>
Loading.clear()
RailsFlashLoader.loadFlash(flash)

# Rails wants our Spree::Address data to be provided with _attributes
preprocess: ->
Expand Down
46 changes: 42 additions & 4 deletions spec/javascripts/unit/darkswarm/services/checkout_spec.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ describe 'Checkout service', ->
orderData = null
$httpBackend = null
Navigation = null
navigationSpy = null
flash = null
scope = null
FlashLoaderMock =
loadFlash: (arg)->
loadFlash: (arg) ->
Loading =
clear: (arg)->
paymentMethods = [{
id: 99
test: "foo"
Expand Down Expand Up @@ -48,6 +51,7 @@ describe 'Checkout service', ->
module 'Darkswarm'
module ($provide)->
$provide.value "RailsFlashLoader", FlashLoaderMock
$provide.value "Loading", Loading
$provide.value "currentOrder", orderData
$provide.value "shippingMethods", shippingMethods
$provide.value "paymentMethods", paymentMethods
Expand All @@ -61,7 +65,7 @@ describe 'Checkout service', ->
scope.Checkout = Checkout
Navigation = $injector.get("Navigation")
flash = $injector.get("flash")
spyOn(Navigation, "go") # Stubbing out writes to window.location
navigationSpy = spyOn(Navigation, "go") # Stubbing out writes to window.location

it "defaults to no shipping method", ->
expect(Checkout.order.shipping_method_id).toEqual null
Expand Down Expand Up @@ -116,12 +120,46 @@ describe 'Checkout service', ->
$httpBackend.flush()
expect(FlashLoaderMock.loadFlash).toHaveBeenCalledWith {error: "frogs"}

it "puts errors into the scope", ->
$httpBackend.expectPUT("/checkout.json").respond 400, {errors: {error: "frogs"}}
it "puts errors into the scope when there is a flash messages", ->
$httpBackend.expectPUT("/checkout.json").respond 400, {errors: {error: "frogs"}, flash: {error: "flash frogs"}}
Checkout.submit()

$httpBackend.flush()
expect(Checkout.errors).toEqual {error: "frogs"}

it "throws exception and sends generic flash message when there are errors but no flash message", ->
$httpBackend.expectPUT("/checkout.json").respond 400, {errors: {error: "broken response"}}
try
Checkout.submit()
$httpBackend.flush()
catch error
expect(error.data.errors.error).toBe("broken response")

expect(Checkout.errors).toEqual {}

it "throws an exception and sends a flash message to the flash service when reponse doesnt contain errors nor a flash message", ->
spyOn(FlashLoaderMock, "loadFlash") # Stubbing out writes to window.location
$httpBackend.expectPUT("/checkout.json").respond 400, "broken response"
try
Checkout.submit()
$httpBackend.flush()
catch error
expect(error.data).toBe("broken response")

expect(FlashLoaderMock.loadFlash).toHaveBeenCalledWith({ error: t("checkout.failed") })

it "throws an exception and sends a flash message to the flash service when an exception is thrown while handling the error", ->
spyOn(FlashLoaderMock, "loadFlash") # Stubbing out writes to window.location
navigationSpy.and.callFake(-> throw "unexpected error")
$httpBackend.expectPUT("/checkout.json").respond 400, {path: 'path'}
try
Checkout.submit()
$httpBackend.flush()
catch error
expect(error).toBe("unexpected error")

expect(FlashLoaderMock.loadFlash).toHaveBeenCalledWith({ error: t("checkout.failed") })

describe "when using the Stripe Connect gateway", ->
beforeEach inject ($injector, StripeElements) ->
Checkout.order.payment_method_id = 666
Expand Down