From 55f53d1c00bab3bbec8bc42f6ab12bbe8a407ff7 Mon Sep 17 00:00:00 2001 From: Sarah Dayan <5370675+sarahdayan@users.noreply.github.com> Date: Fri, 8 Apr 2022 13:27:42 +0200 Subject: [PATCH] fix(render): pass `renderer.render` to default `render` function (#940) --- .../src/components/Autocomplete.tsx | 11 +- .../react-instantsearch/src/Autocomplete.js | 5 +- .../vue-instantsearch/src/Autocomplete.vue | 4 +- examples/vue/src/App.vue | 4 +- .../src/__tests__/renderer.test.ts | 122 +++++++++++++----- .../autocomplete-js/src/getDefaultOptions.ts | 4 +- packages/autocomplete-js/src/render.tsx | 2 +- .../src/types/AutocompleteRender.ts | 2 +- 8 files changed, 100 insertions(+), 54 deletions(-) diff --git a/examples/react-instantsearch-hooks/src/components/Autocomplete.tsx b/examples/react-instantsearch-hooks/src/components/Autocomplete.tsx index d742cbdfd..662e91574 100644 --- a/examples/react-instantsearch-hooks/src/components/Autocomplete.tsx +++ b/examples/react-instantsearch-hooks/src/components/Autocomplete.tsx @@ -1,10 +1,9 @@ import type { SearchClient } from 'algoliasearch/lite'; import type { BaseItem } from '@algolia/autocomplete-core'; -import type { AutocompleteOptions } from '@algolia/autocomplete-js'; +import type { AutocompleteOptions, Render } from '@algolia/autocomplete-js'; import { createElement, - ReactElement, Fragment, useEffect, useMemo, @@ -228,13 +227,7 @@ export function Autocomplete({ }); } }, - renderer: { - createElement, - Fragment, - }, - render({ children }, root) { - render(children as ReactElement, root); - }, + renderer: { createElement, Fragment, render: render as Render }, }); return () => autocompleteInstance.destroy(); diff --git a/examples/react-instantsearch/src/Autocomplete.js b/examples/react-instantsearch/src/Autocomplete.js index 8389aea2b..4f87de11d 100644 --- a/examples/react-instantsearch/src/Autocomplete.js +++ b/examples/react-instantsearch/src/Autocomplete.js @@ -14,10 +14,7 @@ export function Autocomplete(props) { const search = autocomplete({ container: containerRef.current, - renderer: { createElement, Fragment }, - render({ children }, root) { - render(children, root); - }, + renderer: { createElement, Fragment, render }, ...props, }); diff --git a/examples/vue-instantsearch/src/Autocomplete.vue b/examples/vue-instantsearch/src/Autocomplete.vue index e42159593..6491a6b8f 100644 --- a/examples/vue-instantsearch/src/Autocomplete.vue +++ b/examples/vue-instantsearch/src/Autocomplete.vue @@ -244,9 +244,7 @@ export default { renderer: { createElement, Fragment, - }, - render({ children }, root) { - render(children, root); + render, }, }); }, diff --git a/examples/vue/src/App.vue b/examples/vue/src/App.vue index 74ddc3d37..ed10e0ede 100644 --- a/examples/vue/src/App.vue +++ b/examples/vue/src/App.vue @@ -53,9 +53,7 @@ export default { renderer: { createElement, Fragment, - }, - render({ children }, root) { - render(children, root); + render, }, }); }); diff --git a/packages/autocomplete-js/src/__tests__/renderer.test.ts b/packages/autocomplete-js/src/__tests__/renderer.test.ts index 105e8f22f..a0306602d 100644 --- a/packages/autocomplete-js/src/__tests__/renderer.test.ts +++ b/packages/autocomplete-js/src/__tests__/renderer.test.ts @@ -1,4 +1,5 @@ import { warnCache } from '@algolia/autocomplete-shared'; +import { fireEvent, waitFor } from '@testing-library/dom'; import { createElement as preactCreateElement, Fragment as PreactFragment, @@ -17,6 +18,8 @@ describe('renderer', () => { }); test('defaults to the Preact implementation', () => { + expect.assertions(3); + const container = document.createElement('div'); const panelContainer = document.createElement('div'); @@ -47,19 +50,14 @@ describe('renderer', () => { expect(Fragment).toBe(PreactFragment); expect(render).toBe(preactRender); - render(createElement(Fragment, null, 'testSource'), root); - }, - renderNoResults({ createElement, Fragment, render }, root) { - expect(createElement).toBe(preactCreateElement); - expect(Fragment).toBe(PreactFragment); - expect(render).toBe(preactRender); - render(createElement(Fragment, null, 'testSource'), root); }, }); }); test('accepts a custom renderer', () => { + expect.assertions(6); + const container = document.createElement('div'); const panelContainer = document.createElement('div'); const CustomFragment = (props: any) => props.children; @@ -106,26 +104,6 @@ describe('renderer', () => { expect.any(Object) ); }, - renderNoResults( - { children, createElement, Fragment, render, html }, - root - ) { - expect(createElement).toBe(mockCreateElement); - expect(Fragment).toBe(CustomFragment); - expect(render).toBe(mockRender); - expect(mockCreateElement).toHaveBeenCalled(); - - mockCreateElement.mockClear(); - - render(html`
${children}
`, root); - - expect(mockCreateElement).toHaveBeenCalledTimes(1); - expect(mockCreateElement).toHaveBeenLastCalledWith( - 'div', - null, - expect.any(Object) - ); - }, renderer: { createElement: mockCreateElement, Fragment: CustomFragment, @@ -135,6 +113,8 @@ describe('renderer', () => { }); test('defaults `render` when not specified in the renderer', () => { + expect.assertions(1); + const container = document.createElement('div'); const panelContainer = document.createElement('div'); const CustomFragment = (props: any) => props.children; @@ -168,16 +148,96 @@ describe('renderer', () => { preactRender(createElement(Fragment, null, 'testSource'), root); }, - renderNoResults({ createElement, Fragment, render }, root) { - expect(render).toBe(preactRender); + renderer: { + createElement: mockCreateElement, + Fragment: CustomFragment, + }, + }); + }); - preactRender(createElement(Fragment, null, 'testSource'), root); + test('uses a custom `render` via `renderer`', async () => { + const container = document.createElement('div'); + const panelContainer = document.createElement('div'); + + document.body.appendChild(panelContainer); + + const CustomFragment = (props: any) => props.children; + const mockCreateElement = jest.fn(preactCreateElement); + const mockRender = jest.fn().mockImplementation(preactRender); + + autocomplete<{ label: string }>({ + container, + panelContainer, + id: 'autocomplete-0', + getSources() { + return [ + { + sourceId: 'testSource', + getItems() { + return [{ label: '1' }]; + }, + templates: { + item({ item }) { + return item.label; + }, + }, + }, + ]; }, renderer: { - createElement: mockCreateElement, Fragment: CustomFragment, + render: mockRender, + createElement: mockCreateElement, }, }); + + const input = container.querySelector('.aa-Input'); + + fireEvent.input(input, { target: { value: 'apple' } }); + + await waitFor(() => { + expect( + panelContainer.querySelector('.aa-Panel') + ).toBeInTheDocument(); + expect(mockRender).toHaveBeenCalled(); + expect(panelContainer).toMatchInlineSnapshot(` +
+
+
+
+
    +
  • + 1 +
  • +
+
+
+
+
+
+ `); + }); }); test('warns about renderer mismatch when specifying an incomplete renderer', () => { diff --git a/packages/autocomplete-js/src/getDefaultOptions.ts b/packages/autocomplete-js/src/getDefaultOptions.ts index dd5b7c3a1..a61be9c39 100644 --- a/packages/autocomplete-js/src/getDefaultOptions.ts +++ b/packages/autocomplete-js/src/getDefaultOptions.ts @@ -54,11 +54,11 @@ const defaultClassNames: AutocompleteClassNames = { submitButton: 'aa-SubmitButton', }; -const defaultRender: AutocompleteRender = ({ children }, root) => { +const defaultRender: AutocompleteRender = ({ children, render }, root) => { render(children, root); }; -const defaultRenderer: AutocompleteRenderer = { +const defaultRenderer: Required = { createElement: preactCreateElement, Fragment: PreactFragment, render, diff --git a/packages/autocomplete-js/src/render.tsx b/packages/autocomplete-js/src/render.tsx index dd56a5f07..de0e2dfe9 100644 --- a/packages/autocomplete-js/src/render.tsx +++ b/packages/autocomplete-js/src/render.tsx @@ -27,7 +27,7 @@ type RenderProps = { panelContainer: HTMLElement; propGetters: AutocompletePropGetters; state: AutocompleteState; - renderer: AutocompleteRenderer; + renderer: Required; }; export function renderSearchBox({ diff --git a/packages/autocomplete-js/src/types/AutocompleteRender.ts b/packages/autocomplete-js/src/types/AutocompleteRender.ts index 63116e362..8dd24a9c4 100644 --- a/packages/autocomplete-js/src/types/AutocompleteRender.ts +++ b/packages/autocomplete-js/src/types/AutocompleteRender.ts @@ -20,7 +20,7 @@ export type AutocompleteRender = ( createElement: Pragma; Fragment: PragmaFrag; html: HTMLTemplate; - render?: Render; + render: Render; }, root: HTMLElement ) => void;