Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
0ebb1a5d
Commit
0ebb1a5d
authored
3 years ago
by
Paul Slaughter
Committed by
Jose Ivan Vargas
3 years ago
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add top_nav_menu_sections component
parent
9641dac4
No related merge requests found
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
295 additions
and
179 deletions
+295
-179
app/assets/javascripts/nav/components/top_nav_container_view.vue
...ets/javascripts/nav/components/top_nav_container_view.vue
+7
-20
app/assets/javascripts/nav/components/top_nav_dropdown_menu.vue
...sets/javascripts/nav/components/top_nav_dropdown_menu.vue
+21
-62
app/assets/javascripts/nav/components/top_nav_menu_item.vue
app/assets/javascripts/nav/components/top_nav_menu_item.vue
+4
-1
app/assets/javascripts/nav/components/top_nav_menu_sections.vue
...sets/javascripts/nav/components/top_nav_menu_sections.vue
+62
-0
spec/frontend/nav/components/top_nav_container_view_spec.js
spec/frontend/nav/components/top_nav_container_view_spec.js
+13
-24
spec/frontend/nav/components/top_nav_dropdown_menu_spec.js
spec/frontend/nav/components/top_nav_dropdown_menu_spec.js
+56
-65
spec/frontend/nav/components/top_nav_menu_item_spec.js
spec/frontend/nav/components/top_nav_menu_item_spec.js
+25
-7
spec/frontend/nav/components/top_nav_menu_sections_spec.js
spec/frontend/nav/components/top_nav_menu_sections_spec.js
+107
-0
No files found.
app/assets/javascripts/nav/components/top_nav_container_view.vue
View file @
0ebb1a5d
...
...
@@ -2,12 +2,12 @@
import
FrequentItemsApp
from
'
~/frequent_items/components/app.vue
'
;
import
eventHub
from
'
~/frequent_items/event_hub
'
;
import
VuexModuleProvider
from
'
~/vue_shared/components/vuex_module_provider.vue
'
;
import
TopNavMenu
Item
from
'
./top_nav_menu_item
.vue
'
;
import
TopNavMenu
Sections
from
'
./top_nav_menu_sections
.vue
'
;
export
default
{
components
:
{
FrequentItemsApp
,
TopNavMenu
Item
,
TopNavMenu
Sections
,
VuexModuleProvider
,
},
inheritAttrs
:
false
,
...
...
@@ -32,11 +32,11 @@ export default {
},
},
computed
:
{
linkGroup
s
()
{
menuSection
s
()
{
return
[
{
key
:
'
primary
'
,
link
s
:
this
.
linksPrimary
},
{
key
:
'
secondary
'
,
link
s
:
this
.
linksSecondary
},
].
filter
((
x
)
=>
x
.
link
s
?.
length
);
{
id
:
'
primary
'
,
menuItem
s
:
this
.
linksPrimary
},
{
id
:
'
secondary
'
,
menuItem
s
:
this
.
linksSecondary
},
].
filter
((
x
)
=>
x
.
menuItem
s
?.
length
);
},
},
mounted
()
{
...
...
@@ -57,19 +57,6 @@ export default {
</vuex-module-provider>
</div>
</div>
<div
v-for=
"(
{ key, links }, groupIndex) in linkGroups"
:key="key"
:class="{ 'gl-mt-3': groupIndex !== 0 }"
class="gl-mt-auto gl-pt-3 gl-border-1 gl-border-t-solid gl-border-gray-100"
data-testid="menu-item-group"
>
<top-nav-menu-item
v-for=
"(link, linkIndex) in links"
:key=
"link.title"
:menu-item=
"link"
:class=
"
{ 'gl-mt-1': linkIndex !== 0 }"
/>
</div>
<top-nav-menu-sections
class=
"gl-mt-auto"
:sections=
"menuSections"
with-top-border
/>
</div>
</
template
>
This diff is collapsed.
Click to expand it.
app/assets/javascripts/nav/components/top_nav_dropdown_menu.vue
View file @
0ebb1a5d
<
script
>
import
{
cloneDeep
}
from
'
lodash
'
;
import
{
FREQUENT_ITEMS_PROJECTS
,
FREQUENT_ITEMS_GROUPS
}
from
'
~/frequent_items/constants
'
;
import
KeepAliveSlots
from
'
~/vue_shared/components/keep_alive_slots.vue
'
;
import
TopNavContainerView
from
'
./top_nav_container_view.vue
'
;
import
TopNavMenuItem
from
'
./top_nav_menu_item.vue
'
;
const
ACTIVE_CLASS
=
'
gl-shadow-none! gl-font-weight-bold! active
'
;
const
SECONDARY_GROUP_CLASS
=
'
gl-pt-3 gl-mt-3 gl-border-1 gl-border-t-solid gl-border-gray-100
'
;
import
TopNavMenuSections
from
'
./top_nav_menu_sections.vue
'
;
export
default
{
components
:
{
KeepAliveSlots
,
TopNavContainerView
,
TopNavMenu
Item
,
TopNavMenu
Sections
,
},
props
:
{
primary
:
{
...
...
@@ -31,29 +29,25 @@ export default {
},
},
data
()
{
// It's expected that primary & secondary never change, so these are treated as "init" props.
// We need to clone so that we can mutate the data without mutating the props
const
menuSections
=
[
{
id
:
'
primary
'
,
menuItems
:
cloneDeep
(
this
.
primary
)
},
{
id
:
'
secondary
'
,
menuItems
:
cloneDeep
(
this
.
secondary
)
},
].
filter
((
x
)
=>
x
.
menuItems
?.
length
);
return
{
activeId
:
''
,
menuSections
,
};
},
computed
:
{
menuItemGroups
()
{
return
[
{
key
:
'
primary
'
,
items
:
this
.
primary
,
classes
:
''
},
{
key
:
'
secondary
'
,
items
:
this
.
secondary
,
classes
:
SECONDARY_GROUP_CLASS
,
},
].
filter
((
x
)
=>
x
.
items
?.
length
);
},
allMenuItems
()
{
return
this
.
menuItemGroups
.
flatMap
((
x
)
=>
x
.
items
);
},
activeMenuItem
()
{
return
this
.
allMenuItems
.
find
((
x
)
=>
x
.
id
===
this
.
activeId
);
return
this
.
menuSections
.
flatMap
((
x
)
=>
x
.
menuItems
);
},
activeView
()
{
return
this
.
activeMenuItem
?.
view
;
const
active
=
this
.
allMenuItems
.
find
((
x
)
=>
x
.
active
);
return
active
?.
view
;
},
menuClass
()
{
if
(
!
this
.
activeView
)
{
...
...
@@ -63,61 +57,26 @@ export default {
return
''
;
},
},
created
()
{
// Initialize activeId based on initialization prop
this
.
activeId
=
this
.
allMenuItems
.
find
((
x
)
=>
x
.
active
)?.
id
;
},
methods
:
{
onClick
({
id
,
href
})
{
// If we're a link, let's just do the default behavior so the view won't change
if
(
href
)
{
return
;
}
this
.
activeId
=
id
;
},
menuItemClasses
(
menuItem
)
{
if
(
menuItem
.
id
===
this
.
activeId
)
{
return
ACTIVE_CLASS
;
}
return
''
;
onMenuItemClick
({
id
})
{
this
.
allMenuItems
.
forEach
((
menuItem
)
=>
{
this
.
$set
(
menuItem
,
'
active
'
,
id
===
menuItem
.
id
);
});
},
},
FREQUENT_ITEMS_PROJECTS
,
FREQUENT_ITEMS_GROUPS
,
// expose for unit tests
ACTIVE_CLASS
,
SECONDARY_GROUP_CLASS
,
};
</
script
>
<
template
>
<div
class=
"gl-display-flex gl-align-items-stretch"
>
<div
class=
"gl-w-grid-size-30 gl-flex-shrink-0 gl-bg-gray-10"
class=
"gl-w-grid-size-30 gl-flex-shrink-0 gl-bg-gray-10
gl-py-3 gl-px-5
"
:class=
"menuClass"
data-testid=
"menu-sidebar"
>
<div
class=
"gl-py-3 gl-px-5 gl-h-full gl-display-flex gl-align-items-stretch gl-flex-direction-column"
>
<div
v-for=
"group in menuItemGroups"
:key=
"group.key"
:class=
"group.classes"
data-testid=
"menu-item-group"
>
<top-nav-menu-item
v-for=
"(menu, index) in group.items"
:key=
"menu.id"
data-testid=
"menu-item"
:class=
"[
{ 'gl-mt-1': index !== 0 }, menuItemClasses(menu)]"
:menu-item="menu"
@click="onClick(menu)"
/>
</div>
</div>
<top-nav-menu-sections
:sections=
"menuSections"
@
menu-item-click=
"onMenuItemClick"
/>
</div>
<keep-alive-slots
v-show=
"activeView"
...
...
This diff is collapsed.
Click to expand it.
app/assets/javascripts/nav/components/top_nav_menu_item.vue
View file @
0ebb1a5d
...
...
@@ -4,6 +4,8 @@ import { kebabCase, mapKeys } from 'lodash';
const
getDataKey
=
(
key
)
=>
`data-
${
kebabCase
(
key
)}
`
;
const
ACTIVE_CLASS
=
'
gl-shadow-none! gl-font-weight-bold! active
'
;
export
default
{
components
:
{
GlButton
,
...
...
@@ -20,6 +22,7 @@ export default {
return
mapKeys
(
this
.
menuItem
.
data
||
{},
(
value
,
key
)
=>
getDataKey
(
key
));
},
},
ACTIVE_CLASS
,
};
</
script
>
...
...
@@ -28,7 +31,7 @@ export default {
category=
"tertiary"
:href=
"menuItem.href"
class=
"top-nav-menu-item gl-display-block"
:class=
"
menuItem.css_class
"
:class=
"
[menuItem.css_class,
{ [$options.ACTIVE_CLASS]: menuItem.active }]
"
v-bind="dataAttrs"
v-on="$listeners"
>
...
...
This diff is collapsed.
Click to expand it.
app/assets/javascripts/nav/components/top_nav_menu_sections.vue
0 → 100644
View file @
0ebb1a5d
<
script
>
import
TopNavMenuItem
from
'
./top_nav_menu_item.vue
'
;
const
BORDER_CLASSES
=
'
gl-pt-3 gl-border-1 gl-border-t-solid gl-border-gray-100
'
;
export
default
{
components
:
{
TopNavMenuItem
,
},
props
:
{
sections
:
{
type
:
Array
,
required
:
true
,
},
withTopBorder
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
methods
:
{
onClick
(
menuItem
)
{
// If we're a link, let's just do the default behavior so the view won't change
if
(
menuItem
.
href
)
{
return
;
}
this
.
$emit
(
'
menu-item-click
'
,
menuItem
);
},
getMenuSectionClasses
(
index
)
{
// This is a method instead of a computed so we don't have to incur the cost of
// creating a whole new array/object.
return
{
[
BORDER_CLASSES
]:
this
.
withTopBorder
||
index
>
0
,
'
gl-mt-3
'
:
index
>
0
,
};
},
},
// Expose for unit tests
BORDER_CLASSES
,
};
</
script
>
<
template
>
<div
class=
"gl-display-flex gl-align-items-stretch gl-flex-direction-column"
>
<div
v-for=
"(
{ id, menuItems }, sectionIndex) in sections"
:key="id"
:class="getMenuSectionClasses(sectionIndex)"
data-testid="menu-section"
>
<top-nav-menu-item
v-for=
"(menuItem, menuItemIndex) in menuItems"
:key=
"menuItem.id"
:menu-item=
"menuItem"
data-testid=
"menu-item"
:class=
"
{ 'gl-mt-1': menuItemIndex > 0 }"
@click="onClick(menuItem)"
/>
</div>
</div>
</
template
>
This diff is collapsed.
Click to expand it.
spec/frontend/nav/components/top_nav_container_view_spec.js
View file @
0ebb1a5d
...
...
@@ -4,7 +4,7 @@ import FrequentItemsApp from '~/frequent_items/components/app.vue';
import
{
FREQUENT_ITEMS_PROJECTS
}
from
'
~/frequent_items/constants
'
;
import
eventHub
from
'
~/frequent_items/event_hub
'
;
import
TopNavContainerView
from
'
~/nav/components/top_nav_container_view.vue
'
;
import
TopNavMenu
Item
from
'
~/nav/components/top_nav_menu_item
.vue
'
;
import
TopNavMenu
Sections
from
'
~/nav/components/top_nav_menu_sections
.vue
'
;
import
VuexModuleProvider
from
'
~/vue_shared/components/vuex_module_provider.vue
'
;
import
{
TEST_NAV_DATA
}
from
'
../mock_data
'
;
...
...
@@ -34,11 +34,7 @@ describe('~/nav/components/top_nav_container_view.vue', () => {
});
};
const
findMenuItems
=
(
parent
=
wrapper
)
=>
parent
.
findAll
(
TopNavMenuItem
);
const
findMenuItemsModel
=
(
parent
=
wrapper
)
=>
findMenuItems
(
parent
).
wrappers
.
map
((
x
)
=>
x
.
props
());
const
findMenuItemGroups
=
()
=>
wrapper
.
findAll
(
'
[data-testid="menu-item-group"]
'
);
const
findMenuItemGroupsModel
=
()
=>
findMenuItemGroups
().
wrappers
.
map
(
findMenuItemsModel
);
const
findMenuSections
=
()
=>
wrapper
.
findComponent
(
TopNavMenuSections
);
const
findFrequentItemsApp
=
()
=>
{
const
parent
=
wrapper
.
findComponent
(
VuexModuleProvider
);
...
...
@@ -89,23 +85,16 @@ describe('~/nav/components/top_nav_container_view.vue', () => {
});
});
it
(
'
renders menu item groups
'
,
()
=>
{
expect
(
findMenuItemGroupsModel
()).
toEqual
([
TEST_NAV_DATA
.
primary
.
map
((
menuItem
)
=>
({
menuItem
})),
TEST_NAV_DATA
.
secondary
.
map
((
menuItem
)
=>
({
menuItem
})),
]);
});
it
(
'
only the first group does not have margin top
'
,
()
=>
{
expect
(
findMenuItemGroups
().
wrappers
.
map
((
x
)
=>
x
.
classes
(
'
gl-mt-3
'
))).
toEqual
([
false
,
true
]);
});
it
(
'
only the first menu item does not have margin top
'
,
()
=>
{
const
actual
=
findMenuItems
(
findMenuItemGroups
().
at
(
1
)).
wrappers
.
map
((
x
)
=>
x
.
classes
(
'
gl-mt-1
'
),
);
it
(
'
renders menu sections
'
,
()
=>
{
const
sections
=
[
{
id
:
'
primary
'
,
menuItems
:
TEST_NAV_DATA
.
primary
},
{
id
:
'
secondary
'
,
menuItems
:
TEST_NAV_DATA
.
secondary
},
];
expect
(
actual
).
toEqual
([
false
,
...
TEST_NAV_DATA
.
secondary
.
slice
(
1
).
fill
(
true
)]);
expect
(
findMenuSections
().
props
()).
toEqual
({
sections
,
withTopBorder
:
true
,
});
});
});
...
...
@@ -117,8 +106,8 @@ describe('~/nav/components/top_nav_container_view.vue', () => {
});
it
(
'
renders one menu item group
'
,
()
=>
{
expect
(
findMenu
ItemGroupsModel
(
)).
toEqual
([
TEST_NAV_DATA
.
primary
.
map
((
menuItem
)
=>
({
menuItem
}))
,
expect
(
findMenu
Sections
().
props
(
'
sections
'
)).
toEqual
([
{
id
:
'
primary
'
,
menuItems
:
TEST_NAV_DATA
.
primary
}
,
]);
});
});
...
...
This diff is collapsed.
Click to expand it.
spec/frontend/nav/components/top_nav_dropdown_menu_spec.js
View file @
0ebb1a5d
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
{
shallowMount
,
mount
}
from
'
@vue/test-utils
'
;
import
{
nextTick
}
from
'
vue
'
;
import
TopNavDropdownMenu
from
'
~/nav/components/top_nav_dropdown_menu.vue
'
;
import
TopNavMenuItem
from
'
~/nav/components/top_nav_menu_item.vue
'
;
import
TopNavMenuSections
from
'
~/nav/components/top_nav_menu_sections.vue
'
;
import
KeepAliveSlots
from
'
~/vue_shared/components/keep_alive_slots.vue
'
;
import
{
TEST_NAV_DATA
}
from
'
../mock_data
'
;
const
SECONDARY_GROUP_CLASSES
=
TopNavDropdownMenu
.
SECONDARY_GROUP_CLASS
.
split
(
'
'
);
describe
(
'
~/nav/components/top_nav_dropdown_menu.vue
'
,
()
=>
{
let
wrapper
;
const
createComponent
=
(
props
=
{})
=>
{
wrapper
=
shallowMount
(
TopNavDropdownMenu
,
{
const
createComponent
=
(
props
=
{}
,
mountFn
=
shallowMount
)
=>
{
wrapper
=
mountFn
(
TopNavDropdownMenu
,
{
propsData
:
{
primary
:
TEST_NAV_DATA
.
primary
,
secondary
:
TEST_NAV_DATA
.
secondary
,
views
:
TEST_NAV_DATA
.
views
,
...
props
,
},
stubs
:
{
// Stub the keep-alive-slots so we don't render frequent items which uses a store
KeepAliveSlots
:
true
,
},
});
};
const
findMenuItems
=
(
parent
=
wrapper
)
=>
parent
.
findAll
(
'
[data-testid="menu-item"]
'
);
const
findMenuItemsModel
=
(
parent
=
wrapper
)
=>
findMenuItems
(
parent
).
wrappers
.
map
((
x
)
=>
({
menuItem
:
x
.
props
(
'
menuItem
'
),
isActive
:
x
.
classes
(
'
active
'
),
}));
const
findMenuItemGroups
=
()
=>
wrapper
.
findAll
(
'
[data-testid="menu-item-group"]
'
);
const
findMenuItemGroupsModel
=
()
=>
findMenuItemGroups
().
wrappers
.
map
((
x
)
=>
({
classes
:
x
.
classes
(),
items
:
findMenuItemsModel
(
x
),
}));
const
findMenuItems
=
()
=>
wrapper
.
findAllComponents
(
TopNavMenuItem
);
const
findMenuSections
=
()
=>
wrapper
.
find
(
TopNavMenuSections
);
const
findMenuSidebar
=
()
=>
wrapper
.
find
(
'
[data-testid="menu-sidebar"]
'
);
const
findMenuSubview
=
()
=>
wrapper
.
findComponent
(
KeepAliveSlots
);
const
hasFullWidthMenuSidebar
=
()
=>
findMenuSidebar
().
classes
(
'
gl-w-full
'
);
const
createItemsGroupModelExpectation
=
({
primary
=
TEST_NAV_DATA
.
primary
,
secondary
=
TEST_NAV_DATA
.
secondary
,
activeIndex
=
-
1
,
}
=
{})
=>
[
{
classes
:
[],
items
:
primary
.
map
((
menuItem
,
index
)
=>
({
isActive
:
index
===
activeIndex
,
menuItem
})),
},
{
classes
:
SECONDARY_GROUP_CLASSES
,
items
:
secondary
.
map
((
menuItem
)
=>
({
isActive
:
false
,
menuItem
})),
},
];
const
withActiveIndex
=
(
menuItems
,
activeIndex
)
=>
menuItems
.
map
((
x
,
idx
)
=>
({
...
x
,
active
:
idx
===
activeIndex
,
}));
afterEach
(()
=>
{
wrapper
.
destroy
();
});
beforeEach
(()
=>
{
jest
.
spyOn
(
console
,
'
error
'
).
mockImplementation
();
});
describe
(
'
default
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
();
});
it
(
'
renders menu item groups
'
,
()
=>
{
expect
(
findMenuItemGroupsModel
()).
toEqual
(
createItemsGroupModelExpectation
());
it
(
'
renders menu sections
'
,
()
=>
{
expect
(
findMenuSections
().
props
()).
toEqual
({
sections
:
[
{
id
:
'
primary
'
,
menuItems
:
TEST_NAV_DATA
.
primary
},
{
id
:
'
secondary
'
,
menuItems
:
TEST_NAV_DATA
.
secondary
},
],
withTopBorder
:
false
,
});
});
it
(
'
has full width menu sidebar
'
,
()
=>
{
...
...
@@ -74,36 +69,25 @@ describe('~/nav/components/top_nav_dropdown_menu.vue', () => {
expect
(
subview
.
isVisible
()).
toBe
(
false
);
expect
(
subview
.
props
()).
toEqual
({
slotKey
:
''
});
});
it
(
'
the first menu item in a group does not render margin top
'
,
()
=>
{
const
actual
=
findMenuItems
(
findMenuItemGroups
().
at
(
0
)).
wrappers
.
map
((
x
)
=>
x
.
classes
(
'
gl-mt-1
'
),
);
expect
(
actual
).
toEqual
([
false
,
...
TEST_NAV_DATA
.
primary
.
slice
(
1
).
fill
(
true
)]);
});
});
describe
(
'
with pre-initialized active view
'
,
()
=>
{
const
primaryWithActive
=
[
TEST_NAV_DATA
.
primary
[
0
],
{
...
TEST_NAV_DATA
.
primary
[
1
],
active
:
true
,
},
...
TEST_NAV_DATA
.
primary
.
slice
(
2
),
];
beforeEach
(()
=>
{
createComponent
({
primary
:
primaryWithActive
,
});
// We opt for a small integration test, to make sure the event is handled correctly
// as it would in prod.
createComponent
(
{
primary
:
withActiveIndex
(
TEST_NAV_DATA
.
primary
,
1
),
},
mount
,
);
});
it
(
'
renders menu item groups
'
,
()
=>
{
expect
(
findMenuItemGroupsModel
()).
toEqual
(
createItemsGroupModelExpectation
({
primary
:
primaryWithActive
,
activeIndex
:
1
}),
);
it
(
'
renders menu sections
'
,
()
=>
{
expect
(
findMenuSections
().
props
(
'
sections
'
)).
toStrictEqual
([
{
id
:
'
primary
'
,
menuItems
:
withActiveIndex
(
TEST_NAV_DATA
.
primary
,
1
)
},
{
id
:
'
secondary
'
,
menuItems
:
TEST_NAV_DATA
.
secondary
},
]);
});
it
(
'
does not have full width menu sidebar
'
,
()
=>
{
...
...
@@ -114,11 +98,11 @@ describe('~/nav/components/top_nav_dropdown_menu.vue', () => {
const
subview
=
findMenuSubview
();
expect
(
subview
.
isVisible
()).
toBe
(
true
);
expect
(
subview
.
props
(
'
slotKey
'
)).
toBe
(
primaryWithActive
[
1
].
view
);
expect
(
subview
.
props
(
'
slotKey
'
)).
toBe
(
TEST_NAV_DATA
.
primary
[
1
].
view
);
});
it
(
'
does not change view if non-view menu item is clicked
'
,
async
()
=>
{
const
secondaryLink
=
findMenuItems
().
at
(
primaryWithActive
.
length
);
const
secondaryLink
=
findMenuItems
().
at
(
TEST_NAV_DATA
.
primary
.
length
);
// Ensure this doesn't have a view
expect
(
secondaryLink
.
props
(
'
menuItem
'
).
view
).
toBeUndefined
();
...
...
@@ -127,10 +111,10 @@ describe('~/nav/components/top_nav_dropdown_menu.vue', () => {
await
nextTick
();
expect
(
findMenuSubview
().
props
(
'
slotKey
'
)).
toBe
(
primaryWithActive
[
1
].
view
);
expect
(
findMenuSubview
().
props
(
'
slotKey
'
)).
toBe
(
TEST_NAV_DATA
.
primary
[
1
].
view
);
});
describe
(
'
when
other view
menu item is clicked
'
,
()
=>
{
describe
(
'
when menu item is clicked
'
,
()
=>
{
let
primaryLink
;
beforeEach
(
async
()
=>
{
...
...
@@ -144,13 +128,20 @@ describe('~/nav/components/top_nav_dropdown_menu.vue', () => {
});
it
(
'
changes active view
'
,
()
=>
{
expect
(
findMenuSubview
().
props
(
'
slotKey
'
)).
toBe
(
primaryWithActive
[
0
].
view
);
expect
(
findMenuSubview
().
props
(
'
slotKey
'
)).
toBe
(
TEST_NAV_DATA
.
primary
[
0
].
view
);
});
it
(
'
changes active status on menu item
'
,
()
=>
{
expect
(
findMenuItemGroupsModel
()).
toStrictEqual
(
createItemsGroupModelExpectation
({
primary
:
primaryWithActive
,
activeIndex
:
0
}),
);
expect
(
findMenuSections
().
props
(
'
sections
'
)).
toStrictEqual
([
{
id
:
'
primary
'
,
menuItems
:
withActiveIndex
(
TEST_NAV_DATA
.
primary
,
0
),
},
{
id
:
'
secondary
'
,
menuItems
:
withActiveIndex
(
TEST_NAV_DATA
.
secondary
,
-
1
),
},
]);
});
});
});
...
...
This diff is collapsed.
Click to expand it.
spec/frontend/nav/components/top_nav_menu_item_spec.js
View file @
0ebb1a5d
...
...
@@ -7,7 +7,6 @@ const TEST_MENU_ITEM = {
icon
:
'
search
'
,
href
:
'
/pretty/good/burger
'
,
view
:
'
burger-view
'
,
css_class
:
'
test-super-crazy test-class
'
,
data
:
{
qa_selector
:
'
not-a-real-selector
'
,
method
:
'
post
'
,
testFoo
:
'
test
'
},
};
...
...
@@ -49,12 +48,6 @@ describe('~/nav/components/top_nav_menu_item.vue', () => {
expect
(
button
.
text
()).
toBe
(
TEST_MENU_ITEM
.
title
);
});
it
(
'
renders button classes
'
,
()
=>
{
const
button
=
findButton
();
expect
(
button
.
classes
()).
toEqual
(
expect
.
arrayContaining
(
TEST_MENU_ITEM
.
css_class
.
split
(
'
'
)));
});
it
(
'
renders button data attributes
'
,
()
=>
{
const
button
=
findButton
();
...
...
@@ -89,4 +82,29 @@ describe('~/nav/components/top_nav_menu_item.vue', () => {
expect
(
findButtonIcons
()).
toEqual
(
expectedIcons
);
});
});
describe
.
each
`
desc | active | cssClass | expectedClasses
${
'
default
'
}
|
${
false
}
|
${
''
}
|
${[]}
${
'
with css class
'
}
|
${
false
}
|
${
'
test-css-class testing-123
'
}
|
${[
'
test-css-class
'
,
'
testing-123
'
]}
${
'
with css class & active
'
}
|
${
true
}
|
${
'
test-css-class
'
}
|
${[
'
test-css-class
'
,
...
TopNavMenuItem
.
ACTIVE_CLASS
.
split
(
'
'
)]}
`
(
'
$desc
'
,
({
active
,
cssClass
,
expectedClasses
})
=>
{
beforeEach
(()
=>
{
createComponent
({
menuItem
:
{
...
TEST_MENU_ITEM
,
active
,
css_class
:
cssClass
,
},
});
});
it
(
'
renders expected classes
'
,
()
=>
{
expect
(
wrapper
.
classes
()).
toStrictEqual
([
'
top-nav-menu-item
'
,
'
gl-display-block
'
,
...
expectedClasses
,
]);
});
});
});
This diff is collapsed.
Click to expand it.
spec/frontend/nav/components/top_nav_menu_sections_spec.js
0 → 100644
View file @
0ebb1a5d
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
TopNavMenuSections
from
'
~/nav/components/top_nav_menu_sections.vue
'
;
const
TEST_SECTIONS
=
[
{
id
:
'
primary
'
,
menuItems
:
[{
id
:
'
test
'
,
href
:
'
/test/href
'
},
{
id
:
'
foo
'
},
{
id
:
'
bar
'
}],
},
{
id
:
'
secondary
'
,
menuItems
:
[{
id
:
'
lorem
'
},
{
id
:
'
ipsum
'
}],
},
];
describe
(
'
~/nav/components/top_nav_menu_sections.vue
'
,
()
=>
{
let
wrapper
;
const
createComponent
=
(
props
=
{})
=>
{
wrapper
=
shallowMount
(
TopNavMenuSections
,
{
propsData
:
{
sections
:
TEST_SECTIONS
,
...
props
,
},
});
};
const
findMenuItemModels
=
(
parent
)
=>
parent
.
findAll
(
'
[data-testid="menu-item"]
'
).
wrappers
.
map
((
x
)
=>
({
menuItem
:
x
.
props
(
'
menuItem
'
),
classes
:
x
.
classes
(),
}));
const
findSectionModels
=
()
=>
wrapper
.
findAll
(
'
[data-testid="menu-section"]
'
).
wrappers
.
map
((
x
)
=>
({
classes
:
x
.
classes
(),
menuItems
:
findMenuItemModels
(
x
),
}));
afterEach
(()
=>
{
wrapper
.
destroy
();
});
describe
(
'
default
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
();
});
it
(
'
renders sections with menu items
'
,
()
=>
{
expect
(
findSectionModels
()).
toEqual
([
{
classes
:
[],
menuItems
:
[
{
menuItem
:
TEST_SECTIONS
[
0
].
menuItems
[
0
],
classes
:
[],
},
...
TEST_SECTIONS
[
0
].
menuItems
.
slice
(
1
).
map
((
menuItem
)
=>
({
menuItem
,
classes
:
[
'
gl-mt-1
'
],
})),
],
},
{
classes
:
[...
TopNavMenuSections
.
BORDER_CLASSES
.
split
(
'
'
),
'
gl-mt-3
'
],
menuItems
:
[
{
menuItem
:
TEST_SECTIONS
[
1
].
menuItems
[
0
],
classes
:
[],
},
...
TEST_SECTIONS
[
1
].
menuItems
.
slice
(
1
).
map
((
menuItem
)
=>
({
menuItem
,
classes
:
[
'
gl-mt-1
'
],
})),
],
},
]);
});
it
(
'
when clicked menu item with href, does nothing
'
,
()
=>
{
const
menuItem
=
wrapper
.
findAll
(
'
[data-testid="menu-item"]
'
).
at
(
0
);
menuItem
.
vm
.
$emit
(
'
click
'
);
expect
(
wrapper
.
emitted
()).
toEqual
({});
});
it
(
'
when clicked menu item without href, emits "menu-item-click"
'
,
()
=>
{
const
menuItem
=
wrapper
.
findAll
(
'
[data-testid="menu-item"]
'
).
at
(
1
);
menuItem
.
vm
.
$emit
(
'
click
'
);
expect
(
wrapper
.
emitted
(
'
menu-item-click
'
)).
toEqual
([[
TEST_SECTIONS
[
0
].
menuItems
[
1
]]]);
});
});
describe
(
'
with withTopBorder=true
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
withTopBorder
:
true
});
});
it
(
'
renders border classes for top section
'
,
()
=>
{
expect
(
findSectionModels
().
map
((
x
)
=>
x
.
classes
)).
toEqual
([
[...
TopNavMenuSections
.
BORDER_CLASSES
.
split
(
'
'
)],
[...
TopNavMenuSections
.
BORDER_CLASSES
.
split
(
'
'
),
'
gl-mt-3
'
],
]);
});
});
});
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment