summaryrefslogtreecommitdiff
path: root/spec/frontend/vue_shared/components/dropdown_keyboard_navigation_spec.js
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/vue_shared/components/dropdown_keyboard_navigation_spec.js')
-rw-r--r--spec/frontend/vue_shared/components/dropdown_keyboard_navigation_spec.js141
1 files changed, 141 insertions, 0 deletions
diff --git a/spec/frontend/vue_shared/components/dropdown_keyboard_navigation_spec.js b/spec/frontend/vue_shared/components/dropdown_keyboard_navigation_spec.js
new file mode 100644
index 00000000000..996df34f2ff
--- /dev/null
+++ b/spec/frontend/vue_shared/components/dropdown_keyboard_navigation_spec.js
@@ -0,0 +1,141 @@
+import { shallowMount } from '@vue/test-utils';
+import DropdownKeyboardNavigation from '~/vue_shared/components/dropdown_keyboard_navigation.vue';
+import { UP_KEY_CODE, DOWN_KEY_CODE, TAB_KEY_CODE } from '~/lib/utils/keycodes';
+
+const MOCK_INDEX = 0;
+const MOCK_MAX = 10;
+const MOCK_MIN = 0;
+const MOCK_DEFAULT_INDEX = 0;
+
+describe('DropdownKeyboardNavigation', () => {
+ let wrapper;
+
+ const defaultProps = {
+ index: MOCK_INDEX,
+ max: MOCK_MAX,
+ min: MOCK_MIN,
+ defaultIndex: MOCK_DEFAULT_INDEX,
+ };
+
+ const createComponent = (props) => {
+ wrapper = shallowMount(DropdownKeyboardNavigation, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ });
+ };
+
+ const helpers = {
+ arrowDown: () => {
+ document.dispatchEvent(new KeyboardEvent('keydown', { keyCode: DOWN_KEY_CODE }));
+ },
+ arrowUp: () => {
+ document.dispatchEvent(new KeyboardEvent('keydown', { keyCode: UP_KEY_CODE }));
+ },
+ tab: () => {
+ document.dispatchEvent(new KeyboardEvent('keydown', { keyCode: TAB_KEY_CODE }));
+ },
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('onInit', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('should $emit @change with the default index', async () => {
+ expect(wrapper.emitted('change')[0]).toStrictEqual([MOCK_DEFAULT_INDEX]);
+ });
+
+ it('should $emit @change with the default index when max changes', async () => {
+ wrapper.setProps({ max: 20 });
+ await wrapper.vm.$nextTick();
+ // The first @change`call happens on created() so we test for the second [1]
+ expect(wrapper.emitted('change')[1]).toStrictEqual([MOCK_DEFAULT_INDEX]);
+ });
+ });
+
+ describe('keydown events', () => {
+ let incrementSpy;
+
+ beforeEach(() => {
+ createComponent();
+ incrementSpy = jest.spyOn(wrapper.vm, 'increment');
+ });
+
+ afterEach(() => {
+ incrementSpy.mockRestore();
+ });
+
+ it('onKeydown-Down calls increment(1)', () => {
+ helpers.arrowDown();
+
+ expect(incrementSpy).toHaveBeenCalledWith(1);
+ });
+
+ it('onKeydown-Up calls increment(-1)', () => {
+ helpers.arrowUp();
+
+ expect(incrementSpy).toHaveBeenCalledWith(-1);
+ });
+
+ it('onKeydown-Tab $emits @tab event', () => {
+ helpers.tab();
+
+ expect(wrapper.emitted('tab')).toHaveLength(1);
+ });
+ });
+
+ describe('increment', () => {
+ describe('when max is 0', () => {
+ beforeEach(() => {
+ createComponent({ max: 0 });
+ });
+
+ it('does not $emit any @change events', () => {
+ helpers.arrowDown();
+
+ // The first @change`call happens on created() so we test that we only have 1 call
+ expect(wrapper.emitted('change')).toHaveLength(1);
+ });
+ });
+
+ describe.each`
+ keyboardAction | direction | index | max | min
+ ${helpers.arrowDown} | ${1} | ${10} | ${10} | ${0}
+ ${helpers.arrowUp} | ${-1} | ${0} | ${10} | ${0}
+ `('moving out of bounds', ({ keyboardAction, direction, index, max, min }) => {
+ beforeEach(() => {
+ createComponent({ index, max, min });
+ keyboardAction();
+ });
+
+ it(`in ${direction} direction does not $emit any @change events`, () => {
+ // The first @change`call happens on created() so we test that we only have 1 call
+ expect(wrapper.emitted('change')).toHaveLength(1);
+ });
+ });
+
+ describe.each`
+ keyboardAction | direction | index | max | min
+ ${helpers.arrowDown} | ${1} | ${0} | ${10} | ${0}
+ ${helpers.arrowUp} | ${-1} | ${10} | ${10} | ${0}
+ `('moving in bounds', ({ keyboardAction, direction, index, max, min }) => {
+ beforeEach(() => {
+ createComponent({ index, max, min });
+ keyboardAction();
+ });
+
+ it(`in ${direction} direction $emits @change event with the correct index ${
+ index + direction
+ }`, () => {
+ // The first @change`call happens on created() so we test for the second [1]
+ expect(wrapper.emitted('change')[1]).toStrictEqual([index + direction]);
+ });
+ });
+ });
+});