"use strict";

var _bluebird = _interopRequireDefault(require("bluebird"));

var _sfcc = require("./sfcc");

var _types = require("../types");

var _testUtils = require("../utils/test-utils");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }

function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }

function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }

function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }

function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

if (_testUtils.isIntegrationTest) {
  jest.setTimeout(45000);
}

var userFixture = function userFixture(key) {
  var time = _testUtils.isIntegrationTest ? new Date().getTime() : '';
  return {
    firstName: "test-v1-".concat(key).concat(time, "-firstName"),
    lastName: "test-v1-".concat(key).concat(time, "-lastName"),
    email: "test-v1-".concat(key).concat(time, "@example-foo.com"),
    password: "test-v1-".concat(key).concat(time, "-P4$$word")
  };
};

var validCredentials = {
  username: 'testuser1@demandware.com',
  password: 'P4$$wordP4'
};
var invalidCredentials = {
  username: 'testuser0@demandware.com',
  password: 'P4$$wordP4'
};
var customerInformation = {
  email: 'engineer@mobify.com'
};
var orderAddress = {
  firstName: 'Test',
  lastName: 'User',
  phone: '5555555555',
  addressLine1: '1600 Pennsylvania Ave NW',
  countryCode: 'US',
  stateCode: 'DC',
  city: 'Washington',
  postalCode: '20500'
};
var cartItem = {
  productId: '008884303989M',
  quantity: 1
};
var payment = {
  amount: 179.98,
  methodId: 'CREDIT_CARD',
  details: {
    ccv: '123',
    type: 'Visa',
    holderName: 'Test User',
    number: '411111111111112',
    expiryMonth: 1,
    expiryYear: 2028
  }
};
describe("The SFCC Connector", function () {
  var makeConnector = function makeConnector() {
    return _sfcc.SalesforceConnector.fromConfig({
      basePath: "https://zzrf-001.sandbox.us01.dx.commercecloud.salesforce.com/s/RefArch/dw/shop/v20_4",
      defaultHeaders: {
        'x-dw-client-id': 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
      }
    });
  };

  describe('Checkout flow', function () {
    var spec0 = test('Registered User', function () {
      return (0, _testUtils.record)(spec0, function () {
        var username = validCredentials.username,
            password = validCredentials.password;
        var connector = makeConnector();
        var cart;
        return connector.login(username, password) // 1. Create a new cart
        .then(function () {
          return connector.createCart();
        }).then(function (data) {
          expect((0, _testUtils.propTypeErrors)(_types.Cart, data)).toBeFalsy();
          cart = data;
        }) // 2. Set customer information
        .then(function () {
          return connector.setCustomerInformation(cart, customerInformation);
        }).then(function (data) {
          expect(data.customerInfo.email).toEqual(customerInformation.email);
          cart = data; // Update local cart variable
        }) // 3. Add Cart Item
        .then(function () {
          return connector.addCartItem(cart, cartItem);
        }).then(function (data) {
          expect(data.items).toHaveLength(1);
          expect(data.items[0].productId).toEqual(cartItem.productId);
          expect(data.items[0].quantity).toEqual(cartItem.quantity);
          cart = data; // Update local cart variable
        }) // 4. Update Cart Item
        .then(function () {
          return connector.updateCartItem(cart, _objectSpread({}, cart.items[0], {
            quantity: 2
          }));
        }).then(function (data) {
          expect(data.items).toHaveLength(1);
          expect(data.items[0].productId).toEqual(cartItem.productId);
          expect(data.items[0].quantity).toEqual(2);
          cart = data;
        }) // 5. Remove Cart item
        .then(function () {
          return connector.removeCartItem(cart, cart.items[0].id);
        }).then(function (data) {
          expect(data.items).toHaveLength(0);
          cart = data; // Update local cart variable
        }) // 5b. Re Add Cart Item so order creation doesn't fail
        .then(function () {
          return connector.addCartItem(cart, cartItem);
        }).then(function (data) {
          cart = data; // Update local cart variable
        }) // 6. Set Billing Address
        .then(function () {
          return connector.setBillingAddress(cart, orderAddress);
        }).then(function (data) {
          expect(data.billingAddress).toMatchObject(orderAddress);
          expect((0, _testUtils.propTypeErrors)(_types.OrderAddress, data.billingAddress)).toBeFalsy();
          cart = data; // Update local cart variable
        }) // 7. Set Shipping Address
        .then(function () {
          return connector.setShippingAddress(cart, orderAddress);
        }).then(function (data) {
          expect(data.shippingAddress).toMatchObject(orderAddress);
          expect((0, _testUtils.propTypeErrors)(_types.OrderAddress, data.shippingAddress)).toBeFalsy();
          cart = data; // Update local cart variable
        }) // 8. Get Shipping Methods
        .then(function () {
          return connector.getShippingMethods(cart);
        }).then(function (data) {
          cart.shippingMethods = data;
          expect(data.length).not.toBeLessThan(0);
          expect((0, _testUtils.propTypeErrors)(_types.Cart, cart)).toBeFalsy();
        }) // 9. Set Shipping Method
        .then(function () {
          return connector.setShippingMethod(cart, cart.shippingMethods[0]);
        }).then(function (data) {
          expect(data.selectedShippingMethodId).toEqual(cart.shippingMethods[0].id);
          expect((0, _testUtils.propTypeErrors)(_types.Cart, data)).toBeFalsy();
          cart = data; // Update local cart variable
        }) // 9b. Set Shipping Method
        .then(function () {
          return expect(connector.setShippingMethod(cart, 'INVALID_SHIPPING_METHOD_ID')).rejects.toThrow();
        }) // 10. Get Payment Methods
        .then(function () {
          return connector.getPaymentMethods(cart);
        }).then(function (data) {
          expect(data.length).not.toBeLessThan(0);
          cart.paymentMethods = data;
          expect((0, _testUtils.propTypeErrors)(_types.Cart, cart)).toBeFalsy();
        }) // 11. Set Payment
        .then(function () {
          return connector.setPayment(cart, payment);
        }).then(function (data) {
          expect(data.payments).toHaveLength(1);
          expect((0, _testUtils.propTypeErrors)(_types.Payment, data.payments[0])).toBeFalsy();
          expect(data.payments[0].methodId).toEqual(payment.methodId);
          cart = data; // Update local cart variable
        }) // 12. Set Payment (Updated Values)
        .then(function () {
          return connector.setPayment(cart, _objectSpread({}, cart.payments[0], {
            amount: 200
          }));
        }).then(function (data) {
          expect(data.payments).toHaveLength(1);
          expect((0, _testUtils.propTypeErrors)(_types.Payment, data.payments[0])).toBeFalsy();
          expect(data.payments[0].amount).toEqual(200);
          cart = data; // Update local cart variable
        }) // 13. Create Order
        .then(function () {
          return connector.createOrder(cart);
        }).then(function (data) {
          expect((0, _testUtils.propTypeErrors)(_types.Order, data)).toBeFalsy();
          return data;
        }) // 14. Verify order by getting it.
        .then(function (order) {
          return _bluebird["default"].all([_bluebird["default"].resolve(order), connector.getOrders([order.id])]);
        }).then(function (_ref) {
          var _ref2 = _slicedToArray(_ref, 2),
              order = _ref2[0],
              orders = _ref2[1];

          expect(orders.count).toEqual(1);
          expect(orders.total).toEqual(1);
          expect(orders.data[0].id).toEqual(order.id); // Delete the cart as placing the order successfully has deleted it.

          cart = undefined;
          return null;
        })["catch"](function (e) {
          // Ensure we delete the cart so our tests don't fail on cart creation next time.
          if (cart) {
            connector.deleteCart(cart.id);
          } // Rethrow the error so that the tests fail.


          throw e;
        });
      });
    });
  });
  describe('Searching for products', function () {
    var sorts = [undefined, {
      query: 'name-ascending',
      key: 'name',
      compare: function compare(a, b) {
        return a.localeCompare(b);
      }
    }, {
      query: 'price-low-to-high',
      key: 'price',
      compare: function compare(a, b) {
        return a - b;
      }
    }];
    sorts.forEach(function (sortOpts) {
      var spec1 = test("with a sort order [sort: ".concat(sortOpts && sortOpts.query, "]"), function () {
        return (0, _testUtils.record)(spec1, function () {
          var connector = makeConnector();

          var query = _objectSpread({
            filters: {
              categoryId: 'root'
            }
          }, sortOpts && {
            sort: sortOpts.query
          });

          return connector.searchProducts(query).then(function (data) {
            expect((0, _testUtils.propTypeErrors)(_types.ProductSearch, data)).toBeFalsy();

            if (sortOpts) {
              var key = sortOpts.key,
                  compare = sortOpts.compare; // eslint-disable-next-line max-nested-callbacks

              var values = data.results.map(function (item) {
                return item[key];
              });
              var expected = values.slice().sort(compare);
              expect(values).toEqual(expected);
            }
          });
        });
      });
    });
    var counts = [2, 8];
    counts.forEach(function (count) {
      var spec2 = test("with a max count (count: ".concat(count, ")"), function () {
        return (0, _testUtils.record)(spec2, function () {
          var connector = makeConnector();
          var query = {
            filters: {
              categoryId: 'root'
            },
            count: count
          };
          return connector.searchProducts(query).then(function (data) {
            expect((0, _testUtils.propTypeErrors)(_types.ProductSearch, data)).toBeFalsy();
            expect(data.results.length).toEqual(count);
          });
        });
      });
    });
  });
  describe('Getting an order', function () {
    var spec3 = test('with an invalid id should reject', function () {
      return (0, _testUtils.record)(spec3, function () {
        var connector = makeConnector();
        return expect(connector.getOrder('1')).rejects.toThrow();
      });
    });
  });
  describe('Getting orders', function () {
    var spec4 = test('with invalid ids should resolve with a OrderList instance with empty data', function () {
      return (0, _testUtils.record)(spec4, function () {
        var connector = makeConnector();
        var invalidIds = ['1', '2'];
        return connector.getOrders(invalidIds).then(function (result) {
          expect((0, _testUtils.propTypeErrors)(_types.OrderList, result)).toBeFalsy();
          expect(result.data.length).toEqual(0);
        });
      });
    });
  });
  describe('Getting a product', function () {
    var spec5 = test('with a valid id should resolve with a Product instance', function () {
      return (0, _testUtils.record)(spec5, function () {
        var connector = makeConnector();
        return connector.getProduct('008884303989M').then(function (data) {
          expect((0, _testUtils.propTypeErrors)(_types.Product, data)).toBeFalsy();
        });
      });
    });
    var spec6 = test('with an invalid id should reject', function () {
      return (0, _testUtils.record)(spec6, function () {
        var connector = makeConnector();
        return expect(connector.getProduct('1')).rejects.toThrow();
      });
    });
  });
  describe('Getting products', function () {
    var spec7 = test('with valid ids should resolve with a ProductList instance with populated data', function () {
      return (0, _testUtils.record)(spec7, function () {
        var connector = makeConnector();
        var validIds = ['008884303989M', '008884303996M'];
        return connector.getProducts(validIds).then(function (result) {
          expect((0, _testUtils.propTypeErrors)(_types.ProductList, result)).toBeFalsy();
          expect(result.data.length).toEqual(validIds.length);
        });
      });
    });
    var spec8 = test('with invalid ids should resolve with a ProductList instance with empty data', function () {
      return (0, _testUtils.record)(spec8, function () {
        var connector = makeConnector();
        var invalidIds = ['1', '2'];
        return connector.getProducts(invalidIds).then(function (result) {
          expect((0, _testUtils.propTypeErrors)(_types.ProductList, result)).toBeFalsy();
          expect(result.data.length).toEqual(0);
        });
      });
    });
    var spec9 = test('with a mix of valid and invalid ids should resolve with a ProductList instance with partial data', function () {
      return (0, _testUtils.record)(spec9, function () {
        var connector = makeConnector();
        var validIds = ['008884303989M', '008884303996M'];
        var invalidIds = ['1', '2'];
        return connector.getProducts([].concat(validIds, invalidIds)).then(function (result) {
          expect((0, _testUtils.propTypeErrors)(_types.ProductList, result)).toBeFalsy();
          expect(result.data.length).toEqual(validIds.length);
          expect(result.total).toEqual(validIds.length);
          expect(result.count).toEqual(validIds.length);
        });
      });
    });
  });
  var spec10 = test('Getting a Store', function () {
    return (0, _testUtils.record)(spec10, function () {
      var connector = makeConnector();
      return connector.getStore('store1').then(function (data) {
        expect((0, _testUtils.propTypeErrors)(_types.Store, data)).toBeFalsy();
      });
    });
  });
  describe('Searching for Stores', function () {
    // searchStoreRequest is using default values for start, count if not provided
    var spec11 = test('Only longitude provided, missing latitude', function () {
      return (0, _testUtils.record)(spec11, function () {
        var connector = makeConnector();
        var searchStoreRequest = {
          latlon: {
            longitude: -118.225606
          }
        };
        expect(function () {
          connector.searchStores(searchStoreRequest);
        }).toThrowError('Provide Latitude and Longitude coordinates');
      });
    });
    var spec12 = test('Only latitude provided, missing longitude', function () {
      return (0, _testUtils.record)(spec12, function () {
        var connector = makeConnector();
        var searchStoreRequest = {
          latlon: {
            latitude: 34.014613
          }
        };
        expect(function () {
          connector.searchStores(searchStoreRequest);
        }).toThrowError('Provide Latitude and Longitude coordinates');
      });
    });
    var spec13 = test('Valid latitude and longitude provided', function () {
      return (0, _testUtils.record)(spec13, function () {
        var connector = makeConnector();
        var searchStoreRequest = {
          latlon: {
            latitude: 34.014613,
            longitude: -118.225606
          }
        };
        return connector.searchStores(searchStoreRequest).then(function (data) {
          expect(data.stores).not.toHaveLength(0);
          expect(data.stores).toHaveLength(data.count);
          expect((0, _testUtils.propTypeErrors)(_types.StoreSearchResult, data)).toBeFalsy();
        });
      });
    });
    var spec14 = test('0.0, 1.0 geo-coordinates allowed', function () {
      return (0, _testUtils.record)(spec14, function () {
        var connector = makeConnector();
        var searchStoreRequest = {
          latlon: {
            latitude: 0.0,
            longitude: 0.0
          }
        };
        return connector.searchStores(searchStoreRequest).then(function (data) {
          expect(data.stores).not.toHaveLength(0);
          expect(data.stores).toHaveLength(data.count);
          expect((0, _testUtils.propTypeErrors)(_types.StoreSearchResult, data)).toBeFalsy();
        });
      });
    });
  });
  describe('Get Product Categories', function () {
    var spec15 = test("getCategory should resolve to a Category instance", function () {
      return (0, _testUtils.record)(spec15, function () {
        var connector = makeConnector();
        var category = 'root';
        return connector.getCategory(category, {
          levels: 2
        }).then(function (data) {
          expect((0, _testUtils.propTypeErrors)(_types.Category, data)).toBeFalsy();
          expect(data.id).toEqual(category);
        });
      });
    });
    var spec16 = test("getCategories should resolve to a CategoryList instance", function () {
      return (0, _testUtils.record)(spec16, function () {
        var connector = makeConnector();
        var categories = ['mens', 'womens'];
        return connector.getCategories(categories, {
          levels: 2
        }).then(function (result) {
          expect((0, _testUtils.propTypeErrors)(_types.CategoryList, result)).toBeFalsy();
          expect(result.count).toEqual(2);
          expect(result.data[0].id).toEqual(categories[0]);
          expect(result.data[1].id).toEqual(categories[1]);
        });
      });
    });
  });
  describe('Customer Authorization', function () {
    var spec17 = test("authorizing a valid customer should return said customer", function () {
      return (0, _testUtils.record)(spec17, function () {
        var connector = makeConnector();
        var username = validCredentials.username,
            password = validCredentials.password;
        return connector.login(username, password).then(function (customer) {
          expect((0, _testUtils.propTypeErrors)(_types.Customer, customer)).toBeFalsy();
          expect(customer.email).toEqual(username);
        });
      });
    });
    var spec18 = test("authorizing an invalid customer should throw", function () {
      return (0, _testUtils.record)(spec18, function () {
        var connector = makeConnector();
        var username = invalidCredentials.username,
            password = invalidCredentials.password;
        return expect(connector.login(username, password)).rejects.toThrow();
      });
    });
    var spec19 = test("authorizing as a guest should return a customer", function () {
      return (0, _testUtils.record)(spec19, function () {
        var connector = makeConnector();
        return connector.login().then(function (customer) {
          expect((0, _testUtils.propTypeErrors)(_types.Customer, customer)).toBeFalsy();
        });
      });
    });
  });
  describe('Account management', function () {
    var spec20 = test('Should support creating a new user account', function () {
      return (0, _testUtils.record)(spec20, function () {
        var data = userFixture('creating-accounts');
        var connector = makeConnector();
        return _bluebird["default"].resolve().then(function () {
          return connector.login();
        }).then(function () {
          return connector.registerCustomer(data);
        }).then(function (customer) {
          expect((0, _testUtils.propTypeErrors)(_types.Customer, customer)).toBeFalsy();
          return connector.getCustomer(customer.id); // Protected endpoint
        }).then(function (customer) {
          expect((0, _testUtils.propTypeErrors)(_types.Customer, customer)).toBeFalsy();
          Object.keys(data).filter(function (k) {
            return k !== 'password';
          }).forEach(function (k) {
            return expect(data[k]).toEqual(customer[k]);
          });
          expect(customer).not.toHaveProperty('password');
        });
      });
    });
  });
  describe('Getting a customer', function () {
    var spec21 = test("getting any customer without logging in first should throw", function () {
      return (0, _testUtils.record)(spec21, function () {
        var connector = makeConnector();
        var customerId = 'bcyyeR5KK0gGKjf2uZHarcK93Z';
        var error = {
          arguments: undefined,
          message: "Unauthorized request: The 'Authorization' header is missing.",
          type: 'AuthorizationHeaderMissingException'
        };
        return expect(connector.getCustomer(customerId)).rejects.toEqual(error);
      });
    });
    var spec22 = test("getting the logged in customer after logging in should return the customer", function () {
      return (0, _testUtils.record)(spec22, function () {
        var connector = makeConnector();
        var username = validCredentials.username,
            password = validCredentials.password;
        return connector.login(username, password).then(function (customer) {
          return connector.getCustomer(customer.id);
        }).then(function (customer) {
          expect((0, _testUtils.propTypeErrors)(_types.Category, customer)).toBeFalsy();
          expect(customer.email).toEqual(username);
        });
      });
    });
    var spec23 = test("can set default headers to maintain authentication tokens between connectors", function () {
      return (0, _testUtils.record)(spec23, function () {
        var connector1 = makeConnector();
        var connector2 = makeConnector();
        var username = validCredentials.username,
            password = validCredentials.password;
        return connector1.login(username, password).then(function (customer) {
          connector2.setDefaultHeaders(connector1.getDefaultHeaders());
          return connector2.getCustomer(customer.id);
        }).then(function (customer) {
          expect((0, _testUtils.propTypeErrors)(_types.Category, customer)).toBeFalsy();
          expect(customer.email).toEqual(username);
        });
      });
    });
  });
  describe('Coupon support', function () {
    var testBody = function testBody(connector) {
      return connector.createCart().then(function (cart) {
        return connector.addCartItem(cart, cartItem);
      }).then(function (cart) {
        return connector.addCouponEntry(cart, 'orderLevel');
      }).then(function (cart) {
        expect((0, _testUtils.propTypeErrors)(_types.Cart, cart)).toBeFalsy();
        expect(cart.items.length).toEqual(1);
        expect(cart.couponEntries[0].code).toEqual('orderLevel');
        expect(cart.couponEntries[0].id).toBeDefined();
        expect(cart.discounts).toBeLessThan(0);
        return cart;
      }).then(function (cart) {
        return connector.removeCouponEntry(cart, cart.couponEntries[0].id);
      }).then(function (cart) {
        expect((0, _testUtils.propTypeErrors)(_types.Cart, cart)).toBeFalsy();
        expect(cart.items.length).toEqual(1);
        expect(cart.couponEntries).toEqual([]);
        expect(cart.discounts).toBe(0);
        return cart;
      }).then(function (cart) {
        return expect(connector.addCouponEntry(cart, 'INVALID_COUPON')).rejects.toThrow().then(function () {
          return cart;
        });
      }).then(function (cart) {
        return expect(connector.removeCouponEntry(cart, 'INVALID_COUPONENTRY_ID')).rejects.toThrow().then(function () {
          return cart;
        });
      });
    };

    var spec1 = test('Should allow a registered user to add/remove a CouponEntry to/from their cart', function () {
      return (0, _testUtils.record)(spec1, function () {
        var userCreateFixture = userFixture('coupons-1');
        var connector = makeConnector();
        return connector.login().then(function () {
          return connector.registerCustomer(userCreateFixture);
        }).then(function () {
          return testBody(connector);
        });
      });
    });
    var spec2 = test('Should allow a guest user to add/remove a CouponEntry to/from their cart', function () {
      return (0, _testUtils.record)(spec2, function () {
        var connector = makeConnector();
        return connector.login().then(function () {
          return testBody(connector);
        });
      });
    });
  });
});