Halmurat T.
Halmurat T.

Senior SDET

Home Blog Books ask About

The Dispatch

Weekly QA notes from the trenches.

Welcome aboard!

You're on the list. Expect real-world QA insights — no fluff, no spam.

© 2026 Halmurat T.

Automation 24
  • Selenium
  • Playwright
  • Appium
  • Cypress
AI Testing 5
CI/CD 6
  • GitHub Actions
  • Slack Reporting
QA Strategy 4
Case Studies 5
Blog/Automation
AutomationHalmurat T./August 6, 2024/8 min

How We Stopped Arguing About Whose Tests Failed

Filed underselenium/framework-design/design-patterns
How We Stopped Arguing About Whose Tests Failed

Table of Contents
  • The Problem: Reports Nobody Owns
  • Step 1: Tag Your Feature Files by Squad
  • Tag at the feature level
  • Keep one squad per feature file
  • Make the suffix part of the contract
  • Step 2: Extract Squad Tags in Your Report Hook
  • Step 3: Configure the Extent Report Adapter
  • What the Report Looks Like
  • Taking It Further: Slack Notifications Per Squad
  • The Results
  • What I’d Do Differently
  • Your Next Step

On this page

  • The Problem: Reports Nobody Owns
  • Step 1: Tag Your Feature Files by Squad
  • Tag at the feature level
  • Keep one squad per feature file
  • Make the suffix part of the contract
  • Step 2: Extract Squad Tags in Your Report Hook
  • Step 3: Configure the Extent Report Adapter
  • What the Report Looks Like
  • Taking It Further: Slack Notifications Per Squad
  • The Results
  • What I’d Do Differently
  • Your Next Step

On a mobile automation project with 6 squads and about 1,400 Cucumber scenarios, our nightly test report was a 40-page PDF that nobody read. When failures came in, the standup conversation went the same way every morning: “Is that our test or yours?” Nobody owned the failures because nobody could quickly tell which squad’s tests had broken. We spent 15–20 minutes every standup just triaging test ownership before anyone could start investigating.

The fix was simple. We tagged every feature file with the owning squad, then wired Extent Reports to automatically group and filter results by those tags. Standup triage dropped to under 3 minutes. Each squad could pull up their own failures in one click. Here’s exactly how we built it.

The Problem: Reports Nobody Owns

In a single-team project, test report ownership is obvious — it’s your team’s code, your team’s tests, your team’s failures. But when you scale to multiple squads sharing a single test suite, the report becomes a shared dumping ground.

Here’s what we were dealing with:

  • 6 squads contributing scenarios to the same Cucumber-Appium repo
  • ~1,400 scenarios running nightly against 3 device configurations
  • One flat Extent Report with every test listed sequentially — no grouping, no filtering
  • No way to answer “how is my squad’s test health?” without manually scanning the entire report

The result was predictable. Failures got ignored because nobody felt responsible. The suite’s pass rate drifted from 92% to 78% over two months because broken tests sat unfixed — each squad assumed the failures belonged to someone else.

Step 1: Tag Your Feature Files by Squad

The convention is straightforward. Every feature file gets a tag ending in -squad that identifies the owning team. Put it at the feature level so every scenario in the file inherits it.

src/test/resources/features/energy/validate-settings.feature
@energy-squad
Feature: Energy settings configuration
@smoke
Scenario: User updates energy preference
Given the user is on the settings screen
When they select "Solar" as their energy source
Then the preference should be saved successfully
@regression
Scenario: User views energy usage history
Given the user is on the energy dashboard
When they tap "Usage History"
Then the last 30 days of usage should display
src/test/resources/features/devices/pair-device.feature
@device-squad
Feature: Device pairing flow
@smoke
Scenario: User pairs a new thermostat
Given the user is on the devices screen
When they initiate pairing for "Smart Thermostat"
Then the device should appear in the paired list

Tag at the feature level

If a squad owns the feature, they own all its scenarios. Tagging individual scenarios creates maintenance overhead and invites arguments about shared scenarios.

Keep one squad per feature file

If a feature file has scenarios owned by two different squads, that’s a code smell — split the file. Shared ownership means no ownership.

Make the suffix part of the contract

Always use @team-name-squad. The -squad suffix is what the code keys on, so deviating from the pattern (like @team-energy or @squad-energy) silently drops the test from squad filtering.

Step 2: Extract Squad Tags in Your Report Hook

Here’s where Extent Reports picks up the squad tags. In your AfterScenario hook (or equivalent adapter callback), iterate through the scenario’s tags and assign any squad tag as an Extent Report category.

src/test/java/hooks/ReportingHooks.java
public class ReportingHooks {
private static final ThreadLocal<ExtentTest> scenarioThreadLocal = new ThreadLocal<>();
private final List<String> squads = new ArrayList<>();
@After
public void afterScenario(Scenario scenario) {
for (String tag : scenario.getSourceTagNames()) {
if (tag.toLowerCase().endsWith("-squad")) {
String squadName = tag.toLowerCase()
.replace("@", "")
.replace("-squad", "")
.trim();
squads.add(squadName);
scenarioThreadLocal.get().assignCategory(tag);
}
}
}
}

What’s happening here:

  1. Filter on the -squad suffix — this ignores functional tags like @smoke, @regression, or @wip and only picks up ownership tags.
  2. Normalize the squad name — strip the @ prefix and -squad suffix to get a clean team name (energy, device, billing) for any downstream processing.
  3. Assign the full tag as an Extent Report category — keeping the @energy-squad format in the report makes it immediately recognizable and searchable.
  4. Thread-safe with ThreadLocal — critical if you’re running scenarios in parallel across threads, which you almost certainly are in a suite this size.
[ NOTE ]

If you’re unfamiliar with thread safety in test automation, I covered thread safety in parallel test execution in a separate post. Using ThreadLocal here is non-negotiable in parallel execution — without it, concurrent scenarios will overwrite each other’s ExtentTest instances and your report will be a jumbled mess.

Step 3: Configure the Extent Report Adapter

If you’re using the ExtentCucumberAdapter, you’ll need the right configuration to enable category grouping. Add this to your extent.properties file.

src/test/resources/extent.properties
extent.reporter.spark.start=true
extent.reporter.spark.out=target/extent-reports/spark-report.html
# Enable category view — this is what makes squad filtering work
extent.reporter.spark.vieworder=dashboard,test,category,exception,author

The key line is vieworder including category. Without it, the squad tags get assigned but there’s no dedicated view to filter by them. I’ve seen teams implement the tagging correctly and then wonder why they can’t see squad groupings — this config line is usually what’s missing.

What the Report Looks Like

Once this is wired up, the Extent Report’s Category tab becomes your squad dashboard:

  • Category: @energy-squad — 142 scenarios, 138 passed, 4 failed
  • Category: @device-squad — 98 scenarios, 95 passed, 3 failed
  • Category: @billing-squad — 210 scenarios, 201 passed, 9 failed

Each squad lead opens the report, clicks their tag, and sees only their tests. No scrolling through 1,400 results. No guessing. No standup arguments.

You can also cross-reference squad tags with functional tags. A scenario tagged @energy-squad @smoke shows up under both the squad category and the smoke category. This means your QA lead can answer “how are our smoke tests doing?” while each squad lead can answer “how are our tests doing?” — from the same report.

Taking It Further: Slack Notifications Per Squad

Once you have squad tags in your reporting pipeline, the natural next step is routing failure notifications to the right Slack channel. Instead of blasting one #qa-failures channel that everyone mutes, you send each squad’s failures to their own channel.

src/test/java/notifications/SlackNotifier.java
public class SlackNotifier {
public void notifySquads(Map<String, List<TestResult>> resultsBySquad) {
for (Map.Entry<String, List<TestResult>> entry : resultsBySquad.entrySet()) {
String channel = "#" + entry.getKey() + "-test-failures";
List<TestResult> failures = entry.getValue().stream()
.filter(r -> r.getStatus() == Status.FAIL)
.collect(Collectors.toList());
if (!failures.isEmpty()) {
sendSlackMessage(channel, formatFailureReport(failures));
}
}
}
}

This maps @energy-squad failures to #energy-test-failures, @device-squad to #device-test-failures, and so on. If you want the full setup for color-coded Slack notifications with pass/fail indicators, I walked through that in our guide to sending test results to Slack.

The Results

§ Delta · Standup Triage Time 85% faster

Before

15–20 min

→ ↓

After

Under 3 min

Within two weeks of rolling this out:

  • Standup triage time dropped from 15–20 minutes to under 3 minutes
  • Mean time to fix broken tests went from 4.2 days to 1.1 days — because the owning squad saw the failure immediately
  • Overall pass rate climbed back from 78% to 94% within a month — turns out tests get fixed fast when there’s clear ownership
  • Zero “whose test is this?” conversations in standup. The report answered that question before the meeting started.

The biggest surprise wasn’t the tooling — it was the cultural shift. When each squad could see their own test health score in isolation, they started taking pride in it. One squad lead started a friendly competition for highest pass rate. That kind of ownership doesn’t come from process documents or Jira tickets. It comes from visibility.

What I’d Do Differently

If I were building this from scratch today, I’d make two changes:

  1. Enforce squad tags in CI. Add a pre-merge check that rejects any feature file without a -squad tag. We had a few orphaned feature files that slipped through without tags and showed up as “uncategorized” in the report. A simple lint rule would have caught those.

  2. Add squad-level metrics to the CI dashboard. Extent Reports are great for detailed results, but squad leads also want a trend line — “are my tests getting more or less stable over time?” Exporting squad pass rates to a Grafana dashboard or even a simple Google Sheet would close that loop.

Your Next Step

If your team has more than one squad contributing to a shared test suite, add -squad tags to your feature files this week. Start with just the tagging — you can wire up the Extent Report integration later. Even without automated reporting, having explicit ownership tags in your feature files forces the conversation about who owns what, and that conversation alone is worth the effort.

§ Further Reading 03 of 03
01Automation

XPath text() vs Dot — Why Your Text Match Fails

The real difference between XPath text(), dot, contains(), and normalize-space() for test automation — with examples that explain real flaky failures.

Read →
02Automation

Stop Launching a Browser Per Test in Playwright

Launching a new browser per test in Playwright wastes 3-6 seconds each time. BrowserContext gives you the same isolation in milliseconds. Here's how to switch.

Read →
03Automation

Stop Using locator() for Everything in Playwright

Most Playwright teams still use CSS selectors via locator() out of habit. getByRole and getByText find elements the way users do — and survive redesigns.

Read →

Don't miss a thing

Subscribe to get updates straight to your inbox.

HT

No spam · Unsubscribe anytime

Welcome aboard!

You're on the list. Expect real-world QA insights — no fluff, no spam.

§ Colophon

Halmurat T. — Senior SDET writing about test automation, CI/CD, and QA strategy from 10+ years in the enterprise trenches.

Set in
IBM Plex Sans, Lora, and IBM Plex Mono.
Built with
Astro, MDX, Tailwind CSS & Expressive Code. Served by Vercel.
Privacy
No cookies. No tracking scripts on the main thread — analytics run sandboxed via Partytown.
Source
github.com/Halmurat-Uyghur
Terminal
Try /ask to query Halmurat's notes in a shell prompt.

© 2026 Halmurat T. · Written in plain text, shipped in plain time.

Search
Esc

Search is not available in dev mode.

Run npm run build then npm run preview:local to test search locally.