Skip to content

Commit

Permalink
Merge pull request #146 from alexlafroscia/one-way-data-flow
Browse files Browse the repository at this point in the history
feat: one-way-bind the `currentStep` property
  • Loading branch information
alexlafroscia committed Jun 10, 2019
2 parents b7b64f6 + 72efb43 commit 22e8af9
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 69 deletions.
21 changes: 15 additions & 6 deletions addon/components/step-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ export default class StepManagerComponent extends Component {
*/
currentStep;

/**
* Called when the state machine transitions, if provided
*
* Passed the new step identifier
*
* @property {function} onTransition;
* @public
*/
onTransition;

/**
* @property {boolean} boolean
* @public
Expand Down Expand Up @@ -165,20 +175,19 @@ export default class StepManagerComponent extends Component {
transitionTo(to) {
const destination = to instanceof StepNode ? to.name : to;
const transitions = get(this, 'transitions');
const onTransition = get(this, 'onTransition');
let currentStepNode = get(transitions, 'currentStepNode');

if (currentStepNode && currentStepNode.onDeactivate) {
currentStepNode.onDeactivate();
}

// If `currentStep` is present, it's probably something the user wants
// two-way-bound with the new value
if (!isNone(this.currentStep)) {
set(this, 'currentStep', destination);
}

this.transitions.activate(destination);

if (onTransition) {
onTransition(destination);
}

currentStepNode = get(transitions, 'currentStepNode');

if (currentStepNode && currentStepNode.onActivate) {
Expand Down
135 changes: 72 additions & 63 deletions tests/integration/step-manager-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,85 +55,94 @@ module('step-manager', function(hooks) {
assert.dom('[data-test-second]').doesNotExist();
});

module('updating the target object from the component', function() {
test("mutates the target object's property when a mutable value is provided", async function(assert) {
this.set('step', 'first');
await render(hbs`
{{#step-manager currentStep=(mut step) as |w|}}
{{w.step name='first'}}
{{w.step name='second'}}
test('does not mutate the `currentStep` property', async function(assert) {
this.set('step', 'first');

<button {{action w.transition-to 'second'}}>
Next
</button>
{{/step-manager}}
`);
await render(hbs`
{{#step-manager currentStep=step as |w|}}
{{w.step name='first'}}
{{w.step name='second'}}
await click('button');
<button {{action w.transition-to 'second'}}>
Next
</button>
{{/step-manager}}
`);

assert.equal(this.get('step'), 'second');
});
await click('button');

test("mutates the target object's property when a regular value is provided", async function(assert) {
this.set('step', 'first');
await render(hbs`
{{#step-manager currentStep=step as |w|}}
{{w.step name='first'}}
{{w.step name='second'}}
assert.equal(this.get('step'), 'first');
});

<button {{action w.transition-to 'second'}}>
Next
</button>
{{/step-manager}}
`);
test('subscribing to step changes', async function(assert) {
this.set('step', 'first');
this.set('onTransition', td.function());

await click('button');
await render(hbs`
{{#step-manager currentStep=step onTransition=onTransition as |w|}}
{{w.step name='first'}}
{{w.step name='second'}}
assert.equal(this.get('step'), 'second');
});
<button {{action w.transition-to 'second'}}>
Next
</button>
{{/step-manager}}
`);

test('does not update the target object with an unbound value', async function(assert) {
this.set('step', 'first');
await render(hbs`
{{#step-manager currentStep=(unbound step) as |w|}}
{{w.step name='first'}}
{{w.step name='second'}}
await click('button');

<button {{action w.transition-to 'second'}}>
Next
</button>
{{/step-manager}}
`);
assert.verify(
this.onTransition('second'),
'Called with the new step name'
);
});

await click('button');
test('emulating a two-way binding to the current step', async function(assert) {
this.set('step', 'first');

assert.equal(this.get('step'), 'first');
});
await render(hbs`
{{#step-manager currentStep=step onTransition=(action (mut step)) as |w|}}
{{w.step name='first'}}
{{w.step name='second'}}
test('does not reset back to first step on any attribute change', async function(assert) {
this.set('initialStep', 'second');
this.set('randomAttribute', 'initial value');
<button {{action w.transition-to 'second'}}>
Next
</button>
{{/step-manager}}
`);

await render(hbs`
{{#step-manager randomAttribute=randomAttribute initialStep=initialStep as |w|}}
{{#w.step name='first'}}
<div data-test-first></div>
{{/w.step}}
{{#w.step name='second'}}
<div data-test-second></div>
{{/w.step}}
{{/step-manager}}
`);
await click('button');

assert.dom('[data-test-second]').exists();
assert.dom('[data-test-first]').doesNotExist();
assert.equal(
this.get('step'),
'second',
'Step was updated to the new value'
);
});

this.set('initialStep', 'second');
this.set('randomAttribute', 'a new value');
test('does not reset back to first step on any attribute change', async function(assert) {
this.set('initialStep', 'second');
this.set('randomAttribute', 'initial value');

assert.dom('[data-test-second]').exists();
assert.dom('[data-test-first]').doesNotExist();
});
await render(hbs`
{{#step-manager randomAttribute=randomAttribute initialStep=initialStep as |w|}}
{{#w.step name='first'}}
<div data-test-first></div>
{{/w.step}}
{{#w.step name='second'}}
<div data-test-second></div>
{{/w.step}}
{{/step-manager}}
`);

assert.dom('[data-test-second]').exists();
assert.dom('[data-test-first]').doesNotExist();

this.set('initialStep', 'second');
this.set('randomAttribute', 'a new value');

assert.dom('[data-test-second]').exists();
assert.dom('[data-test-first]').doesNotExist();
});
});

Expand Down

0 comments on commit 22e8af9

Please sign in to comment.