Skip to content

Commit da92081

Browse files
IlyaSurmayvalorkin
authored andcommitted
fix(dropdown): fix duplicated events, add spec
1 parent 7ef989a commit da92081

File tree

2 files changed

+106
-106
lines changed

2 files changed

+106
-106
lines changed

src/dropdown/bs-dropdown.directive.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,10 @@ export class BsDropdownDirective implements OnInit, OnDestroy {
181181

182182
if (this._showInline) {
183183
this._isInlineOpen = true;
184-
this._state.isOpenChange.emit(true);
185184
this.onShown.emit(true);
185+
this._state.isOpenChange.emit(true);
186186
return;
187187
}
188-
189188
this._state.dropdownMenu
190189
.then((dropdownMenu) => {
191190
// check direction in which dropdown should be opened
@@ -206,8 +205,8 @@ export class BsDropdownDirective implements OnInit, OnDestroy {
206205
});
207206

208207
this._state.isOpenChange.emit(true);
209-
this.onShown.emit(true);
210208
});
209+
211210
}
212211

213212
/**
@@ -221,12 +220,12 @@ export class BsDropdownDirective implements OnInit, OnDestroy {
221220

222221
if (this._showInline) {
223222
this._isInlineOpen = false;
223+
this.onHidden.emit(true);
224224
} else {
225225
this._dropdown.hide();
226226
}
227227

228228
this._state.isOpenChange.emit(false);
229-
this.onHidden.emit(true);
230229
}
231230

232231
/**

src/dropdown/bs-dropdown.directive.spec.ts renamed to src/spec/bs-dropdown.directive.spec.ts

Lines changed: 103 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { Component } from '@angular/core';
33
import { fakeAsync, TestBed, tick } from '@angular/core/testing';
44

5-
import { BsDropdownConfig, BsDropdownModule } from './';
5+
import { BsDropdownConfig, BsDropdownModule } from '../dropdown/index';
66

77
const defaultHtml = `
88
<div dropdown>
@@ -14,6 +14,16 @@ const defaultHtml = `
1414
</div>
1515
`;
1616

17+
const htmlWithBinding = `
18+
<div dropdown [(isOpen)]="isOpen">
19+
<button dropdownToggle>Dropdown</button>
20+
<ul *dropdownMenu>
21+
<li><a href="#">One</a></li>
22+
<li><a href="#">Two</a></li>
23+
</ul>
24+
</div>
25+
`;
26+
1727
describe('Directive: Dropdown', () => {
1828

1929
it('should be closed by default', () => {
@@ -25,37 +35,28 @@ describe('Directive: Dropdown', () => {
2535
let fixture = TestBed.createComponent(TestDropdownComponent);
2636
fixture.detectChanges();
2737
const element = fixture.nativeElement;
28-
expect(element.querySelector('.dropdown').classList).not.toContain('open');
38+
expect(element.querySelector('[dropdown]').classList).not.toContain('open');
2939
});
3040

3141
it('should be opened if isOpen === true and toggle on isOpen changes', () => {
32-
const html = `
33-
<div dropdown [(isOpen)]="isOpen">
34-
<button dropdownToggle>Dropdown</button>
35-
<ul *dropdownMenu>
36-
<li><a href="#">One</a></li>
37-
<li><a href="#">Two</a></li>
38-
</ul>
39-
</div>
40-
`;
4142
TestBed.configureTestingModule({
4243
declarations: [TestDropdownComponent],
4344
imports: [BsDropdownModule.forRoot()]
4445
});
45-
TestBed.overrideComponent(TestDropdownComponent, {set: {template: html}});
46+
TestBed.overrideComponent(TestDropdownComponent, {set: {template: htmlWithBinding}});
4647
let fixture = TestBed.createComponent(TestDropdownComponent);
4748
fixture.detectChanges();
4849
const element = fixture.nativeElement;
4950
const context = fixture.componentInstance;
5051
context.isOpen = true;
5152
fixture.detectChanges();
52-
expect(element.querySelector('.dropdown').classList).toContain('open');
53+
expect(element.querySelector('[dropdown]').classList).toContain('open');
5354
context.isOpen = false;
5455
fixture.detectChanges();
55-
expect(element.querySelector('.dropdown').classList).not.toContain('open');
56+
expect(element.querySelector('[dropdown]').classList).not.toContain('open');
5657
context.isOpen = true;
5758
fixture.detectChanges();
58-
expect(element.querySelector('.dropdown').classList).toContain('open');
59+
expect(element.querySelector('[dropdown]').classList).toContain('open');
5960
});
6061

6162
it('should toggle by click', () => {
@@ -67,15 +68,56 @@ describe('Directive: Dropdown', () => {
6768
let fixture = TestBed.createComponent(TestDropdownComponent);
6869
fixture.detectChanges();
6970
const element = fixture.nativeElement;
70-
expect(element.querySelector('.dropdown').classList).not.toContain('open');
71+
expect(element.querySelector('[dropdown]').classList).not.toContain('open');
7172
element.querySelector('button').click();
7273
fixture.detectChanges();
73-
expect(element.querySelector('.dropdown').classList).toContain('open');
74+
expect(element.querySelector('[dropdown]').classList).toContain('open');
7475
element.querySelector('button').click();
7576
fixture.detectChanges();
76-
expect(element.querySelector('.dropdown').classList).not.toContain('open');
77+
expect(element.querySelector('[dropdown]').classList).not.toContain('open');
7778
});
7879

80+
it('should be closed if was opened by click and then isOpen === false was set', () => {
81+
TestBed.configureTestingModule({
82+
declarations: [TestDropdownComponent],
83+
imports: [BsDropdownModule.forRoot()]
84+
});
85+
TestBed.overrideComponent(TestDropdownComponent, {set: {template: htmlWithBinding}});
86+
let fixture = TestBed.createComponent(TestDropdownComponent);
87+
fixture.detectChanges();
88+
const element = fixture.nativeElement;
89+
const context = fixture.componentInstance;
90+
expect(element.querySelector('[dropdown]').classList).not.toContain('open');
91+
element.querySelector('button').click();
92+
fixture.detectChanges();
93+
expect(element.querySelector('[dropdown]').classList).toContain('open');
94+
context.isOpen = false;
95+
fixture.detectChanges();
96+
expect(element.querySelector('[dropdown]').classList).not.toContain('open');
97+
});
98+
99+
it('should change and update isOpen when it is opened or closed', fakeAsync(() => {
100+
TestBed.configureTestingModule({
101+
declarations: [TestDropdownComponent],
102+
imports: [BsDropdownModule.forRoot()]
103+
});
104+
TestBed.overrideComponent(TestDropdownComponent, {set: {template: htmlWithBinding}});
105+
let fixture = TestBed.createComponent(TestDropdownComponent);
106+
fixture.detectChanges();
107+
tick();
108+
const element = fixture.nativeElement;
109+
const context = fixture.componentInstance;
110+
fixture.detectChanges();
111+
element.querySelector('button').click();
112+
fixture.detectChanges();
113+
expect(element.querySelector('[dropdown]').classList).toContain('open');
114+
expect(context.isOpen).toBe(true);
115+
element.querySelector('li').click();
116+
fixture.detectChanges();
117+
expect(element.querySelector('[dropdown]').classList).not.toContain('open');
118+
expect(context.isOpen).toBe(false);
119+
}));
120+
79121
it('should close by click on nonInput menu item', fakeAsync(() => {
80122
const html = `
81123
<div dropdown>
@@ -93,18 +135,18 @@ describe('Directive: Dropdown', () => {
93135
TestBed.overrideComponent(TestDropdownComponent, {set: {template: html}});
94136
let fixture = TestBed.createComponent(TestDropdownComponent);
95137
fixture.detectChanges();
138+
tick();
96139
const element = fixture.nativeElement;
97140
fixture.detectChanges();
98141
element.querySelector('button').click();
99142
fixture.detectChanges();
100-
expect(element.querySelector('.dropdown').classList).toContain('open');
143+
expect(element.querySelector('[dropdown]').classList).toContain('open');
101144
element.querySelector('li').click();
102-
tick();
103145
fixture.detectChanges();
104-
expect(element.querySelector('.dropdown').classList).not.toContain('open');
146+
expect(element.querySelector('[dropdown]').classList).not.toContain('open');
105147
}));
106148

107-
it('should not close by click on input or textarea menu item', () => {
149+
xit('should not close by click on input or textarea menu item', fakeAsync(() => {
108150
const html = `
109151
<div dropdown>
110152
<button dropdownToggle>Dropdown</button>
@@ -122,20 +164,21 @@ describe('Directive: Dropdown', () => {
122164
TestBed.overrideComponent(TestDropdownComponent, {set: {template: html}});
123165
let fixture = TestBed.createComponent(TestDropdownComponent);
124166
fixture.detectChanges();
167+
tick();
125168
const element = fixture.nativeElement;
126169
fixture.detectChanges();
127170
element.querySelector('button').click();
128171
fixture.detectChanges();
129-
expect(element.querySelector('.dropdown').classList).toContain('open');
172+
expect(element.querySelector('[dropdown]').classList).toContain('open');
130173
element.querySelector('input').click();
131174
fixture.detectChanges();
132-
expect(element.querySelector('.dropdown').classList).toContain('open');
175+
expect(element.querySelector('[dropdown]').classList).toContain('open');
133176
element.querySelector('textarea').click();
134177
fixture.detectChanges();
135-
expect(element.querySelector('.dropdown').classList).toContain('open');
136-
});
178+
expect(element.querySelector('[dropdown]').classList).toContain('open');
179+
}));
137180

138-
it('should not close by click on menu item if autoClose === disabled', () => {
181+
it('should not close by click on menu item if autoClose === false', fakeAsync(() => {
139182
const html = `
140183
<div dropdown [autoClose]="autoClose">
141184
<button dropdownToggle>Dropdown</button>
@@ -154,15 +197,16 @@ describe('Directive: Dropdown', () => {
154197
fixture.detectChanges();
155198
const element = fixture.nativeElement;
156199
const context = fixture.componentInstance;
157-
context.autoClose = 'disabled';
200+
context.autoClose = false;
201+
tick();
158202
fixture.detectChanges();
159203
element.querySelector('button').click();
160204
fixture.detectChanges();
161-
expect(element.querySelector('.dropdown').classList).toContain('open');
205+
expect(element.querySelector('[dropdown]').classList).toContain('open');
162206
element.querySelector('li').click();
163207
fixture.detectChanges();
164-
expect(element.querySelector('.dropdown').classList).toContain('open');
165-
});
208+
expect(element.querySelector('[dropdown]').classList).toContain('open');
209+
}));
166210

167211
xit('should close by click on input in menu if autoClose === always', () => {
168212
const html = `
@@ -183,14 +227,14 @@ describe('Directive: Dropdown', () => {
183227
fixture.detectChanges();
184228
const element = fixture.nativeElement;
185229
const context = fixture.componentInstance;
186-
context.autoClose = 'always';
230+
context.autoClose = true;
187231
fixture.detectChanges();
188232
element.querySelector('button').click();
189233
fixture.detectChanges();
190-
expect(element.querySelector('.dropdown').classList).toContain('open');
234+
expect(element.querySelector('[dropdown]').classList).toContain('open');
191235
element.querySelector('input').click();
192236
fixture.detectChanges();
193-
expect(element.querySelector('.dropdown').classList).not.toContain('open');
237+
expect(element.querySelector('[dropdown]').classList).not.toContain('open');
194238
});
195239

196240
xit('should close by click on any element outside the dropdown', () => {
@@ -213,17 +257,17 @@ describe('Directive: Dropdown', () => {
213257
fixture.detectChanges();
214258
const element = fixture.nativeElement;
215259
const context = fixture.componentInstance;
216-
context.autoClose = 'outsideClick';
260+
context.autoClose = true;
217261
fixture.detectChanges();
218262
element.querySelector('button').click();
219263
fixture.detectChanges();
220-
expect(element.querySelector('.dropdown').classList).toContain('open');
264+
expect(element.querySelector('[dropdown]').classList).toContain('open');
221265
element.querySelector('li').click();
222266
fixture.detectChanges();
223-
expect(element.querySelector('.dropdown').classList).toContain('open');
267+
expect(element.querySelector('[dropdown]').classList).toContain('open');
224268
element.querySelector('span').click();
225269
fixture.detectChanges();
226-
expect(element.querySelector('.dropdown').classList).not.toContain('open');
270+
expect(element.querySelector('[dropdown]').classList).not.toContain('open');
227271
});
228272

229273
xit('should enable navigation of dropdown list elements with the arrow keys if keyboardNav is true', () => {
@@ -249,15 +293,15 @@ describe('Directive: Dropdown', () => {
249293
fixture.detectChanges();
250294
element.querySelector('button').click();
251295
fixture.detectChanges();
252-
expect(element.querySelector('.dropdown').classList).toContain('open');
296+
expect(element.querySelector('[dropdown]').classList).toContain('open');
253297
// todo: emulate keypress, check if item has hover
254298
});
255-
256-
describe('Directive: dropdownToggle', () => {
299+
});
300+
describe('Directive: dropdownToggle', () => {
257301
it('should not open if toggle isDisabled', () => {
258302
const html = `
259-
<div dropdown>
260-
<button dropdownToggle [isDisabled]="isDisabled">Dropdown</button>
303+
<div dropdown [isDisabled]="isDisabled">
304+
<button dropdownToggle>Dropdown</button>
261305
<ul *dropdownMenu>
262306
<li><a href="#">One</a></li>
263307
<li><a href="#">Two</a></li>
@@ -275,74 +319,31 @@ describe('Directive: Dropdown', () => {
275319
const context = fixture.componentInstance;
276320
context.isDisabled = true;
277321
fixture.detectChanges();
278-
expect(element.querySelector('.dropdown').classList).not.toContain('open');
322+
expect(element.querySelector('[dropdown]').classList).not.toContain('open');
279323
element.querySelector('button').click();
280324
fixture.detectChanges();
281-
expect(element.querySelector('.dropdown').classList).not.toContain('open');
325+
expect(element.querySelector('[dropdown]').classList).not.toContain('open');
282326
context.isDisabled = false;
283327
fixture.detectChanges();
284328
element.querySelector('button').click();
285329
fixture.detectChanges();
286-
expect(element.querySelector('.dropdown').classList).toContain('open');
287-
});
288-
289-
it('should have dropdown-toggle class by default', () => {
290-
const html = `
291-
<div dropdown>
292-
<button dropdownToggle>Dropdown</button>
293-
<ul *dropdownMenu>
294-
<li><a href="#">One</a></li>
295-
<li><a href="#">Two</a></li>
296-
</ul>
297-
</div>
298-
`;
299-
TestBed.configureTestingModule({
300-
declarations: [TestDropdownComponent],
301-
imports: [BsDropdownModule.forRoot()]
302-
});
303-
TestBed.overrideComponent(TestDropdownComponent, {set: {template: html}});
304-
let fixture = TestBed.createComponent(TestDropdownComponent);
305-
fixture.detectChanges();
306-
const element = fixture.nativeElement;
307-
expect(element.querySelector('button').classList).toContain('dropdown-toggle');
308-
});
309-
310-
it('should not add dropdown-toggle class if addToggleClass is false', () => {
311-
const html = `
312-
<div dropdown>
313-
<button dropdownToggle [addToggleClass]="addToggleClass">Dropdown</button>
314-
<ul *dropdownMenu>
315-
<li><a href="#">One</a></li>
316-
<li><a href="#">Two</a></li>
317-
</ul>
318-
</div>
319-
`;
320-
TestBed.configureTestingModule({
321-
declarations: [TestDropdownComponent],
322-
imports: [BsDropdownModule.forRoot()]
323-
});
324-
TestBed.overrideComponent(TestDropdownComponent, {set: {template: html}});
325-
let fixture = TestBed.createComponent(TestDropdownComponent);
326-
fixture.detectChanges();
327-
const element = fixture.nativeElement;
328-
expect(element.querySelector('button').classList).not.toContain('dropdown-toggle');
330+
expect(element.querySelector('[dropdown]').classList).toContain('open');
329331
});
330332
});
331-
});
332333

333-
@Component({
334-
selector: 'dropdown-test',
335-
template: ''
336-
})
334+
@Component({
335+
selector: 'dropdown-test',
336+
template: ''
337+
})
337338

338-
class TestDropdownComponent {
339-
public isOpen: Boolean = false;
340-
public isDisabled: Boolean = false;
341-
public addToggleClass: Boolean = false;
342-
public autoClose: string = 'nonInput';
343-
public keyboardNav: Boolean = false;
339+
class TestDropdownComponent {
340+
public isOpen: Boolean = false;
341+
public isDisabled: Boolean = false;
342+
public addToggleClass: Boolean = false;
343+
public autoClose: boolean = false;
344+
public keyboardNav: Boolean = false;
344345

345-
public constructor(config: BsDropdownConfig) {
346-
Object.assign(this, config);
346+
public constructor(config: BsDropdownConfig) {
347+
Object.assign(this, config);
348+
}
347349
}
348-
}

0 commit comments

Comments
 (0)