为什么 HTML 组合框中的向下箭头会跳过一个但显示输入中的上一个选择?

Why does a down arrow in an HTML combo box skip one but shows the previous choice in the input?

我在 elasti-search 机制中有一个下拉框。

我正在使用 Angular,发生的事情是在代码重构之后,向下箭头跳过了一个选择,但它显示了输入中的先前选择。

我的意思是:

所以这是原始代码:

  onKeydown(event: KeyboardEvent) {
    Refactor this function to reduce its Cognitive Complexity from 52 to the 15 allowed.Why is this an issue?
    
    let index = 0;
        if (this.selectedItemIndex === null || this.selectedItemIndex < 0) {
          this.changeAria.emit('showall');
        } else {
          if ((event.key === 'ArrowDown' || event.key === 'Down') && this.isFocused) {
            index = this.selectedItemIndex;
            this.inputRef.nativeElement.getAttribute('aria-activedescendant');
            if(index >= 0 && index <= this.filteredItems.length - 1){
              this.inputRef.nativeElement.value=this.filteredItems[index];
            }
          } else if ((event.key === 'ArrowUp' || event.key === 'Up') && this.isFocused) {
            index = this.selectedItemIndex - 2;
            this.inputRef.nativeElement.getAttribute('aria-activedescendant');
            if(index >= 0 && index <= this.filteredItems.length - 1){
              this.inputRef.nativeElement.value=this.filteredItems[index];
            }
          } else if (index !== null && index >= 0) {
            this.changeAria.emit(this.filteredItems[index]);
          }
        }
    if (event.key === 'Enter' && this.isFocused && this.selectedItemIndex > 0) {
          if (this.selectedItemIndex === 0) {
            event.preventDefault();
            const item = (this.filter !== undefined && this.filter !== null && this.filter !== '') ? this.filter : '';
            this.onItemSelect(null, item);
          } else if (this.selectedItemIndex > 0) {
            event.preventDefault();
            this.onItemSelect(null, this.filteredItems[this.selectedItemIndex - 1]);
          }
        } else if ((event.key === 'ArrowUp' || event.key === 'Up') && this.isFocused) {
          event.preventDefault();
          if (this.selectedItemIndex === null || this.selectedItemIndex === 0) {
            this.selectedItemIndex = this.filteredItems.length;
          } else {
            if (this.selectedItemIndex > 0) {
              this.selectedItemIndex--;
            }
          }
        } else if ((event.key === 'ArrowDown' || event.key === 'Down') && this.isFocused) {
          event.preventDefault();
          if (this.selectedItemIndex === null) {
            this.selectedItemIndex = 0;
          } else {
            if (this.selectedItemIndex >= 0 && this.selectedItemIndex < this.filteredItems.length) {
              this.selectedItemIndex++;
            } else {
              this.selectedItemIndex = 0;
            }
          }
        }else if ((event.keyCode==27) && this.isFocused) {
          this.clearFocus();
          this.inputRef.nativeElement.focus();
        }
      }

这是仅与 up/down 箭头移动相关的重构代码

  /**
   * @name: checkForSelected
   * @description: Checks for Selected Index
   * @argument: NONE
   * @returns: boolean - meaning: there's no selected index found
   */
  checkForSelected(): boolean {
    if (this.selectedItemIndex === null || this.selectedItemIndex < 0) {
      this.hasNothingSelected = false;
    } else {
      this.hasNothingSelected = true;
    }
    return this.hasNothingSelected;
  }

  /**
   * @name: checkForArrowDnUp
   * @description: Checks for Arrow is up or down and has focused
   * @param event as ANY
   * @returns: boolean - meaning, whether the arrow is up or down 'and' focused
   */
  checkForArrowDnUp(event: KeyboardEvent, index: number): string {
    if ((event.key === 'ArrowDown' || event.key === 'Down') && this.isFocused) {
      index = this.selectedItemIndex;
      if (index >= 0 && index <= this.filteredItems.length - 1) {
        this.autoCompleteInput.value = this.filteredItems[index];
      }
      this.arrowDnKeyDn = event.key;
    } else if ((event.key === 'ArrowUp' || event.key === 'Up') && this.isFocused) {
      index = this.selectedItemIndex - 2;
      if (index >= 0 && index <= this.filteredItems.length - 1) {
        this.autoCompleteInput.value = this.filteredItems[index];
      }
      this.arrowDnKeyDn = event.key;
    } else {
      this.arrowDnKeyDn = '';
    }
    return this.arrowDnKeyDn;
  }

  /**
   * @name: checkForNullOrZero
   * @description: Checks for index being NULL or ZERO
   * @param index
   * @returns: boolean - Meaning, yes index is null OR Zero or greater than ZERO
   */
  checkForNullOrZero(index: number): boolean {

    this.isNdxNullOrZero = false;

    if (index !== null && index >= 0) {
      this.isNdxNullOrZero = true;
    }

    return this.isNdxNullOrZero;
  }

  /**
   * @name: checkForEnterKeyUpDn
   * @description: Checks for keyboard event if the user PRESSES the ENTER KEY
   * @param event
   * @returns: boolean - Meaning, YES the user has indeed pressed the ENTER KEY
   * @default: variable DEFAULTS to FALSE
   */
  checkForEnterKeyUpDn(event: KeyboardEvent): boolean {

    this.isEnterKeyUpDn = false;

    if (event.key === 'Enter' && this.isFocused && this.selectedItemIndex > 0) {
      this.isEnterKeyUpDn = true;
    }
    return this.isEnterKeyUpDn;
  }

  /**
   * @name: checkForSelectedItemIndexFiltered
   * @description: Checks if the selected item has been filtered to a specific item index or not
   * @param: NONE
   * @returns: boolean - Meaning, YES the selected item has indeed been filter
   * @default: variable DEFAULTS to FALSE
   */
  checkForSelectedItemIndexFiltered(): boolean {

    this.isSelectedItemNdxFoundFiltered = false;

    if (this.selectedItemIndex >= 0 && this.selectedItemIndex < this.filteredItems.length) {
      this.selectedItemIndex++;
    } else {
      this.selectedItemIndex = 0;
    }
    return this.isSelectedItemNdxFoundFiltered;
  }

  checkForKeyEscape(event: KeyboardEvent): boolean {
    this.isKeyDnUpEscape = false;
    if ((event.key === 'Escape') && this.isFocused) {
      this.isKeyDnUpEscape = true;
    }
    return this.isKeyDnUpEscape;
  }

  checkArrowKeysNullZero(arrownnullkey: string, nullzero: boolean, index: number): void {
    this.autoCompleteInput.getAttribute('aria-activedescendant');
    if (arrownnullkey) {
      index = this.selectedItemIndex;
    } else if (!arrownnullkey) {
      index = this.selectedItemIndex - 2;
    }

    if (index >= 0 && index <= this.filteredItems.length - 1) {
      this.autoCompleteInput.value = this.filteredItems[index];
    }
  }


  @HostListener('document:keydown', ['$event'])
  handleOnKeydown(event: KeyboardEvent): void {

    let item = this.filter;
    let index = 0;
    let nothingSelected = this.checkForSelected();
    let arrowDnKeyUpDn = this.checkForArrowDnUp(event, index);
    let enterKeyUpDn = this.checkForEnterKeyUpDn(event);
    let indexNullOrZero = this.checkForNullOrZero(index);
    let selectedItemNdxFiltered = this.checkForSelectedItemIndexFiltered();
    let keyIsEscape = this.checkForKeyEscape(event);

    if (nothingSelected) {
      this.changeAria.emit('showall');
    } else {
      index = this.selectedItemIndex;
      if (indexNullOrZero) {
        this.changeAria.emit(this.filteredItems[index]);
      } else {
        this.checkArrowKeysNullZero(arrowDnKeyUpDn, indexNullOrZero, index);
      }
      if (index !== null && index >= 0) {
        this.changeAria.emit(this.filteredItems[index]);
      }
    }

    if (keyIsEscape) { // KeyCode = 27
      this.clearFocus();
      this.autoCompleteInput.focus();
    } else {
      if (enterKeyUpDn) {
        this.enterKeyUpDown(item);
      } else if (arrowDnKeyUpDn) {
        this.arrowDownKeyUpDown(event, arrowDnKeyUpDn);
      } else {
        this.notArrowDownKeyUpDown(selectedItemNdxFiltered);
      }
    }
  }

  enterKeyUpDown(item: string): void {
    switch (true) {
      case this.selectedItemIndex === 0:
        this.onItemSelect(null, item);
        // this.onItemSelect(null, this.filteredItems[this.selectedItemIndex + 1]);
        break;
      case this.selectedItemIndex > 0:
        this.onItemSelect(null, this.filteredItems[this.selectedItemIndex - 1]);
        break;
      default:
        break;
    }
  }

  arrowDownKeyUpDown(event: any, arrkeyvalue: string): void {

    switch (arrkeyvalue) {
      case 'ArrowUp':
      case 'Up':
        this.isArrowUp(event)
        break;
      case 'ArrowDown':
      case 'Down':
        this.isArrowDown(event);
        break;
      default:
        if (this.selectedItemIndex > 0) {
          this.selectedItemIndex--;
        }
        break;
    }
  }

  isArrowUp(event: KeyboardEvent): void {
    if (this.isFocused) {
      event.preventDefault();
      if (this.selectedItemIndex === null || this.selectedItemIndex === 0) {
        this.selectedItemIndex = this.filteredItems.length;
      } else {
        if (this.selectedItemIndex > 0) {
          this.selectedItemIndex--;
          if (this.selectedItemIndex === 0) {
            this.selectedItemIndex = this.filteredItems.length;
          }
        }
      }
    }
  }

  isArrowDown(event: KeyboardEvent): void {
    if (this.isFocused) {
      event.preventDefault();
      if (this.selectedItemIndex === null) {
        this.selectedItemIndex = 0;
      } else {
        if (this.selectedItemIndex >= 0 && this.selectedItemIndex < this.filteredItems.length) {
          this.selectedItemIndex++;
        } else {
          this.selectedItemIndex = 0;
        }
      }
    }
  }

  notArrowDownKeyUpDown(selectedItemNdxFiltered: boolean): void {
    if (this.selectedItemIndex === null) {
      this.selectedItemIndex = 0;
    } else if (selectedItemNdxFiltered) {
      this.selectedItemIndex++;
    } else {
      this.selectedItemIndex = 0;
    }
  }

