Commit 58cad116 authored by Paul Slaughter's avatar Paul Slaughter

Setup HAML, CSS, and Vue for top nav responsive

- Add hide-when-top-nav-open classes
- Set up eventHub for app component to use
- Puts placeholder content which will be
  filled in a follow up since this is behind
  a feature flag
parent b2d828d5
...@@ -36,6 +36,7 @@ import GlFieldErrors from './gl_field_errors'; ...@@ -36,6 +36,7 @@ import GlFieldErrors from './gl_field_errors';
import initUserPopovers from './user_popovers'; import initUserPopovers from './user_popovers';
import initBroadcastNotifications from './broadcast_notification'; import initBroadcastNotifications from './broadcast_notification';
import { initTopNav } from './nav'; import { initTopNav } from './nav';
import navEventHub, { EVENT_RESPONSIVE_TOGGLE } from './nav/event_hub';
import 'ee_else_ce/main_ee'; import 'ee_else_ce/main_ee';
...@@ -203,6 +204,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -203,6 +204,7 @@ document.addEventListener('DOMContentLoaded', () => {
$('.navbar-toggler').on('click', () => { $('.navbar-toggler').on('click', () => {
$('.header-content').toggleClass('menu-expanded'); $('.header-content').toggleClass('menu-expanded');
navEventHub.$emit(EVENT_RESPONSIVE_TOGGLE);
}); });
/** /**
......
<script>
import eventHub, { EVENT_RESPONSIVE_TOGGLE } from '../event_hub';
const TEMPORARY_PLACEHOLDER = 'Placeholder for responsive top nav';
export default {
props: {
navData: {
type: Object,
required: true,
},
},
created() {
eventHub.$on(EVENT_RESPONSIVE_TOGGLE, this.onToggle);
},
beforeDestroy() {
eventHub.$off(EVENT_RESPONSIVE_TOGGLE, this.onToggle);
},
methods: {
onToggle() {
document.body.classList.toggle('top-nav-responsive-open');
},
},
TEMPORARY_PLACEHOLDER,
};
</script>
<template>
<p>{{ $options.TEMPORARY_PLACEHOLDER }}</p>
</template>
import eventHubFactory from '~/helpers/event_hub_factory';
export const EVENT_RESPONSIVE_TOGGLE = 'top-nav-responsive-toggle';
export default eventHubFactory();
export const initTopNav = async () => { // With combined_menu feature flag, there's a benefit to splitting up the import
const importModule = () => import(/* webpackChunkName: 'top_nav' */ './mount');
const tryMountTopNav = async () => {
const el = document.getElementById('js-top-nav'); const el = document.getElementById('js-top-nav');
if (!el) { if (!el) {
return; return;
} }
// With combined_menu feature flag, there's a benefit to splitting up the import const { mountTopNav } = await importModule();
const { mountTopNav } = await import(/* webpackChunkName: 'top_nav' */ './mount');
mountTopNav(el); mountTopNav(el);
}; };
const tryMountTopNavResponsive = async () => {
const el = document.getElementById('js-top-nav-responsive');
if (!el) {
return;
}
const { mountTopNavResponsive } = await importModule();
mountTopNavResponsive(el);
};
export const initTopNav = async () => Promise.all([tryMountTopNav(), tryMountTopNavResponsive()]);
import Vue from 'vue'; import Vue from 'vue';
import Vuex from 'vuex'; import Vuex from 'vuex';
import ResponsiveApp from './components/responsive_app.vue';
import App from './components/top_nav_app.vue'; import App from './components/top_nav_app.vue';
import { createStore } from './stores'; import { createStore } from './stores';
Vue.use(Vuex); Vue.use(Vuex);
export const mountTopNav = (el) => { const mount = (el, Component) => {
const viewModel = JSON.parse(el.dataset.viewModel); const viewModel = JSON.parse(el.dataset.viewModel);
const store = createStore(); const store = createStore();
...@@ -13,7 +14,7 @@ export const mountTopNav = (el) => { ...@@ -13,7 +14,7 @@ export const mountTopNav = (el) => {
el, el,
store, store,
render(h) { render(h) {
return h(App, { return h(Component, {
props: { props: {
navData: viewModel, navData: viewModel,
}, },
...@@ -21,3 +22,7 @@ export const mountTopNav = (el) => { ...@@ -21,3 +22,7 @@ export const mountTopNav = (el) => {
}, },
}); });
}; };
export const mountTopNav = (el) => mount(el, App);
export const mountTopNavResponsive = (el) => mount(el, ResponsiveApp);
...@@ -106,7 +106,7 @@ $top-nav-hover-bg: var(--indigo-900-alpha-008, $indigo-900-alpha-008) !important ...@@ -106,7 +106,7 @@ $top-nav-hover-bg: var(--indigo-900-alpha-008, $indigo-900-alpha-008) !important
&.menu-expanded { &.menu-expanded {
@include media-breakpoint-down(xs) { @include media-breakpoint-down(xs) {
.title-container { .hide-when-menu-expanded {
display: none; display: none;
} }
...@@ -665,3 +665,26 @@ $top-nav-hover-bg: var(--indigo-900-alpha-008, $indigo-900-alpha-008) !important ...@@ -665,3 +665,26 @@ $top-nav-hover-bg: var(--indigo-900-alpha-008, $indigo-900-alpha-008) !important
color: inherit !important; color: inherit !important;
} }
} }
.top-nav-responsive {
@include gl-display-none;
color: var(--indigo-900, $theme-indigo-900);
}
.top-nav-responsive-open {
.hide-when-top-nav-responsive-open {
@include media-breakpoint-down(xs) {
display: none !important;
}
}
.top-nav-responsive {
@include media-breakpoint-down(xs) {
@include gl-display-block;
}
}
.navbar-gitlab .header-content .title-container {
flex: 0;
}
}
...@@ -337,9 +337,6 @@ h1 { ...@@ -337,9 +337,6 @@ h1 {
.d-none { .d-none {
display: none !important; display: none !important;
} }
.d-inline-block {
display: inline-block !important;
}
.d-block { .d-block {
display: block !important; display: block !important;
} }
...@@ -354,9 +351,6 @@ h1 { ...@@ -354,9 +351,6 @@ h1 {
} }
} }
@media (min-width: 992px) { @media (min-width: 992px) {
.d-lg-none {
display: none !important;
}
.d-lg-block { .d-lg-block {
display: block !important; display: block !important;
} }
...@@ -1957,9 +1951,7 @@ body.gl-dark .navbar-gitlab .navbar-collapse { ...@@ -1957,9 +1951,7 @@ body.gl-dark .navbar-gitlab .navbar-collapse {
} }
body.gl-dark .navbar-gitlab .container-fluid .navbar-toggler { body.gl-dark .navbar-gitlab .container-fluid .navbar-toggler {
border-left: 1px solid #b3b3b3; border-left: 1px solid #b3b3b3;
} color: #fafafa;
body.gl-dark .navbar-gitlab .container-fluid .navbar-toggler svg {
fill: #fafafa;
} }
body.gl-dark .navbar-gitlab .navbar-sub-nav > li.active > a, body.gl-dark .navbar-gitlab .navbar-sub-nav > li.active > a,
body.gl-dark .navbar-gitlab .navbar-sub-nav > li.active > button, body.gl-dark .navbar-gitlab .navbar-sub-nav > li.active > button,
...@@ -2146,9 +2138,40 @@ body.gl-dark { ...@@ -2146,9 +2138,40 @@ body.gl-dark {
white-space: nowrap; white-space: nowrap;
width: 1px; width: 1px;
} }
.gl-border-none\! {
border-style: none !important;
}
.gl-display-none {
display: none;
}
@media (min-width: 62rem) {
.gl-lg-display-none {
display: none;
}
}
@media (min-width: 36rem) {
.gl-sm-display-block {
display: block;
}
}
.gl-display-inline-block {
display: inline-block;
}
@media (min-width: 36rem) {
.gl-sm-display-inline-block {
display: inline-block;
}
}
.gl-absolute { .gl-absolute {
position: absolute; position: absolute;
} }
.gl-px-3 {
padding-left: 0.5rem;
padding-right: 0.5rem;
}
.gl-pr-2 {
padding-right: 0.25rem;
}
.gl-ml-3 { .gl-ml-3 {
margin-left: 0.5rem; margin-left: 0.5rem;
} }
......
...@@ -322,9 +322,6 @@ h1 { ...@@ -322,9 +322,6 @@ h1 {
.d-none { .d-none {
display: none !important; display: none !important;
} }
.d-inline-block {
display: inline-block !important;
}
.d-block { .d-block {
display: block !important; display: block !important;
} }
...@@ -339,9 +336,6 @@ h1 { ...@@ -339,9 +336,6 @@ h1 {
} }
} }
@media (min-width: 992px) { @media (min-width: 992px) {
.d-lg-none {
display: none !important;
}
.d-lg-block { .d-lg-block {
display: block !important; display: block !important;
} }
...@@ -1927,9 +1921,40 @@ body.sidebar-refactoring ...@@ -1927,9 +1921,40 @@ body.sidebar-refactoring
white-space: nowrap; white-space: nowrap;
width: 1px; width: 1px;
} }
.gl-border-none\! {
border-style: none !important;
}
.gl-display-none {
display: none;
}
@media (min-width: 62rem) {
.gl-lg-display-none {
display: none;
}
}
@media (min-width: 36rem) {
.gl-sm-display-block {
display: block;
}
}
.gl-display-inline-block {
display: inline-block;
}
@media (min-width: 36rem) {
.gl-sm-display-inline-block {
display: inline-block;
}
}
.gl-absolute { .gl-absolute {
position: absolute; position: absolute;
} }
.gl-px-3 {
padding-left: 0.5rem;
padding-right: 0.5rem;
}
.gl-pr-2 {
padding-right: 0.25rem;
}
.gl-ml-3 { .gl-ml-3 {
margin-left: 0.5rem; margin-left: 0.5rem;
} }
......
...@@ -22,10 +22,7 @@ ...@@ -22,10 +22,7 @@
.container-fluid { .container-fluid {
.navbar-toggler { .navbar-toggler {
border-left: 1px solid lighten($border-and-box-shadow, 10%); border-left: 1px solid lighten($border-and-box-shadow, 10%);
color: $search-and-nav-links;
svg {
fill: $search-and-nav-links;
}
} }
} }
......
.layout-page{ class: page_with_sidebar_class } .layout-page.hide-when-top-nav-responsive-open{ class: page_with_sidebar_class }
- if defined?(nav) && nav - if defined?(nav) && nav
= render "layouts/nav/sidebar/#{nav}" = render "layouts/nav/sidebar/#{nav}"
.content-wrapper.content-wrapper-margin{ class: "#{@content_wrapper_class}" } .content-wrapper.content-wrapper-margin{ class: "#{@content_wrapper_class}" }
...@@ -27,3 +27,5 @@ ...@@ -27,3 +27,5 @@
= render "layouts/flash", extra_flash_class: 'limit-container-width' = render "layouts/flash", extra_flash_class: 'limit-container-width'
= yield :before_content = yield :before_content
= yield = yield
= render "layouts/nav/top_nav_responsive", class: 'layout-page content-wrapper-margin'
...@@ -6,11 +6,12 @@ ...@@ -6,11 +6,12 @@
= header_message = header_message
= render partial: "layouts/header/default", locals: { project: @project, group: @group } = render partial: "layouts/header/default", locals: { project: @project, group: @group }
.mobile-overlay .mobile-overlay
.alert-wrapper .alert-wrapper.hide-when-top-nav-responsive-open
= render 'shared/outdated_browser' = render 'shared/outdated_browser'
= render "layouts/broadcast" = render "layouts/broadcast"
= yield :flash_message = yield :flash_message
= render "layouts/flash" = render "layouts/flash"
.content-wrapper{ id: "content-body", class: "d-flex flex-column align-items-stretch" } .content-wrapper.hide-when-top-nav-responsive-open{ id: "content-body", class: "d-flex flex-column align-items-stretch" }
= yield = yield
= render "layouts/nav/top_nav_responsive", class: "gl-flex-fill-1 gl-overflow-y-auto"
= footer_message = footer_message
- has_impersonation_link = header_link?(:admin_impersonation) - has_impersonation_link = header_link?(:admin_impersonation)
- user_status_data = user_status_properties(current_user) - user_status_data = user_status_properties(current_user)
- use_top_nav_redesign = Feature.enabled?(:combined_menu, current_user, default_enabled: :yaml)
%header.navbar.navbar-gitlab.navbar-expand-sm.js-navbar{ data: { qa_selector: 'navbar' } } %header.navbar.navbar-gitlab.navbar-expand-sm.js-navbar{ data: { qa_selector: 'navbar' } }
%a.gl-sr-only.gl-accessibility{ href: "#content-body" } Skip to content %a.gl-sr-only.gl-accessibility{ href: "#content-body" } Skip to content
.container-fluid .container-fluid
.header-content .header-content
.title-container .title-container{ class: ('hide-when-menu-expanded' if !use_top_nav_redesign) }
%h1.title %h1.title
%span.gl-sr-only GitLab %span.gl-sr-only GitLab
= link_to root_path, title: _('Dashboard'), id: 'logo', **tracking_attrs('main_navigation', 'click_gitlab_logo_link', 'navigation') do = link_to root_path, title: _('Dashboard'), id: 'logo', **tracking_attrs('main_navigation', 'click_gitlab_logo_link', 'navigation') do
...@@ -19,8 +20,9 @@ ...@@ -19,8 +20,9 @@
%span.gl-badge.gl-bg-green-500.gl-text-white.gl-rounded-pill.gl-font-weight-bold.gl-py-1 %span.gl-badge.gl-bg-green-500.gl-text-white.gl-rounded-pill.gl-font-weight-bold.gl-py-1
= _('Next') = _('Next')
- if Feature.enabled?(:combined_menu, current_user, default_enabled: :yaml) - if use_top_nav_redesign
= render "layouts/nav/top_nav" .gl-display-none.gl-sm-display-block
= render "layouts/nav/top_nav"
- else - else
- if current_user - if current_user
= render "layouts/nav/dashboard" = render "layouts/nav/dashboard"
...@@ -30,11 +32,11 @@ ...@@ -30,11 +32,11 @@
.navbar-collapse.collapse .navbar-collapse.collapse
%ul.nav.navbar-nav %ul.nav.navbar-nav
- if current_user - if current_user
= render 'layouts/header/new_dropdown' = render 'layouts/header/new_dropdown', class: ('gl-display-none gl-sm-display-block' if use_top_nav_redesign)
- if header_link?(:search) - if header_link?(:search)
%li.nav-item.d-none.d-lg-block.m-auto %li.nav-item.d-none.d-lg-block.m-auto
= render 'layouts/search' unless current_controller?(:search) = render 'layouts/search' unless current_controller?(:search)
%li.nav-item.d-inline-block.d-lg-none %li.nav-item{ class: use_top_nav_redesign ? "gl-display-none gl-sm-display-inline-block gl-lg-display-none" : "gl-display-inline-block gl-lg-display-none" }
= link_to search_context.search_url, title: _('Search'), aria: { label: _('Search') }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do = link_to search_context.search_url, title: _('Search'), aria: { label: _('Search') }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= sprite_icon('search') = sprite_icon('search')
- if header_link?(:issues) - if header_link?(:issues)
...@@ -115,10 +117,15 @@ ...@@ -115,10 +117,15 @@
- sign_in_text = allow_signup? ? _('Sign in / Register') : _('Sign in') - sign_in_text = allow_signup? ? _('Sign in / Register') : _('Sign in')
= link_to sign_in_text, new_session_path(:user, redirect_to_referer: 'yes'), class: 'gl-button btn btn-default btn-sign-in' = link_to sign_in_text, new_session_path(:user, redirect_to_referer: 'yes'), class: 'gl-button btn btn-default btn-sign-in'
%button.navbar-toggler.d-block.d-sm-none{ type: 'button' } %button.navbar-toggler.d-block.d-sm-none{ type: 'button', class: ('gl-border-none!' if use_top_nav_redesign) }
%span.sr-only= _('Toggle navigation') %span.sr-only= _('Toggle navigation')
= sprite_icon('ellipsis_h', size: 12, css_class: 'more-icon js-navbar-toggle-right') - if use_top_nav_redesign
= sprite_icon('close', size: 12, css_class: 'close-icon js-navbar-toggle-left') %span.more-icon.gl-px-3
%span.gl-pr-2= _('Menu')
= sprite_icon('dot-grid', size: 16)
- else
= sprite_icon('ellipsis_h', size: 12, css_class: 'more-icon')
= sprite_icon('close', size: 12, css_class: 'close-icon')
- if display_whats_new? - if display_whats_new?
#whats-new-app{ data: { version_digest: whats_new_version_digest } } #whats-new-app{ data: { version_digest: whats_new_version_digest } }
......
...@@ -2,10 +2,11 @@ ...@@ -2,10 +2,11 @@
- menu_sections = view_model.fetch(:menu_sections) - menu_sections = view_model.fetch(:menu_sections)
- title = view_model.fetch(:title) - title = view_model.fetch(:title)
- show_headers = menu_sections.length > 1 - show_headers = menu_sections.length > 1
- top_class = local_assigns.fetch(:class, nil)
- return if menu_sections.empty? - return if menu_sections.empty?
%li.header-new.dropdown{ data: { track_label: "new_dropdown", track_event: "click_dropdown", track_experiment: "new_repo" } } %li.header-new.dropdown{ class: top_class, data: { track_label: "new_dropdown", track_event: "click_dropdown", track_experiment: "new_repo" } }
= link_to new_project_path, class: "header-new-dropdown-toggle has-tooltip", id: "js-onboarding-new-project-link", title: title, ref: 'tooltip', aria: { label: title }, data: { toggle: 'dropdown', placement: 'bottom', container: 'body', display: 'static', qa_selector: 'new_menu_toggle' } do = link_to new_project_path, class: "header-new-dropdown-toggle has-tooltip", id: "js-onboarding-new-project-link", title: title, ref: 'tooltip', aria: { label: title }, data: { toggle: 'dropdown', placement: 'bottom', container: 'body', display: 'static', qa_selector: 'new_menu_toggle' } do
= sprite_icon('plus-square') = sprite_icon('plus-square')
= sprite_icon('chevron-down', css_class: 'caret-down') = sprite_icon('chevron-down', css_class: 'caret-down')
......
- return unless Feature.enabled?(:combined_menu, current_user, default_enabled: :yaml)
- top_class = local_assigns.fetch(:class, nil)
- view_model = top_nav_view_model(project: @project, group: @group)
.top-nav-responsive{ class: top_class }
#js-top-nav-responsive{ data: { view_model: view_model.to_json } }
...@@ -337,9 +337,6 @@ h1 { ...@@ -337,9 +337,6 @@ h1 {
.d-none { .d-none {
display: none !important; display: none !important;
} }
.d-inline-block {
display: inline-block !important;
}
.d-block { .d-block {
display: block !important; display: block !important;
} }
...@@ -354,9 +351,6 @@ h1 { ...@@ -354,9 +351,6 @@ h1 {
} }
} }
@media (min-width: 992px) { @media (min-width: 992px) {
.d-lg-none {
display: none !important;
}
.d-lg-block { .d-lg-block {
display: block !important; display: block !important;
} }
...@@ -1957,9 +1951,7 @@ body.gl-dark .navbar-gitlab .navbar-collapse { ...@@ -1957,9 +1951,7 @@ body.gl-dark .navbar-gitlab .navbar-collapse {
} }
body.gl-dark .navbar-gitlab .container-fluid .navbar-toggler { body.gl-dark .navbar-gitlab .container-fluid .navbar-toggler {
border-left: 1px solid #b3b3b3; border-left: 1px solid #b3b3b3;
} color: #fafafa;
body.gl-dark .navbar-gitlab .container-fluid .navbar-toggler svg {
fill: #fafafa;
} }
body.gl-dark .navbar-gitlab .navbar-sub-nav > li.active > a, body.gl-dark .navbar-gitlab .navbar-sub-nav > li.active > a,
body.gl-dark .navbar-gitlab .navbar-sub-nav > li.active > button, body.gl-dark .navbar-gitlab .navbar-sub-nav > li.active > button,
...@@ -2146,9 +2138,40 @@ body.gl-dark { ...@@ -2146,9 +2138,40 @@ body.gl-dark {
white-space: nowrap; white-space: nowrap;
width: 1px; width: 1px;
} }
.gl-border-none\! {
border-style: none !important;
}
.gl-display-none {
display: none;
}
@media (min-width: 62rem) {
.gl-lg-display-none {
display: none;
}
}
@media (min-width: 36rem) {
.gl-sm-display-block {
display: block;
}
}
.gl-display-inline-block {
display: inline-block;
}
@media (min-width: 36rem) {
.gl-sm-display-inline-block {
display: inline-block;
}
}
.gl-absolute { .gl-absolute {
position: absolute; position: absolute;
} }
.gl-px-3 {
padding-left: 0.5rem;
padding-right: 0.5rem;
}
.gl-pr-2 {
padding-right: 0.25rem;
}
.gl-ml-3 { .gl-ml-3 {
margin-left: 0.5rem; margin-left: 0.5rem;
} }
......
...@@ -322,9 +322,6 @@ h1 { ...@@ -322,9 +322,6 @@ h1 {
.d-none { .d-none {
display: none !important; display: none !important;
} }
.d-inline-block {
display: inline-block !important;
}
.d-block { .d-block {
display: block !important; display: block !important;
} }
...@@ -339,9 +336,6 @@ h1 { ...@@ -339,9 +336,6 @@ h1 {
} }
} }
@media (min-width: 992px) { @media (min-width: 992px) {
.d-lg-none {
display: none !important;
}
.d-lg-block { .d-lg-block {
display: block !important; display: block !important;
} }
...@@ -1927,9 +1921,40 @@ body.sidebar-refactoring ...@@ -1927,9 +1921,40 @@ body.sidebar-refactoring
white-space: nowrap; white-space: nowrap;
width: 1px; width: 1px;
} }
.gl-border-none\! {
border-style: none !important;
}
.gl-display-none {
display: none;
}
@media (min-width: 62rem) {
.gl-lg-display-none {
display: none;
}
}
@media (min-width: 36rem) {
.gl-sm-display-block {
display: block;
}
}
.gl-display-inline-block {
display: inline-block;
}
@media (min-width: 36rem) {
.gl-sm-display-inline-block {
display: inline-block;
}
}
.gl-absolute { .gl-absolute {
position: absolute; position: absolute;
} }
.gl-px-3 {
padding-left: 0.5rem;
padding-right: 0.5rem;
}
.gl-pr-2 {
padding-right: 0.25rem;
}
.gl-ml-3 { .gl-ml-3 {
margin-left: 0.5rem; margin-left: 0.5rem;
} }
......
...@@ -10,6 +10,8 @@ const HTML_TO_REMOVE = [ ...@@ -10,6 +10,8 @@ const HTML_TO_REMOVE = [
'#js-peek', '#js-peek',
'.modal', '.modal',
'.feature-highlight', '.feature-highlight',
// The user has to open up the responsive nav, so we don't need it on load
'.top-nav-responsive',
// We don't want to capture all the children of a dropdown-menu // We don't want to capture all the children of a dropdown-menu
'.dropdown-menu', '.dropdown-menu',
]; ];
......
...@@ -97,6 +97,8 @@ RSpec.describe 'Admin mode' do ...@@ -97,6 +97,8 @@ RSpec.describe 'Admin mode' do
end end
it 'can leave admin mode using dropdown menu on smaller screens', :js do it 'can leave admin mode using dropdown menu on smaller screens', :js do
skip('pending responsive development under :combined_menu feature flag') if Feature.enabled?(:combined_menu)
resize_screen_xs resize_screen_xs
visit root_dashboard_path visit root_dashboard_path
...@@ -131,7 +133,7 @@ RSpec.describe 'Admin mode' do ...@@ -131,7 +133,7 @@ RSpec.describe 'Admin mode' do
end end
it 'relocates admin dashboard links to dropdown list on smaller screen', :js do it 'relocates admin dashboard links to dropdown list on smaller screen', :js do
skip('not applicable with :combined_menu feature flag enabled') if Feature.enabled?(:combined_menu) skip('pending responsive development under :combined_menu feature flag') if Feature.enabled?(:combined_menu)
resize_screen_xs resize_screen_xs
visit root_dashboard_path visit root_dashboard_path
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'top nav responsive', :js do
include MobileHelpers
let_it_be(:user) { create(:user) }
let_it_be(:responsive_menu_text) { 'Placeholder for responsive top nav' }
before do
stub_feature_flags(combined_menu: true)
sign_in(user)
visit explore_projects_path
resize_screen_xs
end
context 'before opened' do
it 'has page content and hides responsive menu', :aggregate_failures do
expect(page).to have_css('.page-title', text: 'Projects')
expect(page).to have_no_text(responsive_menu_text)
end
end
context 'when opened' do
before do
click_button('Menu')
end
it 'hides everything and shows responsive menu', :aggregate_failures do
expect(page).to have_no_css('.page-title', text: 'Projects')
expect(page).to have_link('Dashboard', id: 'logo')
expect(page).to have_text(responsive_menu_text)
end
end
end
import { shallowMount } from '@vue/test-utils';
import { range } from 'lodash';
import ResponsiveApp from '~/nav/components/responsive_app.vue';
import eventHub, { EVENT_RESPONSIVE_TOGGLE } from '~/nav/event_hub';
import { TEST_NAV_DATA } from '../mock_data';
describe('~/nav/components/responsive_app.vue', () => {
let wrapper;
const createComponent = () => {
wrapper = shallowMount(ResponsiveApp, {
propsData: {
navData: TEST_NAV_DATA,
},
});
};
const triggerResponsiveToggle = () => eventHub.$emit(EVENT_RESPONSIVE_TOGGLE);
const hasBodyResponsiveOpen = () => document.body.classList.contains('top-nav-responsive-open');
beforeEach(() => {
// Add test class to reset state + assert that we're adding classes correctly
document.body.className = 'test-class';
});
afterEach(() => {
wrapper.destroy();
});
describe('default', () => {
beforeEach(() => {
createComponent();
});
it.each`
times | expectation
${0} | ${false}
${1} | ${true}
${2} | ${false}
`(
'with responsive toggle event triggered $times, body responsive open = $expectation',
({ times, expectation }) => {
range(times).forEach(triggerResponsiveToggle);
expect(hasBodyResponsiveOpen()).toBe(expectation);
},
);
});
describe('when destroyed', () => {
beforeEach(() => {
createComponent();
wrapper.destroy();
});
it('responsive toggle event does nothing', () => {
triggerResponsiveToggle();
expect(hasBodyResponsiveOpen()).toBe(false);
});
});
});
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