Skip to content

Commit 8302467

Browse files
authored
Merge pull request #100 from gadget-inc/resolve-order-blindness
Ensure types.maybe(types.reference()) types are resolved late after construction
2 parents db09494 + 4defbd2 commit 8302467

File tree

4 files changed

+486
-230
lines changed

4 files changed

+486
-230
lines changed

spec/class-model-references.spec.ts

Lines changed: 146 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
import { read } from "fs";
12
import type { IAnyClassModelType, InstanceWithoutSTNTypeForType, IReferenceType, StateTreeNode } from "../src";
23
import { Instance, types } from "../src";
34
import { action, ClassModel, register } from "../src/class-model";
5+
import { Apple } from "./fixtures/FruitAisle";
6+
import { NameExample } from "./fixtures/NameExample";
47
import { create } from "./helpers";
58

69
@register
@@ -37,132 +40,175 @@ class Root extends ClassModel({
3740
refs: types.array(Referrable),
3841
}) {}
3942

40-
describe("clas model references", () => {
41-
test("can resolve valid references", () => {
42-
const root = create(
43-
Root,
44-
{
45-
model: {
46-
ref: "item-a",
43+
describe("class model references", () => {
44+
describe.each([
45+
["read-only", true],
46+
["observable", false],
47+
])("%s", (_name, readOnly) => {
48+
test("can resolve valid references", () => {
49+
const root = create(
50+
Root,
51+
{
52+
model: {
53+
ref: "item-a",
54+
},
55+
refs: [
56+
{ key: "item-a", count: 12 },
57+
{ key: "item-b", count: 523 },
58+
],
4759
},
48-
refs: [
49-
{ key: "item-a", count: 12 },
50-
{ key: "item-b", count: 523 },
51-
],
52-
},
53-
true,
54-
);
60+
readOnly,
61+
);
5562

56-
expect(root.model.ref).toEqual(
57-
expect.objectContaining({
58-
key: "item-a",
59-
count: 12,
60-
}),
61-
);
62-
});
63+
expect(root.model.ref).toEqual(
64+
expect.objectContaining({
65+
key: "item-a",
66+
count: 12,
67+
}),
68+
);
69+
});
70+
71+
test("throws for invalid refs", () => {
72+
const createRoot = () => {
73+
const instance = create(
74+
Root,
75+
{
76+
model: {
77+
ref: "item-c",
78+
},
79+
refs: [
80+
{ key: "item-a", count: 12 },
81+
{ key: "item-b", count: 523 },
82+
],
83+
},
84+
readOnly,
85+
);
86+
instance.model.ref;
87+
};
6388

64-
test("throws for invalid refs", () => {
65-
const createRoot = () =>
66-
create(
89+
expect(createRoot).toThrow();
90+
});
91+
92+
test("can resolve valid safe references", () => {
93+
const root = create(
6794
Root,
6895
{
6996
model: {
70-
ref: "item-c",
97+
ref: "item-a",
98+
safeRef: "item-b",
7199
},
72100
refs: [
73101
{ key: "item-a", count: 12 },
74102
{ key: "item-b", count: 523 },
75103
],
76104
},
77-
true,
105+
readOnly,
78106
);
79107

80-
expect(createRoot).toThrow();
81-
});
108+
expect(root.model.safeRef).toEqual(
109+
expect.objectContaining({
110+
key: "item-b",
111+
count: 523,
112+
}),
113+
);
114+
});
82115

83-
test("can resolve valid safe references", () => {
84-
const root = create(
85-
Root,
86-
{
87-
model: {
88-
ref: "item-a",
89-
safeRef: "item-b",
116+
test("does not throw for invalid safe references", () => {
117+
const root = create(
118+
Root,
119+
{
120+
model: {
121+
ref: "item-a",
122+
safeRef: "item-c",
123+
},
124+
refs: [
125+
{ key: "item-a", count: 12 },
126+
{ key: "item-b", count: 523 },
127+
],
90128
},
91-
refs: [
92-
{ key: "item-a", count: 12 },
93-
{ key: "item-b", count: 523 },
94-
],
95-
},
96-
true,
97-
);
129+
readOnly,
130+
);
98131

99-
expect(root.model.safeRef).toEqual(
100-
expect.objectContaining({
101-
key: "item-b",
102-
count: 523,
103-
}),
104-
);
105-
});
132+
expect(root.model.safeRef).toBeUndefined();
133+
});
106134

107-
test("does not throw for invalid safe references", () => {
108-
const root = create(
109-
Root,
110-
{
111-
model: {
112-
ref: "item-a",
113-
safeRef: "item-c",
135+
test("references are equal to the instances they refer to", () => {
136+
const root = create(
137+
Root,
138+
{
139+
model: {
140+
ref: "item-a",
141+
safeRef: "item-b",
142+
},
143+
refs: [
144+
{ key: "item-a", count: 12 },
145+
{ key: "item-b", count: 523 },
146+
],
114147
},
115-
refs: [
116-
{ key: "item-a", count: 12 },
117-
{ key: "item-b", count: 523 },
118-
],
119-
},
120-
true,
121-
);
148+
readOnly,
149+
);
122150

123-
expect(root.model.safeRef).toBeUndefined();
124-
});
151+
expect(root.model.ref).toBe(root.refs[0]);
152+
expect(root.model.ref).toEqual(root.refs[0]);
153+
expect(root.model.ref).toStrictEqual(root.refs[0]);
154+
});
125155

126-
test("references are equal to the instances they refer to", () => {
127-
const root = create(
128-
Root,
129-
{
130-
model: {
131-
ref: "item-a",
132-
safeRef: "item-b",
156+
test("safe references are equal to the instances they refer to", () => {
157+
const root = create(
158+
Root,
159+
{
160+
model: {
161+
ref: "item-a",
162+
safeRef: "item-b",
163+
},
164+
refs: [
165+
{ key: "item-a", count: 12 },
166+
{ key: "item-b", count: 523 },
167+
],
133168
},
134-
refs: [
135-
{ key: "item-a", count: 12 },
136-
{ key: "item-b", count: 523 },
137-
],
138-
},
139-
true,
140-
);
169+
readOnly,
170+
);
141171

142-
expect(root.model.ref).toBe(root.refs[0]);
143-
expect(root.model.ref).toEqual(root.refs[0]);
144-
expect(root.model.ref).toStrictEqual(root.refs[0]);
145-
});
172+
expect(root.model.safeRef).toBe(root.refs[1]);
173+
expect(root.model.safeRef).toEqual(root.refs[1]);
174+
expect(root.model.safeRef).toStrictEqual(root.refs[1]);
175+
});
146176

147-
test("safe references are equal to the instances they refer to", () => {
148-
const root = create(
149-
Root,
150-
{
151-
model: {
152-
ref: "item-a",
153-
safeRef: "item-b",
177+
@register
178+
class Weird extends ClassModel({
179+
examples: types.map(NameExample),
180+
obj: types.union(types.reference(NameExample), Apple),
181+
}) {}
182+
183+
test("unions where one type is a reference can be resolved as references", () => {
184+
const instance = create(
185+
Weird,
186+
{
187+
examples: {
188+
foo: { key: "foo", name: "foo" },
189+
},
190+
obj: "foo",
154191
},
155-
refs: [
156-
{ key: "item-a", count: 12 },
157-
{ key: "item-b", count: 523 },
158-
],
159-
},
160-
true,
161-
);
192+
readOnly,
193+
);
194+
195+
expect((instance.obj as NameExample).name).toEqual("foo");
196+
});
197+
198+
test("unions where one type is a reference can be resolved a the non-reference type", () => {
199+
const instance = create(
200+
Weird,
201+
{
202+
examples: {
203+
foo: { key: "foo", name: "foo" },
204+
},
205+
obj: { type: "Apple", ripeness: 1 },
206+
},
207+
readOnly,
208+
);
162209

163-
expect(root.model.safeRef).toBe(root.refs[1]);
164-
expect(root.model.safeRef).toEqual(root.refs[1]);
165-
expect(root.model.safeRef).toStrictEqual(root.refs[1]);
210+
expect((instance.obj as Apple).ripeness).toEqual(1);
211+
});
166212
});
167213
});
168214

0 commit comments

Comments
 (0)