diff --git a/ee/app/assets/javascripts/dependencies/components/dependency_vulnerabilities.vue b/ee/app/assets/javascripts/dependencies/components/dependency_vulnerabilities.vue
new file mode 100644
index 0000000000000000000000000000000000000000..6e66130b1c98754d6805e523fbf296fd635567e3
--- /dev/null
+++ b/ee/app/assets/javascripts/dependencies/components/dependency_vulnerabilities.vue
@@ -0,0 +1,46 @@
+
+
+
+
+ -
+
+
+ -
+ {{
+ n__(
+ 'Dependencies|%d additional vulnerability not shown',
+ 'Dependencies|%d additional vulnerabilities not shown',
+ vulnerabilitiesNotShown,
+ )
+ }}
+
+
+
diff --git a/ee/spec/frontend/dependencies/components/__snapshots__/dependency_vulnerabilities_spec.js.snap b/ee/spec/frontend/dependencies/components/__snapshots__/dependency_vulnerabilities_spec.js.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5e968095d9cc34c334398f3b77e3883a8b38f3ff
--- /dev/null
+++ b/ee/spec/frontend/dependencies/components/__snapshots__/dependency_vulnerabilities_spec.js.snap
@@ -0,0 +1,20 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`DependencVulnerabilities component given a huge number vulnerabilities renders the excess message 1`] = `
+
+
+ 1 additional vulnerability not shown
+
+
+`;
+
+exports[`DependencVulnerabilities component given no vulnerabilities renders an empty list 1`] = `
+
+`;
diff --git a/ee/spec/frontend/dependencies/components/dependency_vulnerabilities_spec.js b/ee/spec/frontend/dependencies/components/dependency_vulnerabilities_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..16b481b763e1d225c56e542431a29f51b3804963
--- /dev/null
+++ b/ee/spec/frontend/dependencies/components/dependency_vulnerabilities_spec.js
@@ -0,0 +1,63 @@
+import { shallowMount } from '@vue/test-utils';
+import DependencyVulnerabilities from 'ee/dependencies/components/dependency_vulnerabilities.vue';
+import DependencyVulnerability from 'ee/dependencies/components/dependency_vulnerability.vue';
+import { MAX_DISPLAYED_VULNERABILITIES_PER_DEPENDENCY } from 'ee/dependencies/components/constants';
+import mockDataVulnerabilities from '../../security_dashboard/store/modules/vulnerabilities/data/mock_data_vulnerabilities';
+
+describe('DependencVulnerabilities component', () => {
+ let wrapper;
+
+ const factory = ({ vulnerabilities }) => {
+ wrapper = shallowMount(DependencyVulnerabilities, {
+ propsData: { vulnerabilities },
+ });
+ };
+
+ const findVulnerabilities = () => wrapper.findAll(DependencyVulnerability);
+ const findExcessMessage = () => wrapper.find({ ref: 'excessMessage' });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('given no vulnerabilities', () => {
+ beforeEach(() => {
+ factory({ vulnerabilities: [] });
+ });
+
+ it('renders an empty list', () => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+
+ describe('given some vulnerabilities', () => {
+ beforeEach(() => {
+ factory({ vulnerabilities: mockDataVulnerabilities });
+ });
+
+ it('renders each vulnerability', () => {
+ const components = findVulnerabilities();
+ mockDataVulnerabilities.forEach((vulnerability, i) => {
+ expect(components.at(i).props('vulnerability')).toBe(vulnerability);
+ });
+ });
+ });
+
+ describe('given a huge number vulnerabilities', () => {
+ beforeEach(() => {
+ const hugeNumberOfVulnerabilities = Array(1 + MAX_DISPLAYED_VULNERABILITIES_PER_DEPENDENCY)
+ .fill(null)
+ .map((_, id) => ({ id }));
+
+ factory({ vulnerabilities: hugeNumberOfVulnerabilities });
+ });
+
+ it('does not render all of them', () => {
+ expect(findVulnerabilities().length).toBe(MAX_DISPLAYED_VULNERABILITIES_PER_DEPENDENCY);
+ });
+
+ it('renders the excess message', () => {
+ expect(findExcessMessage().element).toMatchSnapshot();
+ });
+ });
+});