xstate 3.2.1 → 3.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/launch.json +15 -13
- package/README.md +37 -9
- package/dist/xstate.js +1 -1
- package/dist/xstate.utils.js +1 -1
- package/es/Machine.d.ts +2 -2
- package/es/Machine.js +2 -2
- package/es/State.d.ts +8 -7
- package/es/State.js +3 -2
- package/es/StateNode.d.ts +50 -13
- package/es/StateNode.js +617 -412
- package/es/graph.d.ts +9 -6
- package/es/graph.js +31 -24
- package/es/patterns.js +1 -1
- package/es/scxml.d.ts +2 -1
- package/es/scxml.js +33 -10
- package/es/types.d.ts +38 -7
- package/es/utils.d.ts +14 -1
- package/es/utils.js +33 -5
- package/lib/Machine.d.ts +2 -2
- package/lib/Machine.js +2 -2
- package/lib/State.d.ts +8 -7
- package/lib/State.js +3 -2
- package/lib/StateNode.d.ts +50 -13
- package/lib/StateNode.js +616 -411
- package/lib/graph.d.ts +9 -6
- package/lib/graph.js +30 -22
- package/lib/patterns.js +1 -1
- package/lib/scxml.d.ts +2 -1
- package/lib/scxml.js +33 -10
- package/lib/types.d.ts +38 -7
- package/lib/utils.d.ts +14 -1
- package/lib/utils.js +35 -5
- package/package.json +3 -3
- package/src/Machine.ts +5 -3
- package/src/State.ts +10 -2
- package/src/StateNode.ts +966 -590
- package/src/graph.ts +60 -31
- package/src/scxml.ts +80 -49
- package/src/types.ts +48 -7
- package/src/utils.ts +52 -7
- package/test/actions.test.ts +24 -1
- package/test/activities.test.ts +165 -0
- package/test/deep.test.ts +14 -16
- package/test/deterministic.test.ts +26 -5
- package/test/examples/6.17.test.ts +64 -0
- package/test/fixtures/id.ts +1 -1
- package/test/graph.test.ts +39 -16
- package/test/guards.test.ts +172 -15
- package/test/history.test.ts +193 -58
- package/test/invalid.test.ts +48 -0
- package/test/multiple.test.ts +12 -18
- package/test/parallel.test.ts +472 -1
- package/test/scxml.test.ts +13 -4
- package/test/stateIn.test.ts +1 -1
- package/test/transient.test.ts +183 -1
package/test/activities.test.ts
CHANGED
|
@@ -35,6 +35,57 @@ const lightMachine = Machine({
|
|
|
35
35
|
}
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
+
describe('activities with guarded transitions', () => {
|
|
39
|
+
const machine = Machine({
|
|
40
|
+
initial: 'A',
|
|
41
|
+
states: {
|
|
42
|
+
A: {
|
|
43
|
+
on: {
|
|
44
|
+
E: 'B'
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
B: {
|
|
48
|
+
on: {
|
|
49
|
+
'': [{ cond: () => false, target: 'A' }]
|
|
50
|
+
},
|
|
51
|
+
activities: ['B_ACTIVITY']
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should activate even if there are subsequent automatic, but blocked transitions', () => {
|
|
57
|
+
let state = machine.initialState;
|
|
58
|
+
state = machine.transition(state, 'E');
|
|
59
|
+
assert.deepEqual(state.activities, { B_ACTIVITY: true });
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('remembering activities', () => {
|
|
64
|
+
const machine = Machine({
|
|
65
|
+
initial: 'A',
|
|
66
|
+
states: {
|
|
67
|
+
A: {
|
|
68
|
+
on: {
|
|
69
|
+
E: 'B'
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
B: {
|
|
73
|
+
on: {
|
|
74
|
+
E: 'A'
|
|
75
|
+
},
|
|
76
|
+
activities: ['B_ACTIVITY']
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should remember the activities even after an event', () => {
|
|
82
|
+
let state = machine.initialState;
|
|
83
|
+
state = machine.transition(state, 'E');
|
|
84
|
+
state = machine.transition(state, 'IGNORE');
|
|
85
|
+
assert.deepEqual(state.activities, { B_ACTIVITY: true });
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
38
89
|
describe('activities', () => {
|
|
39
90
|
it('identifies initial activities', () => {
|
|
40
91
|
const { initialState } = lightMachine;
|
|
@@ -92,3 +143,117 @@ describe('activities', () => {
|
|
|
92
143
|
]);
|
|
93
144
|
});
|
|
94
145
|
});
|
|
146
|
+
|
|
147
|
+
describe('transient activities', () => {
|
|
148
|
+
const machine = Machine({
|
|
149
|
+
parallel: true,
|
|
150
|
+
states: {
|
|
151
|
+
A: {
|
|
152
|
+
activities: ['A'],
|
|
153
|
+
initial: 'A1',
|
|
154
|
+
states: {
|
|
155
|
+
A1: {
|
|
156
|
+
activities: ['A1'],
|
|
157
|
+
on: {
|
|
158
|
+
A: 'AWAIT'
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
AWAIT: {
|
|
162
|
+
activities: ['AWAIT'],
|
|
163
|
+
on: {
|
|
164
|
+
'': 'A2'
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
A2: {
|
|
168
|
+
activities: ['A2'],
|
|
169
|
+
on: {
|
|
170
|
+
A: 'A1'
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
on: {
|
|
175
|
+
A1: '.A1',
|
|
176
|
+
A2: '.A2'
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
B: {
|
|
180
|
+
initial: 'B1',
|
|
181
|
+
activities: ['B'],
|
|
182
|
+
states: {
|
|
183
|
+
B1: {
|
|
184
|
+
activities: ['B1'],
|
|
185
|
+
on: {
|
|
186
|
+
'': [
|
|
187
|
+
{
|
|
188
|
+
in: 'A.AWAIT',
|
|
189
|
+
target: 'B2'
|
|
190
|
+
}
|
|
191
|
+
],
|
|
192
|
+
B: 'B2'
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
B2: {
|
|
196
|
+
activities: ['B2'],
|
|
197
|
+
on: {
|
|
198
|
+
B: 'B1'
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
on: {
|
|
203
|
+
B1: '.B1',
|
|
204
|
+
B2: '.B2'
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
C: {
|
|
208
|
+
initial: 'C1',
|
|
209
|
+
states: {
|
|
210
|
+
C1: {
|
|
211
|
+
activities: ['C1'],
|
|
212
|
+
on: {
|
|
213
|
+
C: 'C1',
|
|
214
|
+
C_SIMILAR: 'C2'
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
C2: {
|
|
218
|
+
activities: ['C1'],
|
|
219
|
+
},
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should have started initial activities', () => {
|
|
226
|
+
let state = machine.initialState;
|
|
227
|
+
assert.deepEqual(state.activities.A, true);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('should have started deep initial activities', () => {
|
|
231
|
+
let state = machine.initialState;
|
|
232
|
+
assert.deepEqual(state.activities.A1, true);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it('should have kept existing activities', () => {
|
|
236
|
+
let state = machine.initialState;
|
|
237
|
+
state = machine.transition(state, 'A');
|
|
238
|
+
assert.deepEqual(state.activities.A, true);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('should have kept same activities', () => {
|
|
242
|
+
let state = machine.initialState;
|
|
243
|
+
state = machine.transition(state, 'C_SIMILAR');
|
|
244
|
+
assert.deepEqual(state.activities.C1, true);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it('should have kept same activities after self transition', () => {
|
|
248
|
+
let state = machine.initialState;
|
|
249
|
+
state = machine.transition(state, 'C');
|
|
250
|
+
assert.deepEqual(state.activities.C1, true);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it('should have stopped after automatic transitions', () => {
|
|
254
|
+
let state = machine.initialState;
|
|
255
|
+
state = machine.transition(state, 'A');
|
|
256
|
+
assert.deepEqual(state.value, { A: 'A2', B: 'B2', C: 'C1' });
|
|
257
|
+
assert.deepEqual(state.activities.B2, true);
|
|
258
|
+
});
|
|
259
|
+
});
|
package/test/deep.test.ts
CHANGED
|
@@ -6,7 +6,7 @@ describe('deep transitions', () => {
|
|
|
6
6
|
key: 'deep',
|
|
7
7
|
initial: 'A',
|
|
8
8
|
on: {
|
|
9
|
-
MACHINE_EVENT: '#DONE'
|
|
9
|
+
MACHINE_EVENT: '#deep.DONE'
|
|
10
10
|
},
|
|
11
11
|
states: {
|
|
12
12
|
DONE: {},
|
|
@@ -103,7 +103,7 @@ describe('deep transitions', () => {
|
|
|
103
103
|
assert.deepEqual(actual, expected);
|
|
104
104
|
});
|
|
105
105
|
|
|
106
|
-
|
|
106
|
+
it('should exit substates and superstates when exiting (B_EVENT)', () => {
|
|
107
107
|
const actual = deepMachine
|
|
108
108
|
.transition(deepMachine.initialState, 'B_EVENT')
|
|
109
109
|
.actions.map(a => `${a}`);
|
|
@@ -111,7 +111,7 @@ describe('deep transitions', () => {
|
|
|
111
111
|
assert.deepEqual(actual, expected);
|
|
112
112
|
});
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
it('should exit substates and superstates when exiting (C_EVENT)', () => {
|
|
115
115
|
const actual = deepMachine
|
|
116
116
|
.transition(deepMachine.initialState, 'C_EVENT')
|
|
117
117
|
.actions.map(a => `${a}`);
|
|
@@ -119,7 +119,7 @@ describe('deep transitions', () => {
|
|
|
119
119
|
assert.deepEqual(actual, expected);
|
|
120
120
|
});
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
it('should exit superstates when exiting (D_EVENT)', () => {
|
|
123
123
|
const actual = deepMachine
|
|
124
124
|
.transition(deepMachine.initialState, 'D_EVENT')
|
|
125
125
|
.actions.map(a => `${a}`);
|
|
@@ -127,16 +127,14 @@ describe('deep transitions', () => {
|
|
|
127
127
|
assert.deepEqual(actual, expected);
|
|
128
128
|
});
|
|
129
129
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
);
|
|
130
|
+
it('should exit substate when machine handles event (MACHINE_EVENT)', () => {
|
|
131
|
+
// console.log(deepMachine.initialState.value);
|
|
132
|
+
const actual = deepMachine
|
|
133
|
+
.transition(deepMachine.initialState, 'MACHINE_EVENT')
|
|
134
|
+
.actions.map(a => `${a}`);
|
|
135
|
+
const expected = ['EXIT_D', 'EXIT_C', 'EXIT_B', 'EXIT_A'];
|
|
136
|
+
assert.deepEqual(actual, expected);
|
|
137
|
+
});
|
|
140
138
|
|
|
141
139
|
const DBCAPQRS = [
|
|
142
140
|
'EXIT_D',
|
|
@@ -157,7 +155,7 @@ describe('deep transitions', () => {
|
|
|
157
155
|
assert.deepEqual(actual, expected);
|
|
158
156
|
});
|
|
159
157
|
|
|
160
|
-
|
|
158
|
+
it('should exit deep and enter deep (D_P)', () => {
|
|
161
159
|
const actual = deepMachine
|
|
162
160
|
.transition(deepMachine.initialState, 'D_P')
|
|
163
161
|
.actions.map(a => `${a}`);
|
|
@@ -173,7 +171,7 @@ describe('deep transitions', () => {
|
|
|
173
171
|
assert.deepEqual(actual, expected);
|
|
174
172
|
});
|
|
175
173
|
|
|
176
|
-
|
|
174
|
+
it('should exit deep and enter deep (D_S)', () => {
|
|
177
175
|
const actual = deepMachine
|
|
178
176
|
.transition(deepMachine.initialState, 'D_S')
|
|
179
177
|
.actions.map(a => `${a}`);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { assert } from 'chai';
|
|
2
|
-
import { Machine } from '../src/
|
|
2
|
+
import { Machine } from '../src/StateNode';
|
|
3
3
|
|
|
4
4
|
describe('deterministic machine', () => {
|
|
5
5
|
const pedestrianStates = {
|
|
@@ -135,10 +135,7 @@ describe('deterministic machine', () => {
|
|
|
135
135
|
});
|
|
136
136
|
|
|
137
137
|
it('should throw an error for transitions to invalid states', () => {
|
|
138
|
-
assert.throws(
|
|
139
|
-
() => testMachine.transition('a', 'F'),
|
|
140
|
-
"Event 'F' on state 'a' leads to undefined state 'c'."
|
|
141
|
-
);
|
|
138
|
+
assert.throws(() => testMachine.transition('a', 'F'));
|
|
142
139
|
});
|
|
143
140
|
|
|
144
141
|
it('should throw an error for transitions from invalid substates', () => {
|
|
@@ -206,4 +203,28 @@ describe('deterministic machine', () => {
|
|
|
206
203
|
assert.equal(initialState, nextState);
|
|
207
204
|
});
|
|
208
205
|
});
|
|
206
|
+
|
|
207
|
+
describe('state key names', () => {
|
|
208
|
+
const machine = Machine({
|
|
209
|
+
key: 'test',
|
|
210
|
+
initial: 'test',
|
|
211
|
+
states: {
|
|
212
|
+
test: {
|
|
213
|
+
activities: ['activity'],
|
|
214
|
+
onEntry: ['onEntry'],
|
|
215
|
+
on: {
|
|
216
|
+
NEXT: 'test'
|
|
217
|
+
},
|
|
218
|
+
onExit: ['onExit']
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('should work with substate nodes that have the same key', () => {
|
|
224
|
+
assert.deepEqual(
|
|
225
|
+
machine.transition(machine.initialState, 'NEXT').value,
|
|
226
|
+
'test'
|
|
227
|
+
);
|
|
228
|
+
});
|
|
229
|
+
});
|
|
209
230
|
});
|
|
@@ -65,3 +65,67 @@ describe('Example 6.17', () => {
|
|
|
65
65
|
});
|
|
66
66
|
});
|
|
67
67
|
});
|
|
68
|
+
|
|
69
|
+
describe('Jump to ID', () => {
|
|
70
|
+
const machine = Machine({
|
|
71
|
+
initial: 'X',
|
|
72
|
+
states: {
|
|
73
|
+
X: {
|
|
74
|
+
id: 'X',
|
|
75
|
+
on: {
|
|
76
|
+
1: 'Y',
|
|
77
|
+
2: 'Y.A.C', // 6.18
|
|
78
|
+
// 3: { Y: { A: 'C', B: 'F' } } // 6.19
|
|
79
|
+
4: 'Y.A.$history'
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
Y: {
|
|
83
|
+
parallel: true,
|
|
84
|
+
states: {
|
|
85
|
+
A: {
|
|
86
|
+
initial: 'D',
|
|
87
|
+
states: {
|
|
88
|
+
C: {
|
|
89
|
+
on: {
|
|
90
|
+
finish: '#X'
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
D: {},
|
|
94
|
+
E: {}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
B: {
|
|
98
|
+
initial: 'G',
|
|
99
|
+
states: { F: {}, G: {}, H: {} }
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
on: {
|
|
103
|
+
kill: '#X'
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const expected = {
|
|
110
|
+
'Y.B.G': {
|
|
111
|
+
kill: 'X'
|
|
112
|
+
},
|
|
113
|
+
'{"Y":{"A":"C","B":"H"}}': {
|
|
114
|
+
finish: 'X'
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
Object.keys(expected).forEach(fromState => {
|
|
119
|
+
Object.keys(expected[fromState]).forEach(eventTypes => {
|
|
120
|
+
const toState = expected[fromState][eventTypes];
|
|
121
|
+
|
|
122
|
+
it(`should go from ${fromState} to ${JSON.stringify(
|
|
123
|
+
toState
|
|
124
|
+
)} on ${eventTypes}`, () => {
|
|
125
|
+
const resultState = testMultiTransition(machine, fromState, eventTypes);
|
|
126
|
+
|
|
127
|
+
assert.deepEqual(resultState.value, toState);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
});
|
package/test/fixtures/id.ts
CHANGED
package/test/graph.test.ts
CHANGED
|
@@ -62,6 +62,27 @@ describe('graph utilities', () => {
|
|
|
62
62
|
}
|
|
63
63
|
});
|
|
64
64
|
|
|
65
|
+
const condMachine = Machine({
|
|
66
|
+
key: 'cond',
|
|
67
|
+
initial: 'pending',
|
|
68
|
+
states: {
|
|
69
|
+
pending: {
|
|
70
|
+
on: {
|
|
71
|
+
EVENT: [
|
|
72
|
+
{ target: 'foo', cond: (_, e) => e.id === 'foo' },
|
|
73
|
+
{ target: 'bar' }
|
|
74
|
+
],
|
|
75
|
+
STATE: [
|
|
76
|
+
{ target: 'foo', cond: s => s.id === 'foo' },
|
|
77
|
+
{ target: 'bar' }
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
foo: {},
|
|
82
|
+
bar: {}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
65
86
|
const parallelMachine = Machine({
|
|
66
87
|
parallel: true,
|
|
67
88
|
key: 'p',
|
|
@@ -342,24 +363,26 @@ describe('graph utilities', () => {
|
|
|
342
363
|
});
|
|
343
364
|
|
|
344
365
|
it('should not throw when a condition is present', () => {
|
|
345
|
-
const condMachine = Machine({
|
|
346
|
-
initial: 'a',
|
|
347
|
-
states: {
|
|
348
|
-
a: {
|
|
349
|
-
on: {
|
|
350
|
-
NEXT: {
|
|
351
|
-
b: {
|
|
352
|
-
cond: payload => payload.foo
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
},
|
|
357
|
-
b: {}
|
|
358
|
-
}
|
|
359
|
-
});
|
|
360
|
-
|
|
361
366
|
assert.doesNotThrow(() => getShortestPaths(condMachine));
|
|
362
367
|
});
|
|
368
|
+
|
|
369
|
+
it('should represent conditional paths based on extended state', () => {
|
|
370
|
+
assert.deepEqual(getShortestPaths(condMachine, { id: 'foo' }), {
|
|
371
|
+
'"bar"': [
|
|
372
|
+
{
|
|
373
|
+
event: 'EVENT',
|
|
374
|
+
state: 'pending'
|
|
375
|
+
}
|
|
376
|
+
],
|
|
377
|
+
'"foo"': [
|
|
378
|
+
{
|
|
379
|
+
event: 'STATE',
|
|
380
|
+
state: 'pending'
|
|
381
|
+
}
|
|
382
|
+
],
|
|
383
|
+
'"pending"': []
|
|
384
|
+
});
|
|
385
|
+
});
|
|
363
386
|
});
|
|
364
387
|
|
|
365
388
|
describe('getShortestPathsAsArray()', () => {
|
package/test/guards.test.ts
CHANGED
|
@@ -1,26 +1,47 @@
|
|
|
1
1
|
import { assert } from 'chai';
|
|
2
|
-
import { Machine } from '../src/index';
|
|
2
|
+
import { Machine, matchesState } from '../src/index';
|
|
3
3
|
|
|
4
4
|
describe('guard conditions', () => {
|
|
5
|
-
const lightMachine = Machine(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
const lightMachine = Machine(
|
|
6
|
+
{
|
|
7
|
+
key: 'light',
|
|
8
|
+
initial: 'green',
|
|
9
|
+
states: {
|
|
10
|
+
green: {
|
|
11
|
+
on: {
|
|
12
|
+
TIMER: {
|
|
13
|
+
green: {
|
|
14
|
+
cond: ({ elapsed }) => elapsed < 100
|
|
15
|
+
},
|
|
16
|
+
yellow: {
|
|
17
|
+
cond: ({ elapsed }) => elapsed >= 100 && elapsed < 200
|
|
18
|
+
}
|
|
14
19
|
},
|
|
15
|
-
|
|
16
|
-
cond: (
|
|
20
|
+
EMERGENCY: {
|
|
21
|
+
red: { cond: (_, event) => event.isEmergency }
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
yellow: {
|
|
26
|
+
on: {
|
|
27
|
+
TIMER: {
|
|
28
|
+
red: { cond: 'minTimeElapsed' }
|
|
17
29
|
}
|
|
18
30
|
}
|
|
31
|
+
},
|
|
32
|
+
red: {
|
|
33
|
+
on: {
|
|
34
|
+
BAD_COND: { red: { cond: 'doesNotExist' } }
|
|
35
|
+
}
|
|
19
36
|
}
|
|
20
|
-
}
|
|
21
|
-
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
guards: {
|
|
41
|
+
minTimeElapsed: ({ elapsed }) => elapsed >= 100 && elapsed < 200
|
|
42
|
+
}
|
|
22
43
|
}
|
|
23
|
-
|
|
44
|
+
);
|
|
24
45
|
|
|
25
46
|
it('should transition only if condition is met', () => {
|
|
26
47
|
assert.equal(
|
|
@@ -42,6 +63,22 @@ describe('guard conditions', () => {
|
|
|
42
63
|
);
|
|
43
64
|
});
|
|
44
65
|
|
|
66
|
+
it('should transition if condition based on event is met', () => {
|
|
67
|
+
assert.equal(
|
|
68
|
+
lightMachine
|
|
69
|
+
.transition('green', { type: 'EMERGENCY', isEmergency: true })
|
|
70
|
+
.toString(),
|
|
71
|
+
'red'
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should not transition if condition based on event is not met', () => {
|
|
76
|
+
assert.equal(
|
|
77
|
+
lightMachine.transition('green', { type: 'EMERGENCY' }).toString(),
|
|
78
|
+
'green'
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
|
|
45
82
|
it('should not transition if no condition is met', () => {
|
|
46
83
|
const nextState = lightMachine.transition('green', 'TIMER', {
|
|
47
84
|
elapsed: 9000
|
|
@@ -49,4 +86,124 @@ describe('guard conditions', () => {
|
|
|
49
86
|
assert.equal(nextState.value, 'green');
|
|
50
87
|
assert.isEmpty(nextState.actions);
|
|
51
88
|
});
|
|
89
|
+
|
|
90
|
+
it('should work with defined string transitions', () => {
|
|
91
|
+
const nextState = lightMachine.transition('yellow', 'TIMER', {
|
|
92
|
+
elapsed: 150
|
|
93
|
+
});
|
|
94
|
+
assert.equal(nextState.value, 'red');
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should work with defined string transitions (condition not met)', () => {
|
|
98
|
+
const nextState = lightMachine.transition('yellow', 'TIMER', {
|
|
99
|
+
elapsed: 10
|
|
100
|
+
});
|
|
101
|
+
assert.equal(nextState.value, 'yellow');
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should throw if string transition is not defined', () => {
|
|
105
|
+
assert.throws(() => lightMachine.transition('red', 'BAD_COND'));
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe('guard conditions', () => {
|
|
110
|
+
const machine = Machine({
|
|
111
|
+
key: 'microsteps',
|
|
112
|
+
parallel: true,
|
|
113
|
+
states: {
|
|
114
|
+
A: {
|
|
115
|
+
initial: 'A0',
|
|
116
|
+
states: {
|
|
117
|
+
A0: {
|
|
118
|
+
on: {
|
|
119
|
+
A: 'A1'
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
A1: {
|
|
123
|
+
on: {
|
|
124
|
+
A: 'A2'
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
A2: {
|
|
128
|
+
on: {
|
|
129
|
+
A: 'A3'
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
A3: {
|
|
133
|
+
on: {
|
|
134
|
+
'': 'A4'
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
A4: {
|
|
138
|
+
on: {
|
|
139
|
+
'': 'A5'
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
A5: {}
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
B: {
|
|
146
|
+
initial: 'B0',
|
|
147
|
+
states: {
|
|
148
|
+
B0: {
|
|
149
|
+
on: {
|
|
150
|
+
T1: [
|
|
151
|
+
{
|
|
152
|
+
target: 'B1',
|
|
153
|
+
cond: (_state, _event, interim) =>
|
|
154
|
+
matchesState('A.A1', interim)
|
|
155
|
+
}
|
|
156
|
+
],
|
|
157
|
+
T2: [
|
|
158
|
+
{
|
|
159
|
+
target: 'B2',
|
|
160
|
+
cond: (_state, _event, interim) =>
|
|
161
|
+
matchesState('A.A2', interim)
|
|
162
|
+
}
|
|
163
|
+
],
|
|
164
|
+
T3: [
|
|
165
|
+
{
|
|
166
|
+
target: 'B3',
|
|
167
|
+
cond: (_state, _event, interim) =>
|
|
168
|
+
matchesState('A.A3', interim)
|
|
169
|
+
}
|
|
170
|
+
],
|
|
171
|
+
'': [
|
|
172
|
+
{
|
|
173
|
+
target: 'B4',
|
|
174
|
+
cond: (_state, _event, interim) =>
|
|
175
|
+
matchesState('A.A4', interim)
|
|
176
|
+
}
|
|
177
|
+
]
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
B1: {},
|
|
181
|
+
B2: {},
|
|
182
|
+
B3: {},
|
|
183
|
+
B4: {}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('should guard against transition', () => {
|
|
190
|
+
assert.deepEqual(machine.transition({ A: 'A2', B: 'B0' }, 'T1').value, {
|
|
191
|
+
A: 'A2',
|
|
192
|
+
B: 'B0'
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('should allow a matching transition', () => {
|
|
197
|
+
assert.deepEqual(machine.transition({ A: 'A2', B: 'B0' }, 'T2').value, {
|
|
198
|
+
A: 'A2',
|
|
199
|
+
B: 'B2'
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('should check guards with interim states', () => {
|
|
204
|
+
assert.deepEqual(machine.transition({ A: 'A2', B: 'B0' }, 'A').value, {
|
|
205
|
+
A: 'A5',
|
|
206
|
+
B: 'B4'
|
|
207
|
+
});
|
|
208
|
+
});
|
|
52
209
|
});
|