Skip to content

Commit

Permalink
Unify noop and test renderer assertion APIs (#14952)
Browse files Browse the repository at this point in the history
* Throw in tests if work is done before emptying log

Test renderer already does this. Makes it harder to miss unexpected
behavior by forcing you to assert on every logged value.

* Convert ReactNoop tests to use jest matchers

The matchers warn if work is flushed while the log is empty. This is
the pattern we already follow for test renderer. I've used the same APIs
as test renderer, so it should be easy to switch between the two.
  • Loading branch information
acdlite authored Feb 26, 2019
1 parent 870214f commit 8e25ed2
Show file tree
Hide file tree
Showing 30 changed files with 1,072 additions and 1,004 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,16 @@ describe('createSubscription', () => {
);

// Updates while subscribed should re-render the child component
expect(ReactNoop.flush()).toEqual(['default']);
expect(ReactNoop).toFlushAndYield(['default']);
observable.next(123);
expect(ReactNoop.flush()).toEqual([123]);
expect(ReactNoop).toFlushAndYield([123]);
observable.next('abc');
expect(ReactNoop.flush()).toEqual(['abc']);
expect(ReactNoop).toFlushAndYield(['abc']);

// Unmounting the subscriber should remove listeners
ReactNoop.render(<div />);
observable.next(456);
expect(ReactNoop.flush()).toEqual([]);
expect(ReactNoop).toFlushAndYield([]);
});

