Skip to content
This repository has been archived by the owner on Dec 30, 2022. It is now read-only.

Commit

Permalink
Merge pull request #260 from algolia/test/more
Browse files Browse the repository at this point in the history
Make all components SSR ready
  • Loading branch information
rayrutjes authored Aug 8, 2017
2 parents 16497ba + 0702a6e commit 34adf30
Show file tree
Hide file tree
Showing 20 changed files with 138 additions and 26 deletions.
3 changes: 2 additions & 1 deletion docs/docgen/src/components/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ Provide search query parameters:
| index-name | String | `` | The index name |
| query | String | `` | The search query |
| query-parameters | Object | `` | The search query parameters. Available options are [documented here](https://www.algolia.com/doc/api-client/javascript/search/#search-parameters). |
| cache | Boolean | `true` | Wether to cache results or not. See: https://www.algolia.com/doc/tutorials/getting-started/quick-start-with-the-api-client/javascript/#cache |
| cache | Boolean | `true` | Whether to cache results or not. See: https://www.algolia.com/doc/tutorials/getting-started/quick-start-with-the-api-client/javascript/#cache |
| auto-search | Boolean | `true` | Whether to initiate a query to Algolia when this component is mounted |

## Slots

Expand Down
2 changes: 1 addition & 1 deletion docs/docgen/src/getting-started/custom-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ To ensure consistency and re-usability for custom components, we recommend revie
### Vue component

* Use the `Component` mixin that we provide. This will make sure your component can resolve the `searchStore` if not provided. It ensures the `searchStore` prop is available in your component at any time.
* If you need to mutate the `searchStore` multiple times, please use `searchStore.stop()` and `searchStore.start()`, so that other components don't update their rendering on every intermediary state mutation.
* If you need to mutate the `searchStore` multiple times, please use `searchStore.stop()` and `searchStore.start()`, so that other components don't update their rendering on every intermediary state mutation. Do not forget the `searchStore.refresh()` if you want to sync the store afterwards.
* Make sure that when the component is mounted, you catch up with the `searchStore`. You can optionally mutate the state of the `searchStore` at this stage.
* When a component is `unmounted` or `destroyed`, make sure that you leave the `searchStore` in a state that does not include things you might have added (facets / filters / etc.).
* Make sure your component gracefully handles any state of the `searchStore`.
7 changes: 5 additions & 2 deletions docs/docgen/src/getting-started/search-store.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,18 +133,21 @@ store.query = '';
store.queryParameters({'distinct': true});

store.start();
store.refresh();
```

In this example, even if the state is mutated several times, only one call to Algolia will be made after the Store is resumed by the `start()` call.
In this example, even if the state is mutated several times, only one call to Algolia will be made after the Store is resumed by the `start()` and `refresh()` calls.

**Important:** When you manually create a search store, it is stopped by default. You need to manually call `start()` to trigger the first call. This gives you full control over the initial state of the store before the first call to Algolia is sent.
**Important:** When you manually create a search store, it is stopped by default. You need to manually call `start()` and `refresh()` to trigger the first call. This gives you full control over the initial state of the store before the first call to Algolia is sent.
If you pass the store as a prop to an `<ais-index>` component though, it will be started and refreshed when mounted.

```javascript
import { createFromAlgoliaCredentials } from 'vue-instantsearch';

const store = createFromAlgoliaCredentials('appId', 'search_apiKey');
store.indexName = 'new_index';
store.start();
store.refresh();
```

In the example above, the first query will be sent to Algolia after `store.start()` has been called.
1 change: 1 addition & 0 deletions src/__tests__/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ describe('Store', () => {
return { clearCache };
},
};
store.start();
store.disableCache();
store.refresh();
expect(clearCache).toHaveBeenCalledTimes(1);
Expand Down
1 change: 1 addition & 0 deletions src/components/Clear.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export default {
this.searchStore.clearRefinements();
}
this.searchStore.start();
this.searchStore.refresh();
},
},
};
Expand Down
7 changes: 7 additions & 0 deletions src/components/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ export default {
type: Boolean,
default: true,
},
autoSearch: {
type: Boolean,
default: true,
},
},
data() {
return {
Expand Down Expand Up @@ -97,6 +101,9 @@ export default {
},
mounted() {
this._localSearchStore.start();
if (this.autoSearch) {
this._localSearchStore.refresh();
}
},
watch: {
indexName() {
Expand Down
1 change: 1 addition & 0 deletions src/components/Input.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export default {
// without triggering in between ghost queries.
this.$nextTick(function() {
this.searchStore.start();
this.searchStore.refresh();
});
},
},
Expand Down
2 changes: 2 additions & 0 deletions src/components/PriceRange.vue
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export default {
}
this.searchStore.start();
this.searchStore.refresh();
},
},
to: {
Expand Down Expand Up @@ -125,6 +126,7 @@ export default {
this.searchStore.addNumericRefinement(this.attributeName, '<', value);
}
this.searchStore.start();
this.searchStore.refresh();
},
},
},
Expand Down
3 changes: 2 additions & 1 deletion src/components/Rating.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export default {
blockClassName: 'ais-rating',
};
},
mounted() {
created() {
this.searchStore.addFacet(this.attributeName, FACET_OR);
},
destroyed() {
Expand Down Expand Up @@ -141,6 +141,7 @@ export default {
this.searchStore.addFacetRefinement(this.attributeName, val);
}
this.searchStore.start();
this.searchStore.refresh();
return undefined;
},
clear() {
Expand Down
2 changes: 1 addition & 1 deletion src/components/RefinementList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export default {
blockClassName: 'ais-refinement-list',
};
},
mounted() {
created() {
this.searchStore.addFacet(this.attributeName, this.operator);
},
destroyed() {
Expand Down
2 changes: 1 addition & 1 deletion src/components/Results.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default {
blockClassName: 'ais-results',
};
},
mounted() {
created() {
this.updateResultsPerPage();
},
watch: {
Expand Down
2 changes: 1 addition & 1 deletion src/components/ResultsPerPageSelector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default {
},
},
},
mounted() {
created() {
if (this.options.indexOf(this.searchStore.resultsPerPage) === -1) {
this.searchStore.resultsPerPage = this.options[0];
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/SortBySelector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default {
},
},
},
mounted() {
created() {
let match = false;
for (const index in this.indices) {
if (this.indices[index].name === this.indexName) {
Expand Down
2 changes: 1 addition & 1 deletion src/components/TreeMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default {
blockClassName: 'ais-tree-menu',
};
},
mounted() {
created() {
this.searchStore.addFacet(
{
name: this.attribute,
Expand Down
14 changes: 14 additions & 0 deletions src/components/__tests__/__snapshots__/sort-by-selector.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`renders proper HTML 1`] = `
<select class="ais-sort-by-selector">
<option value="index1">
label1
</option>
<option value="index2">
label2
</option>
</select>
`;
6 changes: 6 additions & 0 deletions src/components/__tests__/clear.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,22 @@ describe('Clear component', () => {
const stop = jest.fn();
const start = jest.fn();
const clearRefinements = jest.fn();
const refresh = jest.fn();

const searchStore = {
query: 'whatever',
activeRefinements: ['whatever'],
stop,
start,
clearRefinements,
refresh,
};

beforeEach(() => {
stop.mockClear();
start.mockClear();
clearRefinements.mockClear();
refresh.mockClear();
searchStore.query = 'whatever';
searchStore.activeRefinements = ['whatever'];
});
Expand All @@ -34,6 +37,7 @@ describe('Clear component', () => {
expect(stop).toHaveBeenCalledTimes(1);
expect(clearRefinements).toHaveBeenCalledTimes(1);
expect(start).toHaveBeenCalledTimes(1);
expect(refresh).toHaveBeenCalledTimes(1);
});

test('can disable query clearing', () => {
Expand All @@ -46,6 +50,7 @@ describe('Clear component', () => {
expect(stop).toHaveBeenCalledTimes(1);
expect(clearRefinements).toHaveBeenCalledTimes(1);
expect(start).toHaveBeenCalledTimes(1);
expect(refresh).toHaveBeenCalledTimes(1);
});

test('can disable facets clearing', () => {
Expand All @@ -58,6 +63,7 @@ describe('Clear component', () => {
expect(stop).toHaveBeenCalledTimes(1);
expect(clearRefinements).not.toHaveBeenCalled();
expect(start).toHaveBeenCalledTimes(1);
expect(refresh).toHaveBeenCalledTimes(1);
});

test('has proper HTML rendering', () => {
Expand Down
4 changes: 1 addition & 3 deletions src/components/__tests__/menu-tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,13 @@ test('should add a tree facet to the store when mounted', () => {
const Component = Vue.extend(TreeMenu);
const addFacetMock = jest.fn();
const store = Object.assign({}, searchStore, { addFacet: addFacetMock });
const vm = new Component({
new Component({ // eslint-disable-line
propsData: {
attributes: ['category.lvl1', 'category.lvl2'],
searchStore: store,
},
});

expect(addFacetMock).not.toBeCalled();
vm.$mount();
expect(addFacetMock).toBeCalledWith(
{
name: 'tree-menu',
Expand Down
7 changes: 2 additions & 5 deletions src/components/__tests__/refinement-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,16 @@ test('renders proper HTML', () => {
expect(vm.$el.outerHTML).toMatchSnapshot();
});

test('should add a facet to the store when mounted', () => {
test('should add a facet to the store when created', () => {
const Component = Vue.extend(RefinementList);
const addFacetMock = jest.fn();
const store = Object.assign({}, searchStore, { addFacet: addFacetMock });
const vm = new Component({
new Component({ // eslint-disable-line
propsData: {
attributeName: 'color',
searchStore: store,
},
});

expect(addFacetMock).not.toBeCalled();
vm.$mount();
expect(addFacetMock).toBeCalledWith('color', 'or');
});

Expand Down
64 changes: 64 additions & 0 deletions src/components/__tests__/sort-by-selector.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import Vue from 'vue';
import SortBySelector from '../SortBySelector.vue';

test('renders proper HTML', () => {
const searchStore = {};
const Component = Vue.extend(SortBySelector);
const vm = new Component({
propsData: {
searchStore,
indices: [
{ name: 'index1', label: 'label1' },
{ name: 'index2', label: 'label2' },
],
},
});
vm.$mount();

expect(vm.$el.outerHTML).toMatchSnapshot();
});

test('should use current index name in search store if it is a valid option', () => {
const searchStore = {
indexName: 'index2',
};
const Component = Vue.extend(SortBySelector);
const vm = new Component({
propsData: {
searchStore,
indices: [
{ name: 'index1', label: 'label1' },
{ name: 'index2', label: 'label2' },
],
},
});

expect(vm.searchStore.indexName).toEqual('index2');

vm.$mount();

expect(vm.$el.getElementsByTagName('option')[0].selected).toEqual(false);
expect(vm.$el.getElementsByTagName('option')[1].selected).toEqual(true);
});

test('should use first index if current index name is not a valid option', () => {
const searchStore = {
indexName: 'index3',
};
const Component = Vue.extend(SortBySelector);
const vm = new Component({
propsData: {
searchStore,
indices: [
{ name: 'index1', label: 'label1' },
{ name: 'index2', label: 'label2' },
],
},
});

expect(vm.searchStore.indexName).toEqual('index1');

vm.$mount();

expect(vm.$el.getElementsByTagName('option')[0].selected).toEqual(true);
});
Loading

0 comments on commit 34adf30

Please sign in to comment.