Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(panel): render templates on init with render state #4845

Merged
merged 2 commits into from
Aug 24, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions src/components/Panel/Panel.tsx
Original file line number Diff line number Diff line change
@@ -6,13 +6,10 @@ import cx from 'classnames';
import Template from '../Template/Template';
import type {
PanelCSSClasses,
PanelSharedOptions,
PanelTemplates,
} from '../../widgets/panel/panel';
import type {
ComponentCSSClasses,
RenderOptions,
UnknownWidgetFactory,
} from '../../types';
import type { ComponentCSSClasses, UnknownWidgetFactory } from '../../types';

export type PanelComponentCSSClasses = ComponentCSSClasses<
// `collapseIcon` is only used in the default templates of the widget
@@ -26,7 +23,7 @@ export type PanelProps<TWidget extends UnknownWidgetFactory> = {
hidden: boolean;
collapsible: boolean;
isCollapsed: boolean;
data: RenderOptions | Record<string, never>;
data: PanelSharedOptions<TWidget>;
cssClasses: PanelComponentCSSClasses;
templates: PanelComponentTemplates<TWidget>;
bodyElement: HTMLElement;
251 changes: 231 additions & 20 deletions src/widgets/panel/__tests__/panel-test.ts
Original file line number Diff line number Diff line change
@@ -114,10 +114,12 @@ describe('Templates', () => {
test('with default templates', () => {
const widgetWithPanel = panel()(widgetFactory);

widgetWithPanel({
const widget = widgetWithPanel({
container: document.createElement('div'),
});

widget.init(createInitOptions());

const firstRender = render.mock.calls[0][0] as VNode<
PanelProps<typeof widgetFactory>
>;
@@ -137,10 +139,12 @@ describe('Templates', () => {
},
})(widgetFactory);

widgetWithPanel({
const widget = widgetWithPanel({
container: document.createElement('div'),
});

widget.init(createInitOptions());

const firstRender = render.mock.calls[0][0] as VNode<
PanelProps<typeof widgetFactory>
>;
@@ -156,10 +160,12 @@ describe('Templates', () => {
},
})(widgetFactory);

widgetWithPanel({
const widget = widgetWithPanel({
container: document.createElement('div'),
});

widget.init(createInitOptions());

const firstRender = render.mock.calls[0][0] as VNode<
PanelProps<typeof widgetFactory>
>;
@@ -175,10 +181,12 @@ describe('Templates', () => {
},
})(widgetFactory);

widgetWithPanel({
const widget = widgetWithPanel({
container: document.createElement('div'),
});

widget.init(createInitOptions());

const firstRender = render.mock.calls[0][0] as VNode<
PanelProps<typeof widgetFactory>
>;
@@ -206,32 +214,235 @@ describe('Lifecycle', () => {
container: document.createElement('div'),
});

widgetWithPanel.init!(createInitOptions());
widgetWithPanel.render!(createRenderOptions());
widgetWithPanel.dispose!(createDisposeOptions());
widgetWithPanel.init(createInitOptions());
widgetWithPanel.render(createRenderOptions());
widgetWithPanel.dispose(createDisposeOptions());

expect(widget.init).toHaveBeenCalledTimes(1);
expect(widget.render).toHaveBeenCalledTimes(1);
expect(widget.dispose).toHaveBeenCalledTimes(1);
});

test('returns the `state` from the widget dispose function', () => {
const nextSearchParameters = new algoliasearchHelper.SearchParameters({
facets: ['brands'],
describe('init', () => {
test("calls the wrapped widget's init", () => {
const widget = {
$$type: 'mock.widget',
init: jest.fn(),
};
const widgetFactory = () => widget;

const widgetWithPanel = panel()(widgetFactory)({
container: document.createElement('div'),
});

const initOptions = createInitOptions();

widgetWithPanel.init(initOptions);

expect(widget.init).toHaveBeenCalledTimes(1);
expect(widget.init).toHaveBeenCalledWith(initOptions);
});
const widget = {
$$type: 'mock.widget',
init: jest.fn(),
dispose: jest.fn(() => nextSearchParameters),
};
const widgetFactory = () => widget;

const widgetWithPanel = panel()(widgetFactory)({
container: document.createElement('div'),
test('does not call hidden and collapsed yet', () => {
const renderState = {
widgetParams: {},
swag: true,
};

const widget = {
$$type: 'mock.widget',
render: jest.fn(),
getWidgetRenderState() {
return renderState;
},
};

const widgetFactory = () => widget;

const hiddenFn = jest.fn();
const collapsedFn = jest.fn();

const widgetWithPanel = panel({
hidden: hiddenFn,
collapsed: collapsedFn,
})(widgetFactory)({
container: document.createElement('div'),
});

const initOptions = createInitOptions();

widgetWithPanel.init(initOptions);

expect(hiddenFn).toHaveBeenCalledTimes(0);
expect(collapsedFn).toHaveBeenCalledTimes(0);
});

test('renders with render state', () => {
const renderState = {
widgetParams: {},
swag: true,
};

const widget = {
$$type: 'mock.widget',
render: jest.fn(),
getWidgetRenderState() {
return renderState;
},
};

const widgetFactory = () => widget;

const widgetWithPanel = panel()(widgetFactory)({
container: document.createElement('div'),
});

const initOptions = createInitOptions();

widgetWithPanel.init(initOptions);

const firstRender = render.mock.calls[0][0] as VNode<
PanelProps<typeof widgetFactory>
>;

expect(firstRender.props).toEqual(
expect.objectContaining({
hidden: true,
collapsible: false,
isCollapsed: false,
data: {
...renderState,
...initOptions,
},
})
);
});
});

describe('render', () => {
test("calls the wrapped widget's render", () => {
const widget = {
$$type: 'mock.widget',
render: jest.fn(),
};
const widgetFactory = () => widget;

const widgetWithPanel = panel()(widgetFactory)({
container: document.createElement('div'),
});

const renderOptions = createRenderOptions();

widgetWithPanel.render(renderOptions);

expect(widget.render).toHaveBeenCalledTimes(1);
expect(widget.render).toHaveBeenCalledWith(renderOptions);
});

test("calls hidden and collapsed with the wrapped widget's render state", () => {
const renderState = {
widgetParams: {},
swag: true,
};

const widget = {
$$type: 'mock.widget',
render: jest.fn(),
getWidgetRenderState() {
return renderState;
},
};

const widgetFactory = () => widget;

const hiddenFn = jest.fn();
const collapsedFn = jest.fn();

const widgetWithPanel = panel({
hidden: hiddenFn,
collapsed: collapsedFn,
})(widgetFactory)({
container: document.createElement('div'),
});

const renderOptions = createRenderOptions();

widgetWithPanel.render(renderOptions);

expect(hiddenFn).toHaveBeenCalledTimes(1);
expect(hiddenFn).toHaveBeenCalledWith({
...renderState,
...renderOptions,
});

expect(collapsedFn).toHaveBeenCalledTimes(1);
expect(collapsedFn).toHaveBeenCalledWith({
...renderState,
...renderOptions,
});
});

test('renders with render state', () => {
const renderState = {
widgetParams: {},
swag: true,
};

const widget = {
$$type: 'mock.widget',
render: jest.fn(),
getWidgetRenderState() {
return renderState;
},
};

const widgetFactory = () => widget;

const widgetWithPanel = panel()(widgetFactory)({
container: document.createElement('div'),
});

const renderOptions = createRenderOptions();

widgetWithPanel.render(renderOptions);

const firstRender = render.mock.calls[0][0] as VNode<
PanelProps<typeof widgetFactory>
>;

expect(firstRender.props).toEqual(
expect.objectContaining({
hidden: false,
collapsible: false,
isCollapsed: false,
data: {
...renderState,
...renderOptions,
},
})
);
});
});

const nextState = widgetWithPanel.dispose!(createDisposeOptions({}));
describe('dispose', () => {
test("returns the state from the widget's dispose function", () => {
const nextSearchParameters = new algoliasearchHelper.SearchParameters({
facets: ['brands'],
});
const widget = {
$$type: 'mock.widget',
init: jest.fn(),
dispose: jest.fn(() => nextSearchParameters),
};
const widgetFactory = () => widget;

const widgetWithPanel = panel()(widgetFactory)({
container: document.createElement('div'),
});

const nextState = widgetWithPanel.dispose(createDisposeOptions());

expect(nextState).toEqual(nextSearchParameters);
expect(nextState).toEqual(nextSearchParameters);
});
});
});
Loading