define(['common/js/spec_helpers/template_helpers',
        'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers',
        'js/dashboard/donation'],
    function(TemplateHelpers, AjaxHelpers) {
        'use strict';

        describe('edx.dashboard.donation.DonationView', function() {
            var PAYMENT_URL = 'https://fake.processor.com/pay/';
            var PAYMENT_PARAMS = {
                orderId: 'test-order',
                signature: 'abcd1234'
            };
            var AMOUNT = '45.67';
            var COURSE_ID = 'edx/DemoX/Demo';

            var view = null;
            var requests = null;

            beforeEach(function() {
                setFixtures('<div></div>');
                TemplateHelpers.installTemplate('templates/dashboard/donation');

                view = new edx.dashboard.donation.DonationView({
                    el: $('#jasmine-fixtures'),
                    course: COURSE_ID
                }).render();

                // Stub out the actual submission of the payment form
                // (which would cause the page to reload)
                // This function gets passed the dynamically constructed
                // form with signed payment parameters from the LMS server,
                // so we can verify that the form is constructed correctly.
                spyOn(view, 'submitPaymentForm').and.callFake(function() {});

                // Stub the analytics event tracker
                window.analytics = jasmine.createSpyObj('analytics', ['track']);
            });

            it('processes a donation for a course', function() {
                // Spy on AJAX requests
                requests = AjaxHelpers.requests(this);

                // Enter a donation amount and proceed to the payment page
                view.$amount.val(AMOUNT);
                view.donate();

                // Verify that the client contacts the server to create
                // the donation item in the shopping cart and receive
                // the signed payment params.
                AjaxHelpers.expectRequest(
                    requests, 'POST', '/shoppingcart/donation/',
                    $.param({amount: AMOUNT, course_id: COURSE_ID})
                );

                // Simulate a response from the server containing the signed
                // parameters to send to the payment processor
                AjaxHelpers.respondWithJson(requests, {
                    payment_url: PAYMENT_URL,
                    payment_params: PAYMENT_PARAMS
                });

                // Verify that the payment form has the payment parameters
                // sent by the LMS server, and that it's targeted at the
                // correct payment URL.
                // We stub out the actual submission of the form to avoid
                // leaving the current page during the test.
                expect(view.submitPaymentForm).toHaveBeenCalled();
                var form = view.submitPaymentForm.calls.mostRecent().args[0];
                expect(form.serialize()).toEqual($.param(PAYMENT_PARAMS));
                expect(form.attr('method')).toEqual('post');
                expect(form.attr('action')).toEqual(PAYMENT_URL);
            });

            it('validates the donation amount', function() {
                var assertValidAmount = function(amount, isValid) {
                    expect(view.validateAmount(amount)).toBe(isValid);
                };
                assertValidAmount('', false);
                assertValidAmount('  ', false);
                assertValidAmount('abc', false);
                assertValidAmount('14.', false);
                assertValidAmount('.1', false);
                assertValidAmount('-1', false);
                assertValidAmount('-1.00', false);
                assertValidAmount('-', false);
                assertValidAmount('0', false);
                assertValidAmount('0.00', false);
                assertValidAmount('00.00', false);
                assertValidAmount('3', true);
                assertValidAmount('12.34', true);
                assertValidAmount('278', true);
                assertValidAmount('278.91', true);
                assertValidAmount('0.14', true);
            });

            it('displays validation errors', function() {
                // Attempt to submit an invalid donation amount
                view.$amount.val('');
                view.donate();

                // Verify that the amount field is marked as having a validation error
                expect(view.$amount).toHaveClass('validation-error');

                // Verify that the error message appears
                expect(view.$errorMsg.text()).toEqual('Please enter a valid donation amount.');

                // Expect that the submit button is re-enabled to allow users to submit again
                expect(view.$submit).not.toHaveClass('disabled');

                // Try again, this time submitting a valid amount
                view.$amount.val(AMOUNT);
                view.donate();

                // Expect that the errors are cleared
                expect(view.$errorMsg.text()).toEqual('');

                // Expect that the submit button is disabled
                expect(view.$submit).toHaveClass('disabled');
            });

            it('displays an error when the server cannot be contacted', function() {
                // Spy on AJAX requests
                requests = AjaxHelpers.requests(this);

                // Simulate an error from the LMS servers
                view.donate();
                AjaxHelpers.respondWithError(requests);

                // Expect that the error is displayed
                expect(view.$errorMsg.text()).toEqual('Your donation could not be submitted.');

                // Verify that the submit button is re-enabled
                // so users can try again.
                expect(view.$submit).not.toHaveClass('disabled');
            });

            it('disables the submit button once the user donates', function() {
                // Before we submit, the button should be enabled
                expect(view.$submit).not.toHaveClass('disabled');

                // Simulate starting a donation
                // Since we're not simulating the AJAX response, this will block
                // in the state just after the user kicks off the donation process.
                view.donate();

                // Verify that the submit button is disabled
                expect(view.$submit).toHaveClass('disabled');
            });

            it('sends an analytics event when the user submits a donation', function() {
                // Simulate the submission to the payment processor
                // We skip the intermediary steps here by passing in
                // the payment url and parameters,
                // which the view would ordinarily retrieve from the LMS server.
                view.startPayment({
                    payment_url: PAYMENT_URL,
                    payment_params: PAYMENT_PARAMS
                });

                // Verify that the analytics event was fired
                expect(window.analytics.track).toHaveBeenCalledWith(
                    'edx.bi.user.payment_processor.visited',
                    {
                        category: 'donations',
                        label: COURSE_ID
                    }
                );
            });
        });
    }
);
