Commit 1d599b61 authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

Merge branch '301143-fix-race-condition-for-opening-mobile-top-nav' into 'master'

Fix race condition of `menu-expanded` and top nav

See merge request gitlab-org/gitlab!63687
parents bcbf3f72 45c750b2
......@@ -203,6 +203,9 @@ document.addEventListener('DOMContentLoaded', () => {
});
$('.navbar-toggler').on('click', () => {
// The order is important. The `menu-expanded` is used as a source of truth for now.
// This can be simplified when the :combined_menu feature flag is removed.
// https://gitlab.com/gitlab-org/gitlab/-/issues/333180
$('.header-content').toggleClass('menu-expanded');
navEventHub.$emit(EVENT_RESPONSIVE_TOGGLE);
});
......
......@@ -3,7 +3,7 @@ import { FREQUENT_ITEMS_PROJECTS, FREQUENT_ITEMS_GROUPS } from '~/frequent_items
import { BV_DROPDOWN_SHOW, BV_DROPDOWN_HIDE } from '~/lib/utils/constants';
import KeepAliveSlots from '~/vue_shared/components/keep_alive_slots.vue';
import eventHub, { EVENT_RESPONSIVE_TOGGLE } from '../event_hub';
import { resetMenuItemsActive } from '../utils/reset_menu_items_active';
import { resetMenuItemsActive, hasMenuExpanded } from '../utils';
import ResponsiveHeader from './responsive_header.vue';
import ResponsiveHome from './responsive_home.vue';
import TopNavContainerView from './top_nav_container_view.vue';
......@@ -33,9 +33,11 @@ export default {
},
},
created() {
eventHub.$on(EVENT_RESPONSIVE_TOGGLE, this.onToggle);
eventHub.$on(EVENT_RESPONSIVE_TOGGLE, this.updateResponsiveOpen);
this.$root.$on(BV_DROPDOWN_SHOW, this.showMobileOverlay);
this.$root.$on(BV_DROPDOWN_HIDE, this.hideMobileOverlay);
this.updateResponsiveOpen();
},
beforeDestroy() {
eventHub.$off(EVENT_RESPONSIVE_TOGGLE, this.onToggle);
......@@ -43,8 +45,12 @@ export default {
this.$root.$off(BV_DROPDOWN_HIDE, this.hideMobileOverlay);
},
methods: {
onToggle() {
document.body.classList.toggle('top-nav-responsive-open');
updateResponsiveOpen() {
if (hasMenuExpanded()) {
document.body.classList.add('top-nav-responsive-open');
} else {
document.body.classList.remove('top-nav-responsive-open');
}
},
onMenuItemClick({ view }) {
if (view) {
......
export const hasMenuExpanded = () => {
const header = document.querySelector('.header-content');
return Boolean(header?.classList.contains('menu-expanded'));
};
export * from './has_menu_expanded';
export * from './reset_menu_items_active';
import { shallowMount } from '@vue/test-utils';
import { range } from 'lodash';
import ResponsiveApp from '~/nav/components/responsive_app.vue';
import ResponsiveHeader from '~/nav/components/responsive_header.vue';
import ResponsiveHome from '~/nav/components/responsive_home.vue';
......@@ -32,6 +31,7 @@ describe('~/nav/components/responsive_app.vue', () => {
const hasMobileOverlayVisible = () => findMobileOverlay().classes('mobile-nav-open');
beforeEach(() => {
document.body.innerHTML = '';
// Add test class to reset state + assert that we're adding classes correctly
document.body.className = 'test-class';
});
......@@ -53,14 +53,17 @@ describe('~/nav/components/responsive_app.vue', () => {
});
it.each`
times | expectation
${0} | ${false}
${1} | ${true}
${2} | ${false}
bodyHtml | expectation
${''} | ${false}
${'<div class="header-content"></div>'} | ${false}
${'<div class="menu-expanded"></div>'} | ${false}
${'<div></div><div class="header-content menu-expanded"></div>}'} | ${true}
`(
'with responsive toggle event triggered $times, body responsive open = $expectation',
({ times, expectation }) => {
range(times).forEach(triggerResponsiveToggle);
'with responsive toggle event and html set to $bodyHtml, responsive open = $expectation',
({ bodyHtml, expectation }) => {
document.body.innerHTML = bodyHtml;
triggerResponsiveToggle();
expect(hasBodyResponsiveOpen()).toBe(expectation);
},
......@@ -88,6 +91,17 @@ describe('~/nav/components/responsive_app.vue', () => {
);
});
describe('with menu expanded in body', () => {
beforeEach(() => {
document.body.innerHTML = '<div></div><div class="header-content menu-expanded"></div>';
createComponent();
});
it('sets the body responsive open', () => {
expect(hasBodyResponsiveOpen()).toBe(true);
});
});
const projectsContainerProps = {
containerClass: 'gl-px-3',
frequentItemsDropdownType: ResponsiveApp.FREQUENT_ITEMS_PROJECTS.namespace,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment