Skip to content

Commit 61c7bff

Browse files
tyao1facebook-github-bot
authored andcommitted
Regression test for mutating complex resolver values
Reviewed By: alunyov Differential Revision: D50764867 fbshipit-source-id: ae20dcd9f41b00ea3d5820dc54d79dfa81dbbaf6
1 parent 7bca4e1 commit 61c7bff

File tree

3 files changed

+246
-0
lines changed

3 files changed

+246
-0
lines changed

packages/react-relay/__tests__/RelayResolverModel-test.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ const {
3434
completeTodo,
3535
resetStore,
3636
} = require('relay-runtime/store/__tests__/resolvers/ExampleTodoStore');
37+
const {
38+
chargeBattery,
39+
resetModels,
40+
setIsHuman,
41+
} = require('relay-runtime/store/__tests__/resolvers/MutableModel');
3742
const LiveResolverStore = require('relay-runtime/store/experimental-live-resolvers/LiveResolverStore.js');
3843
const RelayModernEnvironment = require('relay-runtime/store/RelayModernEnvironment');
3944
const RelayRecordSource = require('relay-runtime/store/RelayRecordSource');
@@ -494,4 +499,53 @@ describe.each([
494499
},
495500
});
496501
});
502+
503+
test('should not mutate complex resolver values', () => {
504+
resetModels();
505+
// Do not deep freeze
506+
jest.mock('relay-runtime/util/deepFreeze');
507+
508+
TestRenderer.act(() => {
509+
setIsHuman(true);
510+
});
511+
function GetMutableEntity() {
512+
const data = useClientQuery(
513+
graphql`
514+
query RelayResolverModelTestGetMutableEntityQuery {
515+
mutable_entity
516+
}
517+
`,
518+
{},
519+
);
520+
if (data.mutable_entity == null) {
521+
return null;
522+
}
523+
return `${data.mutable_entity.type}:${data.mutable_entity.props.battery}`;
524+
}
525+
526+
const renderer = TestRenderer.create(
527+
<EnvironmentWrapper environment={environment}>
528+
<GetMutableEntity />
529+
</EnvironmentWrapper>,
530+
);
531+
expect(renderer.toJSON()).toEqual('human:0');
532+
533+
TestRenderer.act(() => {
534+
setIsHuman(false);
535+
jest.runAllImmediates();
536+
});
537+
expect(renderer.toJSON()).toEqual('robot:0');
538+
539+
TestRenderer.act(() => {
540+
chargeBattery();
541+
setIsHuman(true);
542+
jest.runAllImmediates();
543+
});
544+
// TODO: Should be 0. Relay should not mutate the value here.
545+
expect(renderer.toJSON()).toEqual('human:100');
546+
547+
TestRenderer.act(() => {
548+
renderer.unmount();
549+
});
550+
});
497551
});

packages/react-relay/__tests__/__generated__/RelayResolverModelTestGetMutableEntityQuery.graphql.js

Lines changed: 99 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow strict-local
8+
* @format
9+
* @oncall relay
10+
*/
11+
12+
'use strict';
13+
14+
import type {LiveState} from '../../experimental-live-resolvers/LiveResolverStore';
15+
16+
type Entity = {
17+
name: string,
18+
type: string,
19+
props: {
20+
battery: string,
21+
},
22+
};
23+
24+
let HUMAN: Entity = {
25+
name: 'Alice',
26+
type: 'human',
27+
props: {
28+
battery: '0',
29+
},
30+
};
31+
32+
let ROBOT: Entity = {
33+
name: 'Bob',
34+
type: 'robot',
35+
props: {
36+
battery: '0',
37+
},
38+
};
39+
40+
const subscriptions: Array<() => void> = [];
41+
let isHuman: boolean = true;
42+
/**
43+
* @RelayResolver Query.mutable_entity: RelayResolverValue
44+
* @live
45+
46+
*/
47+
function mutable_entity(): LiveState<Entity> {
48+
return {
49+
read() {
50+
return isHuman ? HUMAN : ROBOT;
51+
},
52+
subscribe(cb) {
53+
subscriptions.push(cb);
54+
return () => {
55+
subscriptions.filter(x => x !== cb);
56+
};
57+
},
58+
};
59+
}
60+
61+
function setIsHuman(val: boolean): void {
62+
isHuman = val;
63+
subscriptions.forEach(x => x());
64+
}
65+
66+
function chargeBattery(): void {
67+
ROBOT.props.battery = '100';
68+
subscriptions.forEach(x => x());
69+
}
70+
71+
function resetModels(): void {
72+
HUMAN = {
73+
name: 'Alice',
74+
type: 'human',
75+
props: {
76+
battery: '0',
77+
},
78+
};
79+
ROBOT = {
80+
name: 'Bob',
81+
type: 'robot',
82+
props: {
83+
battery: '0',
84+
},
85+
};
86+
}
87+
88+
module.exports = {
89+
mutable_entity,
90+
setIsHuman,
91+
chargeBattery,
92+
resetModels,
93+
};

0 commit comments

Comments
 (0)