it('should support observable types like RxJS ReplaySubject', () => {
Expand Down Expand Up @@ -102,13 +102,13 @@ describe('createSubscription', () => {
const observable = createReplaySubject('initial');

ReactNoop.render(<Subscription source={observable}>{render}</Subscription>);
expect(ReactNoop.flush()).toEqual(['initial']);
expect(ReactNoop).toFlushAndYield(['initial']);
observable.next('updated');
expect(ReactNoop.flush()).toEqual(['updated']);
expect(ReactNoop).toFlushAndYield(['updated']);

// Unsetting the subscriber prop should reset subscribed values
ReactNoop.render(<Subscription>{render}</Subscription>);
expect(ReactNoop.flush()).toEqual(['default']);
expect(ReactNoop).toFlushAndYield(['default']);
});

describe('Promises', () => {
Expand Down Expand Up @@ -141,19 +141,19 @@ describe('createSubscription', () => {

// Test a promise that resolves after render
ReactNoop.render(<Subscription source={promiseA}>{render}</Subscription>);
expect(ReactNoop.flush()).toEqual(['loading']);
expect(ReactNoop).toFlushAndYield(['loading']);
resolveA(true);
await promiseA;
expect(ReactNoop.flush()).toEqual(['finished']);
expect(ReactNoop).toFlushAndYield(['finished']);

// Test a promise that resolves before render
// Note that this will require an extra render anyway,
// Because there is no way to synchronously get a Promise's value
rejectB(false);
ReactNoop.render(<Subscription source={promiseB}>{render}</Subscription>);
expect(ReactNoop.flush()).toEqual(['loading']);
expect(ReactNoop).toFlushAndYield(['loading']);
await promiseB.catch(() => true);
expect(ReactNoop.flush()).toEqual(['failed']);
expect(ReactNoop).toFlushAndYield(['failed']);
});

it('should still work if unsubscription is managed incorrectly', async () => {
Expand All @@ -177,17 +177,17 @@ describe('createSubscription', () => {

// Subscribe first to Promise A then Promise B
ReactNoop.render(<Subscription source={promiseA}>{render}</Subscription>);
expect(ReactNoop.flush()).toEqual(['default']);
expect(ReactNoop).toFlushAndYield(['default']);
ReactNoop.render(<Subscription source={promiseB}>{render}</Subscription>);
expect(ReactNoop.flush()).toEqual(['default']);
expect(ReactNoop).toFlushAndYield(['default']);

// Resolve both Promises
resolveB(123);
resolveA('abc');
await Promise.all([promiseA, promiseB]);

// Ensure that only Promise B causes an update
expect(ReactNoop.flush()).toEqual([123]);
expect(ReactNoop).toFlushAndYield([123]);
});

it('should not call setState for a Promise that resolves after unmount', async () => {
Expand All @@ -211,11 +211,11 @@ describe('createSubscription', () => {
});

ReactNoop.render(<Subscription source={promise}>{render}</Subscription>);
expect(ReactNoop.flush()).toEqual(['rendered']);
expect(ReactNoop).toFlushAndYield(['rendered']);

// Unmount
ReactNoop.render(null);
ReactNoop.flush();
expect(ReactNoop).toFlushWithoutYielding();

// Resolve Promise should not trigger a setState warning
resolvePromise(true);
Expand Down Expand Up @@ -245,21 +245,21 @@ describe('createSubscription', () => {
);

// Updates while subscribed should re-render the child component
expect(ReactNoop.flush()).toEqual(['a-0']);
expect(ReactNoop).toFlushAndYield(['a-0']);

// Unsetting the subscriber prop should reset subscribed values
ReactNoop.render(
<Subscription source={observableB}>{render}</Subscription>,
);
expect(ReactNoop.flush()).toEqual(['b-0']);
expect(ReactNoop).toFlushAndYield(['b-0']);

// Updates to the old subscribable should not re-render the child component
observableA.next('a-1');
expect(ReactNoop.flush()).toEqual([]);
expect(ReactNoop).toFlushAndYield([]);

// Updates to the bew subscribable should re-render the child component
observableB.next('b-1');
expect(ReactNoop.flush()).toEqual(['b-1']);
expect(ReactNoop).toFlushAndYield(['b-1']);
});

it('should ignore values emitted by a new subscribable until the commit phase', () => {
Expand Down Expand Up @@ -315,12 +315,12 @@ describe('createSubscription', () => {
const observableB = createBehaviorSubject('b-0');

ReactNoop.render(<Parent observed={observableA} />);
expect(ReactNoop.flush()).toEqual(['Subscriber: a-0', 'Child: a-0']);
expect(ReactNoop).toFlushAndYield(['Subscriber: a-0', 'Child: a-0']);
expect(log).toEqual(['Parent.componentDidMount']);

// Start React update, but don't finish
ReactNoop.render(<Parent observed={observableB} />);
ReactNoop.flushThrough(['Subscriber: b-0']);
expect(ReactNoop).toFlushAndYieldThrough(['Subscriber: b-0']);
expect(log).toEqual(['Parent.componentDidMount']);

// Emit some updates from the uncommitted subscribable
Expand All @@ -335,7 +335,7 @@ describe('createSubscription', () => {
// We expect the last emitted update to be rendered (because of the commit phase value check)
// But the intermediate ones should be ignored,
// And the final rendered output should be the higher-priority observable.
expect(ReactNoop.flush()).toEqual([
expect(ReactNoop).toFlushAndYield([
'Child: b-0',
'Subscriber: b-3',
'Child: b-3',
Expand Down Expand Up @@ -402,12 +402,12 @@ describe('createSubscription', () => {
const observableB = createBehaviorSubject('b-0');

ReactNoop.render(<Parent observed={observableA} />);
expect(ReactNoop.flush()).toEqual(['Subscriber: a-0', 'Child: a-0']);
expect(ReactNoop).toFlushAndYield(['Subscriber: a-0', 'Child: a-0']);
expect(log).toEqual(['Parent.componentDidMount']);

// Start React update, but don't finish
ReactNoop.render(<Parent observed={observableB} />);
ReactNoop.flushThrough(['Subscriber: b-0']);
expect(ReactNoop).toFlushAndYieldThrough(['Subscriber: b-0']);
expect(log).toEqual(['Parent.componentDidMount']);

// Emit some updates from the old subscribable
Expand All @@ -420,7 +420,7 @@ describe('createSubscription', () => {
// Flush everything and ensure that the correct subscribable is used
// We expect the new subscribable to finish rendering,
// But then the updated values from the old subscribable should be used.
expect(ReactNoop.flush()).toEqual([
expect(ReactNoop).toFlushAndYield([
'Child: b-0',
'Subscriber: a-2',
'Child: a-2',
Expand All @@ -433,7 +433,7 @@ describe('createSubscription', () => {

// Updates from the new subscribable should be ignored.
observableB.next('b-1');
expect(ReactNoop.flush()).toEqual([]);
expect(ReactNoop).toFlushAndYield([]);
expect(log).toEqual([
'Parent.componentDidMount',
'Parent.componentDidUpdate',
Expand Down Expand Up @@ -479,7 +479,7 @@ describe('createSubscription', () => {
<Subscription source={observable}>{value => null}</Subscription>,
);

expect(ReactNoop.flush).toThrow(
expect(ReactNoop).toFlushAndThrow(
'A subscription must return an unsubscribe function.',
);
});
Expand Down
4 changes: 2 additions & 2 deletions packages/react-art/src/__tests__/ReactART-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ describe('ReactART', () => {
</CurrentRendererContext.Provider>,
);

ReactNoop.flushThrough(['A']);
expect(ReactNoop).toFlushAndYieldThrough(['A']);

ReactDOM.render(
<Surface>
Expand All @@ -400,7 +400,7 @@ describe('ReactART', () => {
expect(ops).toEqual([null, 'ART']);

ops = [];
expect(ReactNoop.flush()).toEqual(['B', 'C']);
expect(ReactNoop).toFlushAndYield(['B', 'C']);

expect(ops).toEqual(['Test']);
});
Expand Down
Loading

0 comments on commit 8e25ed2

Please sign in to comment.