Skip to content

Commit f7836dc

Browse files
authored
Add two new directives to define a wizard and wizard completion step (#14)
- added a new abstract class WizardCompletionStep which is the parent class for all completion step classes - added a new directive wizardStep - added a new directive wizardCompletionStep - added tests - added the properties stepEnter, stepExit and hidden to the WizardStep class
1 parent 8242405 commit f7836dc

12 files changed

+808
-38
lines changed

src/components/components/wizard-completion-step.component.spec.ts

+7
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,13 @@ describe('WizardCompletionStepComponent', () => {
9595
expect(wizardTest.eventLog).toEqual(['enter Forwards 1', 'exit Forwards 1', 'enter Forwards 3']);
9696
});
9797

98+
it('should set the wizard as completed after entering the completion step', () => {
99+
wizardTest.wizard.goToStep(2);
100+
wizardTestFixture.detectChanges();
101+
102+
expect(wizardTest.wizard.completed).toBe(true);
103+
});
104+
98105
it('should be unable to leave the completion step', () => {
99106
wizardTest.wizard.goToStep(2);
100107
wizardTestFixture.detectChanges();

src/components/components/wizard-completion-step.component.ts

+8-14
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {MovingDirection} from '../util/moving-direction.enum';
77
import {WizardComponent} from './wizard.component';
88
import {WizardStep} from '../util/wizard-step.interface';
99
import {WizardStepTitleDirective} from '../directives/wizard-step-title.directive';
10+
import {WizardCompletionStep} from '../util/wizard-completion-step.inferface';
1011

1112
/**
1213
* The `wizard-completion-step` component can be used to define a completion/success step at the end of your wizard
@@ -49,10 +50,11 @@ import {WizardStepTitleDirective} from '../directives/wizard-step-title.directiv
4950
templateUrl: 'wizard-completion-step.component.html',
5051
styleUrls: ['wizard-completion-step.component.css'],
5152
providers: [
52-
{ provide: WizardStep, useExisting: forwardRef(() => WizardCompletionStepComponent) }
53+
{ provide: WizardStep, useExisting: forwardRef(() => WizardCompletionStepComponent) },
54+
{ provide: WizardCompletionStep, useExisting: forwardRef(() => WizardCompletionStepComponent) }
5355
]
5456
})
55-
export class WizardCompletionStepComponent extends WizardStep {
57+
export class WizardCompletionStepComponent extends WizardCompletionStep {
5658
/**
5759
* @inheritDoc
5860
*/
@@ -78,27 +80,18 @@ export class WizardCompletionStepComponent extends WizardStep {
7880
public navigationSymbolFontFamily: string;
7981

8082
/**
81-
* This EventEmitter is called when the step is entered.
82-
* The bound method should be used to do initialization work.
83-
*
84-
* @type {EventEmitter<MovingDirection>}
83+
* @inheritDoc
8584
*/
8685
@Output()
8786
public stepEnter = new EventEmitter<MovingDirection>();
8887

8988
/**
90-
* This EventEmitter is called when the step is exited.
91-
* The bound method can be used to do cleanup work.
92-
*
93-
* @type {EventEmitter<MovingDirection>}
89+
* @inheritDoc
9490
*/
9591
public stepExit = new EventEmitter<MovingDirection>();
9692

9793
/**
98-
* Returns if this wizard step should be visible to the user.
99-
* If the step should be visible to the user false is returned, otherwise true
100-
*
101-
* @returns {boolean}
94+
* @inheritDoc
10295
*/
10396
@HostBinding('hidden')
10497
public get hidden(): boolean {
@@ -129,6 +122,7 @@ export class WizardCompletionStepComponent extends WizardStep {
129122
* Constructor
130123
* @param wizard The [[WizardComponent]], this completion step is contained inside
131124
*/
125+
/* istanbul ignore next */
132126
constructor(@Inject(forwardRef(() => WizardComponent)) private wizard: WizardComponent) {
133127
super();
134128
}

src/components/components/wizard-step.component.ts

+3-12
Original file line numberDiff line numberDiff line change
@@ -91,28 +91,19 @@ export class WizardStepComponent extends WizardStep {
9191
public canExit: ((direction: MovingDirection) => boolean) | boolean = true;
9292

9393
/**
94-
* This EventEmitter is called when the step is entered.
95-
* The bound method should be used to do initialization work.
96-
*
97-
* @type {EventEmitter<MovingDirection>}
94+
* @inheritDoc
9895
*/
9996
@Output()
10097
public stepEnter = new EventEmitter<MovingDirection>();
10198

10299
/**
103-
* This EventEmitter is called when the step is exited.
104-
* The bound method can be used to do cleanup work.
105-
*
106-
* @type {EventEmitter<MovingDirection>}
100+
* @inheritDoc
107101
*/
108102
@Output()
109103
public stepExit = new EventEmitter<MovingDirection>();
110104

111105
/**
112-
* Returns if this wizard step should be visible to the user.
113-
* If the step should be visible to the user false is returned, otherwise true
114-
*
115-
* @returns {boolean}
106+
* @inheritDoc
116107
*/
117108
@HostBinding('hidden')
118109
public get hidden(): boolean {

src/components/directives/enable-back-links.directive.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {Directive, EventEmitter, Host, OnInit, Output} from '@angular/core';
2-
import {WizardCompletionStepComponent} from '../components/wizard-completion-step.component';
32
import {MovingDirection} from '../util/moving-direction.enum';
3+
import {WizardCompletionStep} from '../util/wizard-completion-step.inferface';
44

55
/**
6-
* The `enableBackLinks` directive can be used to allow the user to leave a [[WizardCompletionStepComponent]] after is has been entered.
6+
* The `enableBackLinks` directive can be used to allow the user to leave a [[WizardCompletionStep]] after is has been entered.
77
*
88
* ### Syntax
99
*
@@ -24,7 +24,7 @@ import {MovingDirection} from '../util/moving-direction.enum';
2424
* @author Marc Arndt
2525
*/
2626
@Directive({
27-
selector: 'wizard-completion-step[enableBackLinks]'
27+
selector: '[enableBackLinks]'
2828
})
2929
export class EnableBackLinksDirective implements OnInit {
3030
/**
@@ -41,7 +41,7 @@ export class EnableBackLinksDirective implements OnInit {
4141
*
4242
* @param completionStep The wizard completion step, which should be exitable
4343
*/
44-
constructor(@Host() private completionStep: WizardCompletionStepComponent) { }
44+
constructor(@Host() private completionStep: WizardCompletionStep) { }
4545

4646
/**
4747
* Initialization work
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/**
2+
* Created by marc on 20.05.17.
3+
*/
4+
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
5+
import {ViewChild, Component} from '@angular/core';
6+
import {WizardComponent} from '../components/wizard.component';
7+
import {MovingDirection} from '../util/moving-direction.enum';
8+
import {By} from '@angular/platform-browser';
9+
import {WizardModule} from '../wizard.module';
10+
import {WizardCompletionStepDirective} from './wizard-completion-step.directive';
11+
12+
@Component({
13+
selector: 'test-wizard',
14+
template: `
15+
<wizard>
16+
<wizard-step title='Steptitle 1' (stepEnter)="enterInto($event, 1)" (stepExit)="exitFrom($event, 1)">
17+
Step 1
18+
</wizard-step>
19+
<wizard-step title='Steptitle 2' [canExit]="isValid"
20+
optionalStep (stepEnter)="enterInto($event, 2)" (stepExit)="exitFrom($event, 2)">
21+
Step 2
22+
</wizard-step>
23+
<div wizardCompletionStep title='Completion steptitle 3' (stepEnter)="enterInto($event, 3)">
24+
Step 3
25+
</div>
26+
</wizard>
27+
`
28+
})
29+
class WizardTestComponent {
30+
@ViewChild(WizardComponent)
31+
public wizard: WizardComponent;
32+
33+
public isValid: any = true;
34+
35+
public eventLog: Array<string> = new Array<string>();
36+
37+
enterInto(direction: MovingDirection, destination: number): void {
38+
this.eventLog.push(`enter ${MovingDirection[direction]} ${destination}`);
39+
}
40+
41+
exitFrom(direction: MovingDirection, source: number): void {
42+
this.eventLog.push(`exit ${MovingDirection[direction]} ${source}`);
43+
}
44+
}
45+
46+
describe('WizardCompletionStepDirective', () => {
47+
let wizardTest: WizardTestComponent;
48+
let wizardTestFixture: ComponentFixture<WizardTestComponent>;
49+
50+
beforeEach(async(() => {
51+
TestBed.configureTestingModule({
52+
declarations: [WizardTestComponent],
53+
imports: [WizardModule]
54+
}).compileComponents();
55+
}));
56+
57+
beforeEach(() => {
58+
wizardTestFixture = TestBed.createComponent(WizardTestComponent);
59+
wizardTest = wizardTestFixture.componentInstance;
60+
wizardTestFixture.detectChanges();
61+
});
62+
63+
it('should create', () => {
64+
expect(wizardTest).toBeTruthy();
65+
expect(wizardTestFixture.debugElement.queryAll(By.css('wizard-step')).length).toBe(2);
66+
expect(wizardTestFixture.debugElement.queryAll(By.directive(WizardCompletionStepDirective)).length).toBe(1);
67+
});
68+
69+
it('should have correct step title', () => {
70+
expect(wizardTest).toBeTruthy();
71+
expect(wizardTest.wizard.getStepAtIndex(0).title).toBe('Steptitle 1');
72+
expect(wizardTest.wizard.getStepAtIndex(1).title).toBe('Steptitle 2');
73+
expect(wizardTest.wizard.getStepAtIndex(2).title).toBe('Completion steptitle 3');
74+
});
75+
76+
it('should enter first step after initialisation', () => {
77+
expect(wizardTest.eventLog).toEqual(['enter Forwards 1']);
78+
});
79+
80+
it('should enter completion step after first step', () => {
81+
expect(wizardTest.wizard.currentStepIndex).toBe(0);
82+
83+
wizardTest.wizard.goToNextStep();
84+
wizardTestFixture.detectChanges();
85+
86+
expect(wizardTest.wizard.currentStepIndex).toBe(1);
87+
expect(wizardTest.eventLog).toEqual(['enter Forwards 1', 'exit Forwards 1', 'enter Forwards 2']);
88+
89+
wizardTest.wizard.goToNextStep();
90+
wizardTestFixture.detectChanges();
91+
92+
expect(wizardTest.wizard.currentStepIndex).toBe(2);
93+
expect(wizardTest.eventLog).toEqual(['enter Forwards 1', 'exit Forwards 1', 'enter Forwards 2',
94+
'exit Forwards 2', 'enter Forwards 3']);
95+
});
96+
97+
it('should enter completion step after jumping over second optional step', () => {
98+
wizardTest.wizard.goToStep(2);
99+
wizardTestFixture.detectChanges();
100+
101+
expect(wizardTest.eventLog).toEqual(['enter Forwards 1', 'exit Forwards 1', 'enter Forwards 3']);
102+
});
103+
104+
it('should set the wizard as completed after entering the completion step', () => {
105+
wizardTest.wizard.goToStep(2);
106+
wizardTestFixture.detectChanges();
107+
108+
expect(wizardTest.wizard.completed).toBe(true);
109+
});
110+
111+
it('should be unable to leave the completion step', () => {
112+
wizardTest.wizard.goToStep(2);
113+
wizardTestFixture.detectChanges();
114+
115+
expect(wizardTest.wizard.canGoToStep(0)).toBe(false);
116+
expect(wizardTest.wizard.canGoToStep(1)).toBe(false);
117+
});
118+
119+
120+
it('should not be able to leave the completion step in any direction', () => {
121+
wizardTest.isValid = false;
122+
123+
wizardTest.wizard.goToStep(2);
124+
wizardTestFixture.detectChanges();
125+
126+
expect(wizardTest.wizard.currentStepIndex).toBe(2);
127+
expect(wizardTest.wizard.currentStep.canExit).toBe(false);
128+
});
129+
130+
it('should not leave the completion step if it can\'t be exited', () => {
131+
wizardTest.isValid = false;
132+
133+
wizardTest.wizard.goToStep(2);
134+
wizardTestFixture.detectChanges();
135+
136+
expect(wizardTest.wizard.currentStepIndex).toBe(2);
137+
138+
wizardTest.wizard.goToPreviousStep();
139+
wizardTestFixture.detectChanges();
140+
141+
expect(wizardTest.wizard.currentStepIndex).toBe(2);
142+
expect(wizardTest.eventLog)
143+
.toEqual(['enter Forwards 1', 'exit Forwards 1', 'enter Forwards 3', 'enter Stay 3']);
144+
});
145+
});

0 commit comments

Comments
 (0)