最后,向上箭头根本不起作用。

如果我放回旧代码,一切都很好。

所以,这一定是我在重构中所做的事情。

我重构的原因是 SonarQube 不喜欢所有的 if、then、else if、嵌套的 if。

从 52 期中,我将它减少到零。

我只需要克服这个障碍。

谢谢。

欧文,先生,你能像以前一样伸出援手吗?

更新!请参阅下面的答案。我修好了。

重构更多后,这是我的解决方案:

TS 文件:

import {
  AfterViewInit, Component, ContentChild, ElementRef, EventEmitter, HostListener,
  Input, Output, Renderer2, OnChanges
} from '@angular/core';

@Component({
  selector: 'uhc-autocomplete',
  templateUrl: './autocomplete.component.html',
  styleUrls: ['./autocomplete.component.scss']
})
export class AutocompleteComponent implements OnChanges, AfterViewInit {

  @ContentChild('secondarySearch') inputRef: ElementRef;
  @Input() filter = '';
  @Input() items: Array<any> = [];
  @Output() itemSelect: EventEmitter<any> = new EventEmitter<any>();
  @Output() changeAria: EventEmitter<any> = new EventEmitter<any>();

  isFocused = true;
  filteredItems = [];
  selectedItemIndex = 0;
  autoCompleteInput: HTMLInputElement;
  keyBoardEvent: string;
  item: string;
  isArrowUpOrDown: string;
  textSelected: any;
  selectedEvent: Event;

  constructor(private renderer: Renderer2) { }

  ngOnChanges() {
    this.filterItems();
  }
  ngAfterViewInit() {

    this.autoCompleteInput = <HTMLInputElement>document.querySelector('.search-input');

    this.bindOnBlurStateEventCallback();
    this.bindOnInputStateEventCallback();
    this.bindOnFocusStateEventCallback();

    if (this.autoCompleteInput && this.autoCompleteInput.value.length > 0) {
      this.renderer.setAttribute(this.autoCompleteInput, 'aria-autocomplete', 'both');
      if (this.filter !== undefined && this.filter !== null && this.filter !== '') {
        this.filter = '';
      }
    }

  }

  bindOnBlurStateEventCallback(): void {

    if (this.autoCompleteInput && this.autoCompleteInput.value.length > 0) {
      console.log('You selected: ', this.autoCompleteInput.value);
      const blurCallback = (message: string) => {
        console.log('Callback Message: ', message);
      }
      console.log('blurCallback ', blurCallback);
      this.bindingBlur();
    }

  }

  bindingBlur(): string {
    console.log('Binding Blur called');
    this.autoCompleteInput.addEventListener('blur', () => {
      console.log('You selected: ', this.autoCompleteInput.value);
      this.clearFocus();
    });
    return this.autoCompleteInput.value;
  }

  bindOnInputStateEventCallback(): void {
    if (this.autoCompleteInput && this.autoCompleteInput.value.length > 0) {
      this.autoCompleteInput.addEventListener('onInput', () => {
        console.log('You selected: ', this.inputRef.nativeElement.value);
      });
      this.bindingInput();
    }
  }

  bindingInput(): string {
    console.log('Binding Input called');
    this.autoCompleteInput.addEventListener('onInput', () => {
      console.log('You selected: ', this.autoCompleteInput.value);
    });
    return this.autoCompleteInput.value;
  }

  bindOnFocusStateEventCallback(): void {
    if (this.autoCompleteInput && this.autoCompleteInput.value.length > 0) {
      this.inputRef.nativeElement.addEventListener('focus', this.onFocus.bind(this));
      this.inputRef.nativeElement.addEventListener('onFocus', () => {
        console.log('You selected: ', this.inputRef.nativeElement.value);
      });
      this.bindingFocus();
    }
  }

  bindingFocus(): string {
    console.log('Binding Focus called');
    this.autoCompleteInput.addEventListener('onFocus', () => {
      console.log('You selected: ', this.autoCompleteInput.value);
    });
    return this.autoCompleteInput.value;
  }

  clearFocus() {
    if (this.autoCompleteInput !== undefined) {
      console.log('Inside Clear Focus! ' + this.autoCompleteInput.value);
      this.autoCompleteInput.blur();
    }
  }

  onBlur() {
    this.selectedItemIndex = 0;
    this.isFocused = false;
  }

  onItemSelect(event: Event, item: string) {
    if (item) {
      this.selectedEvent = event;
      this.itemSelect.emit(item);
      this.clearFocus();
    } else {
      this.clearFocus();
    }
  }

  onFocus(event: Event) {
    this.selectedEvent = event;
    this.filterItems();
    this.isFocused = true;
  }
  onInput(event: Event) {
    this.selectedEvent = event;
    this.filterItems();
  }

  onMouseDown(event: { preventDefault: () => void; }) {
    event.preventDefault();
  }
  mouseEnter(i: number) {
    this.selectedItemIndex = i + 1;
  }

  uniq(a: Iterable<unknown>) {
    return Array.from(new Set(a));
  }
  filterItems() {
    this.filteredItems = this.uniq(this.items);
  }


  keyDownArrowDown(event: KeyboardEvent, index: number): void {
    this.keyBoardEvent = event.key;
    let kybrdEvnt = event.key

    if ((kybrdEvnt === 'ArrowDown' || kybrdEvnt === 'Down') && this.isFocused) {
      index = this.selectedItemIndex;
      this.inputRef.nativeElement.getAttribute('aria-activedescendant');

      if (index >= 0 && index <= this.filteredItems.length - 1) {
        this.inputRef.nativeElement.value = this.filteredItems[index];
      }
    } else if ((kybrdEvnt === 'ArrowUp' || kybrdEvnt === 'Up') && this.isFocused) {
      index = this.selectedItemIndex - 2;
      this.inputRef.nativeElement.getAttribute('aria-activedescendant');
      if (index >= 0 && index <= this.filteredItems.length - 1) {
        this.inputRef.nativeElement.value = this.filteredItems[index];
      }
    } else if (index !== null && index >= 0) {
      this.changeAria.emit(this.filteredItems[index]);
    }
  }

  enterKeyDown(event: KeyboardEvent): void {

    const item = (this.filter !== undefined && this.filter !== null && this.filter !== '') ? this.filter : '';
    this.item = item;

    if (this.selectedItemIndex === 0) {
      event.preventDefault();
      this.onItemSelect(null, item);
    } else if (this.selectedItemIndex > 0) {
      event.preventDefault();
      this.onItemSelect(null, this.filteredItems[this.selectedItemIndex - 1]);
    }

  }

  altArrowUpNoEnter(event: KeyboardEvent): void {

    this.isArrowUpOrDown = event.key;

    if (this.selectedItemIndex === null || this.selectedItemIndex === 0) {
      this.selectedItemIndex = this.filteredItems.length;
    } else {
      if (this.selectedItemIndex > 0) {
        this.selectedItemIndex--;
      }
    }
  }

  altArrowDnNoEnter(event: KeyboardEvent): void {

    this.isArrowUpOrDown = event.key;

    if (this.selectedItemIndex === null) {
      this.selectedItemIndex = 0;
    } else {
      if (this.selectedItemIndex >= 0 && this.selectedItemIndex < this.filteredItems.length) {
        this.selectedItemIndex++;
      } else {
        this.selectedItemIndex = 0;
      }
    }
  }

  @HostListener('document:keydown', ['$event'])
  handleOnKeydown(event: KeyboardEvent) {
    let index = 0;
    if (this.selectedItemIndex === null || this.selectedItemIndex < 0) {
      this.changeAria.emit('showall');
    } else {
      this.keyDownArrowDown(event, index);
    }
    if (event.key === 'Enter' && this.isFocused && this.selectedItemIndex > 0) {
      this.enterKeyDown(event);
    } else if ((event.key === 'ArrowUp' || event.key === 'Up') && this.isFocused) {
      event.preventDefault();
      this.altArrowUpNoEnter(event);
    } else if ((event.key === 'ArrowDown' || event.key === 'Down') && this.isFocused) {
      event.preventDefault();
      this.altArrowDnNoEnter(event);
    } else if ((event.key === 'Escape') && this.isFocused) {
      this.clearFocus();
      this.inputRef.nativeElement.focus();
    }
  }

  patternTextForIdAttribute(text: any): string {
    this.textSelected = text;
    return text.replace(/\ /g, '_');
  }

  handleEvent = (event: KeyboardEvent) => {
    const { key } = event;
  }

}

规范 TS 文件:

    import { TestBed, async, ComponentFixture, fakeAsync, tick } from '@angular/core/testing';
    import { RouterTestingModule } from '@angular/router/testing';
    import { CUSTOM_ELEMENTS_SCHEMA, DebugElement, ɵɵNgOnChangesFeature } from '@angular/core';
    import { AutocompleteComponent } from './autocomplete.component';
    import { not } from '@angular/compiler/src/output/output_ast';

    describe('Auto Complete Component', () => {
        let autoCompleteComponent: AutocompleteComponent;
        let fixture: ComponentFixture<AutocompleteComponent>;
        let autocompleteInput: HTMLInputElement;
        let filteredItems: string[] = [];
        let item: string;
        let nbr: number;
        let selectedItemIndex: number;
        let e1: { ElementRef: { blur: any; }; };
        let e2: { ElementRef: { focus: any; }; };
        let e3: { ElementRef: { input: any; }; };
        let nothingSelected: boolean;
        let rendered: DebugElement;
        let event: Event;
        let eventListenerService: jasmine.SpyObj<AutocompleteComponent>;
        const spy = jasmine.createSpy();


        beforeEach(async(() => {

            eventListenerService = jasmine.createSpyObj('onBlur', ['blur']);

            TestBed.configureTestingModule({
                imports: [
                    RouterTestingModule.withRoutes([])
                ],
                declarations: [
                    AutocompleteComponent
                ],
                providers: [AutocompleteComponent],
                schemas: [CUSTOM_ELEMENTS_SCHEMA]
            }).compileComponents().then(() => {
                fixture = TestBed.createComponent(AutocompleteComponent);
                autoCompleteComponent = fixture.componentInstance;
                autocompleteInput = <HTMLInputElement>document.querySelector('.search-input');
            });
        }));

        it('adds listener events', function () {
            spyOn(document, 'addEventListener').and.callThrough();
            spyOn(window, 'addEventListener').and.callThrough();

            expect(document.addEventListener.prototype).not.toBeTruthy;
            expect(window.addEventListener.prototype).not.toBeTruthy;

            expect(document.addEventListener.prototype).toBeTruthy;
            expect(window.addEventListener.prototype).toBeTruthy;
            // expect(autoCompleteComponent.autoCompleteInput.addEventListener.prototype).toBeTruthy;
        });

        it('should create the app', () => {
            const fixture = TestBed.createComponent(AutocompleteComponent);
            const app = fixture.componentInstance;
            expect(app).toBeTruthy();
        });

        it("when called multiple times ngAfterViewInit() and fires all three callbacks in order", () => {

            spyOn(autoCompleteComponent, 'ngAfterViewInit').and.callThrough();
            autoCompleteComponent.ngAfterViewInit();
            expect(autoCompleteComponent.ngAfterViewInit).toHaveBeenCalled();

            spyOn(autoCompleteComponent, 'bindOnBlurStateEventCallback').and.callThrough();
            autoCompleteComponent.bindOnBlurStateEventCallback();
            expect(autoCompleteComponent.bindOnBlurStateEventCallback).toBeTruthy();
            expect(autoCompleteComponent.bindOnBlurStateEventCallback).toHaveBeenCalled();

            spyOn(autoCompleteComponent, 'bindOnInputStateEventCallback').and.callThrough();
            autoCompleteComponent.bindOnInputStateEventCallback();
            expect(autoCompleteComponent.bindOnInputStateEventCallback).toBeTruthy();
            expect(autoCompleteComponent.bindOnInputStateEventCallback).toHaveBeenCalled();

            spyOn(autoCompleteComponent, 'bindOnFocusStateEventCallback').and.callThrough();
            autoCompleteComponent.bindOnFocusStateEventCallback();
            expect(autoCompleteComponent.bindOnFocusStateEventCallback).toBeTruthy();
            expect(autoCompleteComponent.bindOnFocusStateEventCallback).toHaveBeenCalled();

        });

        it('uniq function call..', () => {
            const filterKeywords = ['drug', 'drug'];
            var removeDupes = autoCompleteComponent.uniq(filterKeywords);
            expect(removeDupes).toEqual(['drug']);
        });

        it('should cover test case for filterItems function', () => {
            const filterKeywords = ['drug', 'drug'];
            autoCompleteComponent.filterItems();
            autoCompleteComponent.filteredItems = autoCompleteComponent.uniq(filterKeywords);
            expect(autoCompleteComponent.filteredItems).toEqual(['drug']);
        });

        it('should call patternTextForIdAttribute function ', () => {

            var result = autoCompleteComponent.patternTextForIdAttribute('site search');
            expect(result).toBe('site_search');
        });

        it('should create call ngOnChanges ', () => {

            spyOn(autoCompleteComponent, 'ngOnChanges').and.callThrough();
            autoCompleteComponent.ngOnChanges();

            spyOn(autoCompleteComponent, 'filterItems').and.callThrough();
            autoCompleteComponent.filterItems();

            expect(autoCompleteComponent.filterItems).toHaveBeenCalled();
            expect(autoCompleteComponent.ngOnChanges).toHaveBeenCalled();

        });


        it('should call onBlur Event ', () => {
            spyOn(autoCompleteComponent, 'onBlur').and.callThrough();

            autoCompleteComponent.onBlur();

            expect(autoCompleteComponent.onBlur).toHaveBeenCalled();
        });

        it('should create call clearFocus ', () => {

            const checkForInputBlur = spyOn(autoCompleteComponent, 'onBlur');
            checkForInputBlur.and.callThrough();
            let autoCompValue = '';

            if (autoCompleteComponent.autoCompleteInput === undefined) {
                autoCompValue = 'Drugs';
            }

            fixture.whenStable().then(() => {
                expect(autoCompleteComponent.autoCompleteInput.blur).toHaveBeenCalled();
                // expect(autoCompleteComponent.autoCompleteInput.onblur).toContain(autocompleteInput);
            });
            if (autoCompValue !== '' || autoCompValue !== undefined) {
                spyOn(autoCompleteComponent,'clearFocus');
                // expect(autoCompleteComponent).toContain('clearFocus');
                expect(autoCompleteComponent.autoCompleteInput).toBeUndefined();
                autoCompleteComponent.clearFocus();
                expect(autoCompleteComponent.clearFocus).toHaveBeenCalled();
            } else {
                expect(autoCompleteComponent.autoCompleteInput).toBeUndefined();
                expect(autoCompleteComponent.clearFocus()).not.toBeUndefined();
            }

        });

        it('should call onItemSelect Event ', () => {

            let item = 'drug';

            spyOn(autoCompleteComponent, 'onItemSelect').and.callThrough();
            if (autoCompleteComponent.item) {
                autoCompleteComponent.onItemSelect(event, item);
                expect(autoCompleteComponent.onItemSelect(event, item)).toHaveBeenCalled();
            } else {
                expect(autoCompleteComponent.onItemSelect(event, item)).toBeUndefined();
            }
            spyOn(autoCompleteComponent, 'clearFocus').and.callThrough();
            // expect(autoCompleteComponent.clearFocus).toHaveBeenCalled();

        });

        it('should call onFocus Event ', () => {

            autoCompleteComponent.onFocus(event);
            spyOn(autoCompleteComponent, 'onFocus').and.callThrough();
            autoCompleteComponent.filterItems();
            spyOn(autoCompleteComponent, 'filterItems').and.callThrough();
            expect(autoCompleteComponent.isFocused).toEqual(true);
            expect(autoCompleteComponent.filteredItems).not.toBeNull;
            expect(autoCompleteComponent.filterItems).not.toHaveBeenCalled();
            expect(autoCompleteComponent.onFocus).not.toHaveBeenCalled();

        });

        it('should call onInput Event ', () => {
            spyOn(autoCompleteComponent, 'onInput').and.callThrough();

            autoCompleteComponent.onInput(event);

            expect(autoCompleteComponent.onInput).toHaveBeenCalled();
        });

        it('should call mouseEnter Event ', () => {

            nbr = 1;

            spyOn(autoCompleteComponent, 'mouseEnter').and.callThrough();

            autoCompleteComponent.mouseEnter(nbr);

            expect(autoCompleteComponent.mouseEnter).toHaveBeenCalled();
        });

        it('should call keyDownArrowDown Event ', () => {

            // const keyDnEvent = window.addEventListener('keydown', e => {
            //     autoCompleteComponent.handleEvent(e); // e is KeyboardEvent
            // });

            // const keyUpEvent = window.addEventListener('keyup', e => {
            //     autoCompleteComponent.handleEvent(e); // e is KeyboardEvent
            // });

            spyOn(autoCompleteComponent, 'keyDownArrowDown').and.callThrough();

            let e = jasmine.createSpyObj('e', ['KeyboardEvent']);

            let index = 0;
            let isFocused: boolean;
            isFocused = true;
            let eventKey = autoCompleteComponent.keyBoardEvent;

            if ((eventKey === 'ArrowDown' || eventKey === 'Down') && this.isFocused) {
                index = this.selectedItemIndex;
                autoCompleteComponent.autoCompleteInput.getAttribute('aria-activedescendant');

                if (index >= 0 && index <= this.filteredItems.length - 1) {
                    autoCompleteComponent.autoCompleteInput.value = autoCompleteComponent.filteredItems[index];
                }
            } else if ((eventKey === 'ArrowUp' || eventKey === 'Up') && autoCompleteComponent.isFocused) {
                index = autoCompleteComponent.selectedItemIndex - 2;
                autoCompleteComponent.autoCompleteInput.getAttribute('aria-activedescendant');
                if (index >= 0 && index <= this.filteredItems.length - 1) {
                    autoCompleteComponent.autoCompleteInput.value = autoCompleteComponent.filteredItems[index];
                }
            } else if (index !== null && index >= 0) {
                autoCompleteComponent.changeAria.emit(autoCompleteComponent.filteredItems[index]);
            }
            // expect(autoCompleteComponent.keyDownArrowDown).toEqual('ArrowDown');
            // expect(autoCompleteComponent.keyDownArrowDown).toBeUndefined();
            expect(autoCompleteComponent.keyDownArrowDown(e, index)).toBeUndefined();

        });



        it('should call handleOnKeydown function ', () => {

            let item = autoCompleteComponent.filter;
            let index = 0;

            spyOn(autoCompleteComponent, 'handleOnKeydown').and.callFake((event: any): void => {

                let index = 0;
                if (this.selectedItemIndex === null || this.selectedItemIndex < 0) {
                    this.changeAria.emit('showall');
                } else {
                    this.keyDownArrowDown(event, index);
                }
                if (event.key === 'Enter' && this.isFocused && this.selectedItemIndex > 0) {
                    this.enterKeyDown(event);
                } else if ((event.key === 'ArrowUp' || event.key === 'Up') && this.isFocused) {
                    event.preventDefault();
                    this.altArrowUpNoEnter(event);
                } else if ((event.key === 'ArrowDown' || event.key === 'Down') && this.isFocused) {
                    event.preventDefault();
                    this.altArrowDnNoEnter(event);
                } else if ((event.key === 'Escape') && this.isFocused) {
                    this.clearFocus();
                    this.inputRef.nativeElement.focus();
                }

            });


        });

        it('should call enterKeyDown function ', () => {

            let item = autoCompleteComponent.item;
            let selectedItemIndex = autoCompleteComponent.selectedItemIndex;
            let filtereditems = autoCompleteComponent.filteredItems;

            spyOn(autoCompleteComponent, 'enterKeyDown').and.callFake(() => {
                if (selectedItemIndex === 0) {
                    event.preventDefault();
                    autoCompleteComponent.onItemSelect(null, item);
                } else if (selectedItemIndex > 0) {
                    event.preventDefault();
                    autoCompleteComponent.onItemSelect(null, filtereditems[selectedItemIndex - 1]);
                }

                expect(autoCompleteComponent.enterKeyDown).toBeUndefined();
                expect(autoCompleteComponent.enterKeyDown).toHaveBeenCalled();
            });

        });

        it('should call altArrowUpNoEnter (ARROWUP UP) function ', () => {

            let e = jasmine.createSpyObj('e', ['preventDefault']);
            autoCompleteComponent.altArrowUpNoEnter(e);

            spyOn(autoCompleteComponent, 'altArrowUpNoEnter').and.callFake((): void => {
                if (autoCompleteComponent.selectedItemIndex === null || autoCompleteComponent.selectedItemIndex === 0) {
                    autoCompleteComponent.selectedItemIndex = autoCompleteComponent.filteredItems.length;
                } else {
                    if (autoCompleteComponent.selectedItemIndex > 0) {
                        autoCompleteComponent.selectedItemIndex--;
                    }
                }
            });

            autoCompleteComponent.altArrowUpNoEnter(e);
            expect(autoCompleteComponent.altArrowUpNoEnter).toBeTruthy();

        });

        it('should call altArrowDnNoEnter (ARROWUP DN) function ', () => {

            let e = jasmine.createSpyObj('e', ['preventDefault']);
            autoCompleteComponent.altArrowDnNoEnter(e);

            spyOn(autoCompleteComponent, 'altArrowDnNoEnter').and.callFake((): void => {
                if (autoCompleteComponent.selectedItemIndex === null || autoCompleteComponent.selectedItemIndex === 0) {
                    autoCompleteComponent.selectedItemIndex = autoCompleteComponent.filteredItems.length;
                } else {
                    if (autoCompleteComponent.selectedItemIndex > 0) {
                        autoCompleteComponent.selectedItemIndex--;
                    }
                }
            });

            autoCompleteComponent.altArrowDnNoEnter(e);
            expect(autoCompleteComponent.altArrowDnNoEnter).toBeTruthy();

        });

        it('should call patternTextForIdAttribute function ', () => {

            let text = autoCompleteComponent.textSelected;
            let retValText: string;

            let retVal = spyOn(autoCompleteComponent, 'patternTextForIdAttribute').and.callFake(() => {

                if (text) {
                    retValText = text.replace(/\ /g, '_');
                } else {
                    retValText = '';
                }

                return retValText;

            });

            autoCompleteComponent.patternTextForIdAttribute(text);
            expect(autoCompleteComponent.patternTextForIdAttribute).toBeTruthy();

        });

    });