UI should explain if no junit report artifacts are available to populate unit test report
Release notes
When examining an old pipeline, there is no indication that a job's artifacts are expired, and we only include There are no test cases to display
as empty state text. We will add clarifying text that the artifacts are expired and that is why the test report is empty.
Problem to solve
The Unit Test report utilizes BuildReportResult
to populate the summary data. This results in top level data (total tests ran, passed, failed, etc.) but no details present when artifacts are expired.
As a Developer looking at an old pipeline, I want some visual indicator that test results are expired on the Unit Test report, so that I don't wait a bunch of time figuring it out myself and can move on.
Example Project: https://gitlab.com/gitlab-org/gitlab-runner/-/pipelines/221552771/test_report
Intended users
Metrics
User experience goal
Clarify why the test case is empty through additional empty state text.
Proposal
Add to the text There are no test cases to display.
additional text on the Unit Test -> Job view when the artifact that would populate the view is expired:
Test details are populated by job artifacts. The job artifacts from this pipeline are expired.
UX
- Add an empty state to the page with the following text: Title: Job artifacts are expired. Description: Test reports require job artifacts but all artifacts are expired. Learn more.
backend
--- a/app/controllers/projects/pipelines/tests_controller.rb
+++ b/app/controllers/projects/pipelines/tests_controller.rb
@@ -23,7 +23,11 @@ def show
format.json do
render json: TestSuiteSerializer
.new(project: project, current_user: @current_user)
- .represent(test_suite, details: true)
+ .represent(
+ test_suite,
+ details: true,
+ artifacts_expired: expired_artifacts?
+ )
end
end
end
@@ -35,6 +39,10 @@ def builds
@builds ||= pipeline.latest_builds.id_in(build_ids).presence || render_404
end
+ # Memoize this call
+ def expired_artifacts?
+ !pipeline.has_reports?(::Ci::JobArtifact.test_reports.not_expired)
+ end
+
def build_ids
return [] unless params[:build_ids]
diff --git a/app/serializers/test_suite_entity.rb b/app/serializers/test_suite_entity.rb
index 15eb2891b22..55590ad24e8 100644
--- a/app/serializers/test_suite_entity.rb
+++ b/app/serializers/test_suite_entity.rb
@@ -15,5 +15,9 @@ class TestSuiteEntity < Grape::Entity
expose :test_cases, using: TestCaseEntity do |test_suite|
test_suite.suite_error ? [] : test_suite.sorted.test_cases.values.flat_map(&:values)
end
+
+ expose :artifacts_expired do |test_suite, opts|
+ opts[:artifacts_expired]
+ end
diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue b/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue
index 51373e712ff..f4039038f8a 100644
--- a/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue
+++ b/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue
@@ -35,10 +35,13 @@ export default {
},
computed: {
...mapState(['pageInfo']),
- ...mapGetters(['getSuiteTests', 'getSuiteTestCount']),
+ ...mapGetters(['getSuiteTests', 'getSuiteTestCount', 'getSuiteArtifactsExpired']),
hasSuites() {
return this.getSuiteTests.length > 0;
},
+ artifactsExpired() {
+ return this.getSuiteArtifactsExpired;
+ },
},
methods: {
...mapActions(['setPage']),
@@ -158,6 +161,13 @@ export default {
<div v-else>
<p class="js-no-test-cases">{{ s__('TestReports|There are no test cases to display.') }}</p>
+ <p v-if="artifactsExpired">
+ {{
+ s__(
+ 'TestReports|Test details are populated by job artifacts. The job artifacts from this pipeline are expired.',
+ )
+ }}
+ </p>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/pipelines/stores/test_reports/getters.js b/app/assets/javascripts/pipelines/stores/test_reports/getters.js
index 03680de0fa9..43f7432f12e 100644
--- a/app/assets/javascripts/pipelines/stores/test_reports/getters.js
+++ b/app/assets/javascripts/pipelines/stores/test_reports/getters.js
@@ -28,4 +28,9 @@ export const getSuiteTests = (state) => {
.slice(start, start + perPage);
};
+export const getSuiteArtifactsExpired = (state) => {
+ const { artifacts_expired: artifactsExpired = false } = getSelectedSuite(state);
+ return artifactsExpired;
+};
+
export const getSuiteTestCount = (state) => getSelectedSuite(state)?.test_cases?.length || 0;
Further details
Permissions and Security
Documentation
Availability & Testing
Available Tier
What does success look like, and how can we measure that?
Less confusion around expired artifacts and why a test report is empty.
What is the type of buyer?
Is this a cross-stage feature?
Links / references
This page may contain information related to upcoming products, features and functionality. It is important to note that the information presented is for informational purposes only, so please do not rely on the information for purchasing or planning purposes. Just like with all projects, the items mentioned on the page are subject to change or delay, and the development, release, and timing of any products, features, or functionality remain at the sole discretion of GitLab Inc.