From 303d080f9a249486562bd12cde66169b6fb03c5c Mon Sep 17 00:00:00 2001 From: Lex-resource <181232912+Lex-resource@users.noreply.github.com> Date: Sun, 7 Jun 2026 13:15:08 +0800 Subject: [PATCH] feat: add tags report tab --- .../qameta/allure/ConfigurationBuilder.java | 3 + .../qameta/allure/DummyReportGenerator.java | 2 + .../io/qameta/allure/tags/TagsTreePlugin.java | 84 +++++++++++++++++++ .../main/javascript/core/registry/index.mts | 2 + .../main/javascript/features/tags/index.mts | 8 ++ .../io/qameta/allure/ReportGeneratorTest.java | 2 + .../allure/tags/TagsTreePluginTest.java | 70 ++++++++++++++++ 7 files changed, 171 insertions(+) create mode 100644 allure-generator/src/main/java/io/qameta/allure/tags/TagsTreePlugin.java create mode 100644 allure-generator/src/main/javascript/features/tags/index.mts create mode 100644 allure-generator/src/test/java/io/qameta/allure/tags/TagsTreePluginTest.java diff --git a/allure-generator/src/main/java/io/qameta/allure/ConfigurationBuilder.java b/allure-generator/src/main/java/io/qameta/allure/ConfigurationBuilder.java index e046b59af..059781c19 100644 --- a/allure-generator/src/main/java/io/qameta/allure/ConfigurationBuilder.java +++ b/allure-generator/src/main/java/io/qameta/allure/ConfigurationBuilder.java @@ -50,6 +50,7 @@ import io.qameta.allure.suites.SuitesPlugin; import io.qameta.allure.summary.SummaryPlugin; import io.qameta.allure.tags.TagsPlugin; +import io.qameta.allure.tags.TagsTreePlugin; import io.qameta.allure.timeline.TimelinePlugin; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; @@ -81,6 +82,7 @@ public class ConfigurationBuilder { private static final List BUNDLED_EXTENSIONS = Arrays.asList( new MarkdownDescriptionsPlugin(), new TagsPlugin(), + new TagsTreePlugin(), new RetryPlugin(), new RetryTrendPlugin(), new SeverityPlugin(), @@ -159,6 +161,7 @@ public ConfigurationBuilder useDefault() { new RandomUidContext(), new MarkdownDescriptionsPlugin(), new TagsPlugin(), + new TagsTreePlugin(), new RetryPlugin(), new RetryTrendPlugin(), new SeverityPlugin(), diff --git a/allure-generator/src/main/java/io/qameta/allure/DummyReportGenerator.java b/allure-generator/src/main/java/io/qameta/allure/DummyReportGenerator.java index 3d94aaa55..054f49f68 100644 --- a/allure-generator/src/main/java/io/qameta/allure/DummyReportGenerator.java +++ b/allure-generator/src/main/java/io/qameta/allure/DummyReportGenerator.java @@ -48,6 +48,7 @@ import io.qameta.allure.suites.SuitesPlugin; import io.qameta.allure.summary.SummaryPlugin; import io.qameta.allure.tags.TagsPlugin; +import io.qameta.allure.tags.TagsTreePlugin; import io.qameta.allure.timeline.TimelinePlugin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -77,6 +78,7 @@ public final class DummyReportGenerator { new RandomUidContext(), new MarkdownDescriptionsPlugin(), new TagsPlugin(), + new TagsTreePlugin(), new RetryPlugin(), new RetryTrendPlugin(), new SeverityPlugin(), diff --git a/allure-generator/src/main/java/io/qameta/allure/tags/TagsTreePlugin.java b/allure-generator/src/main/java/io/qameta/allure/tags/TagsTreePlugin.java new file mode 100644 index 000000000..99068190f --- /dev/null +++ b/allure-generator/src/main/java/io/qameta/allure/tags/TagsTreePlugin.java @@ -0,0 +1,84 @@ +/* + * Copyright 2016-2026 Qameta Software Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.qameta.allure.tags; + +import io.qameta.allure.CommonJsonAggregator2; +import io.qameta.allure.core.LaunchResults; +import io.qameta.allure.entity.TestResult; +import io.qameta.allure.tree.DefaultTreeLayer; +import io.qameta.allure.tree.TestResultTree; +import io.qameta.allure.tree.Tree; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import static io.qameta.allure.entity.TestResult.comparingByTimeAsc; + +/** + * Plugin that generates data for Tags tab. + */ +public class TagsTreePlugin extends CommonJsonAggregator2 { + + protected static final String JSON_FILE_NAME = "tags.json"; + + public TagsTreePlugin() { + super(JSON_FILE_NAME); + } + + static Tree getTagData(final List launchResults) { + final Tree tags = new TestResultTree( + TagsPlugin.TAGS_BLOCK_NAME, + result -> { + final Set values = result.getExtraBlock( + TagsPlugin.TAGS_BLOCK_NAME, + Collections.emptySet() + ); + if (values.isEmpty()) { + return Collections.emptyList(); + } + return Collections.singletonList( + new DefaultTreeLayer( + values.stream().sorted().collect(Collectors.toList()) + ) + ); + } + ); + + launchResults.stream() + .map(LaunchResults::getResults) + .flatMap(Collection::stream) + .filter(TagsTreePlugin::hasTags) + .sorted(comparingByTimeAsc()) + .forEach(tags::add); + return tags; + } + + private static boolean hasTags(final TestResult result) { + final Set values = result.getExtraBlock( + TagsPlugin.TAGS_BLOCK_NAME, + Collections.emptySet() + ); + return !values.isEmpty(); + } + + @Override + protected Tree getData(final List launches) { + return getTagData(launches); + } +} diff --git a/allure-generator/src/main/javascript/core/registry/index.mts b/allure-generator/src/main/javascript/core/registry/index.mts index d2442b163..9ce42bfe6 100644 --- a/allure-generator/src/main/javascript/core/registry/index.mts +++ b/allure-generator/src/main/javascript/core/registry/index.mts @@ -11,6 +11,7 @@ import { } from "../../features/overview/index.mts"; import { packagesTab } from "../../features/packages/index.mts"; import { suitesTab } from "../../features/suites/index.mts"; +import { tagsTab } from "../../features/tags/index.mts"; import { testResultBlocks, testResultTabs } from "../../features/test-result/index.mts"; import { timelineTab } from "../../features/timeline/index.mts"; @@ -40,6 +41,7 @@ const tabs: TabDescriptor[] = [ overviewTab, categoriesTab, suitesTab, + tagsTab, behaviorsTab, packagesTab, graphTab, diff --git a/allure-generator/src/main/javascript/features/tags/index.mts b/allure-generator/src/main/javascript/features/tags/index.mts new file mode 100644 index 000000000..6139a7bd2 --- /dev/null +++ b/allure-generator/src/main/javascript/features/tags/index.mts @@ -0,0 +1,8 @@ +import { createTreeTab } from "../tree/createTreeTab.mts"; + +export const tagsTab = createTreeTab({ + baseUrl: "tags", + title: "testResult.tags.name", + icon: "lineGeneralChecklist3", + url: "data/tags.json", +}); diff --git a/allure-generator/src/test/java/io/qameta/allure/ReportGeneratorTest.java b/allure-generator/src/test/java/io/qameta/allure/ReportGeneratorTest.java index 85e1d8f53..5aaf58394 100644 --- a/allure-generator/src/test/java/io/qameta/allure/ReportGeneratorTest.java +++ b/allure-generator/src/test/java/io/qameta/allure/ReportGeneratorTest.java @@ -103,6 +103,8 @@ void shouldGenerateCategoriesJson() { void shouldGenerateXunitJson() { assertThat(output.resolve("data/suites.json")) .isRegularFile(); + assertThat(output.resolve("data/tags.json")) + .isRegularFile(); } /** diff --git a/allure-generator/src/test/java/io/qameta/allure/tags/TagsTreePluginTest.java b/allure-generator/src/test/java/io/qameta/allure/tags/TagsTreePluginTest.java new file mode 100644 index 000000000..ce3756cf0 --- /dev/null +++ b/allure-generator/src/test/java/io/qameta/allure/tags/TagsTreePluginTest.java @@ -0,0 +1,70 @@ +/* + * Copyright 2016-2026 Qameta Software Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.qameta.allure.tags; + +import io.qameta.allure.Allure; +import io.qameta.allure.ConfigurationBuilder; +import io.qameta.allure.Description; +import io.qameta.allure.core.Configuration; +import io.qameta.allure.core.InMemoryReportStorage; +import io.qameta.allure.core.LaunchResults; +import io.qameta.allure.entity.TestResult; +import io.qameta.allure.tree.Tree; +import io.qameta.allure.tree.TreeNode; +import org.junit.jupiter.api.Test; + +import java.util.HashSet; +import java.util.List; + +import static io.qameta.allure.testdata.TestData.createSingleLaunchResults; +import static java.util.Arrays.asList; +import static java.util.Collections.singleton; +import static org.assertj.core.api.Assertions.assertThat; + +class TagsTreePluginTest { + + @Description("Verifies that a result is grouped under every distinct tag.") + @Test + void shouldGroupResultsByTags() { + final TestResult result = new TestResult().setName("tagged"); + result.addExtraBlock(TagsPlugin.TAGS_BLOCK_NAME, new HashSet<>(asList("jira-123", "smoke"))); + final TestResult untagged = new TestResult().setName("untagged"); + + final Tree tree = Allure.step( + "Build tag tree from a result with two tags", + () -> TagsTreePlugin.getTagData(createSingleLaunchResults(result, untagged)) + ); + + assertThat(tree.getChildren()) + .extracting(TreeNode::getName) + .containsExactly("jira-123", "smoke"); + } + + @Description("Verifies that the tags tree data file is generated.") + @Test + void shouldCreateTagsDataFile() { + final Configuration configuration = ConfigurationBuilder.bundled().build(); + final InMemoryReportStorage storage = new InMemoryReportStorage(); + final TestResult result = new TestResult().setName("tagged"); + result.addExtraBlock(TagsPlugin.TAGS_BLOCK_NAME, singleton("smoke")); + final List launches = createSingleLaunchResults(result); + + Allure.step("Generate tags tree data", () -> new TagsTreePlugin().aggregate(configuration, launches, storage)); + + assertThat(storage.getReportDataFiles()) + .containsKey("data/" + TagsTreePlugin.JSON_FILE_NAME); + } +}