Skip to content

Commit c382b19

Browse files
authored
Merge pull request #2391 from tf/extensible
Turn inline editing decorators into general extensions API
2 parents 0675366 + 61171b7 commit c382b19

27 files changed

Lines changed: 375 additions & 268 deletions
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
import React from 'react';
2+
3+
import '@testing-library/jest-dom/extend-expect'
4+
import {render, act} from '@testing-library/react'
5+
import {
6+
extensible,
7+
provideExtensions,
8+
clearExtensions,
9+
ExtensionsProvider
10+
} from 'frontend/extensions';
11+
import {StaticPreview} from 'frontend/useScrollPositionLifecycle';
12+
13+
describe('extensions', () => {
14+
afterEach(() => {
15+
act(() => clearExtensions());
16+
});
17+
18+
describe('extensible with decorator', () => {
19+
it('wraps component with decorator receiving same props', () => {
20+
const TestComponent = extensible('TestComponent', function TestComponent({text}) {
21+
return <span>{text} Component</span>;
22+
});
23+
24+
provideExtensions({
25+
decorators: {
26+
TestComponent({text, children}) {
27+
return <div>{text} Decorator{children}</div>;
28+
}
29+
}
30+
});
31+
32+
const {container} = render(<TestComponent text="Hello" />);
33+
34+
expect(container).toHaveTextContent('Hello Decorator');
35+
expect(container).toHaveTextContent('Hello Component');
36+
});
37+
38+
it('renders original component when no extensions provided', () => {
39+
const TestComponent = extensible('TestComponent', function TestComponent() {
40+
return <span>Component</span>;
41+
});
42+
43+
const {container} = render(<TestComponent />);
44+
45+
expect(container).toHaveTextContent('Component');
46+
});
47+
48+
it('renders original component in static preview', () => {
49+
const TestComponent = extensible('TestComponent', function TestComponent() {
50+
return <span>Component</span>;
51+
});
52+
53+
provideExtensions({
54+
decorators: {
55+
TestComponent({children}) {
56+
return <div>Decorator{children}</div>;
57+
}
58+
}
59+
});
60+
61+
const {container} = render(
62+
<StaticPreview>
63+
<TestComponent />
64+
</StaticPreview>
65+
);
66+
67+
expect(container).toHaveTextContent('Component');
68+
expect(container).not.toHaveTextContent('Decorator');
69+
});
70+
});
71+
72+
describe('extensible with alternative', () => {
73+
it('renders alternative instead of original', () => {
74+
const TestComponent = extensible('TestComponent', function TestComponent() {
75+
return <span>Original</span>;
76+
});
77+
78+
provideExtensions({
79+
alternatives: {
80+
TestComponent() {
81+
return <span>Alternative</span>;
82+
}
83+
}
84+
});
85+
86+
const {container} = render(<TestComponent />);
87+
88+
expect(container).toHaveTextContent('Alternative');
89+
expect(container).not.toHaveTextContent('Original');
90+
});
91+
92+
it('renders original component in static preview', () => {
93+
const TestComponent = extensible('TestComponent', function TestComponent() {
94+
return <span>Original</span>;
95+
});
96+
97+
provideExtensions({
98+
alternatives: {
99+
TestComponent() {
100+
return <span>Alternative</span>;
101+
}
102+
}
103+
});
104+
105+
const {container} = render(
106+
<StaticPreview>
107+
<TestComponent />
108+
</StaticPreview>
109+
);
110+
111+
expect(container).toHaveTextContent('Original');
112+
expect(container).not.toHaveTextContent('Alternative');
113+
});
114+
});
115+
116+
describe('provideExtensions', () => {
117+
it('re-renders decorator after mount', () => {
118+
const TestComponent = extensible('TestComponent', function TestComponent() {
119+
return <span>Component</span>;
120+
});
121+
122+
const {container} = render(<ExtensionsProvider><TestComponent /></ExtensionsProvider>);
123+
expect(container).not.toHaveTextContent('Decorator');
124+
125+
act(() => {
126+
provideExtensions({
127+
decorators: {
128+
TestComponent({children}) {
129+
return <div>Decorator{children}</div>;
130+
}
131+
}
132+
});
133+
});
134+
135+
expect(container).toHaveTextContent('DecoratorComponent');
136+
});
137+
138+
it('re-renders alternative after mount', () => {
139+
const TestComponent = extensible('TestComponent', function TestComponent() {
140+
return <span>Original</span>;
141+
});
142+
143+
const {container} = render(<ExtensionsProvider><TestComponent /></ExtensionsProvider>);
144+
expect(container).toHaveTextContent('Original');
145+
146+
act(() => {
147+
provideExtensions({
148+
alternatives: {
149+
TestComponent() {
150+
return <span>Alternative</span>;
151+
}
152+
}
153+
});
154+
});
155+
156+
expect(container).toHaveTextContent('Alternative');
157+
expect(container).not.toHaveTextContent('Original');
158+
});
159+
160+
161+
it('replaces previous extensions', () => {
162+
const TestComponent = extensible('TestComponent', function TestComponent() {
163+
return <span>Original</span>;
164+
});
165+
166+
provideExtensions({
167+
alternatives: {
168+
TestComponent() {
169+
return <span>First</span>;
170+
}
171+
}
172+
});
173+
174+
provideExtensions({
175+
alternatives: {
176+
TestComponent() {
177+
return <span>Second</span>;
178+
}
179+
}
180+
});
181+
182+
const {container} = render(<TestComponent />);
183+
184+
expect(container).toHaveTextContent('Second');
185+
expect(container).not.toHaveTextContent('First');
186+
});
187+
});
188+
});

entry_types/scrolled/package/spec/frontend/inlineEditing-spec.js

Lines changed: 0 additions & 51 deletions
This file was deleted.

entry_types/scrolled/package/spec/frontend/inlineEditingWithLoadedComponents-spec.js

Lines changed: 0 additions & 87 deletions
This file was deleted.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import {withInlineEditingAlternative} from './inlineEditing';
1+
import {extensible} from './extensions';
22

3-
export const ActionButton = withInlineEditingAlternative('ActionButton', function ActionButton() {
3+
export const ActionButton = extensible('ActionButton', function ActionButton() {
44
return null;
55
});
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import {withInlineEditingAlternative} from './inlineEditing';
1+
import {extensible} from './extensions';
22

3-
export const ActionButtons = withInlineEditingAlternative('ActionButtons', function ActionButtons() {
3+
export const ActionButtons = extensible('ActionButtons', function ActionButtons() {
44
return null;
55
});

entry_types/scrolled/package/src/frontend/Backdrop/BackgroundContentElement.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import React, {useMemo} from 'react';
33
import {ContentElement} from '../ContentElement';
44
import {useSectionLifecycle} from '../useSectionLifecycle';
55

6-
import {withInlineEditingDecorator} from '../inlineEditing';
6+
import {extensible} from '../extensions';
77

8-
export const BackgroundContentElement = withInlineEditingDecorator(
9-
'BackgroundContentElementDecorator',
8+
export const BackgroundContentElement = extensible(
9+
'BackgroundContentElement',
1010
function BackgroundContentElement({
1111
contentElement, isIntersecting, onMotifAreaUpdate, containerDimension
1212
}) {

entry_types/scrolled/package/src/frontend/Backdrop/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import classNames from 'classnames';
33

4-
import {withInlineEditingDecorator} from '../inlineEditing';
4+
import {extensible} from '../extensions';
55
import useDimension from '../useDimension';
66
import {useSectionLifecycle} from '../useSectionLifecycle';
77

@@ -10,7 +10,7 @@ import {BackgroundAsset} from './BackgroundAsset';
1010
import styles from '../Backdrop.module.css';
1111
import sharedTransitionStyles from '../transitions/shared.module.css';
1212

13-
export const Backdrop = withInlineEditingDecorator('BackdropDecorator', function Backdrop(props) {
13+
export const Backdrop = extensible('Backdrop', function Backdrop(props) {
1414
const [containerDimension, setContainerRef] = useDimension();
1515
const {shouldLoad} = useSectionLifecycle();
1616

entry_types/scrolled/package/src/frontend/Content.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {VhFix} from './VhFix';
55
import {useActiveExcursion} from './useActiveExcursion';
66
import {useCurrentSectionIndexState} from './useCurrentChapter';
77
import {useEntryStructure} from '../entryState';
8-
import {withInlineEditingDecorator} from './inlineEditing';
8+
import {extensible} from './extensions';
99
import {usePostMessageListener} from './usePostMessageListener';
1010
import {useSectionChangeEvents} from './useSectionChangeEvents';
1111
import {sectionChangeMessagePoster} from './sectionChangeMessagePoster';
@@ -22,7 +22,7 @@ import {
2222

2323
import styles from './Content.module.css';
2424

25-
export const Content = withInlineEditingDecorator('ContentDecorator', function Content(props) {
25+
export const Content = extensible('Content', function Content(props) {
2626
const entryStructure = useEntryStructure();
2727
const scrollToTarget = useScrollToTarget();
2828

0 commit comments

Comments
 (0)