Skip to content

Commit 951bf8a

Browse files
committed
Add support for defaultProps on both pure and class components (+ tests). Fixes #5.
1 parent 3ba6c89 commit 951bf8a

File tree

2 files changed

+53
-14
lines changed

2 files changed

+53
-14
lines changed

src/index.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,19 @@ let indent = (s, char) => String(s).replace(/(\n+)/g, '$1' + (char || '\t'));
4646

4747
let isLargeString = s => (String(s).length>40 || String(s).indexOf('\n')!==-1 || String(s).indexOf('<')!==-1);
4848

49+
function assign(obj, props) {
50+
for (let i in props) obj[i] = props[i];
51+
return obj;
52+
}
53+
54+
function getNodeProps(vnode) {
55+
let defaultProps = vnode.nodeName.defaultProps,
56+
props = assign({}, defaultProps || vnode.attributes);
57+
if (defaultProps) assign(props, vnode.attributes);
58+
if (vnode.children) props.children = vnode.children;
59+
return props;
60+
}
61+
4962
/** Render Preact JSX + Components to an HTML string.
5063
* @name render
5164
* @function
@@ -97,7 +110,7 @@ export default function renderToString(vnode, context, opts, inner) {
97110
nodeName = getComponentName(nodeName);
98111
}
99112
else {
100-
let props = { children, ...attributes },
113+
let props = getNodeProps(vnode),
101114
rendered;
102115

103116
if (!nodeName.prototype || typeof nodeName.prototype.render!=='function') {

test/render.js

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ describe('render', () => {
2020

2121
expect(rendered).to.equal(expected);
2222

23-
expect(render(<div foo={0} />)).to.equal(`<div foo="0"></div>`)
23+
expect(render(<div foo={0} />)).to.equal(`<div foo="0"></div>`);
2424
});
2525

2626
it('should collapse collapsible attributes', () => {
@@ -110,17 +110,27 @@ describe('render', () => {
110110
match({})
111111
);
112112
});
113+
114+
it('should apply defaultProps', () => {
115+
const Test = props => <div {...props} />;
116+
Test.defaultProps = {
117+
foo: 'default foo',
118+
bar: 'default bar'
119+
};
120+
121+
expect(render(<Test />), 'defaults').to.equal('<div foo="default foo" bar="default bar"></div>');
122+
expect(render(<Test bar="b" />), 'partial').to.equal('<div foo="default foo" bar="b"></div>');
123+
expect(render(<Test foo="a" bar="b" />), 'overridden').to.equal('<div foo="a" bar="b"></div>');
124+
});
113125
});
114126

115127
describe('Classical Components', () => {
116128
it('should render classical components', () => {
117-
class Test extends Component {
129+
let Test = spy(class Test extends Component {
118130
render({ foo, children }, state) {
119131
return <div foo={foo}>{ children }</div>;
120132
}
121-
}
122-
123-
Test = spy(Test);
133+
});
124134
spy(Test.prototype, 'render');
125135

126136
let rendered = render(<Test foo="test">content</Test>);
@@ -147,13 +157,12 @@ describe('render', () => {
147157
});
148158

149159
it('should render classical components within JSX', () => {
150-
class Test extends Component {
160+
let Test = spy(class Test extends Component {
151161
render({ foo, children }, state) {
152162
return <div foo={foo}>{ children }</div>;
153163
}
154-
}
164+
});
155165

156-
Test = spy(Test);
157166
spy(Test.prototype, 'render');
158167

159168
let rendered = render(
@@ -180,6 +189,22 @@ describe('render', () => {
180189
match({})
181190
);
182191
});
192+
193+
it('should apply defaultProps', () => {
194+
class Test extends Component {
195+
static defaultProps = {
196+
foo: 'default foo',
197+
bar: 'default bar'
198+
};
199+
render(props) {
200+
return <div {...props} />;
201+
}
202+
}
203+
204+
expect(render(<Test />), 'defaults').to.equal('<div foo="default foo" bar="default bar"></div>');
205+
expect(render(<Test bar="b" />), 'partial').to.equal('<div foo="default foo" bar="b"></div>');
206+
expect(render(<Test foo="a" bar="b" />), 'overridden').to.equal('<div foo="a" bar="b"></div>');
207+
});
183208
});
184209

185210
describe('High-order components', () => {
@@ -206,18 +231,19 @@ describe('render', () => {
206231
});
207232

208233
it('should render nested high order components when shallowHighOrder=false', () => {
209-
const Outer = () => <Middle />;
210-
const Middle = () => <div><Inner /></div>;
211-
const Inner = () => 'hi';
234+
// using functions for meaningful generation of displayName
235+
function Outer() { return <Middle />; }
236+
function Middle() { return <div><Inner /></div>; }
237+
function Inner() { return 'hi'; }
212238

213239
let rendered = render(<Outer />);
214240
expect(rendered).to.equal('<div>hi</div>');
215241

216242
rendered = render(<Outer />, null, { shallow:true });
217-
expect(rendered).to.equal('<Middle></Middle>');
243+
expect(rendered, '{shallow:true}').to.equal('<Middle></Middle>');
218244

219245
rendered = render(<Outer />, null, { shallow:true, shallowHighOrder:false });
220-
expect(rendered).to.equal('<div><Inner></Inner></div>', 'but it should never render nested grandchild components');
246+
expect(rendered, '{shallow:true,shallowHighOrder:false}').to.equal('<div><Inner></Inner></div>', 'but it should never render nested grandchild components');
221247
});
222248
});
223249

0 commit comments

Comments
 (0)