{"id":13665234,"url":"https://github.com/ozontech/allure-go","last_synced_at":"2026-01-19T15:00:48.933Z","repository":{"id":37945722,"uuid":"446818506","full_name":"ozontech/allure-go","owner":"ozontech","description":"Complete Allure provider in Go which doesn't overload the interface usage","archived":false,"fork":false,"pushed_at":"2025-12-12T14:11:33.000Z","size":2161,"stargazers_count":384,"open_issues_count":8,"forks_count":40,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-12-14T05:29:30.166Z","etag":null,"topics":["allure","allure-framework","go","golang","qa","qaautomation","qatools","reporting","reporting-tool","testing"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ozontech.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-01-11T12:47:45.000Z","updated_at":"2025-12-12T18:02:49.000Z","dependencies_parsed_at":"2023-02-19T06:45:26.239Z","dependency_job_id":"2423574c-53fe-4956-8969-010e36f64ebc","html_url":"https://github.com/ozontech/allure-go","commit_stats":null,"previous_names":[],"tags_count":110,"template":false,"template_full_name":null,"purl":"pkg:github/ozontech/allure-go","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ozontech%2Fallure-go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ozontech%2Fallure-go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ozontech%2Fallure-go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ozontech%2Fallure-go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ozontech","download_url":"https://codeload.github.com/ozontech/allure-go/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ozontech%2Fallure-go/sbom","scorecard":{"id":716449,"data":{"date":"2025-08-18","repo":{"name":"github.com/ozontech/allure-go","commit":"0355d7d217b16ccd5604df96c2966f67e6c39a3b"},"scorecard":{"version":"v5.2.1-41-g40576783","commit":"40576783fda6698350fcbbeaea760ff827433034"},"score":5.6,"checks":[{"name":"Maintained","score":10,"reason":"12 commit(s) and 4 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#packaging"}},{"name":"Code-Review","score":7,"reason":"Found 14/19 approved changesets -- score normalized to 7","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/main.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#cii-best-practices"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/ozontech/allure-go/main.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/ozontech/allure-go/main.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:28: update your workflow using https://app.stepsecurity.io/secureworkflow/ozontech/allure-go/main.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:38: update your workflow using https://app.stepsecurity.io/secureworkflow/ozontech/allure-go/main.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:42: update your workflow using https://app.stepsecurity.io/secureworkflow/ozontech/allure-go/main.yml/master?enable=pin","Info:   0 out of   5 GitHub-owned GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#pinned-dependencies"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.md:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE.md:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":6,"reason":"branch protection is not maximal on development and all release branches","details":["Info: 'allow deletion' disabled on branch 'master'","Info: 'force pushes' disabled on branch 'master'","Warn: required approving review count is 1 on branch 'master'","Warn: codeowners review is required - but no codeowners file found in repo","Warn: no status checks found to merge onto branch 'master'","Info: PRs are required in order to make changes on branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#branch-protection"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#security-policy"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 28 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-22T09:50:09.589Z","repository_id":37945722,"created_at":"2025-08-22T09:50:09.589Z","updated_at":"2025-08-22T09:50:09.589Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28572555,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-19T14:39:55.009Z","status":"ssl_error","status_checked_at":"2026-01-19T14:39:01.217Z","response_time":67,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["allure","allure-framework","go","golang","qa","qaautomation","qatools","reporting","reporting-tool","testing"],"created_at":"2024-08-02T06:00:30.177Z","updated_at":"2026-01-19T15:00:48.920Z","avatar_url":"https://github.com/ozontech.png","language":"Go","funding_links":[],"categories":["Repositories","Programming languages and frameworks"],"sub_categories":["Go"],"readme":"# Allure-Go\n\n![](.resources/allure_go_icon.svg)\n\nAllure-Go - the project that provides a complete allure provider in go, without overloading the interface of usage. \u003cbr\u003e\nThe project started as a fork of testify, but over time it got its own runner and its own features. \u003cbr\u003e\n\n## :mortar_board: Head of contents\n\n+ [:mortar_board: Head of contents](#mortar_board-head-of-contents)\n+ [:zap: Features](#zap-features)\n  + [WHAT'S NEW](#whats-new) \n  + [pkg/allure](#sparkles-pkgallure)\n  + [pkg/framework](#sparkles-pkgframework)\n+ [:beginner: Getting Started with framework!](#beginner-getting-started-with-framework)\n  + [No Suite tests](#no-suite-tests)\n  + [Runner](#runner)\n  + [Suite](#suite)\n+ [:wrench: Configure your environment!](#wrench-configure-your-environment)\n+ [:smirk: Going Deeper...](#smirk-going-deeper)\n  + [pkg/allure](#pkgallure)\n  + [pkg/framework](#pkgframework)\n  + [cute](#cute)\n+ [:school_satchel: Few more examples](#school_satchel-few-more-examples)\n  + [:rocket: Async test](#async-test)\n  + [Test with nested steps](#test-with-nested-steps)\n  + [Test with attachments](#test-with-attachment)\n  + [Run few parallel suites](#run-few-parallel-suites)\n  + [Setup hooks](#setup-hooks)\n  + [Access test status in hooks](#access-test-status-in-hooks)\n  + [XSkip](#xskip)\n  + [:rocket: Parametrized tests](#parametrized-test)\n  + [Setup test](#setup-test)\n  + [Prevent loosing allureID in test results](#Prevent-loosing-allureID-in-test-results)\n\n## :zap: Features\n\nProviding a separate package allows you to customize your work with allure.\u003cbr\u003e\n\n### What's new?\n\n**New Feature: Access Test Status in AfterEach Hook**\n\n#### GetCurrentTestResult method\n\nNow you can access test execution result in `AfterEach` hook:\u003cbr\u003e\n- `t.GetCurrentTestResult()` - returns current test result with status and details (read-only copy)\u003cbr\u003e\n\nThis allows you to perform conditional actions based on test status (Passed, Failed, Broken, Skipped).\u003cbr\u003e\n\n**Basic Example:**\n\n```go\nfunc (s *MySuite) AfterEach(t provider.T) {\n    result, ok := t.GetCurrentTestResult()\n    if ok \u0026\u0026 result.Status == allure.Failed {\n        // Save screenshot only for failed tests\n        screenshot := takeScreenshot()\n        t.WithNewAttachment(\"failure.png\", allure.ImagePng, screenshot)\n        \n        // Check error message\n        if strings.Contains(result.StatusDetails.Message, \"Setup failed\") {\n            t.Log(\"Test didn't run - BeforeEach hook failed, skipping cleanup\")\n        }\n    }\n}\n```\n\n**How it works with BeforeEach failures:**\n\nWhen `BeforeEach` fails, the test doesn't run, but you can still detect the failure in `AfterEach`:\n\n```go\nfunc (s *MySuite) BeforeEach(t provider.T) {\n    // This will fail\n    t.Require().True(false, \"Setup failed\")\n}\n\nfunc (s *MySuite) AfterEach(t provider.T) {\n    result, ok := t.GetCurrentTestResult()\n    if ok \u0026\u0026 result.Status == allure.Failed \u0026\u0026 \n       strings.Contains(result.StatusDetails.Message, \"Setup failed\") {\n        t.Log(\"BeforeEach failed - test was not executed\")\n    }\n}\n```\n\n**Important Notes:**\n\n:information_source: This feature **does not change** hook or test behavior - it only provides read-only access to test status.\u003cbr\u003e\n:information_source: `GetCurrentTestResult()` returns `(*allure.CurrentResult, bool)` - a read-only copy with `Status` and `StatusDetails` fields.\u003cbr\u003e\n:information_source: Available **only in `AfterEach` hook** - returns `(nil, false)` in other contexts (BeforeEach, BeforeAll, AfterAll, test body).\u003cbr\u003e\n:information_source: For **parametrized tests** (using `t.Run()`): AfterEach is called once for the parent test, not for each subtest.\u003cbr\u003e\n:information_source: For **nested tests**: AfterEach sees the parent test status, which may be Passed even if subtests failed.\u003cbr\u003e\n\n\n**Release v0.6.17**\n\n#### WithTestSetup/WithTestTeardown methods\n\nNow you can improve your reports with `t.WithTestSetup(func (provider.T))` or `t.WithTeardown(func (provider.T))`.\u003cbr\u003e\nIf you need some more setup customization, now you can pass your steps to `Set up` and `Tear down` right from the test!\u003cbr\u003e\n\nCheck out [our example](./examples/suite_demo/setup_test.go) for more information, or check out example below:\n\n:information_source: Feature works __only__ with Test. If you try to run it in Before/After hook or inside itself - nothing will happen.\u003cbr\u003e\n:information_source: Yes, it works with t.Parallel, but HIGHLY recommended to run t.Parallel AFTER TestSetup.\u003cbr\u003e\n:information_source: Yes, it works with TableTest.\u003cbr\u003e\n\n\n\n**Release v0.6.16**\n\n#### :zap: Parametrized tests\n\nNew absolutely amazing way to build your table tests.\nHave a look at [here](./examples/suite_demo/new_parametrized_test.go) or [here](#parametrizedtestexamplessuite_demonew_parametrized_testgo).\n\n:information_source: you need just create parameter field in suite struct and add argument to the test signature (pretty cool, hah?). \u003cbr\u003e\n\n##### FAQ about table tests: \u003cbr\u003e\n\n+ :question: Can I use this amazing feature with my common tests?\u003cbr\u003e\n+ :information_source: **YES**, it works with any other type of suite's tests. \u003cbr\u003e\n\n\n+ :question:Can I use structs, pointers or interfaces as parameters? \u003cbr\u003e\n+ :information_source: **YES** you can (and, I guess, you should) use it with structs and interfaces as params. \u003cbr\u003e\n\n\n+ :question: Can I use it with `TestRunner` object? \u003cbr\u003e\n+ :information_source: **NO**, `TestRunner` object doesn't support this.\n\n#### SuiteResult\n\nNow `suite.RunSuite` and `runner.RunTests` returns new adorable struct `SuiteResult` to customize your integrations.\n\n:information_source: `SuiteResult` contains information about suite `Container` and each test's `Container` and `Result`.\n\n### :sparkles: pkg/allure\n\nThe package containing the data model for Allure. \u003cbr\u003e\nComplete list of allure objects:\n\n+ `Attachment`\n+ `Container`\n+ `Label`\n+ `Link`\n+ `Parameter`\n+ `Result`\n+ `Step`\n\n### :sparkles: pkg/framework\n\nThe package provides a fully integrated with Allure JUNIT-like framework for working with tests.\u003cbr\u003e\nMain features:\n\n:white_check_mark: **Allure support**\n\n+ Test plan support (Allure TestOps feature)\n+ Tests as code\n+ Extensive configuration options for test steps\n+ Testify's asserts already wrapped with `allure.Step`!\n+ xSkip support (you can mark test as `t.XSkip()` and it will be skipped on fail)\n\n:white_check_mark: **Suite support**\n\n+ Before/After feature\n+ Suite as go-struct\n+ Suite as sub-test\n\n:white_check_mark: **Parallel running**\n\n+ Parallel tests in suite structs\n+ Parallel steps in test functions\n\n## :beginner: Getting Started with framework!\n\n**Step 0.** Install package\n\n```bash\ngo get github.com/ozontech/allure-go/pkg/framework\n```\n\n### No Suite tests\n\n**NOTE:** No suite tests doesn't support before after hooks\n\n**Step 1.** Describe tests\n\n```go\npackage test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ozontech/allure-go/pkg/framework/provider\"\n\t\"github.com/ozontech/allure-go/pkg/framework/runner\"\n)\n\nfunc TestRunner(t *testing.T) {\n\trunner.Run(t, \"My first test\", func(t provider.T) {\n\t\tt.NewStep(\"My First Step!\")\n\t})\n\trunner.Run(t, \"My second test\", func(t provider.T) {\n\t\tt.WithNewStep(\"My Second Step!\", func(sCtx provider.StepCtx) {\n\t\t\tsCtx.NewStep(\"My First SubStep!\")\n\t\t})\n\t})\n}\n```\n\n**Step 2.** Run it!\n\n```bash\ngo test ./test/... \n```\n\n### Suite\n\n**Step 1.** Make your first test suite\n\n```go\npackage tests\n\nimport (\n\t\"github.com/ozontech/allure-go/pkg/framework/suite\"\n)\n\ntype MyFirstSuite struct {\n\tsuite.Suite\n}\n```\n\n**Step 2.** Extend it with tests\n\n```go\npackage tests\n\nimport (\n\t\"github.com/ozontech/allure-go/pkg/framework/provider\"\n\t\"github.com/ozontech/allure-go/pkg/framework/suite\"\n)\n\ntype MyFirstSuite struct {\n\tsuite.Suite\n}\n\nfunc (s *MyFirstSuite) TestMyFirstTest(t provider.T) {\n\tt.NewStep(\"My First Step!\")\n}\n\nfunc (s *MyFirstSuite) TestMySecondTest(t provider.T) {\n\tt.WithNewStep(\"My Second Step!\", func(sCtx provider.StepCtx) {\n\t\tsCtx.NewStep(\"My First SubStep!\")\n\t})\n}\n```\n\n**Step 3.** Describe suite runner function\n\n```go\npackage test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ozontech/allure-go/pkg/framework/provider\"\n\t\"github.com/ozontech/allure-go/pkg/framework/suite\"\n)\n\ntype MyFirstSuite struct {\n\tsuite.Suite\n}\n\nfunc (s *MyFirstSuite) TestMyFirstTest(t provider.T) {\n\tt.NewStep(\"My First Step!\")\n}\n\nfunc (s *MyFirstSuite) TestMySecondTest(t provider.T) {\n\tt.WithNewStep(\"My Second Step!\", func(sCtx provider.StepCtx) {\n\t\tsCtx.NewStep(\"My First SubStep!\")\n\t})\n}\n\nfunc TestSuiteRunner(t *testing.T) {\n\tsuite.RunSuite(t, new(MyFirstSuite))\n}\n```\n\n**Step 4.** Run it!\n\n```bash\ngo test ./test/... \n```\n\n### Runner\n\n**Step 1.** Init runner object\n\n```go\npackage test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ozontech/allure-go/pkg/framework/provider\"\n\t\"github.com/ozontech/allure-go/pkg/framework/runner\"\n)\n\nfunc TestRunner(t *testing.T) {\n\tr := runner.NewRunner(t, \"My First Suite!\")\n}\n```\n\n**Step 2.** Extend it with tests\n\n```go\npackage test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ozontech/allure-go/pkg/framework/provider\"\n\t\"github.com/ozontech/allure-go/pkg/framework/runner\"\n)\n\nfunc TestRunner(t *testing.T) {\n\tr := runner.NewRunner(t, \"My First Suite!\")\n\tr.NewTest(\"My first test\", func(t provider.T) {\n\t\tt.NewStep(\"My First Step!\")\n\t})\n\n\tr.NewTest(\"My second test\", func(t provider.T) {\n\t\tt.WithNewStep(\"My Second Step!\", func(sCtx provider.StepCtx) {\n\t\t\tsCtx.NewStep(\"My First SubStep!\")\n\t\t})\n\t})\n}\n```\n\n**Step 3.** Call RunTests function from runner\n\n```go\npackage test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ozontech/allure-go/pkg/framework/provider\"\n\t\"github.com/ozontech/allure-go/pkg/framework/runner\"\n)\n\nfunc TestRunner(t *testing.T) {\n\tr := runner.NewRunner(t, \"My First Suite!\")\n\tr.NewTest(\"My first test\", func(t provider.T) {\n\t\tt.NewStep(\"My First Step!\")\n\t})\n\n\tr.NewTest(\"My second test\", func(t provider.T) {\n\t\tt.WithNewStep(\"My Second Step!\", func(sCtx provider.StepCtx) {\n\t\t\tsCtx.NewStep(\"My First SubStep!\")\n\t\t})\n\t})\n\tr.RunTests()\n}\n```\n\n**Step 4.** Run it!\n\n```bash\ngo test ./test/... \n```\n\n## :wrench: Configure your environment!\n\n### Configure Behavior\n\nThe path to allure reports is gathered from the two global variables: `${ALLURE_OUTPUT_FOLDER}/${ALLURE_OUTPUT_PATH}` \n\n:zap: The `ALLURE_OUTPUT_FOLDER` is the name of the folder where the allure reports will be stored (by\n  default, `allure-results`).\n\n---\n\n:zap: The `ALLURE_OUTPUT_PATH` is the path where the `ALLURE_OUTPUT_FOLDER` will be created (by default this is the root\n  folder root folder of the test launcher).\n\n---\nYou can also specify several global configurations to integrate with your TMS or Task Tracker:\n\n:zap: `ALLURE_ISSUE_PATTERN` - Specifies the url pattern for your Issues. Has no default value. **Mandatory**. Must\n  contain `%s`.\n\nIf `ALLURE_ISSUE_PATTERN` is not specified, the link will be read in its entirety.\n\nExample:\n\n```go\npackage provider_demo\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ozontech/allure-go/pkg/framework/provider\"\n\t\"github.com/ozontech/allure-go/pkg/framework/runner\"\n)\n\nfunc TestSampleDemo(t *testing.T) {\n\trunner.Run(t, \"Just Link\", func(t provider.T) {\n\t\tt.SetIssue(\"https://pkg.go.dev/github.com/stretchr/testify\")\n\t})\n\n\trunner.Run(t, \"With Pattern\", func(t provider.T) {\n\t\t_ = os.Setenv(\"ALLURE_ISSUE_PATTERN\", \"https://pkg.go.dev/github.com/stretchr/%s\")\n\t\tt.SetIssue(\"testify\")\n\t})\n\n}\n\n```\n---\n:zap: `ALLURE_TESTCASE_PATTERN` - Specifies the url pattern for your TestCases. Has no default value. **Mandatory**. Must\n  contain `%s`.\n\nIf `ALLURE_TESTCASE_PATTERN` is not specified, the link will be read in its entirety.\n\nExample:\n\n```go\npackage provider_demo\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ozontech/allure-go/pkg/framework/provider\"\n\t\"github.com/ozontech/allure-go/pkg/framework/runner\"\n)\n\nfunc TestSampleDemo(t *testing.T) {\n\trunner.Run(t, \"Just Link\", func(t provider.T) {\n\t\tt.SetTestCase(\"https://pkg.go.dev/github.com/stretchr/testify\")\n\t})\n\n\trunner.Run(t, \"With Pattern\", func(t provider.T) {\n\t\t_ = os.Setenv(\"ALLURE_TESTCASE_PATTERN\", \"https://pkg.go.dev/github.com/stretchr/%s\")\n\t\tt.SetTestCase(\"testify\")\n\t})\n\n}\n\n```\n---\n:zap: `ALLURE_LAUNCH_TAGS` - Sheds a list of tags that will be applied to each test by default. It has no default value.\n\n:information_source: **Tip:** `ALLURE_LAUNCH_TAGS` - Very handy to use with CI/CD. For example, you can define test groups in it by your\nci-jobs, or you can roll the name of a branch.\n\n---\n:zap: `ALLURE_TESTPLAN_PATH` - describes path to your test plan json. \n\n:information_source: **Tip:** To use this feature you need to work with [Allure TestOps](https://docs.qameta.io/allure-testops/ecosystem/allurectl/#tests-rerun-and-selective-run-with-allurectl)\n\n## :smirk: Going Deeper...\n\n### pkg/allure\n\n:page_facing_up: [pkg/allure documentation](./pkg/allure/README.md)\n\n### pkg/framework\n\n:page_facing_up: [pkg/framework documentation](./pkg/framework/README.md)\n\n### cute\n\n:full_moon_with_face: [You can find cute here!](https://github.com/ozontech/cute)\n\nCute - is library for simply creating HTTP tests in Go with Allure reports.\n\nMain features:\u003cbr\u003e\n:zap: Full integration with Allure \u003cbr\u003e\n:zap: Expressive and intuitive syntax \u003cbr\u003e\n:zap: Built-in JSON support \u003cbr\u003e\n:zap: Custom asserts \u003cbr\u003e\n:zap: One step to BDD \u003cbr\u003e\n\nCute can simply improve your allure-go testing experience! Try it :wink:\n\n## :school_satchel: Few more examples\n\n### [Async test](examples/async/async_step_test.go)\n\n:rocket: **YES!** We really **can** run **parallel** tests in **suites**. \u003cbr\u003e\n:rocket: Even with async steps. \u003cbr\u003e\n:rocket: Example below.\n\nTest code:\n\n```go\npackage async\n\nimport (\n  \"fmt\"\n  \"time\"\n  \n  \"github.com/ozontech/allure-go/pkg/framework/provider\"\n  \"github.com/ozontech/allure-go/pkg/framework/suite\"\n)\n\ntype AsyncSuiteStepDemo struct {\n  suite.Suite\n}\n\nfunc (s *AsyncSuiteStepDemo) BeforeEach(t provider.T) {\n  t.Epic(\"Async\")\n  t.Feature(\"Async Steps\")\n  t.Tags(\"async\", \"suite\", \"steps\")\n}\n\nfunc (s *AsyncSuiteStepDemo) TestAsyncStepDemo1(t provider.T) {\n  t.Title(\"Async Test with async steps 1\")\n\n  t.Parallel()\n\n  t.WithNewAsyncStep(\"Async Step 1\", func(ctx provider.StepCtx) {\n    ctx.WithNewParameters(\"Start\", fmt.Sprintf(\"%s\", time.Now()))\n    time.Sleep(3 * time.Second)\n    ctx.WithNewParameters(\"Stop\", fmt.Sprintf(\"%s\", time.Now()))\n  })\n\n  t.WithNewAsyncStep(\"Async Step 2\", func(ctx provider.StepCtx) {\n    ctx.WithNewParameters(\"Start\", fmt.Sprintf(\"%s\", time.Now()))\n    time.Sleep(3 * time.Second)\n    ctx.Logf(\"Step 2 Stopped At: %s\", fmt.Sprintf(\"%s\", time.Now()))\n    ctx.WithNewParameters(\"Stop\", fmt.Sprintf(\"%s\", time.Now()))\n  })\n}\n```\n\nAllure output:\n\n![](.resources/example_async_test.png)\n\n### [Test with nested steps](examples/suite_demo/step_tree_test.go):\n\nTest code:\n\n```go\npackage examples\n\nimport (\n\t\"github.com/ozontech/allure-go/pkg/framework/provider\"\n\t\"github.com/ozontech/allure-go/pkg/framework/suite\"\n)\n\ntype StepTreeDemoSuite struct {\n\tsuite.Suite\n}\n\nfunc (s *StepTreeDemoSuite) TestInnerSteps(t provider.T) {\n\tt.Epic(\"Demo\")\n\tt.Feature(\"Inner Steps\")\n\tt.Title(\"Simple Nesting\")\n\tt.Description(`\n\t\tStep A is parent step for Step B and Step C\n\t\tCall order will be saved in allure report\n\t\tA -\u003e (B, C)`)\n\n\tt.Tags(\"Steps\", \"Nesting\")\n\n\tt.WithNewStep(\"Step A\", func(ctx provider.StepCtx) {\n\t\tctx.NewStep(\"Step B\")\n\t\tctx.NewStep(\"Step C\")\n\t})\n}\n```\n\nOutput to Allure:\n\n![](.resources/example_step_tree.png)\n\n### [Test with Attachment](examples/suite_demo/attachments_test.go)\n\nTest code:\n\n```go\npackage examples\n\nimport (\n\t\"encoding/json\"\n\n\t\"github.com/ozontech/allure-go/pkg/allure\"\n\t\"github.com/ozontech/allure-go/pkg/framework/provider\"\n\t\"github.com/ozontech/allure-go/pkg/framework/suite\"\n)\n\ntype JSONStruct struct {\n\tMessage string `json:\"message\"`\n}\n\ntype AttachmentTestDemoSuite struct {\n\tsuite.Suite\n}\n\nfunc (s *AttachmentTestDemoSuite) TestAttachment(t provider.T) {\n\tt.Epic(\"Demo\")\n\tt.Feature(\"Attachments\")\n\tt.Title(\"Test Attachments\")\n\tt.Description(`\n\t\tTest's test body and all steps inside can contain attachments`)\n\n\tt.Tags(\"Attachments\", \"BeforeAfter\", \"Steps\")\n\n\tattachmentText := `THIS IS A TEXT ATTACHMENT`\n\tt.Attachment(allure.NewAttachment(\"Text Attachment if TestAttachment\", allure.Text, []byte(attachmentText)))\n\n\tstep := allure.NewSimpleStep(\"Step A\")\n\tvar ExampleJson = JSONStruct{\"this is JSON message\"}\n\tattachmentJSON, _ := json.Marshal(ExampleJson)\n\tstep.Attachment(allure.NewAttachment(\"Json Attachment for Step A\", allure.JSON, attachmentJSON))\n\tt.Step(step)\n}\n```\n\nOutput to Allure:\n\n![](.resources/example_attachments.png)\n\n### [Run few parallel suites](examples/suite_demo/running_test.go)\n\nTest code:\n\n```go\npackage examples\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ozontech/allure-go/pkg/framework/provider\"\n\t\"github.com/ozontech/allure-go/pkg/framework/suite\"\n)\n\ntype TestRunningDemoSuite struct {\n\tsuite.Suite\n}\n\nfunc (s *TestRunningDemoSuite) TestBeforesAfters(t provider.T) {\n\tt.Parallel()\n\t// use RunInner to run suite of tests\n\ts.RunSuite(t, new(BeforeAfterDemoSuite))\n}\n\nfunc (s *TestRunningDemoSuite) TestFails(t provider.T) {\n\tt.Parallel()\n\ts.RunSuite(t, new(FailsDemoSuite))\n}\n\nfunc (s *TestRunningDemoSuite) TestLabels(t provider.T) {\n\tt.Parallel()\n\ts.RunSuite(t, new(LabelsDemoSuite))\n}\n\nfunc TestRunDemo(t *testing.T) {\n\t// use RunSuites to run suite of suites\n\tsuite.RunSuite(t, new(TestRunningDemoSuite))\n}\n```\n\nOutput to Allure:\n\n![](.resources/example_multiple_suites_run.png)\n\n### [Setup hooks](examples/suite_demo/befores_afters_test.go)\n\nTest code:\n\n```go\npackage examples\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ozontech/allure-go/pkg/framework/provider\"\n\t\"github.com/ozontech/allure-go/pkg/framework/suite\"\n)\n\ntype BeforeAfterDemoSuite struct {\n\tsuite.Suite\n}\n\nfunc (s *BeforeAfterDemoSuite) BeforeEach(t provider.T) {\n\tt.NewStep(\"Before Test Step\")\n}\n\nfunc (s *BeforeAfterDemoSuite) AfterEach(t provider.T) {\n\tt.NewStep(\"After Test Step\")\n}\n\nfunc (s *BeforeAfterDemoSuite) BeforeAll(t provider.T) {\n\tt.NewStep(\"Before suite Step\")\n}\n\nfunc (s *BeforeAfterDemoSuite) AfterAll(t provider.T) {\n\tt.NewStep(\"After suite Step\")\n}\n\nfunc (s *BeforeAfterDemoSuite) TestBeforeAfterTest(t provider.T) {\n\tt.Epic(\"Demo\")\n\tt.Feature(\"BeforeAfter\")\n\tt.Title(\"Test wrapped with SetUp \u0026 TearDown\")\n\tt.Description(`\n\t\tThis test wrapped with SetUp and TearDown containert.`)\n\n\tt.Tags(\"BeforeAfter\")\n}\n\nfunc TestBeforesAfters(t *testing.T) {\n\tt.Parallel()\n\tsuite.RunSuite(t, new(BeforeAfterDemoSuite))\n}\n```\n\nOutput to Allure:\n\n![](.resources/example_befores_afters.png)\n\n### [Access test status in hooks](examples/suite_demo/test_status_in_hooks_test.go)\n\nYou can access test execution result in `AfterEach` hook to perform conditional actions based on test status.\n\nTest code:\n\n```go\npackage suite_demo\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/ozontech/allure-go/pkg/allure\"\n\t\"github.com/ozontech/allure-go/pkg/framework/provider\"\n\t\"github.com/ozontech/allure-go/pkg/framework/suite\"\n)\n\ntype StatusInHooksSuite struct {\n\tsuite.Suite\n}\n\nfunc (s *StatusInHooksSuite) AfterEach(t provider.T) {\n\t// Get the test result from execution context (read-only copy)\n\tresult, ok := t.GetCurrentTestResult()\n\t\n\tif ok {\n\t\tswitch result.Status {\n\t\tcase allure.Failed:\n\t\t\t// Check if BeforeEach failed\n\t\t\tif strings.Contains(result.StatusDetails.Message, \"Setup failed\") {\n\t\t\t\tt.Log(\"BeforeEach hook failed, skipping cleanup\")\n\t\t\t\treturn\n\t\t\t}\n\t\t\t\n\t\t\t// Handle test failure\n\t\t\tt.Log(\"Test failed\")\n\t\t\t// You can save screenshot, logs, etc.\n\t\t\t// screenshot := takeScreenshot()\n\t\t\t// t.WithNewAttachment(\"failure.png\", allure.ImagePng, screenshot)\n\t\t\t\n\t\tcase allure.Passed:\n\t\t\tt.Log(\"Test passed\")\n\t\t\t// Cleanup test data for successful tests\n\t\t\t\n\t\tcase allure.Broken:\n\t\t\tt.Log(\"Test broken\")\n\t\t}\n\t}\n}\n\nfunc (s *StatusInHooksSuite) TestExample(t provider.T) {\n\tt.Title(\"Example test\")\n\tt.Require().Equal(1, 1)\n}\n\nfunc TestStatusInHooks(t *testing.T) {\n\tsuite.RunSuite(t, new(StatusInHooksSuite))\n}\n```\n\nKey points:\n- `t.GetCurrentTestResult()` returns `(*allure.CurrentResult, bool)` with test status and details in `AfterEach`\n- `allure.CurrentResult` is a read-only copy containing `Status` and `StatusDetails` fields\n- Available statuses: `allure.Passed`, `allure.Failed`, `allure.Broken`, `allure.Skipped`\n- Returns `(nil, false)` in contexts other than `AfterEach` (e.g., in test body, `BeforeEach`, or `AfterAll`)\n- Check `result.StatusDetails.Message` or `result.StatusDetails.Trace` to analyze failure reasons\n- Does not change hook or test behavior - only provides read-only access to test status\n\n\n### [XSkip](examples/suite_demo/fails_test.go)\n\nTest code:\n\n```go\npackage examples\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/ozontech/allure-go/pkg/framework/provider\"\n\t\"github.com/ozontech/allure-go/pkg/framework/suite\"\n)\n\ntype DemoSuite struct {\n\tsuite.Suite\n}\n\nfunc (s *DemoSuite) TestXSkipFail(t provider.T) {\n\tt.Title(\"This test skipped by assert with message\")\n\tt.Description(`\n\t\tThis Test will be skipped with assert Error.\n\t\tError text: Assertion Failed`)\n\tt.Tags(\"fail\", \"xskip\", \"assertions\")\n\n\tt.XSkip()\n\tt.Require().Equal(1, 2, \"Assertion Failed\")\n}\n\nfunc TestDemoSuite(t *testing.T) {\n\tt.Parallel()\n\tsuite.RunSuite(t, new(DemoSuite))\n}\n```\n\nOutput to Allure:\n\n![](.resources/example_xskip.png)\n\n### [Parametrized Test](examples/suite_demo/new_parametrized_test.go)\n\nTest code:\n\n```go\npackage suite_demo\n\nimport (\n  \"testing\"\n\n  \"github.com/jackc/fake\"\n  \"github.com/ozontech/allure-go/pkg/framework/provider\"\n  \"github.com/ozontech/allure-go/pkg/framework/suite\"\n)\n\ntype ParametrizedSuite struct {\n  suite.Suite\n  ParamCities []string\n}\n\nfunc (s *ParametrizedSuite) BeforeAll(t provider.T) {\n  for i := 0; i \u003c 10; i++ {\n    s.ParamCities = append(s.ParamCities, fake.City())\n  }\n}\n\nfunc (s *ParametrizedSuite) TableTestCities(t provider.T, city string) {\n  t.Parallel()\n  t.Require().NotEmpty(city)\n}\n\nfunc TestNewParametrizedDemo(t *testing.T) {\n  suite.RunSuite(t, new(ParametrizedSuite))\n}\n```\n\nOutput to Allure:\n\n![](.resources/example_table_test.png)\n\n### [Setup test](examples/suite_demo/setup_test.go)\n\nThis feature allows you to extend your test setting up/tearing down functional\n\nTest code:\n\n```go\npackage suite_demo\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/ozontech/allure-go/pkg/framework/provider\"\n\t\"github.com/ozontech/allure-go/pkg/framework/suite\"\n)\n\ntype SetupSuite struct {\n\tsuite.Suite\n}\n\nfunc (s *SetupSuite) TestMyTest(t provider.T) {\n\tvar (\n\t\tv1  string\n\t\tv2  int\n\t\tctx context.Context\n\t)\n\tt.WithTestSetup(func(t provider.T) {\n\t\tt.WithNewStep(\"init v1\", func(sCtx provider.StepCtx) {\n\t\t\tv1 = \"string\"\n\t\t\tsCtx.WithNewParameters(\"v1\", v1)\n\t\t})\n\t\tt.WithNewStep(\"init v2\", func(sCtx provider.StepCtx) {\n\t\t\tv2 = 123\n\t\t\tsCtx.WithNewParameters(\"v2\", v2)\n\t\t})\n\t\tt.WithNewStep(\"init ctx\", func(sCtx provider.StepCtx) {\n\t\t\tctx = context.Background()\n\t\t\tsCtx.WithNewParameters(\"ctx\", ctx)\n\t\t})\n\t})\n\tdefer t.WithTestTeardown(func(t provider.T) {\n\t\tt.WithNewStep(\"Close ctx\", func(sCtx provider.StepCtx) {\n\t\t\tctx.Done()\n\t\t\tsCtx.WithNewParameters(\"ctx\", ctx)\n\t\t})\n\t})\n}\n\nfunc TestRunner(t *testing.T) {\n\tsuite.RunSuite(t, new(SetupSuite))\n}\n```\n\nAllure output:\n\n![](.resources/example_setup_test.png)\n\n### Prevent loosing allureID in test results\n\nWhen suit fails at the setup stage (beforeAll), report will not contain `ALLURE_ID` field.\nTo prevent it you can use `GetAllureID(testName string) string` method for common tests and\n`InitializeTestsParams()` method for parametrized tests.\n\n**Example for `GetAllureID` method:**\n\n```go\npackage suite_demo\n\nimport (\n  \"testing\"\n\n  \"github.com/ozontech/allure-go/pkg/framework/provider\"\n  \"github.com/ozontech/allure-go/pkg/framework/suite\"\n)\n\ntype AllureIDSuite struct {\n  suite.Suite\n}\n\nfunc (testSuit *AllureIDSuite) GetAllureID(testName string) string {\n  switch testName {\n  case \"TestWithAllureIDFirst\":\n    return \"9001\"\n  case \"TestWithAllureIDSecond\":\n    return \"9002\"\n  default:\n    return \"\"\n  }\n}\n\nfunc (s *AllureIDSuite) BeforeAll(t provider.T) {\n  // code that can fail here\n}\n\nfunc (s *AllureIDSuite) TestWithAllureIDFirst(t provider.T) {\n  // code of your test here\n}\n\nfunc (s *AllureIDSuite) TestWithAllureIDSecond(t provider.T) {\n  // code of your test here\n}\n\nfunc TestNewDemo(t *testing.T) {\n  suite.RunSuite(t, new(AllureIDSuite))\n}\n\n```\n\n**Example for `InitializeTestsParams` method:**\n\n```go\npackage suite_demo\n\nimport (\n  \"testing\"\n\n  \"github.com/jackc/fake\"\n  \"github.com/ozontech/allure-go/pkg/framework/provider\"\n  \"github.com/ozontech/allure-go/pkg/framework/suite\"\n)\n\ntype CitiesParam struct {\n\tallureID    string\n\ttitle       string\n\tvalue       string\n}\n\nfunc (p CitiesParam) GetAllureID() string {\n  return p.allureID\n}\nfunc (p CitiesParam) GetAllureTitle() string {\n  return p.title\n}\n\ntype ParametrizedSuite struct {\n  suite.Suite\n  ParamCities []CitiesParam\n}\n\nfunc (s *ParametrizedSuite) InitializeTestsParams() {\n  s.ParamCities = make([]CitiesParam, 2)\n  s.ParamCities[0] = CitiesParam{\n    title:    \"Title for city test #1\",\n    allureID: \"101\",\n    value:    fake.City(),\n  }\n\n  s.ParamCities[1] = CitiesParam{\n    title:    \"Title for city test #2\",\n    allureID: \"102\",\n    value:    fake.City(),\n  }\n}\n\n\nfunc (s *ParametrizedSuite) BeforeAll(t provider.T) {\n  // setup suit here\n}\n\nfunc (s *ParametrizedSuite) TableTestCities(t provider.T, city CitiesParam) {\n  t.Parallel()\n  t.Require().NotEmpty(city.value)\n}\n\nfunc TestNewParametrizedDemo(t *testing.T) {\n  suite.RunSuite(t, new(ParametrizedSuite))\n}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fozontech%2Fallure-go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fozontech%2Fallure-go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fozontech%2Fallure-go/lists"}