diff --git a/CHANGELOG.md b/CHANGELOG.md index 751e2906f..2e0f0f2b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ - - [#449] @@ -214,7 +223,7 @@ Changelog is rather internal in nature. See release notes for the public overvie [#426]: https://github.com/learningequality/kolibri-design-system/pull/426 - [#426] - - **Description:** Fix `KTabsList` focus state + - **Description:** Fix `KTabsList` focus state - **Products impact:** bugfix - **Addresses:** - - **Components:** `KTabsList`, `KTabs` @@ -338,7 +347,7 @@ Changelog is rather internal in nature. See release notes for the public overvie - **Description:** Fix `KDropdownMenu` not showing after its refactor in [#346] by adding missing template tags to `KButton` - **Products impact:** bugfix - **Addresses:** https://github.com/learningequality/kolibri/issues/9754 - - **Components:** `KDropdownMenu`, `KButton` + - **Components:** `KDropdownMenu`, `KButton` - **Breaking:** no - **Impacts a11y:** no - **Guidance:** - diff --git a/lib/tabs/__tests__/KTabsPanel.spec.js b/lib/tabs/__tests__/KTabsPanel.spec.js index f5c2143dd..01dd383e5 100644 --- a/lib/tabs/__tests__/KTabsPanel.spec.js +++ b/lib/tabs/__tests__/KTabsPanel.spec.js @@ -92,12 +92,17 @@ describe(`KTabsPanel`, () => { // switch to a tab which has no focusable elements wrapper.setProps({ activeTabId: 'lessonsTab' }); + + // Need to wait two ticks - initial value change is in response to a watcher on the updated prop, + // and then the value is only updated after the nextTick + await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick(); expect(wrapper.attributes('tabindex')).toBe('0'); // switch to a tab with a focusable element wrapper.setProps({ activeTabId: 'groupsTab' }); await wrapper.vm.$nextTick(); + await wrapper.vm.$nextTick(); expect(wrapper.attributes('tabindex')).toBe('-1'); }); }); diff --git a/lib/useKResponsiveWindow/__tests__/useKResponsiveWindow.spec.js b/lib/useKResponsiveWindow/__tests__/useKResponsiveWindow.spec.js index c320c4565..146a4882f 100644 --- a/lib/useKResponsiveWindow/__tests__/useKResponsiveWindow.spec.js +++ b/lib/useKResponsiveWindow/__tests__/useKResponsiveWindow.spec.js @@ -4,10 +4,14 @@ import { defineComponent } from '@vue/composition-api'; import { mount } from '@vue/test-utils'; import useKResponsiveWindow from '..'; -const resizeWindow = (width, height) => { +const resizeWindow = (width, height = 768) => { window.innerWidth = width; window.innerHeight = height; window.dispatchEvent(new Event('resize')); + setMedia({ + width: `${width}px`, + height: `${height}px`, + }); }; const TestComponent = () => @@ -28,9 +32,10 @@ describe('useKResponsiveWindow composable', () => { }); }); - it('check if returned properties are initialized on mount', () => { - resizeWindow(1700, 768); + it('check if returned properties are initialized on mount', async () => { + resizeWindow(1700); const wrapper = mount(TestComponent()); + await wrapper.vm.$nextTick(); expect(wrapper.vm.windowWidth).toEqual(1700); expect(wrapper.vm.windowHeight).toEqual(768); expect(wrapper.vm.windowBreakpoint).toEqual(7); @@ -44,121 +49,107 @@ describe('useKResponsiveWindow composable', () => { }); describe('check if windowBreakpoint is set on width change', () => { - it('windowBreakpoint is 0 if width <= 480px', () => { - setMedia({ - width: '400px', - }); + it('windowBreakpoint is 0 if width <= 480px', async () => { + resizeWindow(400); const wrapper = mount(TestComponent()); + await wrapper.vm.$nextTick(); expect(wrapper.vm.windowBreakpoint).toEqual(0); }); - it('windowBreakpoint is 1 if 480px < width <= 600px', () => { - setMedia({ - width: '540px', - }); + it('windowBreakpoint is 1 if 480px < width <= 600px', async () => { + resizeWindow(540); const wrapper = mount(TestComponent()); + await wrapper.vm.$nextTick(); expect(wrapper.vm.windowBreakpoint).toEqual(1); }); - it('windowBreakpoint is 2 if 600px < width <= 840px', () => { - setMedia({ - width: '800px', - }); + it('windowBreakpoint is 2 if 600px < width <= 840px', async () => { + resizeWindow(800); const wrapper = mount(TestComponent()); + await wrapper.vm.$nextTick(); expect(wrapper.vm.windowBreakpoint).toEqual(2); }); - it('windowBreakpoint is 3 if 840px < width <= 944px', () => { - setMedia({ - width: '944px', - }); + it('windowBreakpoint is 3 if 840px < width <= 944px', async () => { + resizeWindow(944); const wrapper = mount(TestComponent()); + await wrapper.vm.$nextTick(); expect(wrapper.vm.windowBreakpoint).toEqual(3); }); - it('windowBreakpoint is 4 if 944px < width <= 1264px', () => { - setMedia({ - width: '1264px', - }); + it('windowBreakpoint is 4 if 944px < width <= 1264px', async () => { + resizeWindow(1264); const wrapper = mount(TestComponent()); + await wrapper.vm.$nextTick(); expect(wrapper.vm.windowBreakpoint).toEqual(4); }); - it('windowBreakpoint is 5 if 1264px < width <= 1424px', () => { - setMedia({ - width: '1424px', - }); + it('windowBreakpoint is 5 if 1264px < width <= 1424px', async () => { + resizeWindow(1424); const wrapper = mount(TestComponent()); + await wrapper.vm.$nextTick(); expect(wrapper.vm.windowBreakpoint).toEqual(5); }); - it('windowBreakpoint is 6 if 1424px < width <= 1584px', () => { - setMedia({ - width: '1584px', - }); + it('windowBreakpoint is 6 if 1424px < width <= 1584px', async () => { + resizeWindow(1584); const wrapper = mount(TestComponent()); + await wrapper.vm.$nextTick(); expect(wrapper.vm.windowBreakpoint).toEqual(6); }); - it('windowBreakpoint is 7 if width >= 1601px', () => { - setMedia({ - width: '1800px', - }); + it('windowBreakpoint is 7 if width >= 1601px', async () => { + resizeWindow(1800); const wrapper = mount(TestComponent()); + await wrapper.vm.$nextTick(); expect(wrapper.vm.windowBreakpoint).toEqual(7); }); }); describe('check if windowIsSmall is set on width change', () => { - it('windowIsSmall is false if width > 600px', () => { - setMedia({ - width: '601px', - }); + it('windowIsSmall is false if width > 600px', async () => { + resizeWindow(601); const wrapper = mount(TestComponent()); + await wrapper.vm.$nextTick(); expect(wrapper.vm.windowIsSmall).toEqual(false); }); - it('windowIsSmall is true if width <= 600px', () => { - setMedia({ - width: '600px', - }); + it('windowIsSmall is true if width <= 600px', async () => { + resizeWindow(600); const wrapper = mount(TestComponent()); + await wrapper.vm.$nextTick(); expect(wrapper.vm.windowIsSmall).toEqual(true); }); }); describe('check if windowIsMedium is set on width change', () => { - it('windowIsMedium is false if width <= 600px', () => { - setMedia({ - width: '600px', - }); + it('windowIsMedium is false if width <= 600px', async () => { + resizeWindow(600); const wrapper = mount(TestComponent()); + await wrapper.vm.$nextTick(); expect(wrapper.vm.windowIsMedium).toEqual(false); }); - it('windowIsMedium is true if 600px < width >= 840px', () => { - setMedia({ - width: '700px', - }); + it('windowIsMedium is true if 600px < width <= 840px', async () => { + resizeWindow(700); const wrapper = mount(TestComponent()); + await wrapper.vm.$nextTick(); expect(wrapper.vm.windowIsMedium).toEqual(true); }); }); describe('check if windowIsLarge is set on width change', () => { - it('windowIsLarge is false if width <= 840px', () => { - setMedia({ - width: '840px', - }); + it('windowIsLarge is false if width <= 840px', async () => { + resizeWindow(840); const wrapper = mount(TestComponent()); + await wrapper.vm.$nextTick(); expect(wrapper.vm.windowIsLarge).toEqual(false); }); - it('windowIsLarge is true if width > 840px', () => { - setMedia({ - width: '841px', - }); + it('windowIsLarge is true if width > 840px', async () => { + resizeWindow(841); const wrapper = mount(TestComponent()); + await wrapper.vm.$nextTick(); expect(wrapper.vm.windowIsLarge).toEqual(true); }); }); @@ -191,27 +182,24 @@ describe('useKResponsiveWindow composable', () => { }); describe('check if windowGutter is set on width change', () => { - it('windowGutter is 16px if windowIsSmall is true(width <= 600px)', () => { - setMedia({ - width: '600px', - }); + it('windowGutter is 16px if windowIsSmall is true(width <= 600px)', async () => { + resizeWindow(600); const wrapper = mount(TestComponent()); + await wrapper.vm.$nextTick(); expect(wrapper.vm.windowIsSmall).toEqual(true); expect(wrapper.vm.windowGutter).toEqual(16); }); - it('windowGutter is 16px if windowBreakpoint < 4(width < 1264px) and smallest dimension(width, height) is smaller than 600px', () => { - setMedia({ - width: '500px', - }); + it('windowGutter is 16px if windowBreakpoint < 4(width < 1264px) and smallest dimension(width, height) is smaller than 600px', async () => { + resizeWindow(500, 500); const wrapper = mount(TestComponent()); + await wrapper.vm.$nextTick(); expect(wrapper.vm.windowBreakpoint).toEqual(1); expect(wrapper.vm.windowGutter).toEqual(16); }); - it('windowGutter is 24px if windowIsSmall is false(width > 600px)', () => { - setMedia({ - width: '841px', - }); + it('windowGutter is 24px if windowIsSmall is false(width > 600px)', async () => { + resizeWindow(841); const wrapper = mount(TestComponent()); + await wrapper.vm.$nextTick(); expect(wrapper.vm.windowGutter).toEqual(24); }); }); diff --git a/lib/useKResponsiveWindow/index.js b/lib/useKResponsiveWindow/index.js index f713a2b14..299ce46ae 100644 --- a/lib/useKResponsiveWindow/index.js +++ b/lib/useKResponsiveWindow/index.js @@ -36,7 +36,7 @@ const heightQuery = new MediaQuery('screen and (max-height: 600px)', event => { function initProps() { orientationQuery.eventHandler(orientationQuery.mediaQueryList); heightQuery.eventHandler(heightQuery.mediaQueryList); -}; +} initProps(); @@ -46,7 +46,7 @@ initProps(); function startListening() { orientationQuery.startListening(); heightQuery.startListening(); -}; +} /** * Stop listening to media query changes @@ -54,7 +54,7 @@ function startListening() { function stopListening() { orientationQuery.stopListening(); heightQuery.stopListening(); -}; +} /** * Update window breakpoint @@ -62,22 +62,26 @@ function stopListening() { function updateBreakPoint() { const SCROLL_BAR = 16; const widthBreakpoints = [ - 480, 600, 840, 960 - SCROLL_BAR, 1280 - SCROLL_BAR, 1440 - SCROLL_BAR, 1600 - SCROLL_BAR, + 480, + 600, + 840, + 960 - SCROLL_BAR, + 1280 - SCROLL_BAR, + 1440 - SCROLL_BAR, + 1600 - SCROLL_BAR, ]; // if windowWidth is null (upon initialization), breakpoint = 0 const firstMatchingWidthIndex = windowWidth.value - ? widthBreakpoints.findIndex(matchingWidth => windowWidth.value < matchingWidth) + ? widthBreakpoints.findIndex(matchingWidth => windowWidth.value <= matchingWidth) : 0; // if windowWidth > 1585, breakpoint = 7 - const matchingBreakpoint = firstMatchingWidthIndex >= 0 - ? firstMatchingWidthIndex - : 7; + const matchingBreakpoint = firstMatchingWidthIndex >= 0 ? firstMatchingWidthIndex : 7; windowBreakpoint.value = matchingBreakpoint; updateGutter(); -}; +} watch([windowWidth, windowHeight], updateBreakPoint); @@ -90,7 +94,7 @@ function updateGutter() { } else { windowGutter.value = 24; } -}; +} /** * Check if the smallest window dimension(width or height) is smaller than the specified dimension @@ -98,10 +102,8 @@ function updateGutter() { * @returns {Boolean} */ function smallestWindowDimensionIsLessThan(dimension) { - return ( - windowBreakpoint.value < 4 && Math.min(windowWidth.value, windowHeight.value) < dimension - ); -}; + return windowBreakpoint.value < 4 && Math.min(windowWidth.value, windowHeight.value) < dimension; +} /** * Update window orientation @@ -110,7 +112,7 @@ function smallestWindowDimensionIsLessThan(dimension) { function updateOrientation(portrait) { windowIsPortrait.value = portrait; windowIsLandscape.value = !windowIsPortrait.value; -}; +} /** * Export window properties