describe 'Checkout service', -> BugsnagMock = notify: (arg) -> Checkout = null orderData = null currentHub = null $httpBackend = null Navigation = null navigationSpy = null flash = null scope = null FlashLoaderMock = loadFlash: (arg) -> Loading = clear: (arg)-> paymentMethods = [{ id: 99 test: "foo" method_type: "gateway" }, { id: 123 test: "bar" method_type: "check" }, { id: 666 test: "qux" method_type: "stripe" }] shippingMethods = [ { id: 7 require_ship_address: true price: 0.0 }, { id: 25 require_ship_address: false price: 13 }] beforeEach -> orderData = id: 3102 shipping_method_id: null payment_method_id: null email: "test@test.com" bill_address: test: "foo" firstname: "Robert" lastname: "Harrington" ship_address: {test: "bar"} user_id: 901 currentHub = hub: id: 99 window.Bugsnag = BugsnagMock module 'Darkswarm' module ($provide)-> $provide.value "RailsFlashLoader", FlashLoaderMock $provide.value "Loading", Loading $provide.value "currentOrder", orderData $provide.value "shippingMethods", shippingMethods $provide.value "currentHub", currentHub $provide.value "paymentMethods", paymentMethods $provide.value "StripeInstancePublishableKey", "instance_publishable_key" null inject ($injector, _$httpBackend_, $rootScope)-> $httpBackend = _$httpBackend_ Checkout = $injector.get("Checkout") spyOn(Checkout, "terms_and_conditions_accepted") scope = $rootScope.$new() scope.Checkout = Checkout Navigation = $injector.get("Navigation") flash = $injector.get("flash") navigationSpy = spyOn(Navigation, "go") # Stubbing out writes to window.location it "defaults to no shipping method", -> expect(Checkout.order.shipping_method_id).toEqual null expect(Checkout.shippingMethod()).toEqual undefined it "has a shipping price of zero with no shipping method", -> expect(Checkout.shippingPrice()).toEqual 0.0 describe "with shipping method", -> beforeEach -> Checkout.order.shipping_method_id = 7 it 'Tracks whether a ship address is required', -> expect(Checkout.requireShipAddress()).toEqual true Checkout.order.shipping_method_id = 25 expect(Checkout.requireShipAddress()).toEqual false it 'Gets the current shipping price', -> expect(Checkout.shippingPrice()).toEqual 0.0 Checkout.order.shipping_method_id = 25 expect(Checkout.shippingPrice()).toEqual 13 it 'Gets the current payment method', -> expect(Checkout.paymentMethod()).toBeUndefined() Checkout.order.payment_method_id = 99 expect(Checkout.paymentMethod()).toEqual paymentMethods[0] describe "submitting", -> it "Posts the Checkout to the server", -> $httpBackend.expectPUT("/checkout.json", {order: Checkout.preprocess()}).respond 200, {path: "test"} Checkout.submit() $httpBackend.flush() it "Redirects to the returned path", -> $httpBackend.expectPUT("/checkout.json", {order: Checkout.preprocess()}).respond 200, {path: "/test"} Checkout.submit() $httpBackend.flush() expect(Navigation.go).toHaveBeenCalledWith '/test' describe "when there is an error", -> it "redirects when a redirect is given", -> $httpBackend.expectPUT("/checkout.json").respond 400, {path: 'path'} Checkout.submit() $httpBackend.flush() expect(Navigation.go).toHaveBeenCalledWith 'path' it "sends flash messages to the flash service", -> spyOn(FlashLoaderMock, "loadFlash") # Stubbing out writes to window.location $httpBackend.expectPUT("/checkout.json").respond 400, {flash: {error: "frogs"}} Checkout.submit() $httpBackend.flush() expect(FlashLoaderMock.loadFlash).toHaveBeenCalledWith {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", -> spyOn(BugsnagMock, "notify") $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 {} expect(BugsnagMock.notify).toHaveBeenCalled() 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 spyOn(BugsnagMock, "notify") $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") }) expect(BugsnagMock.notify).toHaveBeenCalled() 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 spyOn(BugsnagMock, "notify") 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") }) expect(BugsnagMock.notify).toHaveBeenCalled() describe "when using the Stripe Connect gateway", -> beforeEach inject ($injector, StripeElements) -> Checkout.order.payment_method_id = 666 it "requests a Stripe token before submitting", inject (StripeElements) -> spyOn(StripeElements, "requestToken") Checkout.purchase() expect(StripeElements.requestToken).toHaveBeenCalled() it "doesn't hit Stripe when reusing a credit card", inject (StripeElements) -> spyOn(StripeElements, "requestToken") Checkout.secrets.selected_card = 1 Checkout.purchase() expect(StripeElements.requestToken).not.toHaveBeenCalled() describe "data preprocessing", -> beforeEach -> Checkout.order.payment_method_id = 99 Checkout.secrets = card_number: "1234567890123456" card_month: "10" card_year: "2015" card_verification_value: "123" it "munges the order attributes to add _attributes as Rails needs", -> expect(Checkout.preprocess().bill_address_attributes).not.toBe(undefined) expect(Checkout.preprocess().bill_address).toBe(undefined) expect(Checkout.preprocess().ship_address_attributes).not.toBe(undefined) expect(Checkout.preprocess().ship_address).toBe(undefined) it "munges the order attributes to clone ship address from bill address", -> Checkout.ship_address_same_as_billing = false expect(Checkout.preprocess().ship_address_attributes).toEqual(orderData.ship_address) Checkout.ship_address_same_as_billing = true expect(Checkout.preprocess().ship_address_attributes).toEqual(orderData.bill_address) it "munges the default as billing address and shipping address", -> expect(Checkout.preprocess().default_bill_address).toEqual(false) expect(Checkout.preprocess().default_ship_address).toEqual(false) Checkout.default_bill_address = true Checkout.default_ship_address = true expect(Checkout.preprocess().default_bill_address).toEqual(true) expect(Checkout.preprocess().default_ship_address).toEqual(true) it "creates attributes for card fields", -> source_attributes = Checkout.preprocess().payments_attributes[0].source_attributes expect(source_attributes).toBeDefined() expect(source_attributes.number).toBe Checkout.secrets.card_number expect(source_attributes.month).toBe Checkout.secrets.card_month expect(source_attributes.year).toBe Checkout.secrets.card_year expect(source_attributes.verification_value).toBe Checkout.secrets.card_verification_value expect(source_attributes.first_name).toBe Checkout.order.bill_address.firstname expect(source_attributes.last_name).toBe Checkout.order.bill_address.lastname it "does not create attributes for card fields when no card is supplied", -> Checkout.order.payment_method_id = 123 source_attributes = Checkout.preprocess().payments_attributes[0].source_attributes expect(source_attributes).not.toBeDefined() describe "when the payment method is the Stripe Connect gateway", -> beforeEach -> Checkout.order.payment_method_id = 666 Checkout.secrets = token: "stripe_token" cc_type: "mastercard" card: last4: "1234" exp_year: "2099" exp_month: "10" it "creates source attributes for the submitted card", -> source_attributes = Checkout.preprocess().payments_attributes[0].source_attributes expect(source_attributes).toBeDefined() expect(source_attributes.gateway_payment_profile_id).toBe "stripe_token" expect(source_attributes.cc_type).toBe "mastercard" expect(source_attributes.last_digits).toBe "1234" expect(source_attributes.year).toBe "2099" expect(source_attributes.month).toBe "10" expect(source_attributes.first_name).toBe orderData.bill_address.firstname expect(source_attributes.last_name).toBe orderData.bill_address.lastname describe "when a saved card from Stripe is used", -> beforeEach -> Checkout.order.payment_method_id = 666 it "passes the card ID in source attributes if a saved card is selected", -> Checkout.secrets.selected_card = 1 source_attributes = Checkout.preprocess() expect(source_attributes).toBeDefined() expect(source_attributes.existing_card_id).toBe 1