diff --git a/app/assets/javascripts/pipeline_editor/components/header/pipeline_editor_mini_graph.vue b/app/assets/javascripts/pipeline_editor/components/header/pipeline_editor_mini_graph.vue
index 3662100d5266c5ce8c3c932105ae02ace15788ca..7beabcfe4035dfc63351f9795c37fd15b1436f77 100644
--- a/app/assets/javascripts/pipeline_editor/components/header/pipeline_editor_mini_graph.vue
+++ b/app/assets/javascripts/pipeline_editor/components/header/pipeline_editor_mini_graph.vue
@@ -10,6 +10,8 @@ export default {
   },
   components: {
     PipelineMiniGraph,
+    LinkedPipelinesMiniList: () =>
+      import('ee_component/vue_shared/components/linked_pipelines_mini_list.vue'),
   },
   inject: ['projectFullPath'],
   props: {
@@ -45,6 +47,9 @@ export default {
     downstreamPipelines() {
       return this.linkedPipelines?.downstream?.nodes || [];
     },
+    hasDownstreamPipelines() {
+      return this.downstreamPipelines.length > 0;
+    },
     hasPipelineStages() {
       return this.pipelineStages.length > 0;
     },
@@ -82,11 +87,23 @@ export default {
 </script>
 
 <template>
-  <pipeline-mini-graph
+  <div
     v-if="hasPipelineStages"
-    :downstream-pipelines="downstreamPipelines"
-    :pipeline-path="pipelinePath"
-    :stages="pipelineStages"
-    :upstream-pipeline="upstreamPipeline"
-  />
+    class="gl-align-items-center gl-display-inline-flex gl-flex-wrap stage-cell gl-mr-5"
+  >
+    <linked-pipelines-mini-list
+      v-if="upstreamPipeline"
+      :triggered-by="/* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ [
+        upstreamPipeline,
+      ] /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */"
+      data-testid="pipeline-editor-mini-graph-upstream"
+    />
+    <pipeline-mini-graph :stages="pipelineStages" />
+    <linked-pipelines-mini-list
+      v-if="hasDownstreamPipelines"
+      :triggered="downstreamPipelines"
+      :pipeline-path="pipelinePath"
+      data-testid="pipeline-editor-mini-graph-downstream"
+    />
+  </div>
 </template>
diff --git a/app/assets/javascripts/pipeline_editor/components/header/pipeline_status.vue b/app/assets/javascripts/pipeline_editor/components/header/pipeline_status.vue
index 137dfca68d6d0873b87c6ee7314f3be46d20f79a..4b9c98135ec60030d09a112b15a3be39c2887ef9 100644
--- a/app/assets/javascripts/pipeline_editor/components/header/pipeline_status.vue
+++ b/app/assets/javascripts/pipeline_editor/components/header/pipeline_status.vue
@@ -174,7 +174,7 @@ export default {
       <div class="gl-display-flex gl-flex-wrap">
         <pipeline-editor-mini-graph :pipeline="pipeline" v-on="$listeners" />
         <gl-button
-          class="gl-ml-3"
+          class="gl-mt-2 gl-md-mt-0"
           category="secondary"
           variant="confirm"
           :href="status.detailsPath"
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_mini_graph.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_mini_graph.vue
index f1edc3d4be8d73e382c6a51163ce079688906f2e..05cb2ebb769e6a0f8f0d62653f9ced09d4207229 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_mini_graph.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_mini_graph.vue
@@ -1,60 +1,32 @@
 <script>
-import { GlIcon } from '@gitlab/ui';
-import PipelineStages from '~/pipelines/components/pipelines_list/pipeline_stages.vue';
+import PipelineStage from '~/pipelines/components/pipelines_list/pipeline_stage.vue';
 /**
  * Renders the pipeline mini graph.
  */
 export default {
   components: {
-    GlIcon,
-    PipelineStages,
-    LinkedPipelinesMiniList: () =>
-      import('ee_component/vue_shared/components/linked_pipelines_mini_list.vue'),
+    PipelineStage,
   },
-  arrowStyles: [
-    'arrow-icon gl-display-inline-block gl-mx-1 gl-text-gray-500 gl-vertical-align-middle!',
-  ],
   props: {
-    downstreamPipelines: {
+    stages: {
       type: Array,
-      required: false,
-      default: () => [],
+      required: true,
     },
-    isMergeTrain: {
+    updateDropdown: {
       type: Boolean,
       required: false,
       default: false,
     },
-    pipelinePath: {
-      type: String,
-      required: false,
-      default: '',
-    },
-    stages: {
-      type: Array,
-      required: true,
-      default: () => [],
-    },
     stagesClass: {
       type: [Array, Object, String],
       required: false,
       default: '',
     },
-    updateDropdown: {
+    isMergeTrain: {
       type: Boolean,
       required: false,
       default: false,
     },
-    upstreamPipeline: {
-      type: Object,
-      required: false,
-      default: () => {},
-    },
-  },
-  computed: {
-    hasDownstreamPipelines() {
-      return Boolean(this.downstreamPipelines.length);
-    },
   },
   methods: {
     onPipelineActionRequestComplete() {
@@ -64,39 +36,19 @@ export default {
 };
 </script>
 <template>
-  <div class="stage-cell" data-testid="pipeline-mini-graph">
-    <linked-pipelines-mini-list
-      v-if="upstreamPipeline"
-      :triggered-by="/* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ [
-        upstreamPipeline,
-      ] /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */"
-      data-testid="pipeline-mini-graph-upstream"
-    />
-    <gl-icon
-      v-if="upstreamPipeline"
-      :class="$options.arrowStyles"
-      name="long-arrow"
-      data-testid="upstream-arrow-icon"
-    />
-    <pipeline-stages
-      :is-merge-train="isMergeTrain"
-      :stages="stages"
-      :update-dropdown="updateDropdown"
-      :stages-class="stagesClass"
-      data-testid="pipeline-stages"
-      @pipelineActionRequestComplete="onPipelineActionRequestComplete"
-    />
-    <gl-icon
-      v-if="hasDownstreamPipelines"
-      :class="$options.arrowStyles"
-      name="long-arrow"
-      data-testid="downstream-arrow-icon"
-    />
-    <linked-pipelines-mini-list
-      v-if="hasDownstreamPipelines"
-      :triggered="downstreamPipelines"
-      :pipeline-path="pipelinePath"
-      data-testid="pipeline-mini-graph-downstream"
-    />
+  <div data-testid="pipeline-mini-graph" class="gl-display-inline gl-vertical-align-middle">
+    <div
+      v-for="stage in stages"
+      :key="stage.name"
+      :class="stagesClass"
+      class="dropdown gl-display-inline-block gl-mr-2 gl-my-2 gl-vertical-align-middle stage-container"
+    >
+      <pipeline-stage
+        :stage="stage"
+        :update-dropdown="updateDropdown"
+        :is-merge-train="isMergeTrain"
+        @pipelineActionRequestComplete="onPipelineActionRequestComplete"
+      />
+    </div>
   </div>
 </template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stages.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stages.vue
deleted file mode 100644
index f1923e94a477a3d282d159a8665ac7594988dde4..0000000000000000000000000000000000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stages.vue
+++ /dev/null
@@ -1,54 +0,0 @@
-<script>
-import PipelineStage from '~/pipelines/components/pipelines_list/pipeline_stage.vue';
-/**
- * Renders the pipeline stages portion of the pipeline mini graph.
- */
-export default {
-  components: {
-    PipelineStage,
-  },
-  props: {
-    stages: {
-      type: Array,
-      required: true,
-    },
-    updateDropdown: {
-      type: Boolean,
-      required: false,
-      default: false,
-    },
-    stagesClass: {
-      type: [Array, Object, String],
-      required: false,
-      default: '',
-    },
-    isMergeTrain: {
-      type: Boolean,
-      required: false,
-      default: false,
-    },
-  },
-  methods: {
-    onPipelineActionRequestComplete() {
-      this.$emit('pipelineActionRequestComplete');
-    },
-  },
-};
-</script>
-<template>
-  <div data-testid="pipeline-stages" class="gl-display-inline gl-vertical-align-middle">
-    <div
-      v-for="stage in stages"
-      :key="stage.name"
-      :class="stagesClass"
-      class="dropdown gl-display-inline-block gl-mr-2 gl-my-2 gl-vertical-align-middle stage-container"
-    >
-      <pipeline-stage
-        :stage="stage"
-        :update-dropdown="updateDropdown"
-        :is-merge-train="isMergeTrain"
-        @pipelineActionRequestComplete="onPipelineActionRequestComplete"
-      />
-    </div>
-  </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue
index 4046ee69428dec3f553080abfc9d67d1202ee6d7..53da98434b0d8c2a0bb7efbf3bf2188a059889c0 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue
@@ -17,6 +17,8 @@ const DEFAULT_TH_CLASSES =
 export default {
   components: {
     GlTableLite,
+    LinkedPipelinesMiniList: () =>
+      import('ee_component/vue_shared/components/linked_pipelines_mini_list.vue'),
     PipelineMiniGraph,
     PipelineOperations,
     PipelinesStatusBadge,
@@ -167,14 +169,29 @@ export default {
       </template>
 
       <template #cell(stages)="{ item }">
-        <pipeline-mini-graph
-          :downstream-pipelines="item.triggered"
-          :pipeline-path="item.path"
-          :stages="item.details.stages"
-          :update-dropdown="updateGraphDropdown"
-          :upstream-pipeline="item.triggered_by"
-          @pipelineActionRequestComplete="onPipelineActionRequestComplete"
-        />
+        <div class="stage-cell">
+          <!-- This empty div should be removed, see https://gitlab.com/gitlab-org/gitlab/-/issues/323488 -->
+          <div></div>
+          <linked-pipelines-mini-list
+            v-if="item.triggered_by"
+            :triggered-by="/* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ [
+              item.triggered_by,
+            ] /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */"
+            data-testid="mini-graph-upstream"
+          />
+          <pipeline-mini-graph
+            v-if="item.details && item.details.stages && item.details.stages.length > 0"
+            :stages="item.details.stages"
+            :update-dropdown="updateGraphDropdown"
+            @pipelineActionRequestComplete="onPipelineActionRequestComplete"
+          />
+          <linked-pipelines-mini-list
+            v-if="item.triggered.length"
+            :triggered="item.triggered"
+            :pipeline-path="item.path"
+            data-testid="mini-graph-downstream"
+          />
+        </div>
       </template>
 
       <template #cell(actions)="{ item }">
diff --git a/app/assets/javascripts/projects/commit_box/info/components/commit_box_pipeline_mini_graph.vue b/app/assets/javascripts/projects/commit_box/info/components/commit_box_pipeline_mini_graph.vue
index a4044106a531b2d85cee27c0dd982f69b8b18ed5..1cdf26b76b752e9f88ee7efdc4cea1f6b3e69b67 100644
--- a/app/assets/javascripts/projects/commit_box/info/components/commit_box_pipeline_mini_graph.vue
+++ b/app/assets/javascripts/projects/commit_box/info/components/commit_box_pipeline_mini_graph.vue
@@ -2,11 +2,11 @@
 import { GlLoadingIcon } from '@gitlab/ui';
 import createFlash from '~/flash';
 import { __ } from '~/locale';
+import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
 import {
   getQueryHeaders,
   toggleQueryPollingByVisibility,
 } from '~/pipelines/components/graph/utils';
-import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
 import { formatStages } from '../utils';
 import getLinkedPipelinesQuery from '../graphql/queries/get_linked_pipelines.query.graphql';
 import getPipelineStagesQuery from '../graphql/queries/get_pipeline_stages.query.graphql';
@@ -21,6 +21,8 @@ export default {
   components: {
     GlLoadingIcon,
     PipelineMiniGraph,
+    LinkedPipelinesMiniList: () =>
+      import('ee_component/vue_shared/components/linked_pipelines_mini_list.vue'),
   },
   inject: {
     fullPath: {
@@ -90,12 +92,12 @@ export default {
     };
   },
   computed: {
+    hasDownstream() {
+      return this.pipeline?.downstream?.nodes.length > 0;
+    },
     downstreamPipelines() {
       return this.pipeline?.downstream?.nodes;
     },
-    pipelinePath() {
-      return this.pipeline?.path ?? '';
-    },
     upstreamPipeline() {
       return this.pipeline?.upstream;
     },
@@ -126,13 +128,23 @@ export default {
 <template>
   <div class="gl-pt-2">
     <gl-loading-icon v-if="$apollo.queries.pipeline.loading" />
-    <pipeline-mini-graph
-      v-else
-      data-testid="commit-box-pipeline-mini-graph"
-      :downstream-pipelines="downstreamPipelines"
-      :pipeline-path="pipelinePath"
-      :stages="formattedStages"
-      :upstream-pipeline="upstreamPipeline"
-    />
+    <div v-else class="gl-align-items-center gl-display-flex">
+      <linked-pipelines-mini-list
+        v-if="upstreamPipeline"
+        :triggered-by="/* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ [
+          upstreamPipeline,
+        ] /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */"
+        data-testid="commit-box-mini-graph-upstream"
+      />
+
+      <pipeline-mini-graph :stages="formattedStages" data-testid="commit-box-mini-graph" />
+
+      <linked-pipelines-mini-list
+        v-if="hasDownstream"
+        :triggered="downstreamPipelines"
+        :pipeline-path="pipeline.path"
+        data-testid="commit-box-mini-graph-downstream"
+      />
+    </div>
   </div>
 </template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
index 5ecf49b51be8112b85ccd5637d5927a0f279819b..1e1a20494145715440559ba2e9c5815b47ac52b5 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
@@ -11,8 +11,8 @@ import {
 } from '@gitlab/ui';
 import mrWidgetPipelineMixin from 'ee_else_ce/vue_merge_request_widget/mixins/mr_widget_pipeline';
 import { s__, n__ } from '~/locale';
-import PipelineArtifacts from '~/pipelines/components/pipelines_list/pipelines_artifacts.vue';
 import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
+import PipelineArtifacts from '~/pipelines/components/pipelines_list/pipelines_artifacts.vue';
 import CiIcon from '~/vue_shared/components/ci_icon.vue';
 import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
 import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
@@ -31,6 +31,8 @@ export default {
     PipelineMiniGraph,
     TimeAgoTooltip,
     TooltipOnTruncate,
+    LinkedPipelinesMiniList: () =>
+      import('ee_component/vue_shared/components/linked_pipelines_mini_list.vue'),
   },
   directives: {
     GlTooltip: GlTooltipDirective,
@@ -274,15 +276,17 @@ export default {
           </div>
         </div>
         <div>
-          <span class="gl-align-items-center gl-display-inline-flex">
-            <pipeline-mini-graph
-              v-if="pipeline.details.stages"
-              :downstream-pipelines="triggered"
-              :is-merge-train="isMergeTrain"
-              :stages="pipeline.details.stages"
-              :upstream-pipeline="triggeredBy[0]"
-              stages-class="mr-widget-pipeline-stages"
-            />
+          <span class="gl-align-items-center gl-display-inline-flex mr-widget-pipeline-graph">
+            <span class="gl-align-items-center gl-display-inline-flex gl-flex-wrap stage-cell">
+              <linked-pipelines-mini-list v-if="triggeredBy.length" :triggered-by="triggeredBy" />
+              <pipeline-mini-graph
+                v-if="hasStages"
+                stages-class="mr-widget-pipeline-stages"
+                :stages="pipeline.details.stages"
+                :is-merge-train="isMergeTrain"
+              />
+            </span>
+            <linked-pipelines-mini-list v-if="triggered.length" :triggered="triggered" />
             <pipeline-artifacts :pipeline-id="pipeline.id" :artifacts="artifacts" class="gl-ml-3" />
           </span>
         </div>
diff --git a/app/assets/stylesheets/page_bundles/merge_requests.scss b/app/assets/stylesheets/page_bundles/merge_requests.scss
index 269afd01615e32e5a7f6f178b9cbeaecb8b776e9..14873c54cd77d8f6cddbf0ed82b76811ef1c737c 100644
--- a/app/assets/stylesheets/page_bundles/merge_requests.scss
+++ b/app/assets/stylesheets/page_bundles/merge_requests.scss
@@ -400,6 +400,12 @@ $tabs-holder-z-index: 250;
     display: block;
   }
 
+  .mr-widget-pipeline-graph {
+    .dropdown-menu {
+      z-index: $zindex-dropdown-menu;
+    }
+  }
+
   .normal {
     flex: 1;
     flex-basis: auto;
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index 19318d8773127c63d7052430852adda1b6beab41..c96d8ecc782ee805b286ed6c1c325846f8f47688 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -33,6 +33,12 @@
       height: 22px;
     }
   }
+
+  .mr-widget-pipeline-graph {
+    .dropdown-menu {
+      margin-top: 11px;
+    }
+  }
 }
 
 .branch-info .commit-icon {
diff --git a/ee/app/assets/javascripts/vue_shared/components/linked_pipelines_mini_list.vue b/ee/app/assets/javascripts/vue_shared/components/linked_pipelines_mini_list.vue
index 4d180dfcd824905ca818d51914257c944e64134a..4ebe9539411cb469eae60a8908ef311b9f16729e 100644
--- a/ee/app/assets/javascripts/vue_shared/components/linked_pipelines_mini_list.vue
+++ b/ee/app/assets/javascripts/vue_shared/components/linked_pipelines_mini_list.vue
@@ -1,18 +1,20 @@
 <script>
-import { GlTooltipDirective } from '@gitlab/ui';
+import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
 import { sprintf, s__ } from '~/locale';
 import CiIcon from '~/vue_shared/components/ci_icon.vue';
 import { accessValue } from '../accessors/linked_pipelines_accessors';
-/**
- * Renders the upstream/downstream portions of the pipeline mini graph.
- */
+
 export default {
   directives: {
     GlTooltip: GlTooltipDirective,
   },
   components: {
     CiIcon,
+    GlIcon,
   },
+  arrowStyles: [
+    'arrow-icon gl-display-inline-block gl-mx-1 gl-text-gray-500 gl-vertical-align-middle!',
+  ],
   inject: {
     dataMethod: {
       default: 'rest',
@@ -99,6 +101,8 @@ export default {
     }"
     class="linked-pipeline-mini-list gl-display-inline gl-vertical-align-middle"
   >
+    <gl-icon v-if="isDownstream" :class="$options.arrowStyles" name="long-arrow" />
+
     <a
       v-for="pipeline in linkedPipelinesTrimmed"
       :key="pipeline.id"
@@ -128,5 +132,7 @@ export default {
     >
       {{ counterLabel }}
     </a>
+
+    <gl-icon v-if="isUpstream" :class="$options.arrowStyles" name="long-arrow" />
   </span>
 </template>
diff --git a/ee/spec/frontend/commit_box/components/commit_box_pipeline_mini_graph_spec.js b/ee/spec/frontend/commit_box/components/commit_box_pipeline_mini_graph_spec.js
index 4dd6e9e54867aa553ddfd668dc71f05424f4a384..ceb43768657a0bbe134c0e71c932d7093d524d2d 100644
--- a/ee/spec/frontend/commit_box/components/commit_box_pipeline_mini_graph_spec.js
+++ b/ee/spec/frontend/commit_box/components/commit_box_pipeline_mini_graph_spec.js
@@ -7,7 +7,6 @@ import { extendedWrapper } from 'helpers/vue_test_utils_helper';
 import waitForPromises from 'helpers/wait_for_promises';
 import createFlash from '~/flash';
 import CommitBoxPipelineMiniGraph from '~/projects/commit_box/info/components/commit_box_pipeline_mini_graph.vue';
-import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
 import { COMMIT_BOX_POLL_INTERVAL } from '~/projects/commit_box/info/constants';
 import getLinkedPipelinesQuery from '~/projects/commit_box/info/graphql/queries/get_linked_pipelines.query.graphql';
 import getPipelineStagesQuery from '~/projects/commit_box/info/graphql/queries/get_pipeline_stages.query.graphql';
@@ -38,7 +37,9 @@ describe('Commit box pipeline mini graph', () => {
   const stagesHandler = jest.fn().mockResolvedValue(mockPipelineStagesQueryResponse);
 
   const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
-  const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
+  const findMiniGraph = () => wrapper.findByTestId('commit-box-mini-graph');
+  const findUpstream = () => wrapper.findByTestId('commit-box-mini-graph-upstream');
+  const findDownstream = () => wrapper.findByTestId('commit-box-mini-graph-downstream');
 
   const advanceToNextFetch = () => {
     jest.advanceTimersByTime(COMMIT_BOX_POLL_INTERVAL);
@@ -79,25 +80,18 @@ describe('Commit box pipeline mini graph', () => {
       createComponent();
 
       expect(findLoadingIcon().exists()).toBe(true);
-      expect(findPipelineMiniGraph().exists()).toBe(false);
+      expect(findMiniGraph().exists()).toBe(false);
     });
   });
 
   describe('loaded state', () => {
-    const samplePipeline = {
-      id: expect.any(String),
-      path: expect.any(String),
-      project: expect.any(Object),
-      detailedStatus: expect.any(Object),
-    };
-
     it('should not display loading state after the query is resolved', async () => {
       createComponent();
 
       await waitForPromises();
 
       expect(findLoadingIcon().exists()).toBe(false);
-      expect(findPipelineMiniGraph().exists()).toBe(true);
+      expect(findMiniGraph().exists()).toBe(true);
     });
 
     it('should pass the pipeline path prop for the counter badge', async () => {
@@ -106,45 +100,24 @@ describe('Commit box pipeline mini graph', () => {
       await waitForPromises();
 
       const expectedPath = mockDownstreamQueryResponse.data.project.pipeline.path;
-      const pipelinePath = findPipelineMiniGraph().props('pipelinePath');
-
-      expect(pipelinePath).toBe(expectedPath);
-    });
-
-    it('should render a downstream pipeline only', async () => {
-      createComponent(downstreamHandler);
-
-      await waitForPromises();
-
-      const downstreamPipelines = findPipelineMiniGraph().props('downstreamPipelines');
-      const upstreamPipeline = findPipelineMiniGraph().props('upstreamPipeline');
-
-      expect(downstreamPipelines).toEqual(expect.any(Array));
-      expect(upstreamPipeline).toEqual(null);
-    });
-
-    it('should render an upstream pipeline only', async () => {
-      createComponent(upstreamHandler);
-
-      await waitForPromises();
 
-      const downstreamPipelines = findPipelineMiniGraph().props('downstreamPipelines');
-      const upstreamPipeline = findPipelineMiniGraph().props('upstreamPipeline');
-
-      expect(upstreamPipeline).toEqual(samplePipeline);
-      expect(downstreamPipelines).toHaveLength(0);
+      expect(findDownstream().props('pipelinePath')).toBe(expectedPath);
     });
 
-    it('should render downstream and upstream pipelines', async () => {
-      createComponent(upstreamDownstreamHandler);
-
-      await waitForPromises();
+    describe.each`
+      handler                      | downstreamRenders | upstreamRenders
+      ${downstreamHandler}         | ${true}           | ${false}
+      ${upstreamHandler}           | ${false}          | ${true}
+      ${upstreamDownstreamHandler} | ${true}           | ${true}
+    `('given a linked pipeline', ({ handler, downstreamRenders, upstreamRenders }) => {
+      it('should render the correct linked pipelines', async () => {
+        createComponent(handler);
 
-      const downstreamPipelines = findPipelineMiniGraph().props('downstreamPipelines');
-      const upstreamPipeline = findPipelineMiniGraph().props('upstreamPipeline');
+        await waitForPromises();
 
-      expect(upstreamPipeline).toEqual(samplePipeline);
-      expect(downstreamPipelines).toEqual(expect.arrayContaining([samplePipeline]));
+        expect(findDownstream().exists()).toBe(downstreamRenders);
+        expect(findUpstream().exists()).toBe(upstreamRenders);
+      });
     });
 
     it('formatted stages should be passed to the pipeline mini graph', async () => {
@@ -166,7 +139,7 @@ describe('Commit box pipeline mini graph', () => {
 
       await waitForPromises();
 
-      expect(findPipelineMiniGraph().props('stages')).toEqual(expectedStages);
+      expect(findMiniGraph().props('stages')).toEqual(expectedStages);
     });
   });
 
diff --git a/ee/spec/frontend/pipeline_editor/components/header/pipeline_editor_mini_graph_spec.js b/ee/spec/frontend/pipeline_editor/components/header/pipeline_editor_mini_graph_spec.js
index c6700a74e34fa164c76527de9ad4ac3d493aab5f..cd4910e77411ebea0bb74b1f9931e0475bf12b13 100644
--- a/ee/spec/frontend/pipeline_editor/components/header/pipeline_editor_mini_graph_spec.js
+++ b/ee/spec/frontend/pipeline_editor/components/header/pipeline_editor_mini_graph_spec.js
@@ -1,9 +1,9 @@
 import { shallowMount } from '@vue/test-utils';
 import Vue from 'vue';
 import VueApollo from 'vue-apollo';
+import waitForPromises from 'helpers/wait_for_promises';
 import createMockApollo from 'helpers/mock_apollo_helper';
 import PipelineEditorMiniGraph from '~/pipeline_editor/components/header/pipeline_editor_mini_graph.vue';
-import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
 import getLinkedPipelinesQuery from '~/projects/commit_box/info/graphql/queries/get_linked_pipelines.query.graphql';
 import { mockLinkedPipelines, mockProjectFullPath, mockProjectPipeline } from '../../mock_data';
 
@@ -39,7 +39,9 @@ describe('Pipeline Status', () => {
     });
   };
 
-  const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
+  const findUpstream = () => wrapper.find('[data-testid="pipeline-editor-mini-graph-upstream"]');
+  const findDownstream = () =>
+    wrapper.find('[data-testid="pipeline-editor-mini-graph-downstream"]');
 
   beforeEach(() => {
     mockLinkedPipelinesQuery = jest.fn();
@@ -50,31 +52,33 @@ describe('Pipeline Status', () => {
     wrapper.destroy();
   });
 
-  describe('when querying pipeline stages', () => {
-    describe('when query returns data', () => {
+  describe('when querying upstream and downstream pipelines', () => {
+    describe('when query succeeds', () => {
       beforeEach(() => {
         mockLinkedPipelinesQuery.mockResolvedValue(mockLinkedPipelines());
         createComponentWithApollo();
       });
 
-      describe('pipeline mini graph rendering based on given data', () => {
-        it('renders pipeline mini graph', () => {
-          expect(findPipelineMiniGraph().exists()).toBe(true);
-        });
-      });
-    });
-
-    describe('when query returns no data', () => {
-      beforeEach(() => {
-        mockLinkedPipelinesQuery.mockResolvedValue(mockLinkedPipelines());
-        const hasStages = false;
-        createComponentWithApollo(hasStages);
-      });
+      describe('linked pipeline rendering based on given data', () => {
+        it.each`
+          hasDownstream | hasUpstream | downstreamRenderAction | upstreamRenderAction
+          ${true}       | ${true}     | ${'renders'}           | ${'renders'}
+          ${true}       | ${false}    | ${'renders'}           | ${'hides'}
+          ${false}      | ${true}     | ${'hides'}             | ${'renders'}
+          ${false}      | ${false}    | ${'hides'}             | ${'hides'}
+        `(
+          '$downstreamRenderAction downstream and $upstreamRenderAction upstream',
+          async ({ hasDownstream, hasUpstream }) => {
+            mockLinkedPipelinesQuery.mockResolvedValue(
+              mockLinkedPipelines({ hasDownstream, hasUpstream }),
+            );
+            createComponentWithApollo();
+            await waitForPromises();
 
-      describe('pipeline mini graph rendering based on given data', () => {
-        it('does not render pipeline mini graph', () => {
-          expect(findPipelineMiniGraph().exists()).toBe(false);
-        });
+            expect(findUpstream().exists()).toBe(hasUpstream);
+            expect(findDownstream().exists()).toBe(hasDownstream);
+          },
+        );
       });
     });
   });
diff --git a/ee/spec/frontend/pipelines/pipelines_table_spec.js b/ee/spec/frontend/pipelines/pipelines_table_spec.js
index b17ab954c568be52bbda044c91f0ce8f7ab6cc5a..5ce7f28dee1939be8e255ba0e6045f421c4d5562 100644
--- a/ee/spec/frontend/pipelines/pipelines_table_spec.js
+++ b/ee/spec/frontend/pipelines/pipelines_table_spec.js
@@ -2,7 +2,6 @@ import { mount } from '@vue/test-utils';
 import fixture from 'test_fixtures/pipelines/pipelines.json';
 import { extendedWrapper } from 'helpers/vue_test_utils_helper';
 import PipelinesTable from '~/pipelines/components/pipelines_list/pipelines_table.vue';
-import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
 import { PipelineKeyOptions } from '~/pipelines/constants';
 
 import { triggeredBy, triggered } from './mock_data';
@@ -36,7 +35,8 @@ describe('Pipelines Table', () => {
     );
   };
 
-  const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
+  const findUpstream = () => wrapper.findByTestId('mini-graph-upstream');
+  const findDownstream = () => wrapper.findByTestId('mini-graph-downstream');
 
   beforeEach(() => {
     pipeline = createMockPipeline();
@@ -47,19 +47,6 @@ describe('Pipelines Table', () => {
   });
 
   describe('Pipelines Table', () => {
-    describe('pipeline mini graph', () => {
-      beforeEach(() => {
-        pipeline = createMockPipeline();
-        pipeline.triggered_by = triggeredBy;
-
-        createComponent({ pipelines: [pipeline] });
-      });
-
-      it('should render a pipeline mini graph', () => {
-        expect(findPipelineMiniGraph().exists()).toBe(true);
-      });
-    });
-
     describe('upstream linked pipelines', () => {
       beforeEach(() => {
         pipeline = createMockPipeline();
@@ -69,17 +56,16 @@ describe('Pipelines Table', () => {
       });
 
       it('should render only a upstream pipeline', () => {
-        const upstreamPipeline = findPipelineMiniGraph().props('upstreamPipeline');
-        const downstreamPipelines = findPipelineMiniGraph().props('downstreamPipelines');
-
-        expect(upstreamPipeline).toEqual(expect.any(Object));
-        expect(downstreamPipelines).toHaveLength(0);
+        expect(findUpstream().exists()).toBe(true);
+        expect(findDownstream().exists()).toBe(false);
       });
 
-      it('should pass an object of the correct data to the linked pipeline component', () => {
-        const upstreamPipeline = findPipelineMiniGraph().props('upstreamPipeline');
+      it('should pass an array of the correct data to the linked pipeline component', () => {
+        const triggeredByProps = findUpstream().props('triggeredBy');
 
-        expect(upstreamPipeline).toBe(triggeredBy);
+        expect(triggeredByProps).toEqual(expect.any(Array));
+        expect(triggeredByProps).toHaveLength(1);
+        expect(triggeredByProps[0]).toBe(triggeredBy);
       });
     });
 
@@ -92,22 +78,12 @@ describe('Pipelines Table', () => {
       });
 
       it('should pass the pipeline path prop for the counter badge', () => {
-        const pipelinePath = findPipelineMiniGraph().props('pipelinePath');
-        expect(pipelinePath).toBe(pipeline.path);
+        expect(findDownstream().props('pipelinePath')).toBe(pipeline.path);
       });
 
       it('should render only a downstream pipeline', () => {
-        const upstreamPipeline = findPipelineMiniGraph().props('upstreamPipeline');
-        const downstreamPipelines = findPipelineMiniGraph().props('downstreamPipelines');
-
-        expect(downstreamPipelines).toEqual(expect.any(Array));
-        expect(upstreamPipeline).toEqual(null);
-      });
-
-      it('should pass an array of the correct data to the linked pipeline component', () => {
-        const downstreamPipelines = findPipelineMiniGraph().props('downstreamPipelines');
-
-        expect(downstreamPipelines).toEqual(triggered);
+        expect(findDownstream().exists()).toBe(true);
+        expect(findUpstream().exists()).toBe(false);
       });
     });
 
@@ -121,11 +97,8 @@ describe('Pipelines Table', () => {
       });
 
       it('should render both downstream and upstream pipelines', () => {
-        const upstreamPipeline = findPipelineMiniGraph().props('upstreamPipeline');
-        const downstreamPipelines = findPipelineMiniGraph().props('downstreamPipelines');
-
-        expect(downstreamPipelines).toEqual(triggered);
-        expect(upstreamPipeline).toEqual(triggeredBy);
+        expect(findDownstream().exists()).toBe(true);
+        expect(findUpstream().exists()).toBe(true);
       });
     });
   });
diff --git a/ee/spec/frontend/vue_mr_widget/mr_widget_pipeline_spec.js b/ee/spec/frontend/vue_mr_widget/mr_widget_pipeline_spec.js
index 7b87df4d5cf3a55b7564e51f90697ecf44d9e5aa..8c35938fcb9c875363572cfa4ec64b53dbc6c925 100644
--- a/ee/spec/frontend/vue_mr_widget/mr_widget_pipeline_spec.js
+++ b/ee/spec/frontend/vue_mr_widget/mr_widget_pipeline_spec.js
@@ -1,14 +1,14 @@
 import { shallowMount } from '@vue/test-utils';
+import LinkedPipelinesMiniList from 'ee/vue_shared/components/linked_pipelines_mini_list.vue';
 import mockData from 'ee_jest/vue_mr_widget/mock_data';
 import MrWidgetPipeline from '~/vue_merge_request_widget/components/mr_widget_pipeline.vue';
-import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
 import mockLinkedPipelines from '../vue_shared/components/linked_pipelines_mock_data';
 
 describe('MRWidgetPipeline', () => {
   let wrapper;
 
   const findPipelineInfoContainer = () => wrapper.find('[data-testid="pipeline-info-container"');
-  const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
+  const findPipelinesMiniList = () => wrapper.findComponent(LinkedPipelinesMiniList);
 
   const createWrapper = (props) => {
     wrapper = shallowMount(MrWidgetPipeline, {
@@ -75,14 +75,20 @@ describe('MRWidgetPipeline', () => {
         createWrapper({ pipeline });
       });
 
-      it('should render the pipeline mini graph', () => {
-        expect(findPipelineMiniGraph().exists()).toBe(true);
+      it('should render the linked pipelines mini list', () => {
+        expect(findPipelinesMiniList().exists()).toBe(true);
       });
 
-      it('should send upstream pipeline', () => {
-        const upstreamPipeline = findPipelineMiniGraph().props('upstreamPipeline');
+      it('should render the linked pipelines mini list as an upstream list', () => {
+        expect(findPipelinesMiniList().classes('is-upstream')).toBe(true);
+      });
+
+      it('should add a single triggeredBy into an array', () => {
+        const triggeredBy = findPipelinesMiniList().props('triggeredBy');
 
-        expect(upstreamPipeline).toBe(mockLinkedPipelines.triggered_by);
+        expect(triggeredBy).toEqual(expect.any(Array));
+        expect(triggeredBy).toHaveLength(1);
+        expect(triggeredBy[0]).toBe(mockLinkedPipelines.triggered_by);
       });
     });
 
@@ -93,14 +99,18 @@ describe('MRWidgetPipeline', () => {
         createWrapper({ pipeline });
       });
 
-      it('should render the pipeline mini graph', () => {
-        expect(findPipelineMiniGraph().exists()).toBe(true);
+      it('should render the linked pipelines mini list', () => {
+        expect(findPipelinesMiniList().exists()).toBe(true);
       });
 
       it('should render the linked pipelines mini list as a downstream list', () => {
-        const downstreamPipelines = findPipelineMiniGraph().props('downstreamPipelines');
+        expect(findPipelinesMiniList().classes('is-downstream')).toBe(true);
+      });
+
+      it('should pass the triggered pipelines', () => {
+        const triggered = findPipelinesMiniList().props('triggered');
 
-        expect(downstreamPipelines).toBe(mockLinkedPipelines.triggered);
+        expect(triggered).toBe(mockLinkedPipelines.triggered);
       });
     });
   });
diff --git a/ee/spec/frontend/vue_shared/components/linked_pipelines_mini_list_spec.js b/ee/spec/frontend/vue_shared/components/linked_pipelines_mini_list_spec.js
index 8896faf5c34b28c5340da867cd378949d47262e4..3cebe451ceb5224a281742cd2a5c88bfe897b920 100644
--- a/ee/spec/frontend/vue_shared/components/linked_pipelines_mini_list_spec.js
+++ b/ee/spec/frontend/vue_shared/components/linked_pipelines_mini_list_spec.js
@@ -7,6 +7,7 @@ import mockData from './linked_pipelines_mock_data';
 describe('Linked pipeline mini list', () => {
   let wrapper;
 
+  const findArrowIcon = () => wrapper.find('[data-testid="long-arrow-icon"]');
   const findCiIcon = () => wrapper.findComponent(CiIcon);
   const findCiIcons = () => wrapper.findAllComponents(CiIcon);
   const findLinkedPipelineCounter = () => wrapper.find('[data-testid="linked-pipeline-counter"]');
@@ -72,6 +73,13 @@ describe('Linked pipeline mini list', () => {
       expect(findCiIcon().classes('ci-status-icon-running')).toBe(true);
     });
 
+    it('should render an arrow icon', () => {
+      expect(findArrowIcon().exists()).toBe(true);
+
+      expect(findArrowIcon().props('name')).toBe('long-arrow');
+      expect(findArrowIcon().classes('arrow-icon')).toBe(true);
+    });
+
     it('should have an activated tooltip', () => {
       expect(findLinkedPipelineMiniItem().exists()).toBe(true);
       const tooltip = getBinding(findLinkedPipelineMiniItem().element, 'gl-tooltip');
@@ -121,6 +129,13 @@ describe('Linked pipeline mini list', () => {
       expect(findCiIcon().classes('ci-status-icon-running')).toBe(true);
     });
 
+    it('should render an arrow icon', () => {
+      expect(findArrowIcon().exists()).toBe(true);
+
+      expect(findArrowIcon().props('name')).toBe('long-arrow');
+      expect(findArrowIcon().classes('arrow-icon')).toBe(true);
+    });
+
     it('should have an activated tooltip', () => {
       expect(findLinkedPipelineMiniItem().exists()).toBe(true);
       const tooltip = getBinding(findLinkedPipelineMiniItem().element, 'gl-tooltip');
diff --git a/spec/features/projects/commit/mini_pipeline_graph_spec.rb b/spec/features/projects/commit/mini_pipeline_graph_spec.rb
index 4740f6e19fe57248dab609c1367ba85fc58b055e..e472cff38cefb34918d88b1793d1ca2995b9626f 100644
--- a/spec/features/projects/commit/mini_pipeline_graph_spec.rb
+++ b/spec/features/projects/commit/mini_pipeline_graph_spec.rb
@@ -27,7 +27,7 @@
     end
 
     it 'displays a mini pipeline graph' do
-      expect(page).to have_selector('[data-testid="commit-box-pipeline-mini-graph"]')
+      expect(page).to have_selector('[data-testid="commit-box-mini-graph"]')
 
       first('[data-testid="mini-pipeline-graph-dropdown"]').click
 
diff --git a/spec/frontend/commit/commit_box_pipeline_mini_graph_spec.js b/spec/frontend/commit/commit_box_pipeline_mini_graph_spec.js
index ab5055de5e3fd1c02d7f16f58501ee623bbbb0ff..b1c8ba48475f7358a18a6227f5e40e194d6993cd 100644
--- a/spec/frontend/commit/commit_box_pipeline_mini_graph_spec.js
+++ b/spec/frontend/commit/commit_box_pipeline_mini_graph_spec.js
@@ -6,7 +6,6 @@ import { extendedWrapper } from 'helpers/vue_test_utils_helper';
 import waitForPromises from 'helpers/wait_for_promises';
 import createFlash from '~/flash';
 import CommitBoxPipelineMiniGraph from '~/projects/commit_box/info/components/commit_box_pipeline_mini_graph.vue';
-import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
 import getLinkedPipelinesQuery from '~/projects/commit_box/info/graphql/queries/get_linked_pipelines.query.graphql';
 import getPipelineStagesQuery from '~/projects/commit_box/info/graphql/queries/get_pipeline_stages.query.graphql';
 import { mockPipelineStagesQueryResponse, mockStages } from './mock_data';
@@ -18,7 +17,9 @@ Vue.use(VueApollo);
 describe('Commit box pipeline mini graph', () => {
   let wrapper;
 
-  const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
+  const findMiniGraph = () => wrapper.findByTestId('commit-box-mini-graph');
+  const findUpstream = () => wrapper.findByTestId('commit-box-mini-graph-upstream');
+  const findDownstream = () => wrapper.findByTestId('commit-box-mini-graph-downstream');
 
   const stagesHandler = jest.fn().mockResolvedValue(mockPipelineStagesQueryResponse);
 
@@ -50,16 +51,13 @@ describe('Commit box pipeline mini graph', () => {
       await createComponent();
     });
 
-    it('should display the pipeline mini graph', () => {
-      expect(findPipelineMiniGraph().exists()).toBe(true);
+    it('should display the mini pipeine graph', () => {
+      expect(findMiniGraph().exists()).toBe(true);
     });
 
     it('should not display linked pipelines', () => {
-      const downstreamPipelines = findPipelineMiniGraph().props('downstreamPipelines');
-      const upstreamPipeline = findPipelineMiniGraph().props('upstreamPipeline');
-
-      expect(downstreamPipelines).toHaveLength(0);
-      expect(upstreamPipeline).toEqual(undefined);
+      expect(findUpstream().exists()).toBe(false);
+      expect(findDownstream().exists()).toBe(false);
     });
   });
 
diff --git a/spec/frontend/pipeline_editor/components/header/pipeline_editor_mini_graph_spec.js b/spec/frontend/pipeline_editor/components/header/pipeline_editor_mini_graph_spec.js
deleted file mode 100644
index 93eb18c90cf16b31852cc411200c14b01347c829..0000000000000000000000000000000000000000
--- a/spec/frontend/pipeline_editor/components/header/pipeline_editor_mini_graph_spec.js
+++ /dev/null
@@ -1,109 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import PipelineEditorMiniGraph from '~/pipeline_editor/components/header/pipeline_editor_mini_graph.vue';
-import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
-import getLinkedPipelinesQuery from '~/projects/commit_box/info/graphql/queries/get_linked_pipelines.query.graphql';
-import { PIPELINE_FAILURE } from '~/pipeline_editor/constants';
-import { mockLinkedPipelines, mockProjectFullPath, mockProjectPipeline } from '../../mock_data';
-
-Vue.use(VueApollo);
-
-describe('Pipeline Status', () => {
-  let wrapper;
-  let mockApollo;
-  let mockLinkedPipelinesQuery;
-
-  const createComponent = ({ hasStages = true, options } = {}) => {
-    wrapper = shallowMount(PipelineEditorMiniGraph, {
-      provide: {
-        dataMethod: 'graphql',
-        projectFullPath: mockProjectFullPath,
-      },
-      propsData: {
-        pipeline: mockProjectPipeline({ hasStages }).pipeline,
-      },
-      ...options,
-    });
-  };
-
-  const createComponentWithApollo = (hasStages = true) => {
-    const handlers = [[getLinkedPipelinesQuery, mockLinkedPipelinesQuery]];
-    mockApollo = createMockApollo(handlers);
-
-    createComponent({
-      hasStages,
-      options: {
-        apolloProvider: mockApollo,
-      },
-    });
-  };
-
-  const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
-
-  beforeEach(() => {
-    mockLinkedPipelinesQuery = jest.fn();
-  });
-
-  afterEach(() => {
-    mockLinkedPipelinesQuery.mockReset();
-    wrapper.destroy();
-  });
-
-  describe('when there are stages', () => {
-    beforeEach(() => {
-      createComponent();
-    });
-
-    it('renders pipeline mini graph', () => {
-      expect(findPipelineMiniGraph().exists()).toBe(true);
-    });
-  });
-
-  describe('when there are no stages', () => {
-    beforeEach(() => {
-      createComponent({ hasStages: false });
-    });
-
-    it('does not render pipeline mini graph', () => {
-      expect(findPipelineMiniGraph().exists()).toBe(false);
-    });
-  });
-
-  describe('when querying upstream and downstream pipelines', () => {
-    describe('when query succeeds', () => {
-      beforeEach(() => {
-        mockLinkedPipelinesQuery.mockResolvedValue(mockLinkedPipelines());
-        createComponentWithApollo();
-      });
-
-      it('should call the query with the correct variables', () => {
-        expect(mockLinkedPipelinesQuery).toHaveBeenCalledTimes(1);
-        expect(mockLinkedPipelinesQuery).toHaveBeenCalledWith({
-          fullPath: mockProjectFullPath,
-          iid: mockProjectPipeline().pipeline.iid,
-        });
-      });
-    });
-
-    describe('when query fails', () => {
-      beforeEach(async () => {
-        mockLinkedPipelinesQuery.mockRejectedValue(new Error());
-        createComponentWithApollo();
-        await waitForPromises();
-      });
-
-      it('should emit an error event when query fails', async () => {
-        expect(wrapper.emitted('showError')).toHaveLength(1);
-        expect(wrapper.emitted('showError')[0]).toEqual([
-          {
-            type: PIPELINE_FAILURE,
-            reasons: [wrapper.vm.$options.i18n.linkedPipelinesFetchError],
-          },
-        ]);
-      });
-    });
-  });
-});
diff --git a/spec/frontend/pipelines/components/pipelines_list/pipeline_stages_spec.js b/spec/frontend/pipelines/components/pipelines_list/pipeline_mini_graph_spec.js
similarity index 92%
rename from spec/frontend/pipelines/components/pipelines_list/pipeline_stages_spec.js
rename to spec/frontend/pipelines/components/pipelines_list/pipeline_mini_graph_spec.js
index 1e31d8a62ffd997941a3d22efc96a66550b8b68e..1cb43c199aa5f70e461dc53ecef07dc4f462fbb0 100644
--- a/spec/frontend/pipelines/components/pipelines_list/pipeline_stages_spec.js
+++ b/spec/frontend/pipelines/components/pipelines_list/pipeline_mini_graph_spec.js
@@ -1,18 +1,18 @@
 import { shallowMount } from '@vue/test-utils';
 import { pipelines } from 'test_fixtures/pipelines/pipelines.json';
+import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
 import PipelineStage from '~/pipelines/components/pipelines_list/pipeline_stage.vue';
-import PipelineStages from '~/pipelines/components/pipelines_list/pipeline_stages.vue';
 
 const mockStages = pipelines[0].details.stages;
 
-describe('Pipeline Stages', () => {
+describe('Pipeline Mini Graph', () => {
   let wrapper;
 
   const findPipelineStages = () => wrapper.findAll(PipelineStage);
   const findPipelineStagesAt = (i) => findPipelineStages().at(i);
 
   const createComponent = (props = {}) => {
-    wrapper = shallowMount(PipelineStages, {
+    wrapper = shallowMount(PipelineMiniGraph, {
       propsData: {
         stages: mockStages,
         ...props,
diff --git a/spec/frontend/pipelines/linked_pipelines_mock_data.js b/spec/frontend/pipelines/linked_pipelines_mock_data.js
deleted file mode 100644
index 117c7f2ae529fc75849d75e27361e40ac9f3a712..0000000000000000000000000000000000000000
--- a/spec/frontend/pipelines/linked_pipelines_mock_data.js
+++ /dev/null
@@ -1,407 +0,0 @@
-export default {
-  triggered_by: {
-    id: 129,
-    active: true,
-    path: '/gitlab-org/gitlab-foss/-/pipelines/129',
-    project: {
-      name: 'GitLabCE',
-    },
-    details: {
-      status: {
-        icon: 'status_running',
-        text: 'running',
-        label: 'running',
-        group: 'running',
-        has_details: true,
-        details_path: '/gitlab-org/gitlab-foss/-/pipelines/129',
-        favicon:
-          '/assets/ci_favicons/dev/favicon_status_running-c3ad2fc53ea6079c174e5b6c1351ff349e99ec3af5a5622fb77b0fe53ea279c1.ico',
-      },
-    },
-    flags: {
-      latest: false,
-      triggered: false,
-      stuck: false,
-      yaml_errors: false,
-      retryable: true,
-      cancelable: true,
-    },
-    ref: {
-      name: '7-5-stable',
-      path: '/gitlab-org/gitlab-foss/commits/7-5-stable',
-      tag: false,
-      branch: true,
-    },
-    commit: {
-      id: '23433d4d8b20d7e45c103d0b6048faad38a130ab',
-      short_id: '23433d4d',
-      title: 'Version 7.5.0.rc1',
-      created_at: '2014-11-17T15:44:14.000+01:00',
-      parent_ids: ['30ac909f30f58d319b42ed1537664483894b18cd'],
-      message: 'Version 7.5.0.rc1\n',
-      author_name: 'Jacob Vosmaer',
-      author_email: 'contact@jacobvosmaer.nl',
-      authored_date: '2014-11-17T15:44:14.000+01:00',
-      committer_name: 'Jacob Vosmaer',
-      committer_email: 'contact@jacobvosmaer.nl',
-      committed_date: '2014-11-17T15:44:14.000+01:00',
-      author_gravatar_url:
-        'http://www.gravatar.com/avatar/e66d11c0eedf8c07b3b18fca46599807?s=80&d=identicon',
-      commit_url:
-        'http://localhost:3000/gitlab-org/gitlab-foss/commit/23433d4d8b20d7e45c103d0b6048faad38a130ab',
-      commit_path: '/gitlab-org/gitlab-foss/commit/23433d4d8b20d7e45c103d0b6048faad38a130ab',
-    },
-    retry_path: '/gitlab-org/gitlab-foss/-/pipelines/129/retry',
-    cancel_path: '/gitlab-org/gitlab-foss/-/pipelines/129/cancel',
-    created_at: '2017-05-24T14:46:20.090Z',
-    updated_at: '2017-05-24T14:46:29.906Z',
-  },
-  triggered: [
-    {
-      id: 132,
-      active: true,
-      path: '/gitlab-org/gitlab-foss/-/pipelines/132',
-      project: {
-        name: 'GitLabCE',
-      },
-      details: {
-        status: {
-          icon: 'status_running',
-          text: 'running',
-          label: 'running',
-          group: 'running',
-          has_details: true,
-          details_path: '/gitlab-org/gitlab-foss/-/pipelines/132',
-          favicon:
-            '/assets/ci_favicons/dev/favicon_status_running-c3ad2fc53ea6079c174e5b6c1351ff349e99ec3af5a5622fb77b0fe53ea279c1.ico',
-        },
-      },
-      flags: {
-        latest: false,
-        triggered: false,
-        stuck: false,
-        yaml_errors: false,
-        retryable: true,
-        cancelable: true,
-      },
-      ref: {
-        name: 'crowd',
-        path: '/gitlab-org/gitlab-foss/commits/crowd',
-        tag: false,
-        branch: true,
-      },
-      commit: {
-        id: 'b9d58c4cecd06be74c3cc32ccfb522b31544ab2e',
-        short_id: 'b9d58c4c',
-        title: 'getting user keys publically through http without any authentication, the github…',
-        created_at: '2013-10-03T12:50:33.000+05:30',
-        parent_ids: ['e219cf7246c6a0495e4507deaffeba11e79f13b8'],
-        message:
-          'getting user keys publically through http without any authentication, the github way. E.g: http://github.com/devaroop.keys\n\nchangelog updated to include ssh key retrieval feature update\n',
-        author_name: 'devaroop',
-        author_email: 'devaroop123@yahoo.co.in',
-        authored_date: '2013-10-02T20:39:29.000+05:30',
-        committer_name: 'devaroop',
-        committer_email: 'devaroop123@yahoo.co.in',
-        committed_date: '2013-10-03T12:50:33.000+05:30',
-        author_gravatar_url:
-          'http://www.gravatar.com/avatar/35df4b155ec66a3127d53459941cf8a2?s=80&d=identicon',
-        commit_url:
-          'http://localhost:3000/gitlab-org/gitlab-foss/commit/b9d58c4cecd06be74c3cc32ccfb522b31544ab2e',
-        commit_path: '/gitlab-org/gitlab-foss/commit/b9d58c4cecd06be74c3cc32ccfb522b31544ab2e',
-      },
-      retry_path: '/gitlab-org/gitlab-foss/-/pipelines/132/retry',
-      cancel_path: '/gitlab-org/gitlab-foss/-/pipelines/132/cancel',
-      created_at: '2017-05-24T14:46:24.644Z',
-      updated_at: '2017-05-24T14:48:55.226Z',
-    },
-    {
-      id: 133,
-      active: true,
-      path: '/gitlab-org/gitlab-foss/-/pipelines/133',
-      project: {
-        name: 'GitLabCE',
-      },
-      details: {
-        status: {
-          icon: 'status_running',
-          text: 'running',
-          label: 'running',
-          group: 'running',
-          has_details: true,
-          details_path: '/gitlab-org/gitlab-foss/-/pipelines/133',
-          favicon:
-            '/assets/ci_favicons/dev/favicon_status_running-c3ad2fc53ea6079c174e5b6c1351ff349e99ec3af5a5622fb77b0fe53ea279c1.ico',
-        },
-      },
-      flags: {
-        latest: false,
-        triggered: false,
-        stuck: false,
-        yaml_errors: false,
-        retryable: true,
-        cancelable: true,
-      },
-      ref: {
-        name: 'crowd',
-        path: '/gitlab-org/gitlab-foss/commits/crowd',
-        tag: false,
-        branch: true,
-      },
-      commit: {
-        id: 'b6bd4856a33df3d144be66c4ed1f1396009bb08b',
-        short_id: 'b6bd4856',
-        title: 'getting user keys publically through http without any authentication, the github…',
-        created_at: '2013-10-02T20:39:29.000+05:30',
-        parent_ids: ['e219cf7246c6a0495e4507deaffeba11e79f13b8'],
-        message:
-          'getting user keys publically through http without any authentication, the github way. E.g: http://github.com/devaroop.keys\n',
-        author_name: 'devaroop',
-        author_email: 'devaroop123@yahoo.co.in',
-        authored_date: '2013-10-02T20:39:29.000+05:30',
-        committer_name: 'devaroop',
-        committer_email: 'devaroop123@yahoo.co.in',
-        committed_date: '2013-10-02T20:39:29.000+05:30',
-        author_gravatar_url:
-          'http://www.gravatar.com/avatar/35df4b155ec66a3127d53459941cf8a2?s=80&d=identicon',
-        commit_url:
-          'http://localhost:3000/gitlab-org/gitlab-foss/commit/b6bd4856a33df3d144be66c4ed1f1396009bb08b',
-        commit_path: '/gitlab-org/gitlab-foss/commit/b6bd4856a33df3d144be66c4ed1f1396009bb08b',
-      },
-      retry_path: '/gitlab-org/gitlab-foss/-/pipelines/133/retry',
-      cancel_path: '/gitlab-org/gitlab-foss/-/pipelines/133/cancel',
-      created_at: '2017-05-24T14:46:24.648Z',
-      updated_at: '2017-05-24T14:48:59.673Z',
-    },
-    {
-      id: 130,
-      active: true,
-      path: '/gitlab-org/gitlab-foss/-/pipelines/130',
-      project: {
-        name: 'GitLabCE',
-      },
-      details: {
-        status: {
-          icon: 'status_running',
-          text: 'running',
-          label: 'running',
-          group: 'running',
-          has_details: true,
-          details_path: '/gitlab-org/gitlab-foss/-/pipelines/130',
-          favicon:
-            '/assets/ci_favicons/dev/favicon_status_running-c3ad2fc53ea6079c174e5b6c1351ff349e99ec3af5a5622fb77b0fe53ea279c1.ico',
-        },
-      },
-      flags: {
-        latest: false,
-        triggered: false,
-        stuck: false,
-        yaml_errors: false,
-        retryable: true,
-        cancelable: true,
-      },
-      ref: {
-        name: 'crowd',
-        path: '/gitlab-org/gitlab-foss/commits/crowd',
-        tag: false,
-        branch: true,
-      },
-      commit: {
-        id: '6d7ced4a2311eeff037c5575cca1868a6d3f586f',
-        short_id: '6d7ced4a',
-        title: 'Whitespace fixes to patch',
-        created_at: '2013-10-08T13:53:22.000-05:00',
-        parent_ids: ['1875141a963a4238bda29011d8f7105839485253'],
-        message: 'Whitespace fixes to patch\n',
-        author_name: 'Dale Hamel',
-        author_email: 'dale.hamel@srvthe.net',
-        authored_date: '2013-10-08T13:53:22.000-05:00',
-        committer_name: 'Dale Hamel',
-        committer_email: 'dale.hamel@invenia.ca',
-        committed_date: '2013-10-08T13:53:22.000-05:00',
-        author_gravatar_url:
-          'http://www.gravatar.com/avatar/cd08930e69fa5ad1a669206e7bafe476?s=80&d=identicon',
-        commit_url:
-          'http://localhost:3000/gitlab-org/gitlab-foss/commit/6d7ced4a2311eeff037c5575cca1868a6d3f586f',
-        commit_path: '/gitlab-org/gitlab-foss/commit/6d7ced4a2311eeff037c5575cca1868a6d3f586f',
-      },
-      retry_path: '/gitlab-org/gitlab-foss/-/pipelines/130/retry',
-      cancel_path: '/gitlab-org/gitlab-foss/-/pipelines/130/cancel',
-      created_at: '2017-05-24T14:46:24.630Z',
-      updated_at: '2017-05-24T14:49:45.091Z',
-    },
-    {
-      id: 131,
-      active: true,
-      path: '/gitlab-org/gitlab-foss/-/pipelines/132',
-      project: {
-        name: 'GitLabCE',
-      },
-      details: {
-        status: {
-          icon: 'status_running',
-          text: 'running',
-          label: 'running',
-          group: 'running',
-          has_details: true,
-          details_path: '/gitlab-org/gitlab-foss/-/pipelines/132',
-          favicon:
-            '/assets/ci_favicons/dev/favicon_status_running-c3ad2fc53ea6079c174e5b6c1351ff349e99ec3af5a5622fb77b0fe53ea279c1.ico',
-        },
-      },
-      flags: {
-        latest: false,
-        triggered: false,
-        stuck: false,
-        yaml_errors: false,
-        retryable: true,
-        cancelable: true,
-      },
-      ref: {
-        name: 'crowd',
-        path: '/gitlab-org/gitlab-foss/commits/crowd',
-        tag: false,
-        branch: true,
-      },
-      commit: {
-        id: 'b9d58c4cecd06be74c3cc32ccfb522b31544ab2e',
-        short_id: 'b9d58c4c',
-        title: 'getting user keys publically through http without any authentication, the github…',
-        created_at: '2013-10-03T12:50:33.000+05:30',
-        parent_ids: ['e219cf7246c6a0495e4507deaffeba11e79f13b8'],
-        message:
-          'getting user keys publically through http without any authentication, the github way. E.g: http://github.com/devaroop.keys\n\nchangelog updated to include ssh key retrieval feature update\n',
-        author_name: 'devaroop',
-        author_email: 'devaroop123@yahoo.co.in',
-        authored_date: '2013-10-02T20:39:29.000+05:30',
-        committer_name: 'devaroop',
-        committer_email: 'devaroop123@yahoo.co.in',
-        committed_date: '2013-10-03T12:50:33.000+05:30',
-        author_gravatar_url:
-          'http://www.gravatar.com/avatar/35df4b155ec66a3127d53459941cf8a2?s=80&d=identicon',
-        commit_url:
-          'http://localhost:3000/gitlab-org/gitlab-foss/commit/b9d58c4cecd06be74c3cc32ccfb522b31544ab2e',
-        commit_path: '/gitlab-org/gitlab-foss/commit/b9d58c4cecd06be74c3cc32ccfb522b31544ab2e',
-      },
-      retry_path: '/gitlab-org/gitlab-foss/-/pipelines/132/retry',
-      cancel_path: '/gitlab-org/gitlab-foss/-/pipelines/132/cancel',
-      created_at: '2017-05-24T14:46:24.644Z',
-      updated_at: '2017-05-24T14:48:55.226Z',
-    },
-    {
-      id: 134,
-      active: true,
-      path: '/gitlab-org/gitlab-foss/-/pipelines/133',
-      project: {
-        name: 'GitLabCE',
-      },
-      details: {
-        status: {
-          icon: 'status_running',
-          text: 'running',
-          label: 'running',
-          group: 'running',
-          has_details: true,
-          details_path: '/gitlab-org/gitlab-foss/-/pipelines/133',
-          favicon:
-            '/assets/ci_favicons/dev/favicon_status_running-c3ad2fc53ea6079c174e5b6c1351ff349e99ec3af5a5622fb77b0fe53ea279c1.ico',
-        },
-      },
-      flags: {
-        latest: false,
-        triggered: false,
-        stuck: false,
-        yaml_errors: false,
-        retryable: true,
-        cancelable: true,
-      },
-      ref: {
-        name: 'crowd',
-        path: '/gitlab-org/gitlab-foss/commits/crowd',
-        tag: false,
-        branch: true,
-      },
-      commit: {
-        id: 'b6bd4856a33df3d144be66c4ed1f1396009bb08b',
-        short_id: 'b6bd4856',
-        title: 'getting user keys publically through http without any authentication, the github…',
-        created_at: '2013-10-02T20:39:29.000+05:30',
-        parent_ids: ['e219cf7246c6a0495e4507deaffeba11e79f13b8'],
-        message:
-          'getting user keys publically through http without any authentication, the github way. E.g: http://github.com/devaroop.keys\n',
-        author_name: 'devaroop',
-        author_email: 'devaroop123@yahoo.co.in',
-        authored_date: '2013-10-02T20:39:29.000+05:30',
-        committer_name: 'devaroop',
-        committer_email: 'devaroop123@yahoo.co.in',
-        committed_date: '2013-10-02T20:39:29.000+05:30',
-        author_gravatar_url:
-          'http://www.gravatar.com/avatar/35df4b155ec66a3127d53459941cf8a2?s=80&d=identicon',
-        commit_url:
-          'http://localhost:3000/gitlab-org/gitlab-foss/commit/b6bd4856a33df3d144be66c4ed1f1396009bb08b',
-        commit_path: '/gitlab-org/gitlab-foss/commit/b6bd4856a33df3d144be66c4ed1f1396009bb08b',
-      },
-      retry_path: '/gitlab-org/gitlab-foss/-/pipelines/133/retry',
-      cancel_path: '/gitlab-org/gitlab-foss/-/pipelines/133/cancel',
-      created_at: '2017-05-24T14:46:24.648Z',
-      updated_at: '2017-05-24T14:48:59.673Z',
-    },
-    {
-      id: 135,
-      active: true,
-      path: '/gitlab-org/gitlab-foss/-/pipelines/130',
-      project: {
-        name: 'GitLabCE',
-      },
-      details: {
-        status: {
-          icon: 'status_running',
-          text: 'running',
-          label: 'running',
-          group: 'running',
-          has_details: true,
-          details_path: '/gitlab-org/gitlab-foss/-/pipelines/130',
-          favicon:
-            '/assets/ci_favicons/dev/favicon_status_running-c3ad2fc53ea6079c174e5b6c1351ff349e99ec3af5a5622fb77b0fe53ea279c1.ico',
-        },
-      },
-      flags: {
-        latest: false,
-        triggered: false,
-        stuck: false,
-        yaml_errors: false,
-        retryable: true,
-        cancelable: true,
-      },
-      ref: {
-        name: 'crowd',
-        path: '/gitlab-org/gitlab-foss/commits/crowd',
-        tag: false,
-        branch: true,
-      },
-      commit: {
-        id: '6d7ced4a2311eeff037c5575cca1868a6d3f586f',
-        short_id: '6d7ced4a',
-        title: 'Whitespace fixes to patch',
-        created_at: '2013-10-08T13:53:22.000-05:00',
-        parent_ids: ['1875141a963a4238bda29011d8f7105839485253'],
-        message: 'Whitespace fixes to patch\n',
-        author_name: 'Dale Hamel',
-        author_email: 'dale.hamel@srvthe.net',
-        authored_date: '2013-10-08T13:53:22.000-05:00',
-        committer_name: 'Dale Hamel',
-        committer_email: 'dale.hamel@invenia.ca',
-        committed_date: '2013-10-08T13:53:22.000-05:00',
-        author_gravatar_url:
-          'http://www.gravatar.com/avatar/cd08930e69fa5ad1a669206e7bafe476?s=80&d=identicon',
-        commit_url:
-          'http://localhost:3000/gitlab-org/gitlab-foss/commit/6d7ced4a2311eeff037c5575cca1868a6d3f586f',
-        commit_path: '/gitlab-org/gitlab-foss/commit/6d7ced4a2311eeff037c5575cca1868a6d3f586f',
-      },
-      retry_path: '/gitlab-org/gitlab-foss/-/pipelines/130/retry',
-      cancel_path: '/gitlab-org/gitlab-foss/-/pipelines/130/cancel',
-      created_at: '2017-05-24T14:46:24.630Z',
-      updated_at: '2017-05-24T14:49:45.091Z',
-    },
-  ],
-};
diff --git a/spec/frontend/pipelines/pipeline_mini_graph_spec.js b/spec/frontend/pipelines/pipeline_mini_graph_spec.js
deleted file mode 100644
index 81aa97ce13fe3db1fee771e1fe52a141c7db2e23..0000000000000000000000000000000000000000
--- a/spec/frontend/pipelines/pipeline_mini_graph_spec.js
+++ /dev/null
@@ -1,149 +0,0 @@
-import { mount } from '@vue/test-utils';
-import { pipelines } from 'test_fixtures/pipelines/pipelines.json';
-import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
-import PipelineStages from '~/pipelines/components/pipelines_list/pipeline_stages.vue';
-import mockLinkedPipelines from './linked_pipelines_mock_data';
-
-const mockStages = pipelines[0].details.stages;
-
-describe('Pipeline Mini Graph', () => {
-  let wrapper;
-
-  const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
-  const findPipelineStages = () => wrapper.findComponent(PipelineStages);
-
-  const findLinkedPipelineUpstream = () =>
-    wrapper.findComponent('[data-testid="pipeline-mini-graph-upstream"]');
-  const findLinkedPipelineDownstream = () =>
-    wrapper.findComponent('[data-testid="pipeline-mini-graph-downstream"]');
-  const findDownstreamArrowIcon = () => wrapper.find('[data-testid="downstream-arrow-icon"]');
-  const findUpstreamArrowIcon = () => wrapper.find('[data-testid="upstream-arrow-icon"]');
-
-  const createComponent = (props = {}) => {
-    wrapper = mount(PipelineMiniGraph, {
-      propsData: {
-        stages: mockStages,
-        ...props,
-      },
-    });
-  };
-
-  describe('rendered state without upstream or downstream pipelines', () => {
-    beforeEach(() => {
-      createComponent();
-    });
-
-    afterEach(() => {
-      wrapper.destroy();
-      wrapper = null;
-    });
-
-    it('should render the pipeline stages', () => {
-      expect(findPipelineStages().exists()).toBe(true);
-    });
-
-    it('should have the correct props', () => {
-      expect(findPipelineMiniGraph().props()).toMatchObject({
-        downstreamPipelines: [],
-        isMergeTrain: false,
-        pipelinePath: '',
-        stages: expect.any(Array),
-        stagesClass: '',
-        updateDropdown: false,
-        upstreamPipeline: undefined,
-      });
-    });
-
-    it('should have no linked pipelines', () => {
-      expect(findLinkedPipelineDownstream().exists()).toBe(false);
-      expect(findLinkedPipelineUpstream().exists()).toBe(false);
-    });
-
-    it('should not render arrow icons', () => {
-      expect(findUpstreamArrowIcon().exists()).toBe(false);
-      expect(findDownstreamArrowIcon().exists()).toBe(false);
-    });
-
-    it('triggers events in "action request complete"', () => {
-      createComponent();
-
-      findPipelineMiniGraph(0).vm.$emit('pipelineActionRequestComplete');
-      findPipelineMiniGraph(1).vm.$emit('pipelineActionRequestComplete');
-
-      expect(wrapper.emitted('pipelineActionRequestComplete')).toHaveLength(2);
-    });
-  });
-
-  describe('rendered state with upstream pipeline', () => {
-    beforeEach(() => {
-      createComponent({
-        upstreamPipeline: mockLinkedPipelines.triggered_by,
-      });
-    });
-
-    afterEach(() => {
-      wrapper.destroy();
-      wrapper = null;
-    });
-
-    it('should have the correct props', () => {
-      expect(findPipelineMiniGraph().props()).toMatchObject({
-        downstreamPipelines: [],
-        isMergeTrain: false,
-        pipelinePath: '',
-        stages: expect.any(Array),
-        stagesClass: '',
-        updateDropdown: false,
-        upstreamPipeline: expect.any(Object),
-      });
-    });
-
-    it('should render the upstream linked pipelines mini list only', () => {
-      expect(findLinkedPipelineUpstream().exists()).toBe(true);
-      expect(findLinkedPipelineDownstream().exists()).toBe(false);
-    });
-
-    it('should render an upstream arrow icon only', () => {
-      expect(findDownstreamArrowIcon().exists()).toBe(false);
-      expect(findUpstreamArrowIcon().exists()).toBe(true);
-      expect(findUpstreamArrowIcon().props('name')).toBe('long-arrow');
-    });
-  });
-
-  describe('rendered state with downstream pipelines', () => {
-    beforeEach(() => {
-      createComponent({
-        downstreamPipelines: mockLinkedPipelines.triggered,
-        pipelinePath: 'my/pipeline/path',
-      });
-    });
-
-    it('should have the correct props', () => {
-      expect(findPipelineMiniGraph().props()).toMatchObject({
-        downstreamPipelines: expect.any(Array),
-        isMergeTrain: false,
-        pipelinePath: 'my/pipeline/path',
-        stages: expect.any(Array),
-        stagesClass: '',
-        updateDropdown: false,
-        upstreamPipeline: undefined,
-      });
-    });
-
-    afterEach(() => {
-      wrapper.destroy();
-      wrapper = null;
-    });
-
-    it('should render the downstream linked pipelines mini list only', () => {
-      expect(findLinkedPipelineDownstream().exists()).toBe(true);
-      expect(findLinkedPipelineUpstream().exists()).toBe(false);
-    });
-
-    it('should render a downstream arrow icon only', () => {
-      expect(findUpstreamArrowIcon().exists()).toBe(false);
-      expect(findDownstreamArrowIcon().exists()).toBe(true);
-      expect(findDownstreamArrowIcon().props('name')).toBe('long-arrow');
-    });
-  });
-});
diff --git a/spec/frontend/pipelines/pipelines_table_spec.js b/spec/frontend/pipelines/pipelines_table_spec.js
index 07818b9dadbe9129ca667de3ecfbb9c7afecac53..7b49baa5a204586f10ed97b826ca7f9e4159782a 100644
--- a/spec/frontend/pipelines/pipelines_table_spec.js
+++ b/spec/frontend/pipelines/pipelines_table_spec.js
@@ -113,28 +113,40 @@ describe('Pipelines Table', () => {
     });
 
     describe('stages cell', () => {
-      it('should render pipeline mini graph', () => {
+      it('should render a pipeline mini graph', () => {
         expect(findPipelineMiniGraph().exists()).toBe(true);
       });
 
       it('should render the right number of stages', () => {
         const stagesLength = pipeline.details.stages.length;
-        expect(findPipelineMiniGraph().props('stages').length).toBe(stagesLength);
+        expect(
+          findPipelineMiniGraph().findAll('[data-testid="mini-pipeline-graph-dropdown"]'),
+        ).toHaveLength(stagesLength);
       });
 
       describe('when pipeline does not have stages', () => {
         beforeEach(() => {
           pipeline = createMockPipeline();
-          pipeline.details.stages = [];
+          pipeline.details.stages = null;
 
           createComponent({ pipelines: [pipeline] });
         });
 
         it('stages are not rendered', () => {
-          expect(findPipelineMiniGraph().props('stages')).toHaveLength(0);
+          expect(findPipelineMiniGraph().exists()).toBe(false);
         });
       });
 
+      it('should not update dropdown', () => {
+        expect(findPipelineMiniGraph().props('updateDropdown')).toBe(false);
+      });
+
+      it('when update graph dropdown is set, should update graph dropdown', () => {
+        createComponent({ pipelines: [pipeline], updateGraphDropdown: true });
+
+        expect(findPipelineMiniGraph().props('updateDropdown')).toBe(true);
+      });
+
       it('when action request is complete, should refresh table', () => {
         findPipelineMiniGraph().vm.$emit('pipelineActionRequestComplete');
 
diff --git a/spec/frontend/vue_mr_widget/components/mr_widget_pipeline_spec.js b/spec/frontend/vue_mr_widget/components/mr_widget_pipeline_spec.js
index a32f61c4567bf6cd2bb7a18627afde00615fbd83..6347e3c3be34cc706c3001069a2b1a0a87c2580d 100644
--- a/spec/frontend/vue_mr_widget/components/mr_widget_pipeline_spec.js
+++ b/spec/frontend/vue_mr_widget/components/mr_widget_pipeline_spec.js
@@ -4,8 +4,9 @@ import axios from 'axios';
 import MockAdapter from 'axios-mock-adapter';
 import { trimText } from 'helpers/text_helper';
 import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import MRWidgetPipelineComponent from '~/vue_merge_request_widget/components/mr_widget_pipeline.vue';
 import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
+import PipelineStage from '~/pipelines/components/pipelines_list/pipeline_stage.vue';
+import PipelineComponent from '~/vue_merge_request_widget/components/mr_widget_pipeline.vue';
 import { SUCCESS } from '~/vue_merge_request_widget/constants';
 import mockData from '../mock_data';
 
@@ -29,13 +30,14 @@ describe('MRWidgetPipeline', () => {
   const findPipelineInfoContainer = () => wrapper.findByTestId('pipeline-info-container');
   const findCommitLink = () => wrapper.findByTestId('commit-link');
   const findPipelineFinishedAt = () => wrapper.findByTestId('finished-at');
+  const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
+  const findAllPipelineStages = () => wrapper.findAllComponents(PipelineStage);
   const findPipelineCoverage = () => wrapper.findByTestId('pipeline-coverage');
   const findPipelineCoverageDelta = () => wrapper.findByTestId('pipeline-coverage-delta');
   const findPipelineCoverageTooltipText = () =>
     wrapper.findByTestId('pipeline-coverage-tooltip').text();
   const findPipelineCoverageDeltaTooltipText = () =>
     wrapper.findByTestId('pipeline-coverage-delta-tooltip').text();
-  const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
   const findMonitoringPipelineMessage = () => wrapper.findByTestId('monitoring-pipeline-message');
   const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
 
@@ -43,7 +45,7 @@ describe('MRWidgetPipeline', () => {
 
   const createWrapper = (props = {}, mountFn = shallowMount) => {
     wrapper = extendedWrapper(
-      mountFn(MRWidgetPipelineComponent, {
+      mountFn(PipelineComponent, {
         propsData: {
           ...defaultProps,
           ...props,
@@ -104,10 +106,8 @@ describe('MRWidgetPipeline', () => {
     });
 
     it('should render pipeline graph', () => {
-      const stagesCount = mockData.pipeline.details.stages.length;
-
       expect(findPipelineMiniGraph().exists()).toBe(true);
-      expect(findPipelineMiniGraph().props('stages')).toHaveLength(stagesCount);
+      expect(findAllPipelineStages()).toHaveLength(mockData.pipeline.details.stages.length);
     });
 
     describe('should render pipeline coverage information', () => {
@@ -176,11 +176,15 @@ describe('MRWidgetPipeline', () => {
       expect(findPipelineInfoContainer().text()).toMatch(mockData.pipeline.details.status.label);
     });
 
-    it('should render pipeline graph', () => {
+    it('should render pipeline graph with correct styles', () => {
       const stagesCount = mockData.pipeline.details.stages.length;
 
       expect(findPipelineMiniGraph().exists()).toBe(true);
-      expect(findPipelineMiniGraph().props('stages')).toHaveLength(stagesCount);
+      expect(findPipelineMiniGraph().findAll('.mr-widget-pipeline-stages')).toHaveLength(
+        stagesCount,
+      );
+
+      expect(findAllPipelineStages()).toHaveLength(stagesCount);
     });
 
     it('should render coverage information', () => {