Skip to content
Merged
Show file tree
Hide file tree
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
39 changes: 20 additions & 19 deletions packages/react-dom/src/__tests__/ReactDOMServerIntegration-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2671,26 +2671,27 @@ describe('ReactDOMServerIntegration', () => {
},
);

// TODO: this being DEV-only is likely a bug.
// https://github.com/facebook/react/issues/11618
if (__DEV__) {
itThrowsWhenRendering(
'if getChildContext exists without childContextTypes',
render => {
class MyComponent extends React.Component {
render() {
return <div />;
}
getChildContext() {
return {foo: 'bar'};
}
itRenders(
'if getChildContext exists but childContextTypes is missing with a warning',
async render => {
function HopefulChild(props, context) {
return context.foo || 'nope';
}
HopefulChild.contextTypes = {
foo: PropTypes.string,
};
class ForgetfulParent extends React.Component {
render() {
return <HopefulChild />;
}
return render(<MyComponent />);
},
'MyComponent.getChildContext(): childContextTypes must be defined ' +
'in order to use getChildContext().',
);
}
getChildContext() {
return {foo: 'bar'};
}
}
const e = await render(<ForgetfulParent />, 1);
expect(e.textContent).toBe('nope');
},
);

itThrowsWhenRendering(
'if getChildContext returns a value not in childContextTypes',
Expand Down
27 changes: 15 additions & 12 deletions packages/react-dom/src/server/ReactPartialRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -461,19 +461,22 @@ function resolve(
var childContext;
if (typeof inst.getChildContext === 'function') {
var childContextTypes = Component.childContextTypes;
invariant(
typeof childContextTypes === 'object',
'%s.getChildContext(): childContextTypes must be defined in order to ' +
'use getChildContext().',
getComponentName(Component) || 'Unknown',
);
childContext = inst.getChildContext();
for (let contextKey in childContext) {
invariant(
contextKey in childContextTypes,
'%s.getChildContext(): key "%s" is not defined in childContextTypes.',
if (typeof childContextTypes === 'object') {
childContext = inst.getChildContext();
for (let contextKey in childContext) {
invariant(
contextKey in childContextTypes,
'%s.getChildContext(): key "%s" is not defined in childContextTypes.',
getComponentName(Component) || 'Unknown',
contextKey,
);
}
} else {
warning(
false,
'%s.getChildContext(): childContextTypes must be defined in order to ' +
'use getChildContext().',
getComponentName(Component) || 'Unknown',
contextKey,
);
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/react-reconciler/src/ReactFiberClassComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -328,14 +328,14 @@ export default function(

const state = instance.state;
if (state && (typeof state !== 'object' || isArray(state))) {
invariant(
warning(
false,
'%s.state: must be set to an object or null',
getComponentName(workInProgress),
);
}
if (typeof instance.getChildContext === 'function') {
invariant(
warning(
typeof workInProgress.type.childContextTypes === 'object',
'%s.getChildContext(): childContextTypes must be defined in order to ' +
'use getChildContext().',
Expand Down
20 changes: 8 additions & 12 deletions packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,9 @@ describe 'ReactCoffeeScriptClass', ->
expect(renderCount).toBe 1
undefined

it 'should throw with non-object in the initial state property', ->
it 'should warn with non-object in the initial state property', ->
spyOnDev console, 'error'

[['an array'], 'a string', 1234].forEach (state) ->
class Foo extends React.Component
constructor: ->
Expand All @@ -158,20 +160,14 @@ describe 'ReactCoffeeScriptClass', ->
render: ->
span()

test React.createElement(Foo), 'SPAN', ''
if __DEV__
expect(->
test React.createElement(Foo), 'SPAN', ''
).toThrowError(
expect(console.error.calls.count()).toBe 1
expect(console.error.calls.argsFor(0)[0]).toContain(
'Foo.state: must be set to an object or null'
)
else
# This is a difference between development and production.
# I'm not sure if this is intentional, as generally we avoid this.
# TODO: investigate if this was intentional or an oversight.
# https://github.com/facebook/react/issues/11618
expect(->
test React.createElement(Foo), 'SPAN', ''
).not.toThrowError()
console.error.calls.reset()

undefined

it 'should render with null in the initial state property', ->
Expand Down
14 changes: 6 additions & 8 deletions packages/react/src/__tests__/ReactES6Class-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ describe('ReactES6Class', () => {
expect(renderCount).toBe(1);
});

it('should throw with non-object in the initial state property', () => {
it('should warn with non-object in the initial state property', () => {
spyOnDev(console, 'error');
[['an array'], 'a string', 1234].forEach(function(state) {
class Foo extends React.Component {
constructor() {
Expand All @@ -174,16 +175,13 @@ describe('ReactES6Class', () => {
return <span />;
}
}
test(<Foo />, 'SPAN', '');
if (__DEV__) {
expect(() => test(<Foo />, 'SPAN', '')).toThrowError(
expect(console.error.calls.count()).toBe(1);
expect(console.error.calls.argsFor(0)[0]).toContain(
'Foo.state: must be set to an object or null',
);
} else {
// This is a difference between development and production.
// I'm not sure if this is intentional, as generally we avoid this.
// TODO: investigate if this was intentional or an oversight.
// https://github.com/facebook/react/issues/11618
expect(() => test(<Foo />, 'SPAN', '')).not.toThrowError();
console.error.calls.reset();
}
});
});
Expand Down
36 changes: 18 additions & 18 deletions packages/react/src/__tests__/ReactTypeScriptClass-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -361,31 +361,31 @@ describe('ReactTypeScriptClass', function() {
expect(renderCount).toBe(1);
});

it('should throw with non-object in the initial state property', function() {
it('should warn with non-object in the initial state property', function() {
spyOnDev(console, 'error');
test(React.createElement(ArrayState), 'SPAN', '');
if (__DEV__) {
expect(() => test(React.createElement(ArrayState), 'SPAN', ''))
.toThrowError(
expect((<any>console.error).calls.count()).toBe(1);
expect((<any>console.error).calls.argsFor(0)[0]).toContain(
'ArrayState.state: must be set to an object or null'
);
expect(() => test(React.createElement(StringState), 'SPAN', ''))
.toThrowError(
(<any>console.error).calls.reset()
}
test(React.createElement(StringState), 'SPAN', '');
if (__DEV__) {
expect((<any>console.error).calls.count()).toBe(1);
expect((<any>console.error).calls.argsFor(0)[0]).toContain(
'StringState.state: must be set to an object or null'
);
expect(() => test(React.createElement(NumberState), 'SPAN', ''))
.toThrowError(
(<any>console.error).calls.reset()
}
test(React.createElement(NumberState), 'SPAN', '');
if (__DEV__) {
expect((<any>console.error).calls.count()).toBe(1);
expect((<any>console.error).calls.argsFor(0)[0]).toContain(
'NumberState.state: must be set to an object or null'
);
} else {
// This is a difference between development and production.
// I'm not sure if this is intentional, as generally we avoid this.
// TODO: investigate if this was intentional or an oversight.
// https://github.com/facebook/react/issues/11618
expect(() => test(React.createElement(ArrayState), 'SPAN', ''))
.not.toThrowError();
expect(() => test(React.createElement(StringState), 'SPAN', ''))
.not.toThrowError();
expect(() => test(React.createElement(NumberState), 'SPAN', ''))
.not.toThrowError();
(<any>console.error).calls.reset()
}
});

Expand Down