import { newSpecPage } from '@stencil/core/testing';
import { BsDropdownOptionList } from '../bs-dropdown-option-list';
import { faker } from '@faker-js/faker';
import { fireEvent } from '@testing-library/dom';
import { MockMutationObserver } from '../../../utils/test/mocks';
describe('bs-dropdown-options-list', () => {
  global.MutationObserver = MockMutationObserver;
  describe('rendering', () => {
    let optionsId;
    let content;
    beforeEach(() => {
      optionsId = faker.random.alphaNumeric(10);
      content = faker.random.words(10);
    });
    // renders basic
    it('renders', async () => {
      const page = await newSpecPage({
        components: [BsDropdownOptionList],
        html: `<bs-dropdown-option-list options-id="${optionsId}">
          ${content}
        </bs-dropdown-option-list>`
      });
      expect(page.root).toEqualHtml(`<bs-dropdown-option-list
        options-id="${optionsId}"
      >
        <ul
          class="bs-dropdown-options"
          id="${optionsId}"
          role="listbox"
        >
          ${content}
        </ul>
      </bs-dropdown-option-list>`);
    });
    // label provided
    it('should set aria-label when label is given', async () => {
      const label = faker.random.words(10);
      const page = await newSpecPage({
        components: [BsDropdownOptionList],
        html: `<bs-dropdown-option-list
          options-id="${optionsId}"
          label="${label}"
        >
          ${content}
        </bs-dropdown-option-list>`
      });
      const ulEl = page.root.querySelector('ul');
      expect(ulEl.getAttribute('aria-label')).toBe(label);
    });
    // set activedescendant
    it('should set aria-activedescendant when an option is selected', async () => {
      const optionId = faker.random.alphaNumeric(10);
      const page = await newSpecPage({
        components: [BsDropdownOptionList],
        html: `<bs-dropdown-option-list
          options-id="${optionsId}"
        >
          ${content}
        </bs-dropdown-option-list>`
      });
      const ulEl = page.root.querySelector('ul');
      page.rootInstance.activeDescendantId = optionId;
      await page.waitForChanges();
      expect(ulEl.getAttribute('aria-activedescendant')).toBe(optionId);
    });
    // set attributes on children
    it('should set attributes on children', async () => {
      const page = await newSpecPage({
        components: [BsDropdownOptionList],
        html: `<bs-dropdown-option-list
          options-id="${optionsId}"
          selected-value="2"
          visible
          focus-delay="0"
        >
          <bs-dropdown-option value="1">Option 1</bs-dropdown-option>
          <bs-dropdown-option value="2">Option 2</bs-dropdown-option>
        </bs-dropdown-options>`
      });
      const optionEl = page.root.querySelectorAll('bs-dropdown-option');
      expect(optionEl[0].getAttribute('index')).toBe('0');
      expect(optionEl[0].getAttribute('options-id')).toBe(optionsId);
      expect(optionEl[0].getAttribute('selected')).toBeNull;
      expect(optionEl[1].getAttribute('index')).toBe('1');
      expect(optionEl[1].getAttribute('options-id')).toBe(optionsId);
      expect(optionEl[1].getAttribute('selected')).toBe('true');
    });
    // focus delay
    it('should focus on selected option after focus delay', async () => {
      const page = await newSpecPage({
        components: [BsDropdownOptionList],
        html: `<bs-dropdown-option-list
          options-id="${optionsId}"
          selected-value="2"
          visible
          focus-delay="300"
        >
          <bs-dropdown-option value="1">Option 1</bs-dropdown-option>
          <bs-dropdown-option value="2">Option 2</bs-dropdown-option>
        </bs-dropdown-options>`
      });
      const optionEls = page.root.querySelectorAll('bs-dropdown-option');
      // Wait for focus delay
      await new Promise(res => setTimeout(res, 300));
      expect(optionEls[0].getAttribute('focused')).toBeNull;
      expect(optionEls[1].getAttribute('focused')).toBe('true');
    });
    // not visible now, remove selected
    it('should remove selected when flipping to not visible', async () => {
      const page = await newSpecPage({
        components: [BsDropdownOptionList],
        html: `<bs-dropdown-option-list
          options-id="${optionsId}"
          selected-value="2"
          visible
          focus-delay="0"
        >
          <bs-dropdown-option value="1">Option 1</bs-dropdown-option>
          <bs-dropdown-option value="2">Option 2</bs-dropdown-option>
        </bs-dropdown-options>`
      });
      const optionEl = page.root.querySelectorAll('bs-dropdown-option');
      page.root.removeAttribute('visible');
      await page.waitForChanges();
      expect(optionEl[1].getAttribute('selected')).toBeNull();
    });
  });
  describe('keyboard navigation', () => {
    let optionsId;
    beforeEach(() => {
      optionsId = faker.random.alphaNumeric(10);
    });
    // not visible, keydown
    it('should not move focus on keydown and not visible', async () => {
      const page = await newSpecPage({
        components: [BsDropdownOptionList],
        html: `<bs-dropdown-option-list
          options-id="${optionsId}"
        >
          <bs-dropdown-option value="1">Option 1</bs-dropdown-option>
          <bs-dropdown-option value="2">Option 2</bs-dropdown-option>
          <bs-dropdown-option value="3">Option 3</bs-dropdown-option>
        </bs-dropdown-options>`
      });
      const optionEls = page.root.querySelectorAll('bs-dropdown-option');
      page.rootInstance.isVisible = false;
      fireEvent.keyDown(window, { key: 'ArrowDown' });
      expect(optionEls[0].getAttribute('focused')).toBeNull;
      expect(optionEls[1].getAttribute('focused')).toBeNull;
      expect(optionEls[2].getAttribute('focused')).toBeNull;
    });
    // keydown: ArrowDown
    it('should move focus down on ArrowDown keydown', async () => {
      const page = await newSpecPage({
        components: [BsDropdownOptionList],
        html: `<bs-dropdown-option-list
          options-id="${optionsId}"
          visible
          focus-delay="0"
        >
          <bs-dropdown-option value="1" focused>Option 1</bs-dropdown-option>
          <bs-dropdown-option value="2">Option 2</bs-dropdown-option>
          <bs-dropdown-option value="3">Option 3</bs-dropdown-option>
        </bs-dropdown-options>`
      });
      const optionEls = page.root.querySelectorAll('bs-dropdown-option');
      page.rootInstance.focusedIndex = 0;
      fireEvent.keyDown(window, { key: 'ArrowDown' });
      expect(optionEls[0].getAttribute('focused')).toBeNull;
      expect(optionEls[1].getAttribute('focused')).toBe('true');
      expect(optionEls[2].getAttribute('focused')).toBeNull;
    });
    // keydown: ArrowUp
    it('should move focus up on ArrowUp keydown', async () => {
      const page = await newSpecPage({
        components: [BsDropdownOptionList],
        html: `<bs-dropdown-option-list
          options-id="${optionsId}"
          visible
          focus-delay="0"
        >
          <bs-dropdown-option value="1">Option 1</bs-dropdown-option>
          <bs-dropdown-option value="2">Option 2</bs-dropdown-option>
          <bs-dropdown-option value="3" focused>Option 3</bs-dropdown-option>
        </bs-dropdown-options>`
      });
      const optionEls = page.root.querySelectorAll('bs-dropdown-option');
      page.rootInstance.focusedIndex = 2;
      fireEvent.keyDown(window, { key: 'ArrowUp' });
      expect(optionEls[0].getAttribute('focused')).toBeNull;
      expect(optionEls[1].getAttribute('focused')).toBe('true');
      expect(optionEls[2].getAttribute('focused')).toBeNull;
    });
    // keydown: Home
    it('should move focus to first item on Home keydown', async () => {
      const page = await newSpecPage({
        components: [BsDropdownOptionList],
        html: `<bs-dropdown-option-list
          options-id="${optionsId}"
          visible
          focus-delay="0"
        >
          <bs-dropdown-option value="1">Option 1</bs-dropdown-option>
          <bs-dropdown-option value="2">Option 2</bs-dropdown-option>
          <bs-dropdown-option value="3" focused>Option 3</bs-dropdown-option>
        </bs-dropdown-options>`
      });
      const optionEls = page.root.querySelectorAll('bs-dropdown-option');
      page.rootInstance.focusedIndex = 2;
      fireEvent.keyDown(window, { key: 'Home' });
      expect(optionEls[0].getAttribute('focused')).toBe('true');
      expect(optionEls[1].getAttribute('focused')).toBeNull;
      expect(optionEls[2].getAttribute('focused')).toBeNull;
    });
    // keydown: End
    it('should move focus to last item on End keydown', async () => {
      const page = await newSpecPage({
        components: [BsDropdownOptionList],
        html: `<bs-dropdown-option-list
          options-id="${optionsId}"
          visible
          focus-delay="0"
        >
          <bs-dropdown-option value="1" focused>Option 1</bs-dropdown-option>
          <bs-dropdown-option value="2">Option 2</bs-dropdown-option>
          <bs-dropdown-option value="3">Option 3</bs-dropdown-option>
        </bs-dropdown-options>`
      });
      const optionEls = page.root.querySelectorAll('bs-dropdown-option');
      page.rootInstance.focusedIndex = 0;
      fireEvent.keyDown(window, { key: 'End' });
      expect(optionEls[0].getAttribute('focused')).toBeNull;
      expect(optionEls[1].getAttribute('focused')).toBeNull;
      expect(optionEls[2].getAttribute('focused')).toBe('true');
    });
    // keydown: ArrowDown wrap
    it('should wrap focus to first item on ArrowDown keydown and last item currently focused', async () => {
      const page = await newSpecPage({
        components: [BsDropdownOptionList],
        html: `<bs-dropdown-option-list
          options-id="${optionsId}"
          visible
          focus-delay="0"
        >
          <bs-dropdown-option value="1">Option 1</bs-dropdown-option>
          <bs-dropdown-option value="2">Option 2</bs-dropdown-option>
          <bs-dropdown-option value="3" focused>Option 3</bs-dropdown-option>
        </bs-dropdown-options>`
      });
      const optionEls = page.root.querySelectorAll('bs-dropdown-option');
      page.rootInstance.focusedIndex = 2;
      fireEvent.keyDown(window, { key: 'ArrowDown' });
      expect(optionEls[0].getAttribute('focused')).toBe('true');
      expect(optionEls[1].getAttribute('focused')).toBeNull;
      expect(optionEls[2].getAttribute('focused')).toBeNull;
    });
    // keydown: ArrowUp wrap
    it('should wrap focus to last item on ArrowUp keydown and first item currently focused', async () => {
      const page = await newSpecPage({
        components: [BsDropdownOptionList],
        html: `<bs-dropdown-option-list
          options-id="${optionsId}"
          visible
          focus-delay="0"
        >
          <bs-dropdown-option value="1" focused>Option 1</bs-dropdown-option>
          <bs-dropdown-option value="2">Option 2</bs-dropdown-option>
          <bs-dropdown-option value="3">Option 3</bs-dropdown-option>
        </bs-dropdown-options>`
      });
      const optionEls = page.root.querySelectorAll('bs-dropdown-option');
      page.rootInstance.focusedIndex = 0;
      fireEvent.keyDown(window, { key: 'ArrowUp' });
      expect(optionEls[0].getAttribute('focused')).toBeNull;
      expect(optionEls[1].getAttribute('focused')).toBeNull;
      expect(optionEls[2].getAttribute('focused')).toBe('true');
    });
  });
  describe('event handling', () => {
    let optionsId;
    beforeEach(() => {
      optionsId = faker.random.alphaNumeric(10);
    });
    // not visible, onmouseenter
    it('should not change focused option on mouseenter when not visible', async () => {
      const page = await newSpecPage({
        components: [BsDropdownOptionList],
        html: `<bs-dropdown-option-list
          options-id="${optionsId}"
        >
          <bs-dropdown-option value="1" focused>Option 1</bs-dropdown-option>
          <bs-dropdown-option value="2">Option 2</bs-dropdown-option>
          <bs-dropdown-option value="3">Option 3</bs-dropdown-option>
        </bs-dropdown-options>`
      });
      const optionEls = page.root.querySelectorAll('bs-dropdown-option');
      const ev = new CustomEvent('onmouseenter', { detail: 1 });
      fireEvent(page.root, ev);
      expect(optionEls[0].getAttribute('focused')).toBe('');
      expect(optionEls[1].getAttribute('focused')).toBeNull;
      expect(optionEls[2].getAttribute('focused')).toBeNull;
    });
    // optmouseenter
    it('should change focused option on mouseenter', async () => {
      const page = await newSpecPage({
        components: [BsDropdownOptionList],
        html: `<bs-dropdown-option-list
          options-id="${optionsId}"
          visible
          focus-delay="0"
        >
          <bs-dropdown-option value="1" focused>Option 1</bs-dropdown-option>
          <bs-dropdown-option value="2">Option 2</bs-dropdown-option>
          <bs-dropdown-option value="3">Option 3</bs-dropdown-option>
        </bs-dropdown-options>`
      });
      const optionEls = page.root.querySelectorAll('bs-dropdown-option');
      const ev = new CustomEvent('optmouseenter', { detail: 1 });
      fireEvent(page.root, ev);
      expect(page.rootInstance.focusedIndex).toEqual(1);
      expect(optionEls[0].getAttribute('focused')).toBeNull;
      expect(optionEls[1].getAttribute('focused')).toBeNull;
      expect(optionEls[2].getAttribute('focused')).toBeNull;
    });
    // optseelect
    it('should set select, emit selected, and close when an option is selected', async () => {
      const optionId = faker.random.alphaNumeric(10);
      const optionValue = faker.random.alphaNumeric(10);
      const page = await newSpecPage({
        components: [BsDropdownOptionList],
        html: `<bs-dropdown-option-list
          options-id="${optionsId}"
          visible
          focus-delay="0"
        >
          <bs-dropdown-option value="1">Option 1</bs-dropdown-option>
          <bs-dropdown-option value="2">Option 2</bs-dropdown-option>
          <bs-dropdown-option value="3">Option 3</bs-dropdown-option>
        </bs-dropdown-options>`
      });
      const ulEl = page.root.querySelector('ul');
      const optionEls = page.root.querySelectorAll('bs-dropdown-option');
      page.rootInstance.focusedIndex = 1;
      const mockSelectEv = jest.fn();
      const ev = new CustomEvent('optselect', {
        detail: {
          id: optionId,
          index: 1,
          value: optionValue
        }
      });
      page.root.addEventListener('optselected', mockSelectEv);
      fireEvent(page.root, ev);
      await page.waitForChanges();
      expect(ulEl.getAttribute('aria-activedescendant')).toBe(optionId);
      expect(optionEls[1].getAttribute('focused')).toBeNull;
      expect(mockSelectEv).toHaveBeenCalled();
    });
  });
});
//# sourceMappingURL=bs-dropdown-option-list.spec.js.map
