diff --git a/app/assets/javascripts/ci/artifacts/components/job_artifacts_table.vue b/app/assets/javascripts/ci/artifacts/components/job_artifacts_table.vue
index c167019861a012e49884b34cf0e5f0da38398497..88ed6afb0ea28c3b6da01bcaf18f17928cbfd78d 100644
--- a/app/assets/javascripts/ci/artifacts/components/job_artifacts_table.vue
+++ b/app/assets/javascripts/ci/artifacts/components/job_artifacts_table.vue
@@ -85,7 +85,8 @@ export default {
       },
       update({ project: { jobs: { nodes = [], pageInfo = {} } = {} } }) {
         this.pageInfo = pageInfo;
-        return nodes
+
+        const jobNodes = nodes
           .map(mapArchivesToJobNodes)
           .map(mapBooleansToJobNodes)
           .map((jobNode) => {
@@ -96,6 +97,12 @@ export default {
               _showDetails: this.expandedJobs.includes(jobNode.id),
             };
           });
+
+        if (jobNodes.some((jobNode) => !jobNode.hasArtifacts)) {
+          this.$apollo.queries.jobArtifacts.refetch();
+        }
+
+        return jobNodes;
       },
       error() {
         createAlert({
@@ -367,6 +374,9 @@ export default {
     createdLabel: I18N_CREATED,
     artifactsCount: I18N_ARTIFACTS_COUNT,
   },
+  TBODY_TR_ATTR: {
+    'data-testid': 'job-artifact-table-row',
+  },
 };
 </script>
 <template>
@@ -391,6 +401,7 @@ export default {
       :busy="$apollo.queries.jobArtifacts.loading"
       stacked="sm"
       details-td-class="gl-bg-gray-10! gl-p-0! gl-overflow-auto"
+      :tbody-tr-attr="$options.TBODY_TR_ATTR"
     >
       <template #table-busy>
         <gl-skeleton-loader v-for="i in 20" :key="i" :width="1000" :height="75">
diff --git a/qa/qa/page/project/artifacts/index.rb b/qa/qa/page/project/artifacts/index.rb
index 19285be430ba58de51542d986abe27f5e60696a4..b0e301c6866bb331d28425b21b054a8674d3b1a9 100644
--- a/qa/qa/page/project/artifacts/index.rb
+++ b/qa/qa/page/project/artifacts/index.rb
@@ -7,6 +7,7 @@ module Artifacts
         class Index < QA::Page::Base
           view 'app/assets/javascripts/ci/artifacts/components/job_artifacts_table.vue' do
             element 'select-all-artifacts-checkbox'
+            element 'job-artifact-table-row'
           end
 
           view 'app/assets/javascripts/ci/artifacts/components/artifacts_bulk_delete.vue' do
@@ -17,11 +18,6 @@ class Index < QA::Page::Base
             element 'artifacts-bulk-delete-modal'
           end
 
-          view 'app/assets/javascripts/ci/artifacts/components/job_artifacts_table.vue' do
-            element 'job-artifacts-count'
-            element 'job-artifacts-size'
-          end
-
           def select_all
             check_element('select-all-artifacts-checkbox', true)
           end
@@ -34,12 +30,8 @@ def delete_selected_artifacts
             end
           end
 
-          def job_artifacts_count_by_row(row: 1)
-            all_elements('job-artifacts-count', minimum: row)[row - 1].text.gsub(/[^0-9]/, '').to_i
-          end
-
-          def job_artifacts_size_by_row(row: 1)
-            all_elements('job-artifacts-size', minimum: row)[row - 1].text.gsub(/[^0-9]/, '').to_f
+          def has_no_artifacts?
+            has_no_element?('job-artifact-table-row')
           end
         end
       end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_project_artifacts/user_can_bulk_delete_artifacts_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_project_artifacts/user_can_bulk_delete_artifacts_spec.rb
index 1f341fe7751aeeeb5a55a6fdc6a1a43c3389db3c..54677ee2ac1d47a1f8ffa3cf6b079f8cd6a0c36a 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/ci_project_artifacts/user_can_bulk_delete_artifacts_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_project_artifacts/user_can_bulk_delete_artifacts_spec.rb
@@ -31,14 +31,8 @@ module QA
           testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/425725' do
           Page::Project::Artifacts::Index.perform do |index|
             index.delete_selected_artifacts
-            position = rand(1..20)
-            artifacts_count = index.job_artifacts_count_by_row(row: position)
-            artifacts_size = index.job_artifacts_size_by_row(row: position)
 
-            aggregate_failures 'job artifacts count and size' do
-              expect(artifacts_count).to eq(0), 'Failed to delete artifact'
-              expect(artifacts_size).to eq(0), 'Failed to delete artifact'
-            end
+            expect(index).to have_no_artifacts
           end
         end
       end
diff --git a/spec/frontend/ci/artifacts/components/job_artifacts_table_spec.js b/spec/frontend/ci/artifacts/components/job_artifacts_table_spec.js
index 8d1f72d2767507e017cf50deb029829f5bc4d197..f8583cd2eabc1e4c406bf7c35b5d225f4a43a88e 100644
--- a/spec/frontend/ci/artifacts/components/job_artifacts_table_spec.js
+++ b/spec/frontend/ci/artifacts/components/job_artifacts_table_spec.js
@@ -118,6 +118,24 @@ describe('JobArtifactsTable component', () => {
   };
 
   const job = getJobArtifactsResponse.data.project.jobs.nodes[0];
+  const emptyJob = {
+    ...job,
+    artifacts: { nodes: [] },
+  };
+
+  const getJobArtifactsResponseWithEmptyJob = {
+    data: {
+      ...getJobArtifactsResponse.data,
+      project: {
+        ...getJobArtifactsResponse.data.project,
+        jobs: {
+          nodes: [emptyJob],
+          pageInfo: { ...getJobArtifactsResponse.data.project.jobs.pageInfo },
+        },
+      },
+    },
+  };
+
   const archiveArtifact = job.artifacts.nodes.find(
     (artifact) => artifact.fileType === ARCHIVE_FILE_TYPE,
   );
@@ -810,6 +828,47 @@ describe('JobArtifactsTable component', () => {
     });
   });
 
+  describe('refetch behavior', () => {
+    describe('without no empty jobs', () => {
+      const query = jest.fn().mockResolvedValue(getJobArtifactsResponse);
+
+      beforeEach(async () => {
+        createComponent({
+          handlers: {
+            getJobArtifactsQuery: query,
+          },
+        });
+
+        await waitForPromises();
+      });
+
+      it('only fetches artifacts once', () => {
+        expect(query).toHaveBeenCalledTimes(1);
+      });
+    });
+
+    describe('with an empty job', () => {
+      const query = jest
+        .fn()
+        .mockResolvedValueOnce(getJobArtifactsResponseWithEmptyJob)
+        .mockResolvedValue(getJobArtifactsResponse);
+
+      beforeEach(async () => {
+        createComponent({
+          handlers: {
+            getJobArtifactsQuery: query,
+          },
+        });
+
+        await waitForPromises();
+      });
+
+      it('refetches to clear empty jobs', () => {
+        expect(query).toHaveBeenCalledTimes(2);
+      });
+    });
+  });
+
   describe('pagination', () => {
     const { pageInfo } = getJobArtifactsResponseThatPaginates.data.project.jobs;
     const query = jest.fn().mockResolvedValue(getJobArtifactsResponseThatPaginates);
diff --git a/spec/frontend/ci/artifacts/utils_spec.js b/spec/frontend/ci/artifacts/utils_spec.js
index 17b4a9f162b04ebb4c96eacfa16d82712e744dc9..475fe800df5aedd8a73c77b40c886324f79aa67d 100644
--- a/spec/frontend/ci/artifacts/utils_spec.js
+++ b/spec/frontend/ci/artifacts/utils_spec.js
@@ -1,8 +1,16 @@
 import getJobArtifactsResponse from 'test_fixtures/graphql/ci/artifacts/graphql/queries/get_job_artifacts.query.graphql.json';
 import { numberToHumanSize } from '~/lib/utils/number_utils';
-import { totalArtifactsSizeForJob } from '~/ci/artifacts/utils';
+import {
+  totalArtifactsSizeForJob,
+  mapArchivesToJobNodes,
+  mapBooleansToJobNodes,
+} from '~/ci/artifacts/utils';
 
 const job = getJobArtifactsResponse.data.project.jobs.nodes[0];
+const emptyJob = {
+  ...job,
+  artifacts: { nodes: [] },
+};
 const artifacts = job.artifacts.nodes;
 
 describe('totalArtifactsSizeForJob', () => {
@@ -14,3 +22,21 @@ describe('totalArtifactsSizeForJob', () => {
     );
   });
 });
+
+describe('mapArchivesToJobNodes', () => {
+  it('sets archive to the archive artifact for each job node', () => {
+    expect([job, emptyJob].map(mapArchivesToJobNodes)).toMatchObject([
+      { archive: { name: 'ci_build_artifacts.zip' } },
+      { archive: {} },
+    ]);
+  });
+});
+
+describe('mapBooleansToJobNodes', () => {
+  it('sets hasArtifacts and hasMetadata for each job node', () => {
+    expect([job, emptyJob].map(mapBooleansToJobNodes)).toMatchObject([
+      { hasArtifacts: true, hasMetadata: true },
+      { hasArtifacts: false, hasMetadata: false },
+    ]);
+  });
+});