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
56dfb49c
Commit
56dfb49c
authored
Nov 22, 2021
by
Daniel Tian
Committed by
Savas Vedova
Nov 22, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Move vulnerabilities GraphQL into its own component
parent
fff3d03e
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
311 additions
and
230 deletions
+311
-230
ee/app/assets/javascripts/security_dashboard/components/group/vulnerability_report_development.vue
...ard/components/group/vulnerability_report_development.vue
+8
-80
ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_list_graphql.vue
...hared/vulnerability_report/vulnerability_list_graphql.vue
+135
-0
ee/spec/frontend/security_dashboard/components/group/vulnerability_report_development_spec.js
...components/group/vulnerability_report_development_spec.js
+8
-150
ee/spec/frontend/security_dashboard/components/shared/vulnerability_report/vulnerability_list_graphql_spec.js
...d/vulnerability_report/vulnerability_list_graphql_spec.js
+160
-0
No files found.
ee/app/assets/javascripts/security_dashboard/components/group/vulnerability_report_development.vue
View file @
56dfb49c
<
script
>
import
{
GlIntersectionObserver
,
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
import
produce
from
'
immer
'
;
import
vulnerabilitiesQuery
from
'
ee/security_dashboard/graphql/queries/group_vulnerabilities.query.graphql
'
;
import
createFlash
from
'
~/flash
'
;
import
{
s__
}
from
'
~/locale
'
;
import
VulnerabilityReportHeader
from
'
../shared/vulnerability_report/vulnerability_report_header.vue
'
;
import
ReportNotConfiguredGroup
from
'
../shared/empty_states/report_not_configured_group.vue
'
;
import
VulnerabilityCounts
from
'
../shared/vulnerability_report/vulnerability_counts.vue
'
;
import
VulnerabilityList
from
'
../shared/vulnerability_report/vulnerability_list
.vue
'
;
import
VulnerabilityList
Graphql
from
'
../shared/vulnerability_report/vulnerability_list_graphql
.vue
'
;
import
VulnerabilityFilters
from
'
../shared/vulnerability_report/vulnerability_filters.vue
'
;
import
{
FIELDS
,
FILTERS
}
from
'
../shared/vulnerability_report/constants
'
;
export
default
{
components
:
{
VulnerabilityCounts
,
VulnerabilityList
,
VulnerabilityList
Graphql
,
VulnerabilityFilters
,
GlIntersectionObserver
,
GlLoadingIcon
,
ReportNotConfiguredGroup
,
VulnerabilityReportHeader
,
},
inject
:
[
'
groupFullPath
'
,
'
canViewFalsePositive
'
,
'
canAdminVulnerability
'
,
'
hasProjects
'
],
inject
:
[
'
canAdminVulnerability
'
,
'
hasProjects
'
],
data
()
{
return
{
vulnerabilities
:
[],
filters
:
undefined
,
sort
:
undefined
,
pageInfo
:
undefined
,
};
},
apollo
:
{
vulnerabilities
:
{
query
:
vulnerabilitiesQuery
,
errorPolicy
:
'
none
'
,
variables
()
{
return
{
fullPath
:
this
.
groupFullPath
,
sort
:
this
.
sort
,
vetEnabled
:
this
.
canViewFalsePositive
,
...
this
.
filters
,
};
},
update
({
group
})
{
this
.
pageInfo
=
group
.
vulnerabilities
.
pageInfo
;
return
group
.
vulnerabilities
.
nodes
;
},
error
()
{
createFlash
({
message
:
s__
(
'
SecurityReports|Error fetching the vulnerability list. Please check your network connection and try again.
'
,
),
});
},
skip
()
{
return
!
this
.
filters
;
},
},
},
computed
:
{
// Used to show the loading icon at the bottom of the vulnerabilities list.
isLoadingVulnerabilities
()
{
return
this
.
$apollo
.
queries
.
vulnerabilities
.
loading
;
},
// Used to show the initial skeleton loader for the vulnerabilities list.
isLoadingInitialVulnerabilities
()
{
return
this
.
isLoadingVulnerabilities
&&
this
.
vulnerabilities
.
length
<=
0
;
},
hasNextPage
()
{
return
this
.
pageInfo
?.
hasNextPage
;
},
fields
()
{
return
[
// Add the checkbox field if the user can use the bulk select feature.
...
...
@@ -85,29 +37,9 @@ export default {
},
},
methods
:
{
updateSort
(
sort
)
{
// Clear out the vulnerabilities so that the skeleton loader is shown.
this
.
vulnerabilities
=
[];
this
.
sort
=
sort
;
},
updateFilters
(
filters
)
{
// Clear out the vulnerabilities so that the skeleton loader is shown.
this
.
vulnerabilities
=
[];
this
.
filters
=
filters
;
},
fetchNextPage
()
{
this
.
$apollo
.
queries
.
vulnerabilities
.
fetchMore
({
variables
:
{
after
:
this
.
pageInfo
.
endCursor
},
updateQuery
:
(
previousResult
,
{
fetchMoreResult
})
=>
{
return
produce
(
fetchMoreResult
,
(
draftData
)
=>
{
draftData
.
group
.
vulnerabilities
.
nodes
=
[
...
previousResult
.
group
.
vulnerabilities
.
nodes
,
...
draftData
.
group
.
vulnerabilities
.
nodes
,
];
});
},
});
},
},
filtersToShow
:
[
FILTERS
.
STATUS
,
...
...
@@ -116,6 +48,7 @@ export default {
FILTERS
.
ACTIVITY
,
FILTERS
.
PROJECT
,
],
vulnerabilitiesQuery
,
};
</
script
>
...
...
@@ -133,17 +66,12 @@ export default {
@
filters-changed=
"updateFilters"
/>
<vulnerability-list
<vulnerability-list
-graphql
class=
"gl-mt-6"
:is-loading=
"isLoadingInitialVulnerabilities"
:vulnerabilities=
"vulnerabilities"
:query=
"$options.vulnerabilitiesQuery"
:fields=
"fields"
should-show-project-namespace
@
sort-changed=
"updateSort"
:filters=
"filters"
show-project-namespace
/>
<gl-intersection-observer
v-if=
"hasNextPage"
@
appear=
"fetchNextPage"
>
<gl-loading-icon
v-if=
"isLoadingVulnerabilities"
size=
"md"
/>
</gl-intersection-observer>
</div>
</
template
>
ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_list_graphql.vue
0 → 100644
View file @
56dfb49c
<
script
>
import
{
GlLoadingIcon
,
GlIntersectionObserver
}
from
'
@gitlab/ui
'
;
import
{
produce
}
from
'
immer
'
;
import
createFlash
from
'
~/flash
'
;
import
{
s__
}
from
'
~/locale
'
;
import
VulnerabilityList
from
'
./vulnerability_list.vue
'
;
// Deep searches an object for a key called 'vulnerabilities'. If it's not found, it will traverse
// down the object's first property until either it's found, or there's nothing left to search. Note
// that this will only check the first property of any object, not all of them.
const
deepFindVulnerabilities
=
(
data
)
=>
{
let
currentData
=
data
;
while
(
currentData
!==
undefined
&&
currentData
.
vulnerabilities
===
undefined
)
{
[
currentData
]
=
Object
.
values
(
currentData
);
}
return
currentData
?.
vulnerabilities
;
};
export
default
{
components
:
{
GlLoadingIcon
,
GlIntersectionObserver
,
VulnerabilityList
},
inject
:
[
'
fullPath
'
,
'
canViewFalsePositive
'
],
props
:
{
query
:
{
type
:
Object
,
required
:
true
,
},
filters
:
{
type
:
Object
,
required
:
false
,
default
:
null
,
},
fields
:
{
type
:
Array
,
required
:
true
,
},
showProjectNamespace
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
data
()
{
return
{
vulnerabilities
:
[],
sort
:
undefined
,
pageInfo
:
undefined
,
};
},
apollo
:
{
vulnerabilities
:
{
query
()
{
return
this
.
query
;
},
errorPolicy
:
'
none
'
,
variables
()
{
return
{
fullPath
:
this
.
fullPath
,
sort
:
this
.
sort
,
vetEnabled
:
this
.
canViewFalsePositive
,
...
this
.
filters
,
};
},
update
(
data
)
{
const
vulnerabilities
=
deepFindVulnerabilities
(
data
);
this
.
pageInfo
=
vulnerabilities
.
pageInfo
;
return
vulnerabilities
.
nodes
;
},
error
()
{
createFlash
({
message
:
s__
(
'
SecurityReports|Error fetching the vulnerability list. Please check your network connection and try again.
'
,
),
});
},
skip
()
{
return
!
this
.
filters
;
},
},
},
computed
:
{
// Used to show the infinite scrolling loading spinner.
isLoadingVulnerabilities
()
{
return
this
.
$apollo
.
queries
.
vulnerabilities
.
loading
;
},
// Used to show the initial skeleton loader.
isLoadingInitialVulnerabilities
()
{
return
this
.
isLoadingVulnerabilities
&&
this
.
vulnerabilities
.
length
<=
0
;
},
hasNextPage
()
{
return
this
.
pageInfo
?.
hasNextPage
;
},
},
watch
:
{
filters
()
{
// Clear out the vulnerabilities so that the skeleton loader is shown.
this
.
vulnerabilities
=
[];
},
},
methods
:
{
updateSort
(
sort
)
{
// Clear out the vulnerabilities so that the skeleton loader is shown.
this
.
vulnerabilities
=
[];
this
.
sort
=
sort
;
},
fetchNextPage
()
{
this
.
$apollo
.
queries
.
vulnerabilities
.
fetchMore
({
variables
:
{
after
:
this
.
pageInfo
.
endCursor
},
updateQuery
:
(
previousResult
,
{
fetchMoreResult
})
=>
{
return
produce
(
fetchMoreResult
,
(
draftData
)
=>
{
deepFindVulnerabilities
(
draftData
).
nodes
.
unshift
(...
this
.
vulnerabilities
);
});
},
});
},
},
};
</
script
>
<
template
>
<div>
<vulnerability-list
:is-loading=
"isLoadingInitialVulnerabilities"
:vulnerabilities=
"vulnerabilities"
:fields=
"fields"
:should-show-project-namespace=
"showProjectNamespace"
@
sort-changed=
"updateSort"
/>
<gl-intersection-observer
v-if=
"hasNextPage"
@
appear=
"fetchNextPage"
>
<gl-loading-icon
v-if=
"isLoadingVulnerabilities"
size=
"md"
/>
</gl-intersection-observer>
</div>
</
template
>
ee/spec/frontend/security_dashboard/components/group/vulnerability_report_development_spec.js
View file @
56dfb49c
import
{
createLocalVue
}
from
'
@vue/test-utils
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
{
nextTick
}
from
'
vue
'
;
import
{
GlIntersectionObserver
}
from
'
@gitlab/ui
'
;
import
VulnerabilityList
from
'
ee/security_dashboard/components/shared/vulnerability_report/vulnerability_list.vue
'
;
import
VulnerabilityListGraphql
from
'
ee/security_dashboard/components/shared/vulnerability_report/vulnerability_list_graphql.vue
'
;
import
VulnerabilityReportDevelopment
from
'
ee/security_dashboard/components/group/vulnerability_report_development.vue
'
;
import
VulnerabilityCounts
from
'
ee/security_dashboard/components/shared/vulnerability_report/vulnerability_counts.vue
'
;
import
VulnerabilityFilters
from
'
ee/security_dashboard/components/shared/vulnerability_report/vulnerability_filters.vue
'
;
import
{
shallowMountExtended
}
from
'
helpers/vue_test_utils_helper
'
;
import
vulnerabilitiesQuery
from
'
ee/security_dashboard/graphql/queries/group_vulnerabilities.query.graphql
'
;
import
createMockApollo
from
'
helpers/mock_apollo_helper
'
;
import
createFlash
from
'
~/flash
'
;
jest
.
mock
(
'
~/flash
'
);
const
localVue
=
createLocalVue
();
localVue
.
use
(
VueApollo
);
const
groupFullPath
=
'
path
'
;
const
createVulnerabilitiesRequestHandler
=
({
hasNextPage
})
=>
jest
.
fn
().
mockResolvedValue
({
data
:
{
group
:
{
vulnerabilities
:
{
nodes
:
[],
pageInfo
:
{
endCursor
:
'
abc
'
,
hasNextPage
},
},
},
},
});
const
vulnerabilitiesRequestHandler
=
createVulnerabilitiesRequestHandler
({
hasNextPage
:
true
});
describe
(
'
Vulnerability counts component
'
,
()
=>
{
let
wrapper
;
const
createWrapper
=
({
vulnerabilitiesHandler
=
vulnerabilitiesRequestHandler
,
canViewFalsePositive
=
true
,
filters
=
{},
}
=
{})
=>
{
const
createWrapper
=
()
=>
{
wrapper
=
shallowMountExtended
(
VulnerabilityReportDevelopment
,
{
localVue
,
apolloProvider
:
createMockApollo
([[
vulnerabilitiesQuery
,
vulnerabilitiesHandler
]]),
provide
:
{
groupFullPath
,
canViewFalsePositive
,
canAdminVulnerability
:
true
,
hasProjects
:
true
,
},
data
:
()
=>
({
filters
}),
});
};
const
findVulnerabilityCounts
=
()
=>
wrapper
.
findComponent
(
VulnerabilityCounts
);
const
findVulnerabilityFilters
=
()
=>
wrapper
.
findComponent
(
VulnerabilityFilters
);
const
findVulnerabilityList
=
()
=>
wrapper
.
findComponent
(
VulnerabilityList
);
const
findIntersectionObserver
=
()
=>
wrapper
.
findComponent
(
GlIntersectionObserver
);
const
findVulnerabilityListGraphql
=
()
=>
wrapper
.
findComponent
(
VulnerabilityListGraphql
);
afterEach
(()
=>
{
wrapper
.
destroy
();
vulnerabilitiesRequestHandler
.
mockClear
();
});
describe
(
'
vulnerability counts component
'
,
()
=>
{
it
(
'
receives the filters prop from the filters component
'
,
()
=>
{
const
filters
=
{};
// Object itself does not matter, we're only checking that it's passed.
createWrapper
({
filters
});
expect
(
findVulnerabilityCounts
().
props
(
'
filters
'
)).
toBe
(
filters
);
});
});
describe
(
'
group vulnerabilities query
'
,
()
=>
{
it
(
'
calls the query once with the expected fullPath variable
'
,
()
=>
{
createWrapper
();
expect
(
vulnerabilitiesRequestHandler
).
toHaveBeenCalledTimes
(
1
);
expect
(
vulnerabilitiesRequestHandler
).
toHaveBeenCalledWith
(
expect
.
objectContaining
({
fullPath
:
groupFullPath
}),
);
});
it
.
each
([
true
,
false
])(
'
calls the query with the expected vetEnabled property when canViewFalsePositive is %s
'
,
(
canViewFalsePositive
)
=>
{
createWrapper
({
canViewFalsePositive
});
expect
(
vulnerabilitiesRequestHandler
).
toHaveBeenCalledWith
(
expect
.
objectContaining
({
vetEnabled
:
canViewFalsePositive
}),
);
},
);
it
(
'
does not call the query if filters are not ready
'
,
()
=>
{
createWrapper
({
filters
:
null
});
expect
(
vulnerabilitiesRequestHandler
).
not
.
toHaveBeenCalled
();
});
it
(
'
shows an error message if the query fails
'
,
async
()
=>
{
const
vulnerabilitiesHandler
=
jest
.
fn
().
mockRejectedValue
(
new
Error
());
createWrapper
({
vulnerabilitiesHandler
});
// Have to wait 2 ticks here, one for the query to finish loading, and one more for the
// GraphQL error handler to be called.
await
nextTick
();
await
nextTick
();
expect
(
createFlash
).
toHaveBeenCalledTimes
(
1
);
});
});
describe
(
'
vulnerability list component
'
,
()
=>
{
it
(
'
gets the expected vulnerabilities prop
'
,
async
()
=>
{
createWrapper
();
const
vulnerabilities
=
[];
await
wrapper
.
setData
({
vulnerabilities
});
expect
(
findVulnerabilityList
().
props
(
'
vulnerabilities
'
)).
toEqual
(
vulnerabilities
);
});
it
(
'
calls the vulnerabilities query with the data from the sort-changed event
'
,
async
()
=>
{
createWrapper
();
// First call should be undefined, which uses the default sort.
expect
(
vulnerabilitiesRequestHandler
).
toHaveBeenCalledWith
(
expect
.
objectContaining
({
sort
:
undefined
}),
);
const
sort
=
'
sort
'
;
findVulnerabilityList
().
vm
.
$emit
(
'
sort-changed
'
,
sort
);
await
nextTick
();
expect
(
vulnerabilitiesRequestHandler
).
toHaveBeenCalledWith
(
expect
.
objectContaining
({
sort
}));
});
});
describe
(
'
intersection observer
'
,
()
=>
{
it
(
'
is not shown when the vulnerabilities query is loading for the first time
'
,
()
=>
{
createWrapper
();
expect
(
findIntersectionObserver
().
exists
()).
toBe
(
false
);
});
it
(
'
will fetch more data when the appear event is fired
'
,
async
()
=>
{
createWrapper
();
await
nextTick
();
const
spy
=
jest
.
spyOn
(
wrapper
.
vm
.
$apollo
.
queries
.
vulnerabilities
,
'
fetchMore
'
);
findIntersectionObserver
().
vm
.
$emit
(
'
appear
'
);
expect
(
spy
).
toHaveBeenCalledTimes
(
1
);
});
it
(
'
is not shown if there is no next page
'
,
async
()
=>
{
createWrapper
({
vulnerabilitiesHandler
:
createVulnerabilitiesRequestHandler
({
hasNextPage
:
false
}),
});
await
nextTick
();
expect
(
findIntersectionObserver
().
exists
()).
toBe
(
false
);
});
});
describe
(
'
vulnerability filters component
'
,
()
=>
{
it
(
'
will pass data from filters-changed event to vulnerabilities GraphQL query
'
,
async
()
=>
{
const
vulnerabilitiesHandler
=
jest
.
fn
().
mockResolvedValue
();
createWrapper
({
vulnerabilitiesHandler
});
// Sanity check, the report component will call this the first time it's mounted.
expect
(
vulnerabilitiesHandler
).
toHaveBeenCalledTimes
(
1
);
it
(
'
will pass data from filters-changed event to the counts and list components
'
,
async
()
=>
{
createWrapper
();
const
data
=
{
a
:
1
};
findVulnerabilityFilters
().
vm
.
$emit
(
'
filters-changed
'
,
data
);
await
nextTick
();
expect
(
vulnerabilitiesHandler
).
toHaveBeenCalledTimes
(
2
);
expect
(
vulnerabilitiesHandler
).
toHaveBeenCalledWith
(
expect
.
objectContaining
(
data
)
);
expect
(
findVulnerabilityCounts
().
props
(
'
filters
'
)).
toBe
(
data
);
expect
(
findVulnerabilityListGraphql
().
props
(
'
filters
'
)).
toBe
(
data
);
});
});
});
ee/spec/frontend/security_dashboard/components/shared/vulnerability_report/vulnerability_list_graphql_spec.js
0 → 100644
View file @
56dfb49c
import
{
createLocalVue
}
from
'
@vue/test-utils
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
{
nextTick
}
from
'
vue
'
;
import
{
GlIntersectionObserver
}
from
'
@gitlab/ui
'
;
import
VulnerabilityListGraphql
from
'
ee/security_dashboard/components/shared/vulnerability_report/vulnerability_list_graphql.vue
'
;
import
VulnerabilityList
from
'
ee/security_dashboard/components/shared/vulnerability_report/vulnerability_list.vue
'
;
import
{
shallowMountExtended
}
from
'
helpers/vue_test_utils_helper
'
;
import
vulnerabilitiesQuery
from
'
ee/security_dashboard/graphql/queries/group_vulnerabilities.query.graphql
'
;
import
createMockApollo
from
'
helpers/mock_apollo_helper
'
;
import
createFlash
from
'
~/flash
'
;
jest
.
mock
(
'
~/flash
'
);
const
localVue
=
createLocalVue
();
localVue
.
use
(
VueApollo
);
const
fullPath
=
'
path
'
;
const
createVulnerabilitiesRequestHandler
=
({
hasNextPage
})
=>
jest
.
fn
().
mockResolvedValue
({
data
:
{
group
:
{
vulnerabilities
:
{
nodes
:
[],
pageInfo
:
{
endCursor
:
'
abc
'
,
hasNextPage
},
},
},
},
});
const
vulnerabilitiesRequestHandler
=
createVulnerabilitiesRequestHandler
({
hasNextPage
:
true
});
describe
(
'
Vulnerability list GraphQL component
'
,
()
=>
{
let
wrapper
;
const
createWrapper
=
({
vulnerabilitiesHandler
=
vulnerabilitiesRequestHandler
,
canViewFalsePositive
=
false
,
showProjectNamespace
=
false
,
filters
=
{},
fields
=
[],
}
=
{})
=>
{
wrapper
=
shallowMountExtended
(
VulnerabilityListGraphql
,
{
localVue
,
apolloProvider
:
createMockApollo
([[
vulnerabilitiesQuery
,
vulnerabilitiesHandler
]]),
provide
:
{
fullPath
,
canViewFalsePositive
,
},
propsData
:
{
query
:
vulnerabilitiesQuery
,
filters
,
fields
,
showProjectNamespace
,
},
});
};
const
findVulnerabilityList
=
()
=>
wrapper
.
findComponent
(
VulnerabilityList
);
const
findIntersectionObserver
=
()
=>
wrapper
.
findComponent
(
GlIntersectionObserver
);
afterEach
(()
=>
{
wrapper
.
destroy
();
vulnerabilitiesRequestHandler
.
mockClear
();
});
describe
(
'
vulnerabilities query
'
,
()
=>
{
it
(
'
calls the query once with the expected fullPath variable
'
,
()
=>
{
createWrapper
();
expect
(
vulnerabilitiesRequestHandler
).
toHaveBeenCalledTimes
(
1
);
expect
(
vulnerabilitiesRequestHandler
).
toHaveBeenCalledWith
(
expect
.
objectContaining
({
fullPath
}),
);
});
it
.
each
([
true
,
false
])(
'
calls the query with the expected vetEnabled property when canViewFalsePositive is %s
'
,
(
canViewFalsePositive
)
=>
{
createWrapper
({
canViewFalsePositive
});
expect
(
vulnerabilitiesRequestHandler
).
toHaveBeenCalledWith
(
expect
.
objectContaining
({
vetEnabled
:
canViewFalsePositive
}),
);
},
);
it
(
'
does not call the query if filters are not ready
'
,
()
=>
{
createWrapper
({
filters
:
null
});
expect
(
vulnerabilitiesRequestHandler
).
not
.
toHaveBeenCalled
();
});
it
(
'
shows an error message if the query fails
'
,
async
()
=>
{
const
vulnerabilitiesHandler
=
jest
.
fn
().
mockRejectedValue
(
new
Error
());
createWrapper
({
vulnerabilitiesHandler
});
// Have to wait 2 ticks here, one for the query to finish loading, and one more for the
// GraphQL error handler to be called.
await
nextTick
();
await
nextTick
();
expect
(
createFlash
).
toHaveBeenCalledTimes
(
1
);
});
});
describe
(
'
vulnerability list component
'
,
()
=>
{
it
(
'
gets the expected props
'
,
async
()
=>
{
const
fields
=
[
'
abc
'
];
const
showProjectNamespace
=
true
;
createWrapper
({
fields
,
showProjectNamespace
});
expect
(
findVulnerabilityList
().
props
(
'
fields
'
)).
toBe
(
fields
);
expect
(
findVulnerabilityList
().
props
(
'
shouldShowProjectNamespace
'
)).
toBe
(
showProjectNamespace
,
);
});
it
(
'
calls the vulnerabilities query with the data from the sort-changed event
'
,
async
()
=>
{
createWrapper
();
// First call should be undefined, which uses the default sort.
expect
(
vulnerabilitiesRequestHandler
).
toHaveBeenCalledWith
(
expect
.
objectContaining
({
sort
:
undefined
}),
);
const
sort
=
'
sort
'
;
findVulnerabilityList
().
vm
.
$emit
(
'
sort-changed
'
,
sort
);
await
nextTick
();
expect
(
vulnerabilitiesRequestHandler
).
toHaveBeenCalledWith
(
expect
.
objectContaining
({
sort
}));
});
});
describe
(
'
intersection observer
'
,
()
=>
{
it
(
'
is not shown when the vulnerabilities query is loading for the first time
'
,
()
=>
{
createWrapper
();
expect
(
findIntersectionObserver
().
exists
()).
toBe
(
false
);
});
it
(
'
will fetch more data when the appear event is fired
'
,
async
()
=>
{
createWrapper
();
await
nextTick
();
const
spy
=
jest
.
spyOn
(
wrapper
.
vm
.
$apollo
.
queries
.
vulnerabilities
,
'
fetchMore
'
);
findIntersectionObserver
().
vm
.
$emit
(
'
appear
'
);
expect
(
spy
).
toHaveBeenCalledTimes
(
1
);
});
it
(
'
is not shown if there is no next page
'
,
async
()
=>
{
createWrapper
({
vulnerabilitiesHandler
:
createVulnerabilitiesRequestHandler
({
hasNextPage
:
false
}),
});
await
nextTick
();
expect
(
findIntersectionObserver
().
exists
()).
toBe
(
false
);
});
});
});
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