deno.land / x / xstate@xstate@4.33.6 / test / history.test.ts
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523import { Machine, createMachine, interpret } from '../src/index';
describe('history states', () => { const historyMachine = createMachine({ key: 'history', initial: 'off', states: { off: { on: { POWER: 'on.hist', H_POWER: 'on.H' } }, on: { initial: 'first', states: { first: { on: { SWITCH: 'second' } }, second: { on: { SWITCH: 'third' } }, third: {}, H: { type: 'history' }, hist: { type: 'history', history: 'shallow' } }, on: { POWER: 'off', H_POWER: 'off' } } } });
it('should go to the most recently visited state', () => { const onSecondState = historyMachine.transition('on', 'SWITCH'); const offState = historyMachine.transition(onSecondState, 'POWER');
expect(historyMachine.transition(offState, 'POWER').value).toEqual({ on: 'second' }); });
it('should go to the most recently visited state (explicit)', () => { const onSecondState = historyMachine.transition('on', 'SWITCH'); const offState = historyMachine.transition(onSecondState, 'H_POWER');
expect(historyMachine.transition(offState, 'H_POWER').value).toEqual({ on: 'second' }); });
it('should go to the initial state when no history present', () => { expect(historyMachine.transition('off', 'POWER').value).toEqual({ on: 'first' }); });
it('should go to the initial state when no history present (explicit)', () => { expect(historyMachine.transition('off', 'H_POWER').value).toEqual({ on: 'first' }); });
it('should dispose of previous histories', () => { const onSecondState = historyMachine.transition('on', 'SWITCH'); const offState = historyMachine.transition(onSecondState, 'H_POWER'); const onState = historyMachine.transition(offState, 'H_POWER'); const nextState = historyMachine.transition(onState, 'H_POWER'); expect(nextState.history!.history).not.toBeDefined(); });
it('should go to the most recently visited state by a transient transition', () => { const machine = createMachine({ initial: 'idle', states: { idle: { id: 'idle', initial: 'absent', states: { absent: { on: { DEPLOY: '#deploy' } }, present: { on: { DEPLOY: '#deploy', DESTROY: '#destroy' } }, hist: { type: 'history' } } }, deploy: { id: 'deploy', on: { SUCCESS: 'idle.present', FAILURE: 'idle.hist' } }, destroy: { id: 'destroy', always: [{ target: 'idle.absent' }] } } });
const service = interpret(machine).start();
service.send('DEPLOY'); service.send('SUCCESS'); service.send('DESTROY'); service.send('DEPLOY'); service.send('FAILURE');
expect(service.state.value).toEqual({ idle: 'absent' }); });
it('should reenter persisted state during external transition targeting a history state', () => { const actual: string[] = [];
const machine = createMachine({ initial: 'a', states: { a: { on: { REENTER: '#b_hist' }, initial: 'a1', states: { a1: { on: { NEXT: 'a2' } }, a2: { entry: () => actual.push('a2 entered'), exit: () => actual.push('a2 exited') }, a3: { type: 'history', id: 'b_hist' } } } } });
const service = interpret(machine).start();
service.send({ type: 'NEXT' });
actual.length = 0; service.send({ type: 'REENTER' });
expect(actual).toEqual(['a2 exited', 'a2 entered']); });});
describe('deep history states', () => { const historyMachine = Machine({ key: 'history', initial: 'off', states: { off: { on: { POWER: 'on.history', DEEP_POWER: 'on.deepHistory' } }, on: { initial: 'first', states: { first: { on: { SWITCH: 'second' } }, second: { initial: 'A', states: { A: { on: { INNER: 'B' } }, B: { initial: 'P', states: { P: { on: { INNER: 'Q' } }, Q: {} } } } }, history: { history: 'shallow' }, deepHistory: { history: 'deep' } }, on: { POWER: 'off' } } } });
describe('history', () => { // on.first -> on.second.A const state2A = historyMachine.transition({ on: 'first' }, 'SWITCH'); // on.second.A -> on.second.B.P const state2BP = historyMachine.transition(state2A, 'INNER'); // on.second.B.P -> on.second.B.Q const state2BQ = historyMachine.transition(state2BP, 'INNER');
it('should go to the shallow history', () => { // on.second.B.P -> off const stateOff = historyMachine.transition(state2BP, 'POWER'); expect(historyMachine.transition(stateOff, 'POWER').value).toEqual({ on: { second: 'A' } }); });
it('should go to the deep history (explicit)', () => { // on.second.B.P -> off const stateOff = historyMachine.transition(state2BP, 'POWER'); expect(historyMachine.transition(stateOff, 'DEEP_POWER').value).toEqual({ on: { second: { B: 'P' } } }); });
it('should go to the deepest history', () => { // on.second.B.Q -> off const stateOff = historyMachine.transition(state2BQ, 'POWER'); expect(historyMachine.transition(stateOff, 'DEEP_POWER').value).toEqual({ on: { second: { B: 'Q' } } }); }); });});
describe('parallel history states', () => { const historyMachine = Machine({ key: 'parallelhistory', initial: 'off', states: { off: { on: { SWITCH: 'on', // go to the initial states POWER: 'on.hist', DEEP_POWER: 'on.deepHistory', PARALLEL_HISTORY: [{ target: ['on.A.hist', 'on.K.hist'] }], PARALLEL_SOME_HISTORY: [{ target: ['on.A.C', 'on.K.hist'] }], PARALLEL_DEEP_HISTORY: [ { target: ['on.A.deepHistory', 'on.K.deepHistory'] } ] } }, on: { type: 'parallel', states: { A: { initial: 'B', states: { B: { on: { INNER_A: 'C' } }, C: { initial: 'D', states: { D: { on: { INNER_A: 'E' } }, E: {} } }, hist: { history: true }, deepHistory: { history: 'deep' } } }, K: { initial: 'L', states: { L: { on: { INNER_K: 'M' } }, M: { initial: 'N', states: { N: { on: { INNER_K: 'O' } }, O: {} } }, hist: { history: true }, deepHistory: { history: 'deep' } } }, hist: { history: true }, shallowHistory: { history: 'shallow' }, deepHistory: { history: 'deep' } }, on: { POWER: 'off' } } } });
describe('history', () => { // on.first -> on.second.A const stateABKL = historyMachine.transition( historyMachine.initialState, 'SWITCH' ); // INNER_A twice const stateACDKL = historyMachine.transition(stateABKL, 'INNER_A'); const stateACEKL = historyMachine.transition(stateACDKL, 'INNER_A');
// INNER_K twice const stateACEKMN = historyMachine.transition(stateACEKL, 'INNER_K'); const stateACEKMO = historyMachine.transition(stateACEKMN, 'INNER_K');
it('should ignore parallel state history', () => { const stateOff = historyMachine.transition(stateACDKL, 'POWER'); expect(historyMachine.transition(stateOff, 'POWER').value).toEqual({ on: { A: 'B', K: 'L' } }); });
it('should remember first level state history', () => { const stateOff = historyMachine.transition(stateACDKL, 'POWER'); expect(historyMachine.transition(stateOff, 'DEEP_POWER').value).toEqual({ on: { A: { C: 'D' }, K: 'L' } }); });
it('should re-enter each regions of parallel state correctly', () => { const stateOff = historyMachine.transition(stateACEKMO, 'POWER'); expect(historyMachine.transition(stateOff, 'DEEP_POWER').value).toEqual({ on: { A: { C: 'E' }, K: { M: 'O' } } }); });
it('should re-enter multiple history states', () => { const stateOff = historyMachine.transition(stateACEKMO, 'POWER'); expect( historyMachine.transition(stateOff, 'PARALLEL_HISTORY').value ).toEqual({ on: { A: { C: 'D' }, K: { M: 'N' } } }); });
it('should re-enter a parallel with partial history', () => { const stateOff = historyMachine.transition(stateACEKMO, 'POWER'); expect( historyMachine.transition(stateOff, 'PARALLEL_SOME_HISTORY').value ).toEqual({ on: { A: { C: 'D' }, K: { M: 'N' } } }); });
it('should re-enter a parallel with full history', () => { const stateOff = historyMachine.transition(stateACEKMO, 'POWER'); expect( historyMachine.transition(stateOff, 'PARALLEL_DEEP_HISTORY').value ).toEqual({ on: { A: { C: 'E' }, K: { M: 'O' } } }); }); });});
describe('transient history', () => { const transientMachine = Machine({ initial: 'A', states: { A: { on: { EVENT: 'B' } }, B: { // eventless transition always: 'C' }, C: {} } });
it('should have history on transient transitions', () => { const nextState = transientMachine.transition('A', 'EVENT'); expect(nextState.value).toEqual('C'); expect(nextState.history).toBeDefined(); });});
describe('internal transition with history', () => { const machine = Machine({ key: 'test', initial: 'first', states: { first: { initial: 'foo', states: { foo: {} }, on: { NEXT: 'second.other' } }, second: { initial: 'nested', states: { nested: {}, other: {}, hist: { history: true } }, on: { NEXT: [ { target: '.hist' } ] } } } });
it('should transition internally to the most recently visited state', () => { // { // $current: 'first', // first: undefined, // second: { // $current: 'nested', // nested: undefined, // other: undefined // } // } const state2 = machine.transition(machine.initialState, 'NEXT'); // { // $current: 'second', // first: undefined, // second: { // $current: 'other', // nested: undefined, // other: undefined // } // } const state3 = machine.transition(state2, 'NEXT'); // { // $current: 'second', // first: undefined, // second: { // $current: 'other', // nested: undefined, // other: undefined // } // }
expect(state3.value).toEqual({ second: 'other' }); });});
describe('multistage history states', () => { const pcWithTurboButtonMachine = Machine({ key: 'pc-with-turbo-button', initial: 'off', states: { off: { on: { POWER: 'starting' } }, starting: { on: { STARTED: 'running.H' } }, running: { initial: 'normal', states: { normal: { on: { SWITCH_TURBO: 'turbo' } }, turbo: { on: { SWITCH_TURBO: 'normal' } }, H: { history: true } }, on: { POWER: 'off' } } } });
it('should go to the most recently visited state', () => { const onTurboState = pcWithTurboButtonMachine.transition( 'running', 'SWITCH_TURBO' ); const offState = pcWithTurboButtonMachine.transition(onTurboState, 'POWER'); const loadingState = pcWithTurboButtonMachine.transition(offState, 'POWER');
expect( pcWithTurboButtonMachine.transition(loadingState, 'STARTED').value ).toEqual({ running: 'turbo' }); });});
Version Info