text: 'use strict';
  
  var algoliaSearchHelper = require('../../../index');
  
  function makeFakeClient() {
    return {
      search: jest.fn(function() {
        return new Promise(function() {});
      }),
      searchForFacetValues: jest.fn(function() {
        return new Promise(function() {});
      })
    };
  }
  
  function runAllMicroTasks() {
    return new Promise(setImmediate);
  }
  
  test('Change events should be emitted with reset page to true on implicit reset methods', function() {
    var changed = jest.fn();
    var fakeClient = makeFakeClient();
    var helper = algoliaSearchHelper(fakeClient, 'Index');
  
    helper.on('change', changed);
  
    expect(changed).toHaveBeenCalledTimes(0);
  
    // Trigger a page reset
    helper.setQuery('Apple');
  
    expect(changed).toHaveBeenCalledTimes(1);
    expect(changed).toHaveBeenLastCalledWith({
      state: expect.any(algoliaSearchHelper.SearchParameters),
      results: null,
      isPageReset: true
    });
  
    // Trigger a page reset
    helper.setQueryParameter('hitsPerPage', 10);
  
    expect(changed).toHaveBeenCalledTimes(2);
    expect(changed).toHaveBeenLastCalledWith({
      state: expect.any(algoliaSearchHelper.SearchParameters),
      results: null,
      isPageReset: true
    });
  });
  
  test('Change events should be emitted with reset page to false on regular methods', function() {
    var changed = jest.fn();
    var fakeClient = makeFakeClient();
    var helper = algoliaSearchHelper(fakeClient, 'Index');
  
    helper.on('change', changed);
  
    expect(changed).toHaveBeenCalledTimes(0);
  
    // Don't trigger a page reset
    helper.setPage(22);
  
    expect(changed).toHaveBeenCalledTimes(1);
    expect(changed).toHaveBeenLastCalledWith({
      state: expect.any(algoliaSearchHelper.SearchParameters),
      results: null,
      isPageReset: false
    });
  
    // Don't trigger a page reset
    helper.setState({
      query: 'Apple',
      page: 22
    });
  
    expect(changed).toHaveBeenCalledTimes(2);
    expect(changed).toHaveBeenLastCalledWith({
      state: expect.any(algoliaSearchHelper.SearchParameters),
      results: null,
      isPageReset: false
    });
  });
  
  test('Change events should be emitted as soon as the state change, but search should be triggered (refactored)', function() {
    var fakeClient = makeFakeClient();
    var helper = algoliaSearchHelper(fakeClient, 'Index', {
      disjunctiveFacets: ['city'],
      disjunctiveFacetsRefinements: {city: ['Paris']},
      facets: ['tower'],
      facetsRefinements: {tower: ['Empire State Building']},
      facetsExcludes: {tower: ['Empire State Building']},
      hierarchicalFacets: [],
      numericRefinements: {
        price: {'>': [300]}
      }
    });
  
    var changeEventCount = 0;
  
    helper.on('change', function() {
      changeEventCount++;
    });
  
    helper.setQuery('a');
    expect(changeEventCount).toBe(1);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.clearRefinements();
    expect(changeEventCount).toBe(2);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.addDisjunctiveRefine('city', 'Paris');
    expect(changeEventCount).toBe(3);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.removeDisjunctiveRefine('city', 'Paris');
    expect(changeEventCount).toBe(4);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.addExclude('tower', 'Empire State Building');
    expect(changeEventCount).toBe(5);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.removeExclude('tower', 'Empire State Building');
    expect(changeEventCount).toBe(6);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.addRefine('tower', 'Empire State Building');
    expect(changeEventCount).toBe(7);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.removeRefine('tower', 'Empire State Building');
    expect(changeEventCount).toBe(8);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.search();
    expect(changeEventCount).toBe(8);
    expect(fakeClient.search).toHaveBeenCalledTimes(1);
  });
  
  test('Change events should only be emitted for meaningful changes', function() {
    var fakeClient = makeFakeClient();
    var helper = algoliaSearchHelper(fakeClient, 'Index', {
      query: 'a',
      disjunctiveFacets: ['city'],
      disjunctiveFacetsRefinements: {city: ['Paris']},
      facets: ['tower'],
      facetsRefinements: {tower: ['Empire State Building']},
      facetsExcludes: {tower: ['Empire State Building']},
      hierarchicalFacets: [{
        name: 'hierarchicalFacet',
        attributes: ['lvl1', 'lvl2']
      }],
      numericRefinements: {
        price: {'>': [300]}
      }
    });
  
    var changeEventCount = 0;
  
    helper.on('change', function() {
      changeEventCount++;
    });
  
    helper.setQuery('a');
    expect(changeEventCount).toBe(0);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.addDisjunctiveRefine('city', 'Paris');
    expect(changeEventCount).toBe(0);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.addExclude('tower', 'Empire State Building');
    expect(changeEventCount).toBe(0);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.addRefine('tower', 'Empire State Building');
    expect(changeEventCount).toBe(0);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.addNumericRefinement('price', '>', 300);
    expect(changeEventCount).toBe(0);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    // This is an actual change
    helper.clearRefinements();
    expect(changeEventCount).toBe(1);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.clearRefinements();
    expect(changeEventCount).toBe(1);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.removeDisjunctiveRefine('city', 'Paris');
    expect(changeEventCount).toBe(1);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.removeExclude('tower', 'Empire State Building');
    expect(changeEventCount).toBe(1);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.removeRefine('tower', 'Empire State Building');
    expect(changeEventCount).toBe(1);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.search();
    expect(changeEventCount).toBe(1);
    expect(fakeClient.search).toHaveBeenCalledTimes(1);
  });
  
  test('search event should be emitted once when the search is triggered and before the request is sent', function() {
    var searched = jest.fn();
    var fakeClient = makeFakeClient();
    var helper = algoliaSearchHelper(fakeClient, 'Index', {
      disjunctiveFacets: ['city'],
      facets: ['tower']
    });
  
    helper.on('search', searched);
  
    helper.setQuery('');
    expect(searched).toHaveBeenCalledTimes(0);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.clearRefinements();
    expect(searched).toHaveBeenCalledTimes(0);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.addDisjunctiveRefine('city', 'Paris');
    expect(searched).toHaveBeenCalledTimes(0);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.removeDisjunctiveRefine('city', 'Paris');
    expect(searched).toHaveBeenCalledTimes(0);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.addExclude('tower', 'Empire State Building');
    expect(searched).toHaveBeenCalledTimes(0);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.removeExclude('tower', 'Empire State Building');
    expect(searched).toHaveBeenCalledTimes(0);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.addRefine('tower', 'Empire State Building');
    expect(searched).toHaveBeenCalledTimes(0);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.removeRefine('tower', 'Empire State Building');
    expect(searched).toHaveBeenCalledTimes(0);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.search();
    expect(searched).toHaveBeenCalledTimes(1);
    expect(searched).toHaveBeenLastCalledWith({
      state: helper.state,
      results: null
    });
    expect(fakeClient.search).toHaveBeenCalledTimes(1);
  });
  
  test('searchOnce event should be emitted once when the search is triggered using searchOnce and before the request is sent', function() {
    var searchedOnce = jest.fn();
    var fakeClient = makeFakeClient();
    var helper = algoliaSearchHelper(fakeClient, 'Index', {
      disjunctiveFacets: ['city'],
      facets: ['tower']
    });
  
    helper.on('searchOnce', searchedOnce);
  
    expect(searchedOnce).toHaveBeenCalledTimes(0);
    expect(fakeClient.search).toHaveBeenCalledTimes(0);
  
    helper.searchOnce({}, function() {});
  
    expect(searchedOnce).toHaveBeenCalledTimes(1);
    expect(searchedOnce).toHaveBeenLastCalledWith({
      state: helper.state
    });
  
    expect(fakeClient.search).toHaveBeenCalledTimes(1);
  });
  
  test('searchForFacetValues event should be emitted once when the search is triggered using' +
       ' searchForFacetValues and before the request is sent', function() {
    var searchedForFacetValues = jest.fn();
    var fakeClient = makeFakeClient();
    var helper = algoliaSearchHelper(fakeClient, 'Index', {
      disjunctiveFacets: ['city'],
      facets: ['tower']
    });
  
    helper.on('searchForFacetValues', searchedForFacetValues);
  
    expect(searchedForFacetValues).toHaveBeenCalledTimes(0);
    expect(fakeClient.searchForFacetValues).toHaveBeenCalledTimes(0);
  
    helper.searchForFacetValues('city', 'NYC');
    expect(searchedForFacetValues).toHaveBeenCalledTimes(1);
    expect(searchedForFacetValues).toHaveBeenLastCalledWith({
      state: helper.state,
      facet: 'city',
      query: 'NYC'
    });
    expect(fakeClient.searchForFacetValues).toHaveBeenCalledTimes(1);
  });
  
  test('result event should be emitted once the request is complete', function() {
    var resulted = jest.fn();
    var fakeClient = makeFakeClient();
    var helper = algoliaSearchHelper(fakeClient, 'Index', {
      disjunctiveFacets: ['city'],
      facets: ['tower']
    });
  
    fakeClient.search.mockImplementationOnce(function() {
      return Promise.resolve({
        results: [{}]
      });
    });
  
    helper.on('result', resulted);
  
    expect(resulted).toHaveBeenCalledTimes(0);
  
    helper.search();
  
    return runAllMicroTasks().then(function() {
      expect(resulted).toHaveBeenCalledTimes(1);
      expect(resulted).toHaveBeenLastCalledWith({
        results: expect.any(algoliaSearchHelper.SearchResults),
        state: helper.state
      });
    });
  });
  
  test('error event should be emitted once the request is complete with errors', function() {
    var errored = jest.fn();
    var fakeClient = makeFakeClient();
    var helper = algoliaSearchHelper(fakeClient, 'Index', {
      disjunctiveFacets: ['city'],
      facets: ['tower']
    });
  
    fakeClient.search.mockImplementationOnce(function() {
      return Promise.reject(new Error('Abort'));
    });
  
    helper.on('error', errored);
  
    expect(errored).toHaveBeenCalledTimes(0);
  
    helper.search();
  
    return runAllMicroTasks().then(function() {
      expect(errored).toHaveBeenCalledTimes(1);
      expect(errored).toHaveBeenLastCalledWith({
        error: expect.any(Error)
      });
    });
  });
  
  test('error event should be emitted if an error happens at request time', function() {
    var errored = jest.fn();
    var fakeClient = makeFakeClient();
    var helper = algoliaSearchHelper(fakeClient, 'Index', {
      disjunctiveFacets: ['city'],
      facets: ['tower']
    });
  
    fakeClient.search.mockImplementationOnce(function() {
      throw new Error('Unexpected error');
    });
  
    helper.on('error', errored);
  
    expect(errored).toHaveBeenCalledTimes(0);
  
    helper.search();
  
    expect(errored).toHaveBeenCalledTimes(1);
    expect(errored).toHaveBeenLastCalledWith({
      error: expect.any(Error)
    });
  });
  