Repository navigation
Document test automation exclusion annotations #40827
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
calvinbayer
wants to merge
4
commits into
master
Choose a base branch
from
codex/test-automation-exclusions
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
0f51a58
docs(tests): document test automation exclusion annotations
calvinbayer dbc5b88
docs(tests): state annotation SDK availability
calvinbayer 0bfb912
Clarify Weaver annotation example framework compatibility
calvinbayer caeb3b9
Clarify Playwright serial group retry exclusions
calvinbayer File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
45 changes: 45 additions & 0 deletions
45
hugo/assets/scripts/tests/test-automation-exclusions.test.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| const fs = require('fs'); | ||
| const path = require('path'); | ||
|
|
||
| const guide = fs.readFileSync( | ||
| path.join(__dirname, '../../../content/en/tests/guides/test_automation_exclusions.md'), | ||
| 'utf8' | ||
| ); | ||
| const sdkRequirements = new Map( | ||
| Array.from(guide.matchAll(/^\|[^|]+\| `([^`]+)` \| ([^|]+) \|$/gm), | ||
| ([, sdk, availability]) => [sdk, availability.trim()]) | ||
| ); | ||
|
|
||
| // Each imported API needs its own compatibility requirement, rather than the | ||
| // older minimum versions for Test Optimization or a test framework. | ||
| describe('test automation annotation SDK requirements', () => { | ||
| test.each([ | ||
| ['dd-trace', /from ['"]dd-trace\/test-optimization['"]|require\(['"]dd-trace\/test-optimization['"]\)/, 'dd-trace-js'], | ||
| ['dd-trace-java', /import datadog\.trace\.api\.civisibility\.(NoAutoRetry|PreventFailureSuppression)/, 'dd-trace-java'], | ||
| ['ddtrace', /from ddtrace\.testing import/, 'dd-trace-py'], | ||
| ])('documents availability for examples that import %s annotations', (sdk, imports, repository) => { | ||
| expect(guide).toMatch(imports); | ||
| expect(sdkRequirements.has(sdk)).toBe(true); | ||
| const availability = sdkRequirements.get(sdk); | ||
| if (availability === 'Unreleased') { | ||
| expect(guide).toMatch(/class="alert alert-warning"[^>]*>[^<]*not available in published SDK releases/); | ||
| } else { | ||
| const releasedVersion = new RegExp( | ||
| `^\\[v?\\d+\\.\\d+\\.\\d+\\]\\(https://github\\.com/DataDog/${repository}/releases/tag/v?\\d+\\.\\d+\\.\\d+\\)$` | ||
| ); | ||
| expect(availability).toMatch(releasedVersion); | ||
| } | ||
| }); | ||
| }); | ||
|
|
||
| // SDK annotation availability does not establish framework tag capabilities. | ||
| describe('Weaver annotation example compatibility', () => { | ||
| test('scopes custom string tag syntax to supported framework versions', () => { | ||
| const weaver = guide.split('**Weaver:**')[1].split(/^## /m)[0]; | ||
| expect(weaver).toMatch(/\.tagged\(TestAutomationExclusions\.NO_AUTO_RETRY\)/); | ||
| const compatibility = weaver.match(/\*\*Framework compatibility:\*\* ([^\n]+)/)?.[1]; | ||
| expect(compatibility).toBeDefined(); | ||
| expect(compatibility).toMatch(/Weaver 0\.8\.4 and 0\.9\.0 support these custom string tags/); | ||
| expect(compatibility).toMatch(/Weaver 0\.13\.0 does not support this API/); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
260 changes: 260 additions & 0 deletions
260
hugo/content/en/tests/guides/test_automation_exclusions.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,260 @@ | ||
| --- | ||
| title: Control Test Automation with Code Annotations | ||
| description: Exclude individual tests from Datadog failure suppression and automatic retries with JavaScript, Java, and Python annotations. | ||
| further_reading: | ||
| - link: "/tests/flaky_management/" | ||
| tag: "Documentation" | ||
| text: "Manage flaky tests" | ||
| - link: "/tests/flaky_tests/auto_test_retries/" | ||
| tag: "Documentation" | ||
| text: "Configure Auto Test Retries" | ||
| - link: "/tests/flaky_tests/early_flake_detection/" | ||
| tag: "Documentation" | ||
| text: "Configure Early Flake Detection" | ||
| --- | ||
|
|
||
| ## Overview | ||
|
|
||
| Use code annotations to exclude individual tests from Datadog automation. For example, protect a critical test from quarantine or disabling, or prevent Datadog from retrying a test with side effects. | ||
|
|
||
| | Annotation | Effect | | ||
| |------------|--------| | ||
| | `prevent_failure_suppression` | Keeps a test eligible to run despite Datadog disabling and prevents Datadog quarantine from suppressing its failures. It does not prevent retries or turn passing tests into failures. | | ||
| | `no_auto_retry` | Excludes a test from Datadog [Auto Test Retries][1], [Early Flake Detection][2], and [Attempt to Fix][3] retries. Explicit retries configured in the test framework remain available. | | ||
|
|
||
| These names describe the shared behavior. Use the language-specific names and syntax in the following sections. Apply either annotation independently, or combine them to exclude a test from both behaviors. | ||
|
|
||
| ## Prerequisites and scope | ||
|
|
||
| <div class="alert alert-warning">These annotation APIs are not available in published SDK releases. Use a development build that includes the annotation implementation for the test framework.</div> | ||
|
|
||
| | Language | Datadog SDK | First supported SDK release | | ||
| |----------|-------------|-----------------------------| | ||
| | JavaScript and TypeScript | `dd-trace` | Unreleased | | ||
| | Java | `dd-trace-java` | Unreleased | | ||
| | Python | `ddtrace` | Unreleased | | ||
|
|
||
| The minimum versions for Test Optimization or a test framework do not establish support for these annotation APIs. | ||
|
|
||
| Set up [Test Optimization][4] with native instrumentation for the test framework. Annotations do not apply to JUnit XML uploads. An annotation only affects automation that the Datadog library supports for that framework. | ||
|
|
||
| Annotations apply to individual test declarations. An annotated parameterized declaration applies to every generated test case. They preserve framework skips, test filters, and expected-failure behavior. They do not override [Test Impact Analysis][5]: a test or file excluded by Test Impact Analysis remains excluded. The annotations do not disable test discovery or flakiness reporting. | ||
|
|
||
| Apply annotations in test source code. Setting a span tag with the same name does not change test execution. The annotations control execution without changing the test's configured state in Flaky Tests Management. | ||
|
|
||
| ## JavaScript and TypeScript | ||
|
|
||
| Import `preventFailureSuppression` and `noAutoRetry` from `dd-trace/test-optimization` and wrap the test callback. For example, with Jest: | ||
|
|
||
| ```javascript | ||
| const { preventFailureSuppression, noAutoRetry } = require('dd-trace/test-optimization') | ||
|
|
||
| test('critical behavior', preventFailureSuppression(noAutoRetry(() => { | ||
| expect(2 + 2).toBe(4) | ||
| }))) | ||
| ``` | ||
|
|
||
| Use the same helpers on callbacks passed to Mocha, Vitest, Cypress, Playwright, and WebdriverIO Jasmine test declarations. Apply them to the callback passed to `test.each` or another parameterized declaration to annotate every generated case. Importing the helpers does not initialize the tracer; configure Test Optimization instrumentation separately. | ||
|
|
||
| For Playwright, wrap the callback that declares the test fixtures: | ||
|
|
||
| ```javascript | ||
| import { test, expect } from '@playwright/test' | ||
| import { preventFailureSuppression, noAutoRetry } from 'dd-trace/test-optimization' | ||
|
|
||
| test('critical behavior', preventFailureSuppression(noAutoRetry(async ({ page }) => { | ||
| await page.setContent('<h1>Checkout</h1>') | ||
| await expect(page.getByRole('heading')).toHaveText('Checkout') | ||
| }))) | ||
| ``` | ||
|
|
||
| ### Cucumber.js | ||
|
|
||
| Use native scenario tags instead of wrapping step definitions: | ||
|
|
||
| ```gherkin | ||
| @datadog:prevent_failure_suppression @datadog:no_auto_retry | ||
| Scenario: Critical behavior | ||
| Given a customer has items in their cart | ||
| When the customer completes checkout | ||
| Then the order is confirmed | ||
| ``` | ||
|
|
||
| Tags on a `Scenario Outline` apply to every example. | ||
|
|
||
| ### Framework requirements | ||
|
|
||
| - Jest requires the `jest-circus` runner. The legacy Jest Jasmine runner does not enforce these helpers. | ||
| - Cypress requires version 12 or later. Datadog retries also require [test isolation][6] to be enabled. | ||
| - Playwright requires version 1.38 or later. | ||
| - Vitest requires version 1.6 or later. Its no-worker-tracer mode requires version 3.2.6 or later. | ||
| - WebdriverIO Jasmine requires WebdriverIO 9 or later. | ||
| - Cucumber.js supports serial scenarios from version 7. Parallel Test Management exclusions require version 11 or later. | ||
|
|
||
| Explicit framework retries, such as `jest.retryTimes`, Mocha retries, Playwright retry settings, and Cucumber.js `--retry`, remain available when `noAutoRetry` is present. | ||
|
|
||
| In Playwright serial groups, `noAutoRetry` excludes the entire group from Datadog retries so tests run with their prerequisites. Explicit Playwright retry settings still apply. | ||
|
|
||
| ## Java | ||
|
|
||
| Add a `com.datadoghq:dd-trace-api` dependency that matches the Datadog Java tracer version used by the tests. Import the annotations from `datadog.trace.api.civisibility`. | ||
|
|
||
| ### Method annotations | ||
|
|
||
| With JUnit 4, JUnit 5, or TestNG, apply `@PreventFailureSuppression` and `@NoAutoRetry` to the test method. For example, with JUnit 5: | ||
|
|
||
| ```java | ||
| import datadog.trace.api.civisibility.NoAutoRetry; | ||
| import datadog.trace.api.civisibility.PreventFailureSuppression; | ||
| import org.junit.jupiter.api.Test; | ||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
|
||
| class CriticalTest { | ||
| @Test | ||
| @PreventFailureSuppression | ||
| @NoAutoRetry | ||
| public void criticalBehavior() { | ||
| assertEquals(4, 2 + 2); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| Use the same annotations with JUnit 4 and TestNG test methods. The annotations target methods, not classes, and apply to every invocation of a parameterized method. Datadog automatic retries, Early Flake Detection, quarantine, and Attempt to Fix require TestNG 7.5 or later. Test disabling is also supported by earlier instrumented TestNG versions. | ||
|
|
||
| ### Spock | ||
|
|
||
| Apply the same annotations to the feature method: | ||
|
|
||
| ```groovy | ||
| import datadog.trace.api.civisibility.NoAutoRetry | ||
| import datadog.trace.api.civisibility.PreventFailureSuppression | ||
| import spock.lang.Specification | ||
|
|
||
| class CriticalSpec extends Specification { | ||
| @PreventFailureSuppression | ||
| @NoAutoRetry | ||
| def "critical behavior"() { | ||
| expect: | ||
| 2 + 2 == 4 | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### Scenario tags | ||
|
|
||
| With Cucumber and Karate, apply native tags to the scenario or Scenario Outline. Java scenario tags use underscores, unlike Cucumber.js tags. For example, with Cucumber: | ||
|
|
||
| ```gherkin | ||
| @datadog_prevent_failure_suppression @datadog_no_auto_retry | ||
| Scenario: Critical behavior | ||
| Given a customer has items in their cart | ||
| When the customer completes checkout | ||
| Then the order is confirmed | ||
| ``` | ||
|
|
||
| With Karate, apply the same tags to its scenario: | ||
|
|
||
| ```gherkin | ||
| @datadog_prevent_failure_suppression @datadog_no_auto_retry | ||
| Scenario: Critical behavior | ||
| * assert 2 + 2 == 4 | ||
| ``` | ||
|
|
||
| ### Scala test frameworks | ||
|
|
||
| **ScalaTest:** Declare native ScalaTest tags with the public constants: | ||
|
|
||
| ```scala | ||
| import datadog.trace.api.civisibility.TestAutomationExclusions | ||
| import org.scalatest.Tag | ||
| import org.scalatest.funsuite.AnyFunSuite | ||
|
|
||
| class CriticalTest extends AnyFunSuite { | ||
| test("critical behavior", | ||
| new Tag(TestAutomationExclusions.PREVENT_FAILURE_SUPPRESSION), | ||
| new Tag(TestAutomationExclusions.NO_AUTO_RETRY)) { | ||
| assert(2 + 2 == 4) | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| **MUnit:** Attach native tags to the test name: | ||
|
|
||
| ```scala | ||
| import datadog.trace.api.civisibility.TestAutomationExclusions | ||
| import munit.FunSuite | ||
|
|
||
| class CriticalTest extends FunSuite { | ||
| test("critical behavior" | ||
| .tag(new munit.Tag(TestAutomationExclusions.PREVENT_FAILURE_SUPPRESSION)) | ||
| .tag(new munit.Tag(TestAutomationExclusions.NO_AUTO_RETRY))) { | ||
| assertEquals(2 + 2, 4) | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| MUnit does not support Datadog test disabling. Its `PREVENT_FAILURE_SUPPRESSION` tag protects against quarantine failure suppression. | ||
|
|
||
| **Weaver:** Add the public tag names to a native `TestName`: | ||
|
|
||
| **Framework compatibility:** Weaver 0.8.4 and 0.9.0 support these custom string tags. Weaver 0.13.0 does not support this API. | ||
|
|
||
| ```scala | ||
| import cats.effect.IO | ||
| import datadog.trace.api.civisibility.TestAutomationExclusions | ||
| import weaver._ | ||
|
|
||
| object CriticalTest extends SimpleIOSuite { | ||
| private def excluded(name: String): TestName = | ||
| TestName.fromString(name) | ||
| .tagged(TestAutomationExclusions.PREVENT_FAILURE_SUPPRESSION) | ||
| .tagged(TestAutomationExclusions.NO_AUTO_RETRY) | ||
|
|
||
| test(excluded("critical behavior")) { | ||
| IO.pure(expect(2 + 2 == 4)) | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| Weaver reports the annotation metadata. It does not support Datadog quarantine, disabling, or automatic retries, so these tags do not change its execution behavior. | ||
|
|
||
| ## Python | ||
|
|
||
| With pytest, import the decorators from `ddtrace.testing` and apply them to the test function: | ||
|
|
||
| ```python | ||
| import pytest | ||
| from ddtrace.testing import no_auto_retry, prevent_failure_suppression | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("value", [1, 2]) | ||
| @prevent_failure_suppression | ||
| @no_auto_retry | ||
| def test_positive(value): | ||
| assert value > 0 | ||
| ``` | ||
|
|
||
| The decorators apply to every parameterized case. Explicit retries configured through a pytest retry plugin remain available. These decorators do not change pytest skips or `xfail` behavior. | ||
|
|
||
| ## Find annotated test executions | ||
|
|
||
| Search in the [Test Optimization Explorer][7] with: | ||
|
|
||
| - `@test.test_management.prevent_failure_suppression:true` | ||
| - `@test.test_management.no_auto_retry:true` | ||
|
|
||
| Datadog reports each annotation as `true` when present and omits its tag when absent. Reported skipped tests also include annotations when the instrumentation discovers them. Annotations do not require tests excluded by selection or Test Impact Analysis to run. | ||
|
|
||
| Test Management tags continue to describe assigned states, even when an annotation overrides the execution behavior. For example, a protected test can retain `test.test_management.is_quarantined:true` while its failure affects the test command. An excluded Attempt to Fix assignment does not produce Attempt to Fix retries or a completion result. | ||
|
|
||
| ## Further reading | ||
|
|
||
| {{< partial name="whats-next/whats-next.html" >}} | ||
|
|
||
| [1]: /tests/flaky_tests/auto_test_retries/ | ||
| [2]: /tests/flaky_tests/early_flake_detection/ | ||
| [3]: /tests/flaky_management/#confirm-fixes-for-flaky-tests | ||
| [4]: /tests/setup/ | ||
| [5]: /tests/test_impact_analysis/ | ||
| [6]: /tests/setup/javascript/?tab=cypress#retries-require-cypress-test-isolation | ||
| [7]: /tests/explorer/ | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.