diff --git a/.flake8 b/.flake8 index 95a292d8..0b443177 100644 --- a/.flake8 +++ b/.flake8 @@ -2,3 +2,8 @@ max-line-length = 120 import-order-style = google inline-quotes = " +exclude = + ./tests/allure_behave/acceptance/**/test-data/** + ./tests/allure_behave/acceptance/behave_support/background/background_steps.py +per-file-ignores = + ./allure-python-commons/src/model2.py:A003 diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 93ae5b14..458db329 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -20,22 +20,32 @@ jobs: - allure-behave/** - allure-python-commons/** - allure-python-commons-test/** + - tests/*.py + - tests/allure_behave/** allure-nose2: - allure-nose2/** - allure-python-commons/** - allure-python-commons-test/** + - tests/*.py + - tests/allure_nose2/** allure-pytest: - allure-pytest/** - allure-python-commons/** - allure-python-commons-test/** + - tests/*.py + - tests/allure_pytest/** allure-pytest-bdd: - allure-pytest-bdd/** - allure-python-commons/** - allure-python-commons-test/** + - tests/*.py + - tests/allure_pytest_bdd/** allure-robotframework: - allure-robotframework/** - allure-python-commons/** - allure-python-commons-test/** + - tests/*.py + - tests/allure_robotframework/** allure-python-commons: allure-python-commons/** allure-python-commons-test: allure-python-commons-test/** @@ -63,9 +73,6 @@ jobs: runs-on: ubuntu-latest needs: [commons, changes] if: ${{ needs.changes.outputs.packages != '[]' }} - strategy: - matrix: - package: ${{ fromJSON(needs.changes.outputs.packages) }} steps: - uses: actions/checkout@v3 @@ -74,24 +81,14 @@ jobs: with: python-version: "3.11" - - name: Get commons from cache - id: commons - uses: actions/cache@v3 - with: - path: dist/ - key: commons-${{ github.sha }} - - - name: Install packages - run: pip install dist/allure-python-commons*.tar.gz && - pip install ./${{ matrix.package }} && - pip install -r ${{ matrix.package }}/requirements.txt + - name: Install linting packages + run: pip install -r ./requirements/linting.txt - - name: Static check ${{ matrix.package }} - working-directory: ${{ matrix.package }} + - name: Linting the codebase run: poe linter build: - name: Build package + name: Test package runs-on: ubuntu-latest needs: [linters, commons, changes] if: ${{ needs.changes.outputs.packages != '[]' }} @@ -120,7 +117,8 @@ jobs: - name: Install packages run: pip install dist/allure-python-commons*.tar.gz && pip install ./${{ matrix.package }} && - pip install -r ${{ matrix.package }}/requirements.txt + pip install -r ./requirements/testing.txt && + pip install -r ./requirements/testing/${{ matrix.package }}.txt - name: Test ${{ matrix.package }} working-directory: ${{ matrix.package }} diff --git a/.gitignore b/.gitignore index af0bb13b..523fc340 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,7 @@ *.egg-info */build -*/dist \ No newline at end of file +*/dist + +/.allure-report +/.allure-results diff --git a/README.md b/README.md index f4e541f9..63a90b75 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ The repository contains adaptors for Python-based test frameworks. Documentation is available [online](https://docs.qameta.io/allure-report/), also you can get help at -[gitter channel](https://gitter.im/allure-framework/allure-core) +[gitter channel](https://gitter.im/allure-framework/allure-core). ## Pytest [![Release @@ -13,7 +13,9 @@ Status](https://img.shields.io/pypi/v/allure-pytest)](https://pypi.python.org/py Allure [pytest](http://pytest.org) integration. It's developed as pytest plugin and distributed via -[pypi](https://pypi.python.org/pypi/allure-pytest) +[pypi](https://pypi.python.org/pypi/allure-pytest). + +[Usage examples](/allure-pytest/examples). ## Behave [![Release @@ -23,7 +25,9 @@ Status](https://img.shields.io/pypi/v/allure-behave)](https://pypi.python.org/py Allure [behave](https://behave.readthedocs.io/en/latest/) integration. Just external formatter that produce test results in allure2 format. This package is available on -[pypi](https://pypi.python.org/pypi/allure-behave) +[pypi](https://pypi.python.org/pypi/allure-behave). + +[Usage examples](/allure-behave/examples). ## Robot Framework [![Release @@ -33,9 +37,11 @@ Status](https://img.shields.io/pypi/v/allure-robotframework)](https://pypi.pytho Allure [RobotFramework](http://robotframework.org/) integration. This integration is a [Listener](http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface\)) -and does not require changing autotests +and does not require changing autotests. + +[Read more ...](/allure-robotframework/README.rst). -[Read more ...](/allure-robotframework/README.rst) +[Usage examples](/allure-robotframework/examples). ## Pytest-BDD @@ -45,7 +51,7 @@ Status](https://img.shields.io/pypi/v/allure-pytest-bdd)](https://pypi.python.or Allure [pytest-bdd](http://pytest.org) integration. It's developed as pytest plugin and distributed via -[pypi](https://pypi.python.org/pypi/allure-pytest-bdd) +[pypi](https://pypi.python.org/pypi/allure-pytest-bdd). ## Nose2 [![Release diff --git a/allure-behave/README.rst b/allure-behave/README.rst index cfbcf9ae..acecb718 100644 --- a/allure-behave/README.rst +++ b/allure-behave/README.rst @@ -1,9 +1,9 @@ Allure Behave Formatter ======================= -.. image:: https://pypip.in/v/allure-behave/badge.png +.. image:: https://img.shields.io/pypi/v/allure-behave :alt: Release Status :target: https://pypi.python.org/pypi/allure-behave -.. image:: https://pypip.in/d/allure-behave/badge.png +.. image:: https://img.shields.io/pypi/dm/allure-behave :alt: Downloads :target: https://pypi.python.org/pypi/allure-behave @@ -37,4 +37,9 @@ like in example below. ### your code - allure_report("path/to/result/dir") \ No newline at end of file + allure_report("path/to/result/dir") + +Usage examples +-------------- + +See usage examples `here `_. diff --git a/allure-behave/examples/attachment.rst b/allure-behave/examples/attachment.rst new file mode 100644 index 00000000..ca684659 --- /dev/null +++ b/allure-behave/examples/attachment.rst @@ -0,0 +1,100 @@ +=========== +Attachments +=========== + +You can attach data and files to behave test results. An attachment can be added +from a step definition function or from a hook. See examples below for more +details. + +---------------------------------- +Attach data from a step definition +---------------------------------- + +The easiest way to add an attachment is to call the :code:`allure.attach` +function from a step definition: + +Feature file: +^^^^^^^^^^^^^ +.. code:: gherkin + :name: data-attachment-feature + + Feature: Allure attachments in behave tests + Scenario: Data attachment from step definitions + Given a step that adds a named attachment + And a step that adds a typed named attachment + +Step definition file: +^^^^^^^^^^^^^^^^^^^^^ +.. code:: python + :name: data-attachment-steps + + import allure + from behave import given + + @given("a step that adds a named attachment") + def step_impl(context): + allure.attach( + "This is the attachment with the name 'step.txt'", + name="step.txt" + ) + + @given("a step that adds a typed named attachment") + def step_impl(context): + allure.attach( + ( + "[DEBUG] This attachment is named 'trace.log' and has TEXT " + "document appearance" + ), + name="trace.log", + attachment_type=allure.attachment_type.TEXT + ) + +---------------------------------- +Attach file from a step definition +---------------------------------- + +Call the :code:`allure.attach.file` function to attach a file: + +Feature file: +^^^^^^^^^^^^^ +.. code:: gherkin + :name: file-attachment-feature + + Feature: Allure attachments in behave tests + Scenario: File attachment from a step definition + Given a step that attaches a file + +Step definition file: +^^^^^^^^^^^^^^^^^^^^^ +.. code:: python + :name: file-attachment-steps + + import allure + from behave import given + + @given("a step that attaches a file") + def step_impl(context): + allure.attach.file( + "./logs/web", + name="web.log", + attachment_type=allure.attachment_type.TEXT + ) + +------------------ +Attach from a hook +------------------ + +You can also attach data and files from a behave hook, e.g., from the +:code:`after_scenario`: + +.. code:: python + :name: attach-hook + + import allure + + def after_scenario(context, scenario): + allure.attach( + "This attachment will appear on a scenario level", + name="attachment.txt", + attachment_type=allure.attachment_type.TEXT + ) diff --git a/allure-behave/examples/description.rst b/allure-behave/examples/description.rst new file mode 100644 index 00000000..d0e9088d --- /dev/null +++ b/allure-behave/examples/description.rst @@ -0,0 +1,114 @@ +===================================== +Provide a description for a test case +===================================== + +Scenario description can be added in various ways: + +#. In a .feature file +#. Dynamically in a step definition +#. Dynamically in a hook (e.g., before_scenario or after_scenario) + +----------------------------- +Description in a feature file +----------------------------- + +The easiest way to add a description to a test is to specify it directly in the +corresponding scenario in the .feature file. For example: + +.. code-block:: gherkin + :name: description-in-feature-feature + + Feature: Allure description for behave tests + Scenario: Description from a .feature file + This scenario has a description. + This description spans across multiple lines. + + Given noop + +The step definition is trivial: + +.. code-block:: python + :name: description-in-feature-steps + + from behave import given + + @given("noop") + def step_impl(context): + pass + +------------------- +Dynamic description +------------------- + +A description can be specified dynamically with the +:code:`allure.dynamic.description` function. This is useful if you want to +include runtime values in the description. + + +Description in a step definition +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Let's suppose, we want to add a description to the following test: + +.. code-block:: gherkin + :name: description-in-step-feature + + Feature: Allure description for behave tests + Scenario: Description from a step definition + Given description is provided in a step definition + +We can achieve that using the following step definition: + +.. code-block:: python + :name: description-in-step-steps + + from behave import given + import allure + + @given("description is provided in a step definition") + def step_impl(context): + allure.dynamic.description( + "This scenario has a description specified by the step definition" + ) + + +Description in a hook +^^^^^^^^^^^^^^^^^^^^^ + +It's also possible to add a description from a hook in the +:code:`environment.py` file. + +Suppose we have the following feature file (and step definition is the same as +in `Description in a feature file`_): + +.. code-block:: gherkin + :name: description-in-hook-feature + + Feature: Allure description for behave tests + Scenario: Description from the before_scenario hook + Given noop + + Scenario: Description from the after_scenario hook + Given noop + +We can provide a description in the :code:`environment.py` like this: + +.. code-block:: python + :name: description-in-hook-env + + import allure + + def before_scenario(context, scenario): + if "before_scenario" in scenario.name: + allure.dynamic.description( + "This scenario has a description specified in the " + "before_scenario hook" + ) + + + def after_scenario(context, scenario): + if "after_scenario" in scenario.name: + allure.dynamic.description( + "This scenario has a description specified in the " + "after_scenario hook" + ) diff --git a/allure-behave/examples/label.rst b/allure-behave/examples/label.rst new file mode 100644 index 00000000..0dcb314f --- /dev/null +++ b/allure-behave/examples/label.rst @@ -0,0 +1,17 @@ +================================= +Add a custom label to a test case +================================= + +It's possible to add a custom label to a behave scenario. Simply apply +:code:`@allure.label.:` tag to your scenario, e.g.: + +.. code:: gherkin + :name: label-feature + + Feature: Allure label for behave tests + @allure.label.author:John-Doe + Scenario: Scenario marked with an author label + Given noop + +Note, that neither the name nor the value of a label, added that way, may +contain a whitespace character. diff --git a/allure-behave/examples/link.rst b/allure-behave/examples/link.rst new file mode 100644 index 00000000..3d653a76 --- /dev/null +++ b/allure-behave/examples/link.rst @@ -0,0 +1,107 @@ +========================= +Add a link to a test case +========================= + +There are two ways of adding a link to a test result: + +#. Using gherkin tags +#. Dynamically in python code + +-------------------------------- +Using gherkin tags to add a link +-------------------------------- + +You can associate a link with a test by applying the +:code:`@allure.link.:` tag to the scenario: + +.. code:: gherkin + :name: link-scenario-feature + + Feature: Allure link support + @allure.link.report:https://qameta.io/allure-report/ + Scenario: Scenario with the link to the allure report website + Given noop + +A link can also be associated with any scenario in a feature by applying the tag +to the feature: + +.. code:: gherkin + :name: link-feature-feature + + @allure.link.homepage:https://qameta.io + Feature: Allure link support + Scenario: Scenario with the link to the homepage + Given noop + + Scenario: Another scenario with the link to the homepage + Given noop + +A link to an issue or a test case can be added with :code:`@allure.issue:` +and :code:`@allure.tms:`: + +.. code:: gherkin + :name: specialized-links-feature + + Feature: Allure link support + @allure.issue:https://github.com/allure-framework/allure-python/issues/1 + Scenario: Scenario associated with the issue + Given noop + + @allure.tms:https://qameta.io/#features + Scenario: Scenario associated with the TMS test case + Given noop + +Please, note, that no whitespaces are allowed in a gherkin tag. Make sure your +URLs are `properly encoded `_. + +---------------------------- +Providing a link dynamically +---------------------------- + +You may also create a link dynamically and associate it with a test case in +various places in your python code. + +Example +^^^^^^^ +Here we add two links dynamically: one from the :code:`before_scenario` hook and +another one from the step definition. + +Feature file: +""""""""""""" + +.. code:: gherkin + :name: dynamic-links-feature + + Feature: Allure link support + Scenario: Issue from the step definition and link from the hook + Given a link is associated with this test case + +Steps definition file: +"""""""""""""""""""""" + +.. code:: python + :name: dynamic-links-steps + + import allure + from behave import given + + @given("a link is associated with this test case") + def step_impl(context): + allure.dynamic.issue( + "https://github.com/allure-framework/allure-python/issues/1", + "Skip None and empty values in json" + ) + +environment.py: +""""""""""""""" + +.. code:: python + :name: dynamic-links-hooks + + import allure + + def before_scenario(context, scenario): + allure.dynamic.link( + "https://qameta.io/allure-report/", + name="Allure Report" + ) diff --git a/allure-behave/examples/severity.rst b/allure-behave/examples/severity.rst new file mode 100644 index 00000000..8a4ec502 --- /dev/null +++ b/allure-behave/examples/severity.rst @@ -0,0 +1,65 @@ +=============================== +Specify severity of a test case +=============================== + +Use one of the following tags to specify severity of a test case: + +#. :code:`@trivial` +#. :code:`@minor` +#. :code:`@normal` +#. :code:`@critical` +#. :code:`@blocker` + +Those tags can be applied to scenarios: + +.. code:: gherkin + :name: severity-on-scenario + + Feature: Allure severity support + @blocker + Scenario: Blocking scenario + Given noop + + @critical + Scenario: Critical scenario + Given noop + + @normal + Scenario: Normal scenario + Given noop + + @minor + Scenario: Minor scenario + Given noop + + @trivial + Scenario: Trivial scenario + Given noop + +A severity tag can also be applied to a feature, affecting all scenarios of the +feature: + +.. code:: gherkin + :name: severity-on-feature + + @critical + Feature: Allure severity support + Scenario: This scenario inherits the @cricial tag + Given noop + + Scenario: This scenario also inherits the @cricial tag + Given noop + +If multiple severity tags are affecting a scenario, the last one wins: + +.. code:: gherkin + :name: multiple-severities + + @critical, @blocker + Feature: Allure severity support + @minor @trivial + Scenario: This is a trivial scenario + Given noop + + Scenario: While this one is a blocker + Given noop diff --git a/allure-behave/examples/tag.rst b/allure-behave/examples/tag.rst new file mode 100644 index 00000000..e010e4c2 --- /dev/null +++ b/allure-behave/examples/tag.rst @@ -0,0 +1,37 @@ +=============== +Tag a test case +=============== + +You can add an allure tag to a test case by to apply a gherkin tag to a +corresponding scenario: + +.. code:: gherkin + :name: tag-scenario-feature + + Feature: Allure tag support + @distributed + Scenario: Applying a tag directly to a scenario + Given noop + +The tag can also be applied to a feature. In that case it propagates to all +scenarios of the feature: + +.. code:: gherkin + :name: tag-feature-feature + + @isolated + Feature: Allure tag support + Scenario: Applying a tag to a feature + Given noop + +You can add any number of tags that way: + +.. code:: gherkin + :name: tag-multiple-feature + + @node-1 @node-2 + Feature: Allure tag support + @node-3 @node-4 + Scenario: Applying multiple tags + Given noop + diff --git a/allure-behave/examples/testplan.rst b/allure-behave/examples/testplan.rst new file mode 100644 index 00000000..5ade291c --- /dev/null +++ b/allure-behave/examples/testplan.rst @@ -0,0 +1,187 @@ +=========================================== +Use allure testplan to selectivly run tests +=========================================== + +You can filter test cases with a testplan file. Just create a JSON file and put +its path in the :code:`ALLURE_TESTPLAN_PATH` environment variable. + +Then, when you run behave, allure will detect a testplan. Only tests that are +explicitly listed in the plan will be executed. + +To demontrate how a testplan works with behave, lets assume the following +directory structure:: + + . + ├── features + │ ├── steps + │ │ └── steps.py + │ ├── testplan-1.feature + │ └── testplan-2.feature + └── testplan.json + +**testplan-1.feature**: + +.. code:: gherkin + :name: fullname-feature-1 + + Feature: Allure testplan support + Scenario: Scenario selection + Given noop + + Scenario: Scenario deselection + Given noop + +**testplan-2.feature**: + +.. code:: gherkin + :name: fullname-feature-2 + + Feature: Allure testplan support 2 + Scenario: Scenario selection 2 + Given noop + + Scenario: Scenario deselection 2 + Given noop + +**steps.py**: + +.. code:: python + :name: steps + + from behave import given + + @given("noop") + def step_impl(context): + pass + +**testplan.json**: + +.. code:: json + :name: fullname-testplan + + { + "version":"1.0", + "tests": [ + { + "selector": "Allure testplan support: Scenario selection" + }, + { + "selector": "Allure testplan support 2: Scenario selection 2" + } + ] + } + +Now, when we run behave with allure and testplan enabled: + +**on Linux or MacOS, with bash**: + +.. code:: bash + + ALLURE_TESTPLAN_PATH=./testplan.json behave -f allure_behave.formatter:AllureFormatter -f pretty -o allure-results + +or: + +.. code:: bash + + export ALLURE_TESTPLAN_PATH=./testplan.json + behave -f allure_behave.formatter:AllureFormatter -f pretty -o allure-results + +**on Windows, with PowerShell**: + +.. code:: powershell + + $Env:ALLURE_TESTPLAN_PATH = "./testplan.json" + behave -f allure_behave.formatter:AllureFormatter -f pretty -o allure-results + +We can see, that only test cases, enumerated in the testplan, are executed:: + + Feature: Allure testplan support # features/testplan-1.feature:1 + + Scenario: Scenario selection # features/testplan-1.feature:2 + Given noop # features/steps/steps.py:3 0.000s + + Scenario: Scenario deselection # features/testplan-1.feature:5 + Given noop # None + + SKIP Scenario Scenario deselection 2: Not in allure test plan + Feature: Allure testplan support 2 # features/testplan-2.feature:1 + + Scenario: Scenario selection 2 # features/testplan-2.feature:2 + Given noop # features/steps/steps.py:3 0.000s + + Scenario: Scenario deselection 2 # features/testplan-2.feature:5 + Given noop # None + + 2 features passed, 0 failed, 0 skipped + 2 scenarios passed, 0 failed, 2 skipped + 2 steps passed, 0 failed, 2 skipped, 0 undefined + Took 0m0.000s + +------------------------------ +Select test cases by allure id +------------------------------ + +If you link you scenarios to corresponding test cases with the :code:`as_id` +label, you can filter them by those IDs instead: + +**testplan-1.feature**: + +.. code:: gherkin + :name: id-feature-1 + + Feature: Allure testplan support + @allure.label.as_id:1004 + Scenario: Scenario selection + Given noop + + @allure.label.as_id:1005 + Scenario: Scenario deselection + Given noop + +**testplan-2.feature**: + +.. code:: gherkin + :name: id-feature-2 + + Feature: Allure testplan support 2 + @allure.label.as_id:1006 + Scenario: Scenario selection 2 + Given noop + + @allure.label.as_id:1007 + Scenario: Scenario deselection 2 + Given noop + +**steps.py**: + +.. code:: json + :name: id-testplan + + { + "version":"1.0", + "tests": [ + {"id": "1004"}, + {"id": "1006"} + ] + } + +If we run behave with this testplan, the same set of scenarios will be executed. + +.. Note:: + + You can read more about allure labels support in behave + `here `_. + +--------------------- +Hiding excluded tests +--------------------- + +To hide tests, excluded by the testplan, add the +:code:`-D AllureFormatter.hide_excluded=True` argument: + +.. code:: shell + + behave -f allure_behave.formatter:AllureFormatter -D AllureFormatter.hide_excluded=True -f pretty -o allure-results + +Skipped tests will still be visible in the behave output, but they will not be +included in the allure report. diff --git a/allure-behave/features/background.feature b/allure-behave/features/background.feature deleted file mode 100644 index 53081104..00000000 --- a/allure-behave/features/background.feature +++ /dev/null @@ -1,43 +0,0 @@ -Feature: Background - - Scenario Outline: Background status - Given feature definition - """ - Feature: Background - - Background: Scenario background with step - Given step in background - And another passed step in background - - Scenario: Scenario with background contains step - Given passed step - And one more passed step - - Scenario: Another scenario with background contains step - Given passed step - """ - - When I run behave with allure formatter - - Then allure report has a scenario with name "Scenario with background contains step" - And this scenario has "" status - And this scenario contains step "Given step in background" - And this step has "" status - And this scenario contains step "And another passed step in background" - And this step has "" status - And this scenario contains step "Given passed step" - And this step has "" status - And this scenario contains step "And one more passed step" - And this step has "" status - - Then allure report has a scenario with name "Another scenario with background contains step" - And this scenario has "" status - And this scenario contains step "Given passed step" - And this step has "" status - - Examples: statuses - | step type | status | other status | - | passed | passed | passed | - | failed | failed | skipped | - | broken | broken | skipped | - | undefined | broken | skipped | diff --git a/allure-behave/features/description.feature b/allure-behave/features/description.feature deleted file mode 100644 index 3a8633b6..00000000 --- a/allure-behave/features/description.feature +++ /dev/null @@ -1,36 +0,0 @@ -Feature: Description - - Scenario: Use description - Given feature definition - """ - Feature: Description - - Scenario: Scenario with description - Scenario description. - Yep, multi-line description! - - Given simple passed step - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with description" - - Scenario: Dynamic description - Given feature definition - """ - Feature: Step status - - Scenario: Scenario with passed step - Given simple passed step - """ - And hooks implementation - """ - import allure - import allure_commons - - @allure_commons.fixture - def before_scenario(context, scenario): - allure.dynamic.description("Test description") - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with passed step" - And scenario has description "Test description" \ No newline at end of file diff --git a/allure-behave/features/hook.feature b/allure-behave/features/hook.feature deleted file mode 100644 index ffeda152..00000000 --- a/allure-behave/features/hook.feature +++ /dev/null @@ -1,248 +0,0 @@ -Feature: Hook - - Scenario Outline: Hook 'scenario' - Given feature definition - """ - Feature: Hook - Scenario: Scenario with " " hook - Given simple passed step - - Scenario: Another scenario with " " hook - Given simple passed step - """ - And hooks implementation - """ - import allure_commons - - - @allure_commons.fixture - def _(context, ): - pass - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with " " hook" - And this scenario has fixture " " - - Then allure report has a scenario with name "Another scenario with " " hook" - And this scenario has fixture " " - - Examples: fixtures - | when | where | - | before | scenario | - | after | scenario | - - - Scenario Outline: Hook 'tag' - Given feature definition - """ - Feature: Hook - - @tag_for_hook - Scenario: Scenario with " " hook - Given simple passed step - - Scenario: Another scenario without " " hook - Given simple passed step - """ - And hooks implementation - """ - import allure_commons - - - @allure_commons.fixture - def _(context, ): - pass - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with " " hook" - And this scenario has fixture " @tag_for_hook" - - Then allure report has a scenario with name "Another scenario without " " hook" - And this scenario has not fixture " @tag_for_hook" - - Examples: fixtures - | when | where | - | before | tag | - | after | tag | - - - Scenario Outline: Hook 'tag' - Given feature definition - """ - @tag_for_hook - Feature: Hook - - Scenario: Scenario with " " hook - Given simple passed step - - Scenario: Another scenario with " " hook - Given simple passed step - """ - And hooks implementation - """ - import allure_commons - - - @allure_commons.fixture - def _(context, ): - pass - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with " " hook" - And this scenario has fixture " @tag_for_hook" - - Then allure report has a scenario with name "Another scenario with " " hook" - And this scenario has fixture " @tag_for_hook" - - Examples: fixtures - | when | where | - | before | tag | - | after | tag | - - - Scenario Outline: Hook 'feature' - Given feature definition - """ - Feature: Hook - Scenario: Scenario with " " hook - Given simple passed step - - Scenario: Another scenario with " " hook - Given simple passed step - """ - And hooks implementation - """ - import allure_commons - - - @allure_commons.fixture - def _(context, ): - pass - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with " " hook" - And this scenario has fixture " " - - Then allure report has a scenario with name "Another scenario with " " hook" - And this scenario has fixture " " - - Examples: fixtures - | when | where | - | before | feature | - | after | feature | - - - Scenario Outline: Hook 'all' - Given feature definition - """ - Feature: Hook - Scenario: Scenario with " " hook - Given simple passed step - - Scenario: Another scenario with " " hook - Given simple passed step - """ - And hooks implementation - """ - import allure_commons - - - @allure_commons.fixture - def _(context): - pass - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with " " hook" - And this scenario has fixture " " - - Then allure report has a scenario with name "Another scenario with " " hook" - And this scenario has fixture " " - - Examples: fixtures - | when | where | - | before | all | - | after | all | - - - Scenario: Hook attachment - Given feature definition - """ - Feature: Hook - Scenario: Scenario with "before_feature" hook and attachment - Given simple passed step - """ - And hooks implementation - """ - import allure - import allure_commons - - - @allure_commons.fixture - def before_feature(context, feature): - allure.attach('Hi there!', name='user attachment', attachment_type=allure.attachment_type.TEXT) - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with "before_feature" hook and attachment" - And this scenario has before fixture "before feature" - And this before has attachment - - - Scenario Outline: Hook step as context - Given feature definition - """ - Feature: Hook - Scenario: Scenario with " " hook and step inside - Given simple passed step - """ - And hooks implementation - """ - import allure - import allure_commons - - - @allure_commons.fixture - def _(context, ): - with allure.step('Step inside fixture'): - pass - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with " " hook and step inside" - And this scenario has fixture " " - And this contains step "Step inside fixture" - - Examples: fixtures - | when | where | - | before | scenario | - | after | scenario | - - - Scenario Outline: Hook step as function - Given feature definition - """ - Feature: Hook - Scenario: Scenario with " " hook and step as function inside - Given simple passed step - """ - And hooks implementation - """ - import allure - import allure_commons - - @allure.step('Step function') - def step(): - pass - - @allure_commons.fixture - def _(context): - step() - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with " " hook and step as function inside" - And this scenario has fixture " " - And this contains step "Step function" - - Examples: fixtures - | when | where | - | before | all | - | after | all | - diff --git a/allure-behave/features/label.feature b/allure-behave/features/label.feature deleted file mode 100644 index 49aa9065..00000000 --- a/allure-behave/features/label.feature +++ /dev/null @@ -1,14 +0,0 @@ -Feature: Label - - Scenario: Scenario label - Given feature definition - """ - Feature: Step status - - @allure.label.owner:me - Scenario: Scenario with passed step - Given simple passed step - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with passed step" - And scenario has "owner" label with value "me" \ No newline at end of file diff --git a/allure-behave/features/link.feature b/allure-behave/features/link.feature deleted file mode 100644 index 82e490ae..00000000 --- a/allure-behave/features/link.feature +++ /dev/null @@ -1,65 +0,0 @@ -Feature: Link - - Scenario: Scenario issue link - Given feature definition - """ - Feature: Step status - - @allure.issue:http://qameta.io - Scenario: Scenario with passed step - Given simple passed step - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with passed step" - And scenario has "http://qameta.io" link with type "issue" - - Scenario: Feature user link - Given feature definition - """ - @allure.link.homepage:http://qameta.io - Feature: Step status - - Scenario: Scenario with passed step - Given simple passed step - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with passed step" - And scenario has "http://qameta.io" link - - Scenario: Feature and scenario user link - Given feature definition - """ - @allure.link.homepage:http://qameta.io - Feature: Step status - - @allure.issue:http://example.com - Scenario: Scenario with passed step - Given simple passed step - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with passed step" - And scenario has "http://qameta.io" link - And scenario has "http://example.com" link with type "issue" - - Scenario: Dynamic link - Given feature definition - """ - Feature: Step status - - Scenario: Scenario with passed step - Given simple passed step - """ - And hooks implementation - """ - import allure - import allure_commons - - @allure_commons.fixture - def before_scenario(context, scenario): - allure.dynamic.link("http://qameta.io") - allure.dynamic.issue("http://example.com") - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with passed step" - And scenario has "http://qameta.io" link - And scenario has "http://example.com" link with type "issue" \ No newline at end of file diff --git a/allure-behave/features/no_skipped.feature b/allure-behave/features/no_skipped.feature deleted file mode 100644 index dffacae9..00000000 --- a/allure-behave/features/no_skipped.feature +++ /dev/null @@ -1,38 +0,0 @@ -Feature: Behave cmd options - - Scenario: Tags in scenario with options "--tags=tag" - Given feature definition - """ - Feature: Tags filtering - - @tag - Scenario: Scenario with tag - Given simple passed step - - Scenario: Scenario without tag - Given simple passed step - """ - When I run behave with allure formatter with options "--tags=tag" - Then allure report has a scenario with name "Scenario with tag" - And this scenario has "passed" status - - Then allure report has a scenario with name "Scenario without tag" - And this scenario has "skipped" status - - Scenario: Tags in scenario with options "--tags=tag --no-skipped" - Given feature definition - """ - Feature: Tags filtering - - @tag - Scenario: Scenario with tag - Given simple passed step - - Scenario: Scenario without tag - Given simple passed step - """ - When I run behave with allure formatter with options "--tags=tag --no-skipped" - Then allure report has a scenario with name "Scenario with tag" - And this scenario has "passed" status - - Then allure report has not a scenario with name "Scenario without tag" diff --git a/allure-behave/features/scenario.feature b/allure-behave/features/scenario.feature deleted file mode 100644 index 6b2f8268..00000000 --- a/allure-behave/features/scenario.feature +++ /dev/null @@ -1,58 +0,0 @@ -Feature: Scenario - - Scenario Outline: Scenario status - Given feature definition - """ - Feature: Scenario - - Scenario: Scenario with step - Given step - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with step" - And this scenario has "" status - And this scenario contains step "Given step" - And this step has "" status - - Examples: statuses - | step type | status | - | passed | passed | - | failed | failed | - | broken | broken | - | undefined | broken | - - - Scenario: Skip steps after fail step - Given feature definition - """ - Feature: Scenario - - Scenario: Scenario with failed step in chain - Given passed step - Given failed step - Given broken step - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with failed step in chain" - And this scenario has "failed" status - - And this scenario contains step "Given passed step" - And this step has "passed" status - - And this scenario contains step "Given failed step" - And this step has "failed" status - - And this scenario contains step "Given broken step" - And this step has "skipped" status - - - Scenario: Scenario without name - Given feature definition - """ - Feature: Scenario - - Scenario: - Given passed step - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario" diff --git a/allure-behave/features/scenario_outline.feature b/allure-behave/features/scenario_outline.feature deleted file mode 100644 index 60907c9f..00000000 --- a/allure-behave/features/scenario_outline.feature +++ /dev/null @@ -1,126 +0,0 @@ -Feature: Scenario Outline - - Scenario: Scenario outline with one examples table - Given feature definition - """ - Feature: Scenario Outline - - Scenario Outline: Scenario outline with one examples table - Given simple passed step with param "" - - Examples: examples table - | user | - | Alice | - | Bob | - """ - When I run behave with allure formatter - - Then allure report has a scenario with name "Scenario outline with one examples table -- @1.1 examples table" - And scenario contains step "Given simple passed step with param "Alice"" - And this scenario has parameter "user" with value "Alice" - - Then allure report has a scenario with name "Scenario outline with one examples table -- @1.2 examples table" - And scenario contains step "Given simple passed step with param "Bob"" - And this scenario has parameter "user" with value "Bob" - - Scenario: Scenario outline with many examples table - Given feature definition - """ - Feature: Scenario Outline - - Scenario Outline: Scenario outline with many examples table - Given simple passed step with params " " - - Examples: first table - | parameter one | parameter two | - | Peter | I | - | Catherine | II | - - Examples: second table - | parameter one | parameter two | - | Richard | the Lionheart | - | Alexander | the Great | - """ - When I run behave with allure formatter - - Then allure report has a scenario with name "Scenario outline with many examples table -- @1.1 first table" - And scenario contains step "Given simple passed step with params "Peter I"" - And this scenario has parameter "parameter one" with value "Peter" - And this scenario has parameter "parameter two" with value "I" - - Then allure report has a scenario with name "Scenario outline with many examples table -- @1.2 first table" - And scenario contains step "Given simple passed step with params "Catherine II"" - And this scenario has parameter "parameter one" with value "Catherine" - And this scenario has parameter "parameter two" with value "II" - - Then allure report has a scenario with name "Scenario outline with many examples table -- @2.1 second table" - And scenario contains step "Given simple passed step with params "Richard the Lionheart"" - And this scenario has parameter "parameter one" with value "Richard" - And this scenario has parameter "parameter two" with value "the Lionheart" - - Then allure report has a scenario with name "Scenario outline with many examples table -- @2.2 second table" - And scenario contains step "Given simple passed step with params "Alexander the Great"" - And this scenario has parameter "parameter one" with value "Alexander" - And this scenario has parameter "parameter two" with value "the Great" - - - Scenario: Many scenario outlines with one examples table - Given feature definition - """ - Feature: Scenario Outline - - Scenario Outline: First scenario outline in feature - Given simple passed step with param "" - - Examples: examples table - | friend | - | Rick | - | Morty | - - - Scenario Outline: Second scenario outline in feature - Given simple passed step with param "" - - Examples: examples table - | hero | - | Finn | - | Jack | - """ - When I run behave with allure formatter - - Then allure report has a scenario with name "First scenario outline in feature -- @1.1 examples table" - And scenario contains step "Given simple passed step with param "Rick"" - And this scenario has parameter "friend" with value "Rick" - - Then allure report has a scenario with name "First scenario outline in feature -- @1.2 examples table" - And scenario contains step "Given simple passed step with param "Morty"" - And this scenario has parameter "friend" with value "Morty" - - Then allure report has a scenario with name "Second scenario outline in feature -- @1.1 examples table" - And scenario contains step "Given simple passed step with param "Finn"" - And this scenario has parameter "hero" with value "Finn" - - Then allure report has a scenario with name "Second scenario outline in feature -- @1.2 examples table" - And scenario contains step "Given simple passed step with param "Jack"" - And this scenario has parameter "hero" with value "Jack" - - Scenario Outline: Scenario outline with one examples table - Given feature definition - """ - Feature: Scenario Outline - - Scenario Outline: Scenario outline with example variable in name - Given simple passed step with param "" - - Examples: examples table - | user | - | Alice | - | Bob | - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario outline with example variable in name " - - Examples: examples table - | user | postfix | - | Alice | -- @1.1 examples table | - | Bob | -- @1.2 examples table | \ No newline at end of file diff --git a/allure-behave/features/severity.feature b/allure-behave/features/severity.feature deleted file mode 100644 index fcbc289c..00000000 --- a/allure-behave/features/severity.feature +++ /dev/null @@ -1,70 +0,0 @@ -Feature: Severity - - Scenario: Default severity is normal - Given feature definition - """ - Feature: Severity - - Scenario: Scenario and feature without severity - Given simple passed step - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario and feature without severity" - And scenario has "normal" severity - - - Scenario: Severity tag in feature - Given feature definition - """ - @critical - Feature: Severity - - Scenario: Scenario in feature with critical severity - Given simple passed step - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario in feature with critical severity" - And scenario has "critical" severity - - - Scenario: Severity tag in scenario - Given feature definition - """ - Feature: Severity - - @critical - Scenario: Scenario with critical severity in feature without severity - Given simple passed step - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with critical severity in feature without severity" - And scenario has "critical" severity - - - Scenario: Severity tag in scenario and feature - Given feature definition - """ - @critical - Feature: Severity - - @minor - Scenario: Scenario with minor severity in feature with critical severity - Given simple passed step - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with minor severity in feature with critical severity" - And scenario has "minor" severity - - - Scenario: Repeated severity tag - Given feature definition - """ - Feature: Severity - - @minor @critical @blocker - Scenario: Scenario with repeated severity tag - Given simple passed step - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with repeated severity tag" - And scenario has "blocker" severity \ No newline at end of file diff --git a/allure-behave/features/step.feature b/allure-behave/features/step.feature deleted file mode 100644 index 7b434b5d..00000000 --- a/allure-behave/features/step.feature +++ /dev/null @@ -1,101 +0,0 @@ -Feature: Step - - Scenario: Failed step - Given feature definition - """ - Feature: Step status - - Scenario: Scenario with failed step - Given simple failed step - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with failed step" - And scenario contains step "Given simple failed step" - And this step has "failed" status - And this step has status details with message "AssertionError: Assert message" - - - Scenario: Broken step - Given feature definition - """ - Feature: Step status - - Scenario: Scenario with broken step - Given simple broken step - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with broken step" - And scenario contains step "Given simple broken step" - And this step has "broken" status - And this step has status details with message "ZeroDivisionError" - - - Scenario: Step text parameter - Given feature definition - """ - Feature: Step Data - - Scenario: Scenario with step contains text data - Given simple passed step with text data - ''' - Some text in step - ''' - And simple passed step - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with step contains text data" - And scenario contains step "Given simple passed step with text data" - And this step has attachment - And this step has "passed" status - - - Scenario: Step table parameter - Given feature definition - """ - Feature: Step Data - - Scenario: Scenario with step contains table data - Given simple passed step with table data - | name | value | - | e | 2 | - | e | 4 | - - And simple passed step - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with step contains table data" - And scenario contains step "Given simple passed step with table data" - And this step has attachment - And this step has "passed" status - - - Scenario: Step attachment - Given feature definition - """ - Feature: Step Data - - Scenario: Scenario with step that attached data - Given passed step with attachment - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with step that attached data" - And scenario contains step "Given passed step with attachment" - And this step has attachment - And this step has "passed" status - - Scenario: Step with table data containing comma - Given feature definition - """ - Feature: Step with data - - Scenario: Step with a table data containing comma - Given step with a table data - |Items A|Items B| - |Item 1, Item 2|Item 3, Item 4| - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Step with a table data containing comma" - And scenario contains step "Given step with a table data" - And this step has attachment ".table" with the following data - |Items A|Items B| - |Item 1, Item 2|Item 3, Item 4| \ No newline at end of file diff --git a/allure-behave/features/steps/behave_steps.py b/allure-behave/features/steps/behave_steps.py deleted file mode 100644 index b90f54dc..00000000 --- a/allure-behave/features/steps/behave_steps.py +++ /dev/null @@ -1,73 +0,0 @@ -import os -from tempfile import mkdtemp -import allure_commons -from allure_commons_test.report import AllureReport -from behave.parser import Parser -from behave.runner import ModelRunner -from behave.configuration import Configuration -from behave.formatter._registry import make_formatters -from behave.formatter.base import StreamOpener -import tempfile -from contextlib import contextmanager - - -@given('feature definition') -@given('feature definition {lang}') -def feature_definition(context, **kwargs): - parser = Parser(language=kwargs.get('lang', None)) - feature = parser.parse(context.text) - if hasattr(context, "feature_definition"): - context.feature_definition.append(feature) - else: - context.feature_definition = [feature] - - -@given('hooks implementation') -def hooks_implementations(context): - context.globals = {} - exec(context.text, context.globals) - - -@given('test plan') -def test_plan_helper(context): - tmp_dir = os.environ.get("TEST_TMP") - file, filename = tempfile.mkstemp(suffix=".json", dir=tmp_dir) - os.environ["ALLURE_TESTPLAN_PATH"] = filename - with os.fdopen(file, 'w') as tmp: - tmp.write(context.text) - context.test_plan = filename - - -@when('I run behave with allure formatter') -@when('I run behave with allure formatter with options "{args}"') -def run_behave_with_allure(context, **kwargs): - with test_context(): - cmd_args = '-f allure_behave.formatter:AllureFormatter' - cmd_options = kwargs.get('args', '') - cmd = f'{cmd_options} {cmd_args}' - config = Configuration(command_args=cmd) - result_tmp_dir = mkdtemp(dir=os.environ.get('TEST_TMP', None)) - stream_opener = StreamOpener(filename=result_tmp_dir) - model_runner = ModelRunner(config, context.feature_definition) - model_runner.formatters = make_formatters(config, [stream_opener]) - model_runner.hooks = getattr(context, 'globals', dict()) - model_runner.run() - context.allure_report = AllureReport(result_tmp_dir) - - os.environ.pop("ALLURE_TESTPLAN_PATH", None) - - -@contextmanager -def test_context(): - def _unregister_plugins(): - plugins = [] - for name, plugin in allure_commons.plugin_manager.list_name_plugin(): - allure_commons.plugin_manager.unregister(plugin=plugin, name=name) - plugins.append(plugin) - return plugins - - plugins = _unregister_plugins() - yield - _unregister_plugins() - for plugin in plugins: - allure_commons.plugin_manager.register(plugin) diff --git a/allure-behave/features/steps/dummy_steps.py b/allure-behave/features/steps/dummy_steps.py deleted file mode 100644 index e63705ad..00000000 --- a/allure-behave/features/steps/dummy_steps.py +++ /dev/null @@ -1,49 +0,0 @@ -import allure -from behave import given - - -@given('passed step') -@given('{what} passed step') -@given('passed step {where}') -@given('{what} passed step {where}') -def step_impl(*args, **kwargs): - if 'with attachment' in kwargs.values(): - allure.attach('Hi there!', name='user attachment', attachment_type=allure.attachment_type.TEXT) - pass - - -@given('failed step') -@given('{what} failed step') -@given('failed step {where}') -@given('{what} failed step {where}') -def step_impl(*args, **kwargs): - assert False, 'Assert message' - - -@given('провальный шаг') -def step_impl(*args, **kwargs): - assert False, 'Фиаско!' - - -@given('провальный шаг с ascii') -def step_impl(*args, **kwargs): - assert False, 'Фиаско!' - - -@given('проходящий шаг') -def step_impl(*args, **kwargs): - pass - - -@given('broken step') -@given('{what} broken step') -@given('broken step {where}') -@given('{what} broken step {where}') -def step_impl(*args, **kwargs): - raise ZeroDivisionError() - - -@given('всегда будет <это>') -@given('всегда буду я') -def step_impl(*args, **kwargs): - pass diff --git a/allure-behave/features/steps/report_steps.py b/allure-behave/features/steps/report_steps.py deleted file mode 100644 index 0e82fe65..00000000 --- a/allure-behave/features/steps/report_steps.py +++ /dev/null @@ -1,193 +0,0 @@ -from functools import partial -from hamcrest import assert_that, contains_string -from hamcrest import not_ -from hamcrest import equal_to -from allure_commons.types import AttachmentType -from allure_commons_test.report import has_test_case -from allure_commons_test.result import with_status -from allure_commons_test.result import has_step -from allure_commons_test.result import has_attachment -from allure_commons_test.result import has_attachment_with_content -from allure_commons_test.result import has_parameter -from allure_commons_test.result import has_status_details -from allure_commons_test.result import with_message_contains -from allure_commons_test.result import has_link -from allure_commons_test.result import has_description -from allure_commons_test.container import has_container -from allure_commons_test.container import has_before, has_after -from allure_commons_test.content import csv_equivalent -from allure_commons_test.label import has_severity -from allure_commons_test.label import has_tag -from allure_commons_test.label import has_label - - -def match(matcher, *args): - for i, arg in enumerate(args): - if not hasattr(arg, '__call__'): - matcher = partial(matcher, arg) - else: - matcher = partial(matcher, match(arg, *args[i+1:])) - break - return matcher() - - -@then('allure report has a scenario with name "{scenario}"') -def step_scenario(context, scenario): - matcher = partial(match, has_test_case, scenario) - context.scenario = matcher - assert_that(context.allure_report, matcher()) - - -@then('allure report has not a scenario with name "{scenario}"') -def step_scenario(context, scenario): - matcher = partial(match, not_, has_test_case, scenario) - context.scenario = matcher - assert_that(context.allure_report, matcher()) - - -@then('scenario has before fixture "{fixture}"') -@then('this scenario has before fixture "{fixture}"') -def step_before_fixture(context, fixture): - context_matcher = context.scenario - matcher = partial(context_matcher, has_container, context.allure_report, has_before, fixture) - context.before = matcher - assert_that(context.allure_report, matcher()) - - -@then('scenario has after fixture "{fixture}"') -@then('this scenario has after fixture "{fixture}"') -def step_after_fixture(context, fixture): - context_matcher = context.scenario - matcher = partial(context_matcher, has_container, context.allure_report, has_after, fixture) - context.after = matcher - assert_that(context.allure_report, matcher()) - - -@then('scenario has not before fixture "{fixture}"') -@then('this scenario has not before fixture "{fixture}"') -def step_no_before_fixture(context, fixture): - context_matcher = context.scenario - matcher = partial(context_matcher, not_, has_container, context.allure_report, has_before, fixture) - assert_that(context.allure_report, matcher()) - - -@then('scenario has not after fixture "{fixture}"') -@then('this scenario has not after fixture "{fixture}"') -def step_impl(context, fixture): - context_matcher = context.scenario - matcher = partial(context_matcher, not_, has_container, context.allure_report, has_after, fixture) - assert_that(context.allure_report, matcher()) - - -@then('{item} contains step "{step}"') -@then('this {item} contains step "{step}"') -def step_step(context, item, step): - context_matcher = getattr(context, item) - matcher = partial(context_matcher, has_step, step) - context.step = matcher - assert_that(context.allure_report, matcher()) - - -@then('{item} has "{status}" status') -@then('this {item} has "{status}" status') -def step_status(context, item, status): - context_matcher = getattr(context, item) - matcher = partial(context_matcher, with_status, status) - assert_that(context.allure_report, matcher()) - - -@then('{item} has status details with message "{message}"') -@then('this {item} has status details with message "{message}"') -def step_status(context, item, message): - context_matcher = getattr(context, item) - matcher = partial(context_matcher, has_status_details, with_message_contains, message) - assert_that(context.allure_report, matcher()) - - -@then('scenario has "{severity}" severity') -@then('this scenario has "{severity}" severity') -def step_severity(context, severity): - context_matcher = context.scenario - matcher = partial(context_matcher, has_severity, severity) - assert_that(context.allure_report, matcher()) - - -@then('scenario has "{tag}" tag') -@then('this scenario has "{tag}" tag') -def step_tag(context, tag): - context_matcher = context.scenario - matcher = partial(context_matcher, has_tag, tag) - assert_that(context.allure_report, matcher()) - - -@then('scenario has "{url}" link') -@then('this scenario has "{url}" link') -@then('scenario has "{url}" link with type "{link_type}"') -@then('this scenario has "{url}" link with type "{link_type}"') -@then('scenario has "{url}" link with type "{link_type}" and name "{name}"') -@then('this scenario has "{url}" link with type "{link_type}" and name "{name}"') -def step_link(context, url, link_type=None, name=None,): - context_matcher = context.scenario - matcher = partial(context_matcher, has_link, url, link_type, name) - assert_that(context.allure_report, matcher()) - - -@then('scenario has "{name}" label with value "{value}"') -@then('this scenario has "{name}" label with value "{value}"') -def step_label(context, name, value): - context_matcher = context.scenario - matcher = partial(context_matcher, has_label, name, value) - assert_that(context.allure_report, matcher()) - - -@then('{item} has parameter "{name}" with value "{value}"') -@then('this {item} has parameter "{name}" with value "{value}"') -def step_parameter(context, item, name, value): - context_matcher = getattr(context, item) - matcher = partial(context_matcher, has_parameter, name, value) - assert_that(context.allure_report, matcher()) - - -@then('{item} has attachment') -@then('this {item} has attachment') -def step_attachment(context, item): - context_matcher = getattr(context, item) - matcher = partial(context_matcher, has_attachment) - assert_that(context.allure_report, matcher()) - - -@then('this {item} has attachment "{name}" with the following data') -def step_attachment_data(context, item, name): - context_matcher = getattr(context, item) - attachment_type, content_matcher = _get_attachment_type_and_matcher(context) - matcher = partial( - context_matcher, - partial( - has_attachment_with_content, - context.allure_report.attachments, - content_matcher, - attachment_type.mime_type, - name - ) - ) - assert_that(context.allure_report, matcher()) - - -@then('scenario has description "{description}"') -def step_description(context, description): - context_matcher = context.scenario - matcher = partial(context_matcher, has_description, contains_string(description)) - assert_that(context.allure_report, matcher()) - -def _get_attachment_type_and_matcher(context): - return ( - AttachmentType.CSV, - csv_equivalent( - [context.table.headings] + [ - r.cells for r in context.table.rows - ] - ) - ) if context.table is not None else ( - AttachmentType.TEXT, - equal_to(context.text) - ) \ No newline at end of file diff --git a/allure-behave/features/tag.feature b/allure-behave/features/tag.feature deleted file mode 100644 index 5e1d8002..00000000 --- a/allure-behave/features/tag.feature +++ /dev/null @@ -1,50 +0,0 @@ -Feature: Tags - - Scenario: Tags in feature - Given feature definition - """ - @uno @due @tre - Feature: Tags - - Scenario: Scenario in feature with tags - Given simple passed step - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario in feature with tags" - And scenario has "uno" tag - And scenario has "due" tag - And scenario has "tre" tag - - - Scenario: Tags in scenario - Given feature definition - """ - Feature: Tags - - @uno @due @tre - Scenario: Scenario with tags - Given simple passed step - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with tags" - And scenario has "uno" tag - And scenario has "due" tag - And scenario has "tre" tag - - - Scenario: Tags in feature and scenario - Given feature definition - """ - @uno @due @tre - Feature: Tags - - @tre @quattro - Scenario: Scenario and feature with tags - Given simple passed step - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario and feature with tags" - And scenario has "uno" tag - And scenario has "due" tag - And scenario has "tre" tag - And scenario has "quattro" tag diff --git a/allure-behave/features/test_plan.feature b/allure-behave/features/test_plan.feature deleted file mode 100644 index 91063178..00000000 --- a/allure-behave/features/test_plan.feature +++ /dev/null @@ -1,130 +0,0 @@ -Feature: Test plan - Scenario: Select scenarios by fullname - Given feature definition - """ - Feature: Test plan example - - Scenario: Scenario with passed step - Given passed step - - Scenario: Ignored scenario - Given passed step - """ - Given feature definition - """ - Feature: Another Test plan example - - Scenario: Another scenario with passed step - Given passed step - - Scenario: Another ignored scenario - Given passed step - """ - Given test plan - """ - { - "version":"1.0", - "tests": [ - { - "selector": "Test plan example: Scenario with passed step" - }, - { - "selector": "Another Test plan example: Another scenario with passed step" - } - ] - } - """ - When I run behave with allure formatter - Then allure report has a scenario with name "Scenario with passed step" - Then allure report has a scenario with name "Ignored scenario" - And this scenario has "skipped" status - Then allure report has a scenario with name "Another scenario with passed step" - Then allure report has a scenario with name "Another ignored scenario" - And this scenario has "skipped" status - - Scenario: Drop unselected test from report - Given feature definition - """ - Feature: Test plan example - - Scenario: Scenario with passed step - Given passed step - - Scenario: Ignored scenario - Given passed step - """ - Given feature definition - """ - Feature: Another Test plan example - - Scenario: Another scenario with passed step - Given passed step - - Scenario: Another ignored scenario - Given passed step - """ - Given test plan - """ - { - "version":"1.0", - "tests": [ - { - "selector": "Test plan example: Scenario with passed step" - }, - { - "selector": "Another Test plan example: Another scenario with passed step" - } - ] - } - """ - When I run behave with allure formatter with options "-D AllureFormatter.hide_excluded=True" - Then allure report has a scenario with name "Scenario with passed step" - Then allure report has not a scenario with name "Ignored scenario" - Then allure report has a scenario with name "Another scenario with passed step" - Then allure report has not a scenario with name "Another ignored scenario" - - - Scenario: Select scenarios by allureid - Given feature definition - """ - Feature: Test plan example - - @allure.as_id:1 - Scenario: Scenario with passed step - Given passed step - - @allure.as_id:2 - Scenario: Ignored scenario - Given passed step - """ - Given feature definition - """ - Feature: Another Test plan example - - @allure.as_id:3 - Scenario: Another scenario with passed step - Given passed step - - @allure.as_id:4 - Scenario: Another ignored scenario - Given passed step - """ - Given test plan - """ - { - "version":"1.0", - "tests": [ - { - "id": "1" - }, - { - "id": "3" - } - ] - } - """ - When I run behave with allure formatter with options "-D AllureFormatter.hide_excluded=True" - Then allure report has a scenario with name "Scenario with passed step" - Then allure report has not a scenario with name "Ignored scenario" - Then allure report has a scenario with name "Another scenario with passed step" - Then allure report has not a scenario with name "Another ignored scenario" \ No newline at end of file diff --git a/allure-behave/features/unicode.feature b/allure-behave/features/unicode.feature deleted file mode 100644 index 67a42fec..00000000 --- a/allure-behave/features/unicode.feature +++ /dev/null @@ -1,49 +0,0 @@ -Feature: Language - Scenario: Use russian - Given feature definition ru - """ - Свойство: Юникод - - Структура сценария: Солнечный круг, небо вокруг - Пусть всегда будет <это> - Пусть всегда буду я - Примеры: - | это | - | солнце | - | небо | - | мама | - """ - When I run behave with allure formatter with options "--lang ru" - Then allure report has a scenario with name "Солнечный круг, небо вокруг" - And scenario contains step "Пусть всегда будет солнце" - And scenario contains step "Пусть всегда будет небо" - And scenario contains step "Пусть всегда будет мама" - And scenario contains step "Пусть всегда буду я" - - - Scenario: Assert message in step - Given feature definition ru - """ - Свойство: Юникод - - Сценарий: Ошибка с utf-8 сообщением - Допустим провальный шаг - """ - When I run behave with allure formatter with options "--lang ru" - Then allure report has a scenario with name "Ошибка с utf-8 сообщением" - And scenario contains step "Допустим провальный шаг" - And step has status details with message "AssertionError: Фиаско!" - - - Scenario: ASCII assert message in step - Given feature definition ru - """ - Свойство: Юникод - - Сценарий: Ошибка с utf-8 сообщением - Допустим провальный шаг с ascii - """ - When I run behave with allure formatter with options "--lang ru" - Then allure report has a scenario with name "Ошибка с utf-8 сообщением" - And scenario contains step "Допустим провальный шаг с ascii" - And step has status details with message "AssertionError: Фиаско!" diff --git a/allure-behave/pyproject.toml b/allure-behave/pyproject.toml index f25e40b6..83bfa75b 100644 --- a/allure-behave/pyproject.toml +++ b/allure-behave/pyproject.toml @@ -1,4 +1,3 @@ [tool.poe.tasks] linter = "flake8 --extend-ignore=A003 ./src" -tests = """behave -f allure_behave.formatter:AllureFormatter -o allure-results - -f pretty ./features""" +tests = """pytest ../tests/allure_behave""" diff --git a/allure-behave/requirements.txt b/allure-behave/requirements.txt index a990291a..f946db6e 100644 --- a/allure-behave/requirements.txt +++ b/allure-behave/requirements.txt @@ -1,3 +1,3 @@ -poethepoet -# linters -flake8 +-r ../requirements/testing.txt +-r ../requirements/linting.txt +-r ../requirements/testing/allure-behave.txt diff --git a/allure-behave/src/listener.py b/allure-behave/src/listener.py index fbcac3cd..dab47789 100644 --- a/allure-behave/src/listener.py +++ b/allure-behave/src/listener.py @@ -217,7 +217,7 @@ def enter(self): self._logger.start_group(group.uuid, group) self._groups.append(group) - def exit(self): + def exit(self): # noqa: A003 group = self._groups.pop() if group.befores or group.afters: self._logger.stop_group(group.uuid) diff --git a/allure-nose2/pyproject.toml b/allure-nose2/pyproject.toml index 0916246f..fc8c91d9 100644 --- a/allure-nose2/pyproject.toml +++ b/allure-nose2/pyproject.toml @@ -1,4 +1,3 @@ [tool.poe.tasks] -linter = "flake8 ./src ./test" -tests = """nose2 --plugin=test.example_loader --plugin=allure_nose2.plugin --allure - --current-example -t . -s ./test""" +linter = "flake8 ./src" +tests = """pytest ../tests/allure_nose2""" diff --git a/allure-nose2/requirements.txt b/allure-nose2/requirements.txt index b7bb2e3a..6bc47501 100644 --- a/allure-nose2/requirements.txt +++ b/allure-nose2/requirements.txt @@ -1,4 +1,3 @@ -poethepoet -# linters -flake8 -flake8-builtins \ No newline at end of file +-r ../requirements/testing.txt +-r ../requirements/linting.txt +-r ../requirements/testing/allure-nose2.txt diff --git a/allure-nose2/src/plugin.py b/allure-nose2/src/plugin.py index 0e5f936f..c7f64608 100644 --- a/allure-nose2/src/plugin.py +++ b/allure-nose2/src/plugin.py @@ -47,7 +47,7 @@ class Allure(Plugin): commandLineSwitch = (None, "allure", "Generate an Allure report") def __init__(self, *args, **kwargs): - super(Allure, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self._host = host_tag() self._thread = thread_tag() self.lifecycle = AllureLifecycle() diff --git a/allure-nose2/test/example_loader.py b/allure-nose2/test/example_loader.py deleted file mode 100644 index e4e3f167..00000000 --- a/allure-nose2/test/example_loader.py +++ /dev/null @@ -1,29 +0,0 @@ -import sys -import types -from importlib import util -from doctest import script_from_examples -from nose2 import events - - -class CurrentExample(events.Plugin): - commandLineSwitch = (None, "current-example", "Method docstring to module") - - def __init__(self, *args, **kwargs): - super(CurrentExample, self).__init__(*args, **kwargs) - self._current_docstring = "" - - def startTest(self, event): - if hasattr(event.test, "_testFunc"): - self._current_docstring = event.test._testFunc.__doc__ - else: - self._current_docstring = event.test._testMethodDoc - - def get_example_module(self): - module = types.ModuleType("stub") - if self._current_docstring: - code = script_from_examples(self._current_docstring) - spec = util.spec_from_loader("example_module", origin="example_module", loader=None) - module = util.module_from_spec(spec) - exec(code, module.__dict__) - sys.modules['example_module'] = module - return module diff --git a/allure-nose2/test/example_runner.py b/allure-nose2/test/example_runner.py deleted file mode 100644 index eb2b5219..00000000 --- a/allure-nose2/test/example_runner.py +++ /dev/null @@ -1,62 +0,0 @@ -import io -import sys -from contextlib import ContextDecorator, redirect_stdout, redirect_stderr -from nose2 import main -from allure_commons import plugin_manager -from allure_commons.logger import AllureMemoryLogger -from allure_commons.logger import AllureFileLogger -from .example_loader import CurrentExample - -_Allure = sys.modules['allure_nose2.plugin'].Allure - - -class TestAllure(_Allure): - commandLineSwitch = (None, "test-allure", "Generate an Allure report") - - def register_allure_plugins(self): - self.fileLoger = AllureFileLogger("examples") - self.logger = AllureMemoryLogger() - plugin_manager.register(self.fileLoger) - plugin_manager.register(self.listener) - plugin_manager.register(self.logger) - - def unregister_allure_plugins(self): - plugin_manager.unregister(plugin=self.fileLoger) - plugin_manager.unregister(plugin=self.listener) - plugin_manager.unregister(plugin=self.logger) - - -def get_plugin(instance, plugin): - return next(iter([p for p in instance.getCurrentSession().plugins if isinstance(p, plugin)])) - - -class test_context(ContextDecorator): - def __enter__(self): - get_plugin(main, _Allure).unregister_allure_plugins() - - def __exit__(self, exc_type, exc_val, exc_tb): - get_plugin(main, _Allure).register_allure_plugins() - - -@test_context() -def run_docstring_example(**kwargs): - kwargs['exit'] = False - # kwargs['plugins'] = ["test.common", "nose2.plugins.mp"] - # kwargs['argv'] = ('nose2', '--test-allure', '--processes=2') - - kwargs['plugins'] = ["test.example_runner"] - kwargs['argv'] = ('nose2', '--test-allure') - - kwargs['module'] = get_plugin(main, CurrentExample).get_example_module() - - test_nose2 = type("TestNose2", (main,), {}) - stdout = io.StringIO() - stderr = io.StringIO() - - with redirect_stderr(stderr): - with redirect_stdout(stdout): - test_nose2_instance = test_nose2(**kwargs) - - # test_nose2_instance = test_nose2(**kwargs) - - return get_plugin(test_nose2_instance, _Allure).logger diff --git a/allure-nose2/test/labels/test_bdd_labels.py b/allure-nose2/test/labels/test_bdd_labels.py deleted file mode 100644 index 6277a893..00000000 --- a/allure-nose2/test/labels/test_bdd_labels.py +++ /dev/null @@ -1,85 +0,0 @@ -import unittest -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.label import has_epic -from allure_commons_test.label import has_feature -from test.example_runner import run_docstring_example - - -class TestBDDLabel(unittest.TestCase): - def test_method_label(self): - """ - >>> import unittest - >>> import allure - - >>> class TestBDDLabelExample(unittest.TestCase): - ... @allure.epic("Label", "Bdd") - ... @allure.feature("Method label") - ... def test_method_label_example(self): - ... pass - """ - allure_report = run_docstring_example() - assert_that(allure_report, - has_test_case("test_method_label_example", - has_epic("Label"), - has_epic("Bdd"), - has_feature("Method label") - ) - ) - - def test_class_label(self): - """ - >>> import unittest - >>> import allure - - >>> @allure.epic("Label", "Bdd") - ... class TestBDDLabelExample(unittest.TestCase): - ... def test_class_label_example(self): - ... pass - """ - allure_report = run_docstring_example() - assert_that(allure_report, - has_test_case("test_class_label_example", - has_epic("Label"), - has_epic("Bdd"), - ) - ) - - def test_class_method_label(self): - """ - >>> import unittest - >>> import allure - - >>> @allure.epic("Label", "Bdd") - ... class TestBDDLabelExample(unittest.TestCase): - ... @allure.feature("Method label") - ... def test_class_and_method_label_example(self): - ... pass - """ - allure_report = run_docstring_example() - assert_that(allure_report, - has_test_case("test_class_and_method_label_example", - has_epic("Label"), - has_epic("Bdd"), - has_feature("Method label") - ) - ) - - -def test_func_label(): - """ - >>> import allure - - >>> @allure.epic("Label", "Bdd") - ... @allure.feature("Function label") - ... def test_func_label_example(): - ... pass - """ - allure_report = run_docstring_example() - assert_that(allure_report, - has_test_case("test_func_label_example", - has_epic("Label"), - has_epic("Bdd"), - has_feature("Function label") - ) - ) diff --git a/allure-nose2/test/parametrized/test_parametrized.py b/allure-nose2/test/parametrized/test_parametrized.py deleted file mode 100644 index 1aff1fd1..00000000 --- a/allure-nose2/test/parametrized/test_parametrized.py +++ /dev/null @@ -1,59 +0,0 @@ -from nose2.tools import params -import unittest -from test.example_runner import run_docstring_example -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_parameter -from allure_commons.utils import represent - - -@params( - (("alpha", "hello"), ("betta", 42)), - (("alpha", "world"), ("betta", 777)) -) -def test_parametrized_func(first, second): - """ - >>> from nose2.tools import params - - >>> @params(("hello", 42), ("world", 777)) - ... def test_parametrized_func_example(alpha, betta): - ... pass - """ - first_param_name, first_param_value = first - second_param_name, second_param_value = second - - allure_report = run_docstring_example() - assert_that(allure_report, - has_test_case("test_parametrized_func_example", - has_parameter(first_param_name, represent(first_param_value)), - has_parameter(second_param_name, represent(second_param_value)) - ) - ) - - -class TestParametrized(unittest.TestCase): - - @params( - (("bravo", {"hello": 4}), ("charlie", [4, 2])), - (("bravo", {"wold": 2}), ("charlie", [7, 7, 7])) - ) - def test_parametrized_method(self, first, second): - """ - >>> import unittest - >>> from nose2.tools import params - - >>> class TestParametrizedExample(unittest.TestCase): - ... @params(({"hello": 4}, [4, 2]), ({"wold": 2}, [7, 7, 7])) - ... def test_parametrized_method_example(self, bravo, charlie): - ... pass - """ - first_param_name, first_param_value = first - second_param_name, second_param_value = second - - allure_report = run_docstring_example() - assert_that(allure_report, - has_test_case("test_parametrized_method_example", - has_parameter(first_param_name, represent(first_param_value)), - has_parameter(second_param_name, represent(second_param_value)) - ) - ) diff --git a/allure-nose2/test/result/test_fullname.py b/allure-nose2/test/result/test_fullname.py deleted file mode 100644 index f904a49c..00000000 --- a/allure-nose2/test/result/test_fullname.py +++ /dev/null @@ -1,39 +0,0 @@ -import unittest -from hamcrest import assert_that -from test.example_runner import run_docstring_example -from hamcrest import has_entry, has_item, has_property - - -def test_func_fullname(): - """ - >>> def test_func_fullname_example(): - ... pass - """ - allure_report = run_docstring_example() - assert_that(allure_report, - has_property("test_cases", - has_item( - has_entry("fullName", "example_module.test_func_fullname_example") - ) - ) - ) - - -class TestFullname(unittest.TestCase): - def test_method_fullname(self): - """ - >>> import unittest - - >>> class TestFullnameExample(unittest.TestCase): - ... def test_method_fullname_example(self): - ... pass - """ - allure_report = run_docstring_example() - assert_that(allure_report, - has_property("test_cases", - has_item( - has_entry("fullName", - "example_module.TestFullnameExample.test_method_fullname_example") - ) - ) - ) diff --git a/allure-nose2/test/result/test_status.py b/allure-nose2/test/result/test_status.py deleted file mode 100644 index 6cc6d059..00000000 --- a/allure-nose2/test/result/test_status.py +++ /dev/null @@ -1,71 +0,0 @@ -import unittest -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import with_status -from allure_commons_test.result import has_status_details -from allure_commons_test.result import with_message_contains -from test.example_runner import run_docstring_example - - -class TestStatus(unittest.TestCase): - def test_passed_status(self): - """ - >>> import unittest - - >>> class TestStatusExample(unittest.TestCase): - ... def test_passed_example(self): - ... assert True - """ - allure_report = run_docstring_example() - assert_that(allure_report, - has_test_case("test_passed_example", - with_status("passed")) - ) - - def test_failed_status(self): - """ - >>> import unittest - - >>> class TestStatusExample(unittest.TestCase): - ... def test_failed_example(self): - ... assert False, "my message" - """ - allure_report = run_docstring_example() - assert_that(allure_report, - has_test_case("test_failed_example", - with_status("failed"), - has_status_details(with_message_contains("my message")) - ) - ) - - def test_broken_status(self): - """ - >>> import unittest - - >>> class TestStatusExample(unittest.TestCase): - ... def test_broken_example(self): - ... raise Exception("my error") - """ - allure_report = run_docstring_example() - assert_that(allure_report, - has_test_case("test_broken_example", - with_status("broken"), - has_status_details(with_message_contains("my error")) - ) - ) - - def test_skipped_status(self): - """ - >>> import unittest - - >>> class TestStatusExample(unittest.TestCase): - ... def test_skipped_example(self): - ... self.skipTest('my skip reason') - """ - allure_report = run_docstring_example() - assert_that(allure_report, - has_test_case("test_skipped_example", - with_status("skipped"), - has_status_details(with_message_contains("my skip reason")) - ) - ) diff --git a/allure-pytest-bdd/features/background.feature b/allure-pytest-bdd/features/background.feature deleted file mode 100644 index 760a0d75..00000000 --- a/allure-pytest-bdd/features/background.feature +++ /dev/null @@ -1 +0,0 @@ -# ToDo ... \ No newline at end of file diff --git a/allure-pytest-bdd/features/outline.feature b/allure-pytest-bdd/features/outline.feature deleted file mode 100644 index 5058739d..00000000 --- a/allure-pytest-bdd/features/outline.feature +++ /dev/null @@ -1,51 +0,0 @@ -Feature: Scenario outline - Scenario: Scenario outline - Given example.feature with content: - """ - Feature: Scenario outline - Scenario Outline: Outline example - Given step - When do nothing - Then step with param - - Examples: - | first | second | - | Alpha | 1 | - | Bravo | 2 | - """ - And example_test.py with content: - """ - from pytest_bdd import scenario - from pytest_bdd import given, then, when, parsers - - @given(parsers.parse("{first} step")) - def given_step(first): - pass - - @when("do nothing") - def nope_step(): - pass - - @then(parsers.parse("step with {second} param")) - def then_step(second): - pass - - @scenario("example.feature", "Outline example") - def test_scenario_outline_example(): - pass - """ - When run pytest-bdd with allure - - Then allure report has result for "Outline example" scenario - Then this scenario has parameter "first" with value "Alpha" - Then this scenario has parameter "second" with value "1" - Then this scenario contains "Given Alpha step" step - Then this scenario contains "Then step with 1 param" step - - Then allure report has result for "Outline example" scenario - Then this scenario has parameter "first" with value "Bravo" - Then this scenario has parameter "second" with value "2" - Then this scenario contains "Given Bravo step" step - Then this scenario contains "Then step with 2 param" step - - diff --git a/allure-pytest-bdd/features/scenario.feature b/allure-pytest-bdd/features/scenario.feature deleted file mode 100644 index c9f402ae..00000000 --- a/allure-pytest-bdd/features/scenario.feature +++ /dev/null @@ -1,32 +0,0 @@ -Feature: Scenario - Scenario: Simple passed scenario - Given example.feature with content: - """ - Feature: Scenario - Scenario: Simple passed example - Given passed step - When passed step - Then passed step - """ - And example_test.py with content: - """ - from pytest_bdd import scenario - from pytest_bdd import given, then, when - - @given("passed step") - def given_passed_step(): - pass - - @when("passed step") - @then("passed step") - def passed_step(): - pass - - @scenario("example.feature", "Simple passed example") - def test_scenario_example(): - pass - """ - When run pytest-bdd with allure - Then allure report has result for "Simple passed example" scenario - Then this scenario has passed status - Then this scenario has a history id diff --git a/allure-pytest-bdd/pyproject.toml b/allure-pytest-bdd/pyproject.toml index 579ac074..ef264568 100644 --- a/allure-pytest-bdd/pyproject.toml +++ b/allure-pytest-bdd/pyproject.toml @@ -1,3 +1,3 @@ [tool.poe.tasks] -linter = "flake8 ./src ./test" -tests = "pytest --alluredir=allure-results --basetemp=tmp test" +linter = "flake8 ./src" +tests = "pytest ../tests/allure_pytest_bdd" diff --git a/allure-pytest-bdd/requirements.txt b/allure-pytest-bdd/requirements.txt index 0dffc5ce..bb3a6759 100644 --- a/allure-pytest-bdd/requirements.txt +++ b/allure-pytest-bdd/requirements.txt @@ -1,5 +1,3 @@ -mock -poethepoet -# linters -flake8 -flake8-builtins \ No newline at end of file +-r ../requirements/testing.txt +-r ../requirements/linting.txt +-r ../requirements/testing/allure-pytest-bdd.txt diff --git a/allure-pytest-bdd/test/conftest.py b/allure-pytest-bdd/test/conftest.py deleted file mode 100644 index 6508c395..00000000 --- a/allure-pytest-bdd/test/conftest.py +++ /dev/null @@ -1,63 +0,0 @@ -import pytest -import mock -from contextlib import contextmanager -import allure_commons -from allure_commons_test.report import AllureReport -from allure_commons.logger import AllureFileLogger -from .steps import * # noqa F401 F403 -from pytest_bdd import given, when, parsers - -pytest_plugins = "pytester" - - -@contextmanager -def fake_logger(path, logger): - blocked_plugins = [] - for name, plugin in allure_commons.plugin_manager.list_name_plugin(): - allure_commons.plugin_manager.unregister(plugin=plugin, name=name) - blocked_plugins.append(plugin) - - with mock.patch(path) as ReporterMock: - ReporterMock.return_value = logger - yield - - for plugin in blocked_plugins: - allure_commons.plugin_manager.register(plugin) - - -class AlluredTestdir: - def __init__(self, testdir, request): - self.testdir = testdir - self.request = request - self.allure_report = None - - def run_with_allure(self): - logger = AllureFileLogger(self.testdir.tmpdir.strpath) - with fake_logger("allure_pytest_bdd.plugin.AllureFileLogger", logger): - self.testdir.runpytest("-s", "-v", "--alluredir", self.testdir.tmpdir) - self.allure_report = AllureReport(self.testdir.tmpdir.strpath) - - -@pytest.fixture -def allured_testdir(testdir, request): - return AlluredTestdir(testdir, request) - - -@pytest.fixture -def context(): - return dict() - - -@pytest.fixture -def allure_report(allured_testdir, context): - return allured_testdir.allure_report - - -@given(parsers.re("(?P\\w+)(?P\\.\\w+) with content:(?:\n)(?P[\\S|\\s]*)")) -def feature_definition(name, extension, content, testdir): - testdir.makefile(extension, **dict([(name, content)])) - - -@when("run pytest-bdd with allure") -def run(allured_testdir): - allured_testdir.run_with_allure() diff --git a/allure-pytest-bdd/test/outline_test.py b/allure-pytest-bdd/test/outline_test.py deleted file mode 100644 index d176148a..00000000 --- a/allure-pytest-bdd/test/outline_test.py +++ /dev/null @@ -1,6 +0,0 @@ -from pytest_bdd import scenario - - -@scenario("../features/outline.feature", "Scenario outline") -def test_scenario_outline(): - pass diff --git a/allure-pytest-bdd/test/scenario_test.py b/allure-pytest-bdd/test/scenario_test.py deleted file mode 100644 index 18362409..00000000 --- a/allure-pytest-bdd/test/scenario_test.py +++ /dev/null @@ -1,6 +0,0 @@ -from pytest_bdd import scenario - - -@scenario("../features/scenario.feature", "Simple passed scenario") -def test_simple_passed_scenario(): - pass diff --git a/allure-pytest-bdd/test/steps.py b/allure-pytest-bdd/test/steps.py deleted file mode 100644 index eac3cc95..00000000 --- a/allure-pytest-bdd/test/steps.py +++ /dev/null @@ -1,57 +0,0 @@ -from pytest_bdd import then -from pytest_bdd import parsers -from functools import partial -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import with_status -from allure_commons_test.result import has_step -from allure_commons_test.result import has_parameter -from allure_commons_test.result import has_history_id - - -def match(matcher, *args): - for i, arg in enumerate(args): - if not hasattr(arg, '__call__'): - matcher = partial(matcher, arg) - else: - matcher = partial(matcher, match(arg, *args[i+1:])) - break - return matcher() - - -@then(parsers.re("allure report has result for (?:\")(?P[\\w|\\s|,]*)(?:\") scenario")) -def match_scenario(allure_report, context, scenario_name): - matcher = partial(match, has_test_case, scenario_name) - assert_that(allure_report, matcher()) - context['scenario'] = matcher - - -@then(parsers.parse("this {item:w} has {status:w} status")) -def item_status(allure_report, context, item, status): - context_matcher = context[item] - matcher = partial(context_matcher, with_status, status) - assert_that(allure_report, matcher()) - - -@then(parsers.parse("this {item:w} has a history id")) -def item_history_id(allure_report, context, item): - context_matcher = context[item] - matcher = partial(context_matcher, has_history_id) - assert_that(allure_report, matcher()) - - -@then(parsers.re("this (?P\\w+) " - "has parameter (?:\")(?P[\\w|\\s]*)(?:\") " - "with value (?:\")(?P[\\w|\\s]*)(?:\")")) -def item_parameter(allure_report, context, item, param_name, param_value): - context_matcher = context[item] - matcher = partial(context_matcher, has_parameter, param_name, param_value) - assert_that(allure_report, matcher()) - - -@then(parsers.re("this (?P\\w+) contains (?:\")(?P[\\w|\\s|>|<]+)(?:\") step")) -def step_step(allure_report, context, item, step): - context_matcher = context[item] - matcher = partial(context_matcher, has_step, step) - context["step"] = matcher - assert_that(allure_report, matcher()) diff --git a/allure-pytest/README.rst b/allure-pytest/README.rst index 3a7c9e27..49923c54 100644 --- a/allure-pytest/README.rst +++ b/allure-pytest/README.rst @@ -1,9 +1,9 @@ Allure Pytest Plugin ==================== -.. image:: https://pypip.in/v/allure-pytest/badge.png +.. image:: https://img.shields.io/pypi/v/allure-pytest :alt: Release Status :target: https://pypi.python.org/pypi/allure-pytest -.. image:: https://pypip.in/d/allure-pytest/badge.png +.. image:: https://img.shields.io/pypi/dm/allure-pytest :alt: Downloads :target: https://pypi.python.org/pypi/allure-pytest @@ -22,3 +22,8 @@ Installation and Usage $ pip install allure-pytest $ py.test --alluredir=%allure_result_folder% ./tests $ allure serve %allure_result_folder% + +Usage examples +-------------- + +See usage examples `here `_. diff --git a/allure-pytest/examples/parameter/dynamic_parameter.rst b/allure-pytest/examples/parameter/dynamic_parameter.rst new file mode 100644 index 00000000..a56cf207 --- /dev/null +++ b/allure-pytest/examples/parameter/dynamic_parameter.rst @@ -0,0 +1,74 @@ +Dynamic parameter +------------------- + +It's possible to dynamically add a parameter to a test result: + + + >>> import allure + + >>> def test_dynamic_parameter(): + ... allure.dynamic.parameter("username", "John Doe") + + +The parameter name and value are shown in the "Parameters" section of the test +details view. Additionally, the value is shown near the test name in the test +tree view. + + +Affecting the history of test execution in Allure TestOps +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Parameters also affect how Allure TestOps keeps history and retry records +across test results. Two test results that differs from each other in a +parameter value are considered as belonging to different test cases, thus +forming separate histories. + +This behavior can be changed with ``excluded`` argument: + + + >>> import allure + ... import os + + >>> def test_excluded_dynamic_parameter(): + ... allure.dynamic.parameter("work-dir", os.getcwd(), excluded=True) + + +Such a parameter isn't taken into account by Allure TestOps when it decides +whether two test results actually belong to a single test case. This is useful +if you want to add environment-related information (such as host names, OS, PID, +paths, versions, etc.) but keep history the same if the information is changed. + + +Masking a sensitive parameter +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A parameter value can be masked with ``mode`` argument. The masked value is shown +as ``******`` in the report. This is useful for sensitive parameters like +passwords or key phrases: + + + >>> import allure + + >>> def test_masked_dynamic_parameter(): + ... allure.dynamic.parameter("password", "qwerty", mode=allure.parameter_mode.MASKED) + + +WARNING: Although the value is masked in the report, it is still present in the +test result files (but not in report files, i.e., the files generated by +allure reporter). + + +Hiding a parameter from the report +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A parameter can be hidden from the report completely. It still affects the +history of the test case though. This is useful if you want to force Allure +TestOps to distribute otherwise indistinguishable test results across different +test cases: + + + >>> import allure + >>> import socket + + >>> def test_hidden_dynamic_parameter(): + ... allure.dynamic.parameter("hostname", socket.gethostname(), mode=allure.parameter_mode.HIDDEN) diff --git a/allure-pytest/pyproject.toml b/allure-pytest/pyproject.toml index b7ba99a6..a65620d3 100644 --- a/allure-pytest/pyproject.toml +++ b/allure-pytest/pyproject.toml @@ -1,3 +1,3 @@ [tool.poe.tasks] -linter = "flake8 ./src ./test" -tests = "pytest --alluredir=allure-results --basetemp=tmp test/acceptance test/integration" +linter = "flake8 ./src" +tests = "pytest ../tests/allure_pytest" diff --git a/allure-pytest/requirements.txt b/allure-pytest/requirements.txt index 70595068..bd3fab25 100644 --- a/allure-pytest/requirements.txt +++ b/allure-pytest/requirements.txt @@ -1,12 +1,3 @@ -# test requirements -pyhamcrest -mock -pytest-check -pytest-flakes -pytest-rerunfailures -pytest-xdist -pytest-lazy-fixture -poethepoet -# linters -flake8 -flake8-builtins \ No newline at end of file +-r ../requirements/testing.txt +-r ../requirements/linting.txt +-r ../requirements/testing/allure-pytest.txt diff --git a/allure-pytest/src/listener.py b/allure-pytest/src/listener.py index 74bc3324..270a8ca5 100644 --- a/allure-pytest/src/listener.py +++ b/allure-pytest/src/listener.py @@ -78,6 +78,12 @@ def pytest_runtest_protocol(self, item, nextitem): test_result = TestResult(name=item.name, uuid=uuid, start=now(), stop=now()) self.allure_logger.schedule_test(uuid, test_result) yield + uuid = self._cache.pop(item.nodeid) + if uuid: + test_result = self.allure_logger.get_test(uuid) + if test_result.status is None: + test_result.status = Status.SKIPPED + self.allure_logger.close_test(uuid) @pytest.hookimpl(hookwrapper=True) def pytest_runtest_setup(self, item): @@ -218,13 +224,6 @@ def pytest_runtest_makereport(self, item, call): if report.capstderr: self.attach_data(report.capstderr, "stderr", AttachmentType.TEXT, None) - @pytest.hookimpl(hookwrapper=True) - def pytest_runtest_logfinish(self, nodeid, location): - yield - uuid = self._cache.pop(nodeid) - if uuid: - self.allure_logger.close_test(uuid) - @allure_commons.hookimpl def attach_data(self, body, name, attachment_type, extension): self.allure_logger.attach_data(uuid4(), body, name=name, attachment_type=attachment_type, extension=extension) diff --git a/allure-pytest/src/utils.py b/allure-pytest/src/utils.py index 146e37c6..56f12157 100644 --- a/allure-pytest/src/utils.py +++ b/allure-pytest/src/utils.py @@ -27,10 +27,7 @@ def get_marker_value(item, keyword): def allure_title(item): - try: - return item._obj.__allure_display_name__ - except AttributeError: - return None + return getattr(item.obj, "__allure_display_name__", None) def allure_description(item): @@ -110,9 +107,12 @@ def allure_package(item): def allure_name(item, parameters): - name = escape_name(item.name) + name = item.name title = allure_title(item) - return SafeFormatter().format(title, **{**parameters, **item.funcargs}) if title else name + return SafeFormatter().format( + title, + **{**parameters, **item.funcargs} + ) if title else name def allure_full_name(item: pytest.Item): @@ -120,7 +120,7 @@ def allure_full_name(item: pytest.Item): class_name = f".{item.parent.name}" if isinstance(item.parent, pytest.Class) else '' test = item.originalname if isinstance(item, pytest.Function) else item.name.split("[")[0] full_name = f'{package}{class_name}#{test}' - return escape_name(full_name) + return full_name def allure_suite_labels(item): @@ -139,10 +139,6 @@ def allure_suite_labels(item): return default_suite_labels -def escape_name(name): - return name.encode('ascii', 'backslashreplace').decode('unicode_escape') - - def get_outcome_status(outcome): _, exception, _ = outcome.excinfo or (None, None, None) return get_status(exception) diff --git a/allure-pytest/test/acceptance/attachment/attachment_class_test.py b/allure-pytest/test/acceptance/attachment/attachment_class_test.py deleted file mode 100644 index 6f229e27..00000000 --- a/allure-pytest/test/acceptance/attachment/attachment_class_test.py +++ /dev/null @@ -1,19 +0,0 @@ -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_attachment - - -def test_class_method_attachment(executed_docstring_source): - """ - >>> import allure - - >>> class TestClass: - ... def test_class_method_attachment(self): - ... allure.attach("text", "failed", allure.attachment_type.TEXT) - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_class_method_attachment", - has_attachment(name="failed") - ) - ) diff --git a/allure-pytest/test/acceptance/attachment/attachment_fixture_test.py b/allure-pytest/test/acceptance/attachment/attachment_fixture_test.py deleted file mode 100644 index caaf4f67..00000000 --- a/allure-pytest/test/acceptance/attachment/attachment_fixture_test.py +++ /dev/null @@ -1,32 +0,0 @@ -""" ./examples/attachment/attachment_fixture.rst """ - -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_attachment -from allure_commons_test.container import has_container -from allure_commons_test.container import has_before -from allure_commons_test.container import has_after - - -def test_fixture_attachment(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_fixture_attachment", - has_container(executed_docstring_path.allure_report, - has_before("fixture_with_attachment", - has_attachment() - ) - ) - ) - ) - - -def test_fixture_finalizer_attachment(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_fixture_finalizer_attachment", - has_container(executed_docstring_path.allure_report, - has_after("fixture_with_attachment_in_finalizer::finalizer", - has_attachment() - ) - ) - ) - ) diff --git a/allure-pytest/test/acceptance/attachment/attachment_hook_test.py b/allure-pytest/test/acceptance/attachment/attachment_hook_test.py deleted file mode 100644 index d6238575..00000000 --- a/allure-pytest/test/acceptance/attachment/attachment_hook_test.py +++ /dev/null @@ -1,49 +0,0 @@ -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_attachment - - -def test_attach_from_runtest_teardown(allured_testdir): - allured_testdir.testdir.makeconftest(""" - import allure - - - def pytest_runtest_teardown(*args, **kwargs): - allure.attach(body="body", name="attachment from teardown") - """) - - allured_testdir.testdir.makepyfile(""" - def test_attach_from_runtest_teardown(): - pass - """) - - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_attach_from_runtest_teardown", - has_attachment(name="attachment from teardown"), - ) - ) - - -def test_attach_from_runtest_logfinish(allured_testdir): - allured_testdir.testdir.makeconftest(""" - import allure - - - def pytest_runtest_logfinish(*args, **kwargs): - allure.attach(body="body", name="attachment from logfinish") - """) - - allured_testdir.testdir.makepyfile(""" - def test_attach_from_runtest_logfinish(): - pass - """) - - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_attach_from_runtest_logfinish", - has_attachment(name="attachment from logfinish"), - ) - ) diff --git a/allure-pytest/test/acceptance/attachment/attachment_parametrized_test.py b/allure-pytest/test/acceptance/attachment/attachment_parametrized_test.py deleted file mode 100644 index 05a8d4ad..00000000 --- a/allure-pytest/test/acceptance/attachment/attachment_parametrized_test.py +++ /dev/null @@ -1,26 +0,0 @@ -import pytest -from hamcrest import assert_that -from hamcrest import all_of -from hamcrest import has_property, has_value -from hamcrest import contains_string -from allure_commons_test.report import has_test_case - - -@pytest.mark.parametrize("param", ["first", "second"]) -def test_parametrized_attachment(executed_docstring_source, param): - """ - >>> import pytest - >>> import allure - - >>> @pytest.mark.parametrize("param", ["first", "second"]) - ... def test_parametrized_attachment_example(param): - ... allure.attach(param) - """ - - assert_that(executed_docstring_source.allure_report, - all_of( - has_test_case(f"test_parametrized_attachment_example[{param}]"), - has_property("attachments", - has_value(contains_string(param)) - ) - )) diff --git a/allure-pytest/test/acceptance/attachment/attachment_step_test.py b/allure-pytest/test/acceptance/attachment/attachment_step_test.py deleted file mode 100644 index bdb14d44..00000000 --- a/allure-pytest/test/acceptance/attachment/attachment_step_test.py +++ /dev/null @@ -1,48 +0,0 @@ -""" ./examples/attachment/attachment_step.rst """ - -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_step -from allure_commons_test.result import has_attachment - - -def test_step_with_attachment(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_step_with_attachment", - has_step("step_with_attachment", - has_attachment() - ), - ) - ) - - -def test_step_with_thread_and_attachment(allured_testdir): - allured_testdir.testdir.makepyfile( - """ - from concurrent.futures import ThreadPoolExecutor - - import allure - import pytest - - @allure.step("thread {x}") - def parallel_step(x=1): - allure.attach("text", str(x), allure.attachment_type.TEXT) - - - def test_thread(): - with allure.step("Start in thread"): - with ThreadPoolExecutor(max_workers=2) as executor: - f_result = executor.map(parallel_step, [1, 2]) - """ - ) - - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_thread", - has_step("Start in thread", - has_step("thread 1", has_attachment(name="1")), - has_step("thread 2", has_attachment(name="2")), - ) - ) - ) diff --git a/allure-pytest/test/acceptance/attachment/attachment_test.py b/allure-pytest/test/acceptance/attachment/attachment_test.py deleted file mode 100644 index 46a2df94..00000000 --- a/allure-pytest/test/acceptance/attachment/attachment_test.py +++ /dev/null @@ -1,29 +0,0 @@ -""" ./examples/attachment/attachment.rst """ - -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_attachment - - -def test_attach_body_with_default_kwargs(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_attach_body_with_default_kwargs", - has_attachment() - ) - ) - - -def test_attach_body(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_attach_body", - has_attachment(attach_type="application/xml", name="some attachment name") - ) - ) - - -def test_attach_file(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_attach_file", - has_attachment() - ) - ) diff --git a/allure-pytest/test/acceptance/capture/capture_attach_test.py b/allure-pytest/test/acceptance/capture/capture_attach_test.py deleted file mode 100644 index b438eb79..00000000 --- a/allure-pytest/test/acceptance/capture/capture_attach_test.py +++ /dev/null @@ -1,126 +0,0 @@ -import pytest -from hamcrest import assert_that -from hamcrest import all_of, is_, is_not, empty -from hamcrest import has_property, has_value -from hamcrest import contains_string - - -@pytest.mark.parametrize("capture", ["sys", "fd", "no"]) -def test_capture_stdout(allured_testdir, capture): - """ - >>> import pytest - >>> import allure - - >>> @pytest.fixture - ... def fixture(request): - ... print ("Start fixture") - ... def finalizer(): - ... print ("Stop fixture") - ... request.addfinalizer(finalizer) - - >>> def test_capture_stdout_example(fixture): - ... print ("Start test") - ... with allure.step("Step"): - ... print ("Start step") - """ - - allured_testdir.parse_docstring_source() - allured_testdir.run_with_allure(f"--capture={capture}") - - if_pytest_capture_ = is_not if capture == "no" else is_ - - assert_that(allured_testdir.allure_report, - has_property("attachments", - all_of( - if_pytest_capture_(has_value(contains_string("Start fixture"))), - if_pytest_capture_(has_value(contains_string("Stop fixture"))), - if_pytest_capture_(has_value(contains_string("Start test"))), - if_pytest_capture_(has_value(contains_string("Start step"))) - ) - ) - ) - - -@pytest.mark.parametrize("capture", ["sys", "fd"]) -def test_capture_empty_stdout(allured_testdir, capture): - """ - >>> import pytest - >>> import allure - - >>> @pytest.fixture - ... def fixture(request): - ... def finalizer(): - ... pass - ... request.addfinalizer(finalizer) - - >>> def test_capture_stdout_example(fixture): - ... with allure.step("Step"): - ... pass - """ - - allured_testdir.parse_docstring_source() - allured_testdir.run_with_allure(f"--capture={capture}") - - assert_that(allured_testdir.allure_report, - has_property("attachments", empty()) - ) - - -@pytest.mark.parametrize("logging", [True, False]) -def test_capture_log(allured_testdir, logging): - """ - >>> import logging - >>> import pytest - >>> import allure - - >>> logger = logging.getLogger(__name__) - - >>> @pytest.fixture - ... def fixture(request): - ... logger.info("Start fixture") - ... def finalizer(): - ... logger.info("Stop fixture") - ... request.addfinalizer(finalizer) - - >>> def test_capture_log_example(fixture): - ... logger.info("Start test") - ... with allure.step("Step"): - ... logger.info("Start step") - """ - - allured_testdir.parse_docstring_source() - - params = [] if logging else ["-p", "no:logging"] - if_logging_ = is_ if logging else is_not - - allured_testdir.run_with_allure("--log-cli-level=INFO", *params) - - assert_that(allured_testdir.allure_report, - has_property("attachments", - all_of( - if_logging_(has_value(contains_string("Start fixture"))), - if_logging_(has_value(contains_string("Stop fixture"))), - if_logging_(has_value(contains_string("Start test"))), - if_logging_(has_value(contains_string("Start step"))) - ) - ) - ) - - -def test_capture_disabled(allured_testdir): - """ - >>> import logging - >>> logger = logging.getLogger(__name__) - - >>> def test_capture_disabled_example(): - ... logger.info("Start logging") - ... print ("Start printing") - - """ - - allured_testdir.parse_docstring_source() - allured_testdir.run_with_allure("--log-cli-level=INFO", "--allure-no-capture") - - assert_that(allured_testdir.allure_report, - has_property("attachments", empty()) - ) diff --git a/allure-pytest/test/acceptance/description/description_test.py b/allure-pytest/test/acceptance/description/description_test.py deleted file mode 100644 index bec2fbac..00000000 --- a/allure-pytest/test/acceptance/description/description_test.py +++ /dev/null @@ -1,37 +0,0 @@ -""" ./examples/description/description.rst """ - -from hamcrest import assert_that, contains_string -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_description, has_description_html - - -def test_description(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_description", - has_description(contains_string("Test description")) - ) - ) - - -def test_description_html(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_description_html", - has_description_html(contains_string("

Html test description

")) - ) - ) - - -def test_docstring_description(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_docstring_description", - has_description(contains_string("Docstring")) - ) - ) - - -def test_unicode_docstring_description(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_unicode_docstring_description", - has_description(contains_string("Докстринг в юникоде")) - ) - ) diff --git a/allure-pytest/test/acceptance/description/dynamic_description_test.py b/allure-pytest/test/acceptance/description/dynamic_description_test.py deleted file mode 100644 index 66091476..00000000 --- a/allure-pytest/test/acceptance/description/dynamic_description_test.py +++ /dev/null @@ -1,21 +0,0 @@ -"""./examples/description/dynamic_description.rst""" - -from hamcrest import assert_that, contains_string -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_description, has_description_html - - -def test_dynamic_description(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_dynamic_description", - has_description(contains_string("Actual description")) - ) - ) - - -def test_dynamic_description_html(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_dynamic_description_html", - has_description_html(contains_string("

Actual HTML description

")) - ) - ) diff --git a/allure-pytest/test/acceptance/display_name/display_name_test.py b/allure-pytest/test/acceptance/display_name/display_name_test.py deleted file mode 100644 index a3021970..00000000 --- a/allure-pytest/test/acceptance/display_name/display_name_test.py +++ /dev/null @@ -1,119 +0,0 @@ -""" ./examples/display_name/display_name.rst""" - -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_title -from allure_commons_test.label import has_label - - -def test_display_name(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_display_name", - has_title("A some test title") - ) - ) - - -def test_display_name_template(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_display_name_template", - has_title("A some test title with param False") - ) - ) - - -def test_unicode_display_name(executed_docstring_source): - """ - >>> import allure - - >>> @allure.title("Лунтик") - >>> def test_unicode_display_name_example(): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_unicode_display_name_example", has_title("Лунтик")) - ) - - -def test_unicode_display_name_template(executed_docstring_source): - """ - >>> import allure - >>> import pytest - - >>> @allure.title("Тест с шаблоном и параметром: {param}") - ... @pytest.mark.parametrize("param", [False]) - ... def test_unicode_display_name_template_example(param): - ... assert param - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_unicode_display_name_template_example", - has_title("Тест с шаблоном и параметром: False") - ) - ) - - -def test_fixture_value_in_display_name(executed_docstring_source): - """ - >>> import allure - >>> import pytest - - >>> @pytest.fixture - ... def fix(): - ... return 'fixture value' - - >>> @allure.title('title with {fix}') - ... def test_fixture_value_name(fix): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_fixture_value_name", - has_title("title with fixture value") - ) - ) - - -def test_display_name_with_features(allured_testdir): - allured_testdir.testdir.makepyfile(""" - import allure - import pytest - - @allure.feature('Feature 1') - @allure.title('Titled test with features') - @allure.feature('Feature 2') - def test_feature_label_for_titled_test(): - pass - """) - - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_feature_label_for_titled_test", - has_label("feature", "Feature 1"), - has_label("feature", "Feature 2"), - has_title("Titled test with features") - ) - ) - - -def test_failed_fixture_value_in_display_name(executed_docstring_source): - """ - >>> import allure - >>> import pytest - - >>> @pytest.fixture - ... def fix(): - ... raise AssertionError("Fixture failed for some reason") - - >>> @allure.title('title with {fix}') - ... def test_fixture_value_name(fix): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_fixture_value_name", - has_title("title with {fix}") - ) - ) diff --git a/allure-pytest/test/acceptance/display_name/dynamic_display_name_test.py b/allure-pytest/test/acceptance/display_name/dynamic_display_name_test.py deleted file mode 100644 index cfd34d9d..00000000 --- a/allure-pytest/test/acceptance/display_name/dynamic_display_name_test.py +++ /dev/null @@ -1,13 +0,0 @@ -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_title - - -def test_dynamic_display_name(executed_docstring_path): - """ ./examples/display_name/dynamic_display_name.rst """ - - assert_that(executed_docstring_path.allure_report, - has_test_case("test_dynamic_display_name", - has_title("It is renamed test") - ) - ) diff --git a/allure-pytest/test/acceptance/duration/duration_time_test.py b/allure-pytest/test/acceptance/duration/duration_time_test.py deleted file mode 100644 index e5afc9d0..00000000 --- a/allure-pytest/test/acceptance/duration/duration_time_test.py +++ /dev/null @@ -1,89 +0,0 @@ -import allure -import pytest -from hamcrest import assert_that, has_entry, greater_than, all_of -from allure_commons_test.report import has_test_case -from allure_commons.utils import now - - -snippets = [ - "pass", - "assert False", - "raise(RuntimeError())", - "pytest.skip()", - "pytest.fail()", - "pytest.xfail()", - pytest.param("pytest.exit('msg')", marks=pytest.mark.skip) -] - - -@pytest.mark.parametrize("snipped", snippets) -def test_duration(allured_testdir, snipped): - allured_testdir.testdir.makepyfile(f""" - def test_duration_example(): - {snipped} - """) - - timestamp = now() - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_duration_example", - all_of( - has_entry("start", greater_than(timestamp)), - has_entry("stop", greater_than(timestamp)) - )) - ) - - -@allure.issue("244") -@pytest.mark.parametrize("snipped", snippets) -def test_with_fixture_duration(allured_testdir, snipped): - allured_testdir.testdir.makepyfile(f""" - import pytest - - @pytest.fixture - def fixture(): - {snipped} - - def test_with_fixture_duration_example(fixture): - pass - """) - - timestamp = now() - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_with_fixture_duration_example", - all_of( - has_entry("start", greater_than(timestamp)), - has_entry("stop", greater_than(timestamp)) - )) - ) - - -@allure.issue("244") -@pytest.mark.parametrize("snipped", snippets) -def test_with_fixture_finalizer_duration(allured_testdir, snipped): - allured_testdir.testdir.makepyfile(f""" - import pytest - - @pytest.fixture - def fixture(request): - def finalizer(): - {snipped} - request.addfinalizef(finalizer) - - def test_with_fixture_finalizer_duration(fixture): - pass - """) - - timestamp = now() - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_with_fixture_finalizer_duration", - all_of( - has_entry("start", greater_than(timestamp)), - has_entry("stop", greater_than(timestamp)) - )) - ) diff --git a/allure-pytest/test/acceptance/fixture/fixture_test.py b/allure-pytest/test/acceptance/fixture/fixture_test.py deleted file mode 100644 index 0167a308..00000000 --- a/allure-pytest/test/acceptance/fixture/fixture_test.py +++ /dev/null @@ -1,413 +0,0 @@ -import pytest -import allure -from hamcrest import assert_that, not_ -from allure_commons_test.report import has_test_case -from allure_commons_test.container import has_container, has_before, has_after -from allure_commons_test.result import has_step -from itertools import combinations_with_replacement - -fixture_scopes = ["session", "module", "class", "function"] - - -@allure.feature("Fixture") -@pytest.mark.parametrize("first_scope", fixture_scopes) -@pytest.mark.parametrize("second_scope", fixture_scopes) -def test_fixture(allured_testdir, first_scope, second_scope): - allured_testdir.testdir.makepyfile(f""" - import pytest - - @pytest.fixture(scope="{first_scope}") - def first_fixture(): - pass - - @pytest.fixture(scope="{second_scope}") - def second_fixture(): - pass - - def test_fixture_example(first_fixture, second_fixture): - pass - """) - - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_fixture_example", - has_container(allured_testdir.allure_report, - has_before("first_fixture") - ), - has_container(allured_testdir.allure_report, - has_before("second_fixture"), - ) - ) - ) - - -@pytest.mark.parametrize( - ["parent_scope", "child_scope"], - list(combinations_with_replacement(fixture_scopes, 2)) -) -def test_nested_fixture(allured_testdir, parent_scope, child_scope): - allured_testdir.testdir.makepyfile(f""" - import pytest - - @pytest.fixture(scope="{parent_scope}") - def parent_fixture(): - pass - - @pytest.fixture(scope="{child_scope}") - def child_fixture(parent_fixture): - pass - - def test_nested_fixture_example(child_fixture): - pass - - def test_fixture_used_in_other_fixtures_example(parent_fixture): - pass - - """) - - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_nested_fixture_example", - has_container(allured_testdir.allure_report, - has_before("parent_fixture") - ), - has_container(allured_testdir.allure_report, - has_before("child_fixture"), - ) - ) - ) - - assert_that(allured_testdir.allure_report, - has_test_case("test_fixture_used_in_other_fixtures_example", - has_container(allured_testdir.allure_report, - has_before("parent_fixture") - ), - not_(has_container(allured_testdir.allure_report, - has_before("child_fixture"), - ) - ) - ) - ) - - -@allure.feature("Fixture") -def test_nested_fixtures(executed_docstring_source): - """ - >>> import pytest - - If we have two fixtures: - >>> @pytest.fixture - ... def first_fixture(): - ... pass - - - >>> @pytest.fixture - ... def second_fixture(): - ... pass - - And one that uses both previous: - >>> @pytest.fixture - ... def child_fixture(first_fixture, second_fixture): - ... pass - - For next test, allure report will contain all tree fixtures: - >>> def test_nested_fixtures_example(child_fixture): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_nested_fixtures_example", - has_container(executed_docstring_source.allure_report, - has_before("first_fixture") - ), - has_container(executed_docstring_source.allure_report, - has_before("second_fixture"), - ), - has_container(executed_docstring_source.allure_report, - has_before("child_fixture"), - ) - ) - ) - - -@allure.feature("Fixture") -def test_fixture_allure_title(allured_testdir): - allured_testdir.testdir.makepyfile(""" - import pytest - import allure - - @pytest.fixture - @allure.title("Allure fixture title") - def first_fixture(): - pass - - def test_titled_fixture_example(first_fixture): - pass - """) - - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_titled_fixture_example", - has_container(allured_testdir.allure_report, - has_before("Allure fixture title") - ) - ) - ) - - -@allure.feature("Fixture") -def test_fixture_allure_title_before(allured_testdir): - allured_testdir.testdir.makepyfile(""" - import pytest - import allure - - @allure.title("Allure fixture title") - @pytest.fixture - def first_fixture(): - pass - - def test_titled_before_fixture_example(first_fixture): - pass - """) - - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_titled_before_fixture_example", - has_container(allured_testdir.allure_report, - has_before("Allure fixture title") - ) - ) - ) - - -def test_titled_fixture_from_conftest(allured_testdir): - allured_testdir.testdir.makeconftest(""" - import allure - import pytest - - @allure.title('Titled fixture before pytest.fixture') - @pytest.fixture - def first_fixture(): - pass - - @pytest.fixture - @allure.title('Titled fixture after pytest.fixture') - def second_fixture(): - pass - """) - - allured_testdir.testdir.makepyfile(""" - def test_with_titled_conftest_fixtures(first_fixture, second_fixture): - pass - """) - - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_with_titled_conftest_fixtures", - has_container(allured_testdir.allure_report, - has_before("Titled fixture before pytest.fixture") - ), - has_container(allured_testdir.allure_report, - has_before("Titled fixture after pytest.fixture") - ) - ) - ) - - -def test_fixture_override(allured_testdir): - allured_testdir.testdir.makeconftest(""" - import pytest - import allure - - @pytest.fixture - def my_fixture(): - with allure.step('Step in before in original fixture'): - pass - yield - with allure.step('Step in after in original fixture'): - pass - - """) - - allured_testdir.testdir.makepyfile(""" - import pytest - import allure - - @pytest.fixture - def my_fixture(my_fixture): - with allure.step('Step in before in redefined fixture'): - pass - yield - with allure.step('Step in after in redefined fixture'): - pass - - def test_with_redefined_fixture(my_fixture): - pass - """) - - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_with_redefined_fixture", - has_container(allured_testdir.allure_report, - has_before("my_fixture", - has_step("Step in before in original fixture") - ), - has_after("my_fixture::0", - has_step("Step in after in original fixture") - ) - ), - has_container(allured_testdir.allure_report, - has_before("my_fixture", - has_step("Step in before in redefined fixture") - ), - has_after("my_fixture::0", - has_step("Step in after in redefined fixture") - ) - ), - ) - ) - - -@pytest.mark.parametrize( - ["parent_scope", "child_scope"], - list(combinations_with_replacement(fixture_scopes, 2)) -) -def test_dynamically_called_fixture(allured_testdir, parent_scope, child_scope): - allured_testdir.testdir.makepyfile(f""" - import pytest - - @pytest.fixture(scope="{parent_scope}", autouse=True) - def parent_auto_call_fixture(): - yield - - @pytest.fixture(scope="{child_scope}") - def child_manual_call_fixture(): - yield - - @pytest.fixture(scope="{parent_scope}") - def parent_dyn_call_fixture(): - yield - - @pytest.fixture(scope="{child_scope}") - def child_dyn_call_fixture(request): - request.getfixturevalue('parent_dyn_call_fixture') - - def test_one(child_manual_call_fixture): - pass - - def test_two(request): - request.getfixturevalue('child_dyn_call_fixture') - - def test_three(request): - request.getfixturevalue('parent_dyn_call_fixture') - """) - - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_one", - has_container(allured_testdir.allure_report, - has_before("parent_auto_call_fixture"), - has_after("parent_auto_call_fixture::0"), - ), - has_container(allured_testdir.allure_report, - has_before("child_manual_call_fixture"), - has_after("child_manual_call_fixture::0"), - ), - not_(has_container(allured_testdir.allure_report, - has_before("parent_dyn_call_fixture"), - has_after("parent_dyn_call_fixture::0"), - ), - ), - not_(has_container(allured_testdir.allure_report, - has_before("child_dyn_call_fixture"), - ), - ) - ) - ) - assert_that(allured_testdir.allure_report, - has_test_case("test_two", - has_container(allured_testdir.allure_report, - has_before("parent_auto_call_fixture"), - has_after("parent_auto_call_fixture::0"), - ), - not_(has_container(allured_testdir.allure_report, - has_before("child_manual_call_fixture"), - has_after("child_manual_call_fixture::0"), - ), - ), - has_container(allured_testdir.allure_report, - has_before("parent_dyn_call_fixture"), - has_after("parent_dyn_call_fixture::0"), - ), - has_container(allured_testdir.allure_report, - has_before("child_dyn_call_fixture"), - ), - ), - ) - assert_that(allured_testdir.allure_report, - has_test_case("test_three", - has_container(allured_testdir.allure_report, - has_before("parent_auto_call_fixture"), - has_after("parent_auto_call_fixture::0"), - ), - not_(has_container(allured_testdir.allure_report, - has_before("child_manual_call_fixture"), - has_after("child_manual_call_fixture::0"), - ), - ), - has_container(allured_testdir.allure_report, - has_before("parent_dyn_call_fixture"), - has_after("parent_dyn_call_fixture::0"), - ), - not_(has_container(allured_testdir.allure_report, - has_before("child_dyn_call_fixture"), - ), - ) - ) - ) - - -def test_one_fixture_on_two_tests(allured_testdir): - allured_testdir.testdir.makepyfile(""" - import pytest - import allure - - @pytest.fixture - def fixture(request): - with allure.step(request.node.name): - pass - - class TestClass: - def test_first(self, fixture): - pass - - def test_second(self, fixture): - pass - """) - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_first", - has_container(allured_testdir.allure_report, - has_before("fixture", has_step("test_first")), - ), - not_(has_container(allured_testdir.allure_report, - has_before("fixture", has_step("test_second")), - )) - ), - has_test_case("test_second", - has_container(allured_testdir.allure_report, - has_before("fixture", has_step("test_second")), - ), - not_(has_container(allured_testdir.allure_report, - has_before("fixture", has_step("test_first")), - )) - ) - ) diff --git a/allure-pytest/test/acceptance/fixture/parametrized_fixture_test.py b/allure-pytest/test/acceptance/fixture/parametrized_fixture_test.py deleted file mode 100644 index 048fb86a..00000000 --- a/allure-pytest/test/acceptance/fixture/parametrized_fixture_test.py +++ /dev/null @@ -1,59 +0,0 @@ -import pytest -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.container import has_container -from allure_commons_test.container import has_before -from allure_commons_test.result import has_parameter - - -def params_name(request): - node_id = request.node.nodeid - _, name = node_id.rstrip("]").split("[") - return name - - -@pytest.mark.parametrize("param", [True, False]) -def test_function_scope_parametrized_fixture(param, executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.fixture(params=[True, False]) - ... def parametrized_fixture(request): - ... pass - - >>> def test_function_scope_parametrized_fixture_example(parametrized_fixture): - ... pass - """ - assert_that(executed_docstring_source.allure_report, - has_test_case(f"test_function_scope_parametrized_fixture_example[{param}]", - has_parameter("parametrized_fixture", str(param)), - has_container(executed_docstring_source.allure_report, - has_before("parametrized_fixture") - ) - ) - ) - - -@pytest.mark.parametrize("param", [True, False], ids=["param_true", "param_false"]) -def test_function_scope_parametrized_fixture_with_ids(param, executed_docstring_source, request): - """ - >>> import pytest - - >>> @pytest.fixture(params=[True, False], ids=["param_true", "param_false"]) - ... def parametrized_fixture(request): - ... pass - - >>> def test_function_scope_parametrized_fixture_with_ids_example(parametrized_fixture): - ... pass - """ - - test_name = f"test_function_scope_parametrized_fixture_with_ids_example[{params_name(request)}]" - - assert_that(executed_docstring_source.allure_report, - has_test_case(test_name, - has_parameter("parametrized_fixture", str(param)), - has_container(executed_docstring_source.allure_report, - has_before("parametrized_fixture") - ) - ) - ) diff --git a/allure-pytest/test/acceptance/history_id/history_id_test.py b/allure-pytest/test/acceptance/history_id/history_id_test.py deleted file mode 100644 index 63bfd762..00000000 --- a/allure-pytest/test/acceptance/history_id/history_id_test.py +++ /dev/null @@ -1,32 +0,0 @@ -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_history_id - - -def test_history_id(executed_docstring_source): - """ - >>> def test_history_id_example(): - ... assert True - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_history_id_example", - has_history_id() - ) - ) - - -def test_history_id_for_skipped(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.mark.skip - ... def test_history_id_for_skipped_example(): - ... assert True - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_history_id_for_skipped_example", - has_history_id() - ) - ) diff --git a/allure-pytest/test/acceptance/label/bdd/bdd_label_test.py b/allure-pytest/test/acceptance/label/bdd/bdd_label_test.py deleted file mode 100644 index 28d72275..00000000 --- a/allure-pytest/test/acceptance/label/bdd/bdd_label_test.py +++ /dev/null @@ -1,31 +0,0 @@ -""" ./examples/label/bdd/bdd_label.rst """ - -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.label import has_epic -from allure_commons_test.label import has_feature -from allure_commons_test.label import has_story - - -def test_single_bdd_label(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_single_bdd_label", - has_epic("My epic"), - has_feature("My feature"), - has_story("My story") - ) - ) - - -def test_multiple_bdd_label(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_multiple_bdd_label", - has_epic("My epic"), - has_epic("Another epic"), - has_feature("My feature"), - has_feature("Another feature"), - has_feature("One more feature"), - has_story("My story"), - has_story("Alternative story") - ) - ) diff --git a/allure-pytest/test/acceptance/label/bdd/dynamic_bdd_label_test.py b/allure-pytest/test/acceptance/label/bdd/dynamic_bdd_label_test.py deleted file mode 100644 index cb80f65a..00000000 --- a/allure-pytest/test/acceptance/label/bdd/dynamic_bdd_label_test.py +++ /dev/null @@ -1,44 +0,0 @@ -""" ./examples/label/bdd/dynamic_bdd_label.rst """ - -import pytest -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.label import has_feature, has_epic, has_story - - -def test_dynamic_labels(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_dynamic_labels", - has_feature("first feature"), - has_feature("second feature"), - has_epic("first epic"), - has_epic("second epic"), - has_story("first story"), - has_story("second story"), - ) - ) - - -@pytest.mark.parametrize("feature, epic, story", [("first feature", "first epic", "first story"), - ("second feature", "second epic", "second story")]) -def test_parametrized_dynamic_labels(executed_docstring_path, feature, epic, story): - assert_that(executed_docstring_path.allure_report, - has_test_case(f"test_parametrized_dynamic_labels[{feature}-{epic}-{story}]", - has_feature(feature), - has_epic(epic), - has_story(story), - ) - ) - - -def test_multiple_dynamic_labels(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_multiple_dynamic_labels", - has_feature("first feature"), - has_feature("second feature"), - has_epic("first epic"), - has_epic("second epic"), - has_story("first story"), - has_story("second story"), - ) - ) diff --git a/allure-pytest/test/acceptance/label/bdd/select_bdd_test.py b/allure-pytest/test/acceptance/label/bdd/select_bdd_test.py deleted file mode 100644 index fe13c4b2..00000000 --- a/allure-pytest/test/acceptance/label/bdd/select_bdd_test.py +++ /dev/null @@ -1,51 +0,0 @@ -""" ./examples/label/bdd/select_tests_by_bdd.rst """ - -import pytest -from hamcrest import assert_that, only_contains, any_of, ends_with - - -@pytest.mark.parametrize( - ["options", "expected_tests"], - [ - ({"epics": ["Another Epic"]}, - [ - "test_with_another_epic_feature_story" - ]), - - ({"features": ["My Feature"]}, - [ - "test_with_epic_feature_story", - "test_with_epic_feature" - ]), - - ({"stories": ["My Story", "Another Story"]}, - [ - "test_with_epic_feature_story", - "test_with_another_epic_feature_story" - ]), - - ({"stories": ["My Story"], "epics": ["Another Epic"]}, - [ - "test_with_epic_feature_story", - "test_with_another_epic_feature_story" - ]) - - ] -) -def test_select_by_bdd_label(allured_testdir, options, expected_tests): - allured_testdir.parse_docstring_path() - - params = [] - - for key in options.keys(): - params.append(f"--allure-{key}") - params.append(",".join(options[key])) - - allured_testdir.run_with_allure(*params) - test_cases = [test_case["fullName"] for test_case in allured_testdir.allure_report.test_cases] - - assert_that(test_cases, only_contains( - any_of( - *[ends_with(name) for name in expected_tests] - ) - )) diff --git a/allure-pytest/test/acceptance/label/custom/custom_label_test.py b/allure-pytest/test/acceptance/label/custom/custom_label_test.py deleted file mode 100644 index 1de5f0ce..00000000 --- a/allure-pytest/test/acceptance/label/custom/custom_label_test.py +++ /dev/null @@ -1,14 +0,0 @@ -""" ./examples/label/custom/custom_label.rst """ - -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.label import has_label - - -def test_custom_label(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_custom_label", - has_label("Application", "desktop"), - has_label("Application", "mobile") - ) - ) diff --git a/allure-pytest/test/acceptance/label/custom/select_custom_label_test.py b/allure-pytest/test/acceptance/label/custom/select_custom_label_test.py deleted file mode 100644 index e92b8fbc..00000000 --- a/allure-pytest/test/acceptance/label/custom/select_custom_label_test.py +++ /dev/null @@ -1,49 +0,0 @@ -""" ./examples/label/custom/select_tests_by_label.rst """ - -import pytest -from hamcrest import assert_that, ends_with, contains_inanyorder - - -@pytest.mark.parametrize( - ["labels", "expected_tests"], - [ - ( - {"Application": ["desktop"]}, - [ - "test_custom_label_one", - "test_custom_label_both" - ] - ), - ( - {"Application": ["mobile"]}, - [ - "test_custom_label_another", - "test_custom_label_both" - ] - ), - ( - {"Application": ["desktop", "mobile"]}, - [ - "test_custom_label_one", - "test_custom_label_another", - "test_custom_label_both" - ] - ), - ( - {"Application": ["mobile"], "layer": ["api"]}, - [ - "test_custom_label_another", - "test_custom_label_both", - "test_layer_label" - ] - ) - ] -) -def test_select_by_custom_label(allured_testdir, labels, expected_tests): - allured_testdir.parse_docstring_path() - allure_labels = [] - for label_name, label_values in labels.items(): - allure_labels.extend(["--allure-label", f"{label_name}={','.join(label_values)}"]) - allured_testdir.run_with_allure(*allure_labels) - test_cases = [test_case["fullName"] for test_case in allured_testdir.allure_report.test_cases] - assert_that(test_cases, contains_inanyorder(*[ends_with(name) for name in expected_tests])) diff --git a/allure-pytest/test/acceptance/label/manual/manual_test.py b/allure-pytest/test/acceptance/label/manual/manual_test.py deleted file mode 100644 index a04a315b..00000000 --- a/allure-pytest/test/acceptance/label/manual/manual_test.py +++ /dev/null @@ -1,21 +0,0 @@ -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.label import has_label - - -def test_allure_manual_label(executed_docstring_path): - """ ./examples/label/manual/allure_manual.rst """ - assert_that(executed_docstring_path.allure_report, - has_test_case("test_manual", - has_label("ALLURE_MANUAL", True) - ) - ) - - -def test_allure_manual_label_dynamic(executed_docstring_path): - """ ./examples/label/manual/allure_manual.rst """ - assert_that(executed_docstring_path.allure_report, - has_test_case("test_manual_dynamic", - has_label("ALLURE_MANUAL", True) - ), - ) diff --git a/allure-pytest/test/acceptance/label/package/regression_test.py b/allure-pytest/test/acceptance/label/package/regression_test.py deleted file mode 100644 index 358fdb5a..00000000 --- a/allure-pytest/test/acceptance/label/package/regression_test.py +++ /dev/null @@ -1,41 +0,0 @@ -import textwrap -from hamcrest import assert_that -from hamcrest import ends_with -from allure_commons_test.report import has_test_case -from allure_commons_test.label import has_package - - -def test_path_with_dots_test(allured_testdir): - path = allured_testdir.testdir.mkpydir("path.with.dots") - - path.join("test_path.py").write( - textwrap.dedent( - """\ - def test_path_with_dots_test_example(): - pass - """) - ) - - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_path_with_dots_test_example", - has_package(ends_with("path.with.dots.test_path")) - ) - ) - - -def test_with_no_package(allured_testdir): - """ - >>> def test_package_less(request): - ... pass - """ - allured_testdir.parse_docstring_source() - - allured_testdir.testdir.makeini("""[pytest]""") - allured_testdir.run_with_allure(allured_testdir.testdir.tmpdir) - - assert_that(allured_testdir.allure_report, - has_test_case("test_package_less", - has_package("test_with_no_package")) - ) diff --git a/allure-pytest/test/acceptance/label/severity/class_severity_test.py b/allure-pytest/test/acceptance/label/severity/class_severity_test.py deleted file mode 100644 index 6de97081..00000000 --- a/allure-pytest/test/acceptance/label/severity/class_severity_test.py +++ /dev/null @@ -1,41 +0,0 @@ -"""./examples/label/severity/class_severity.rst""" - -from hamcrest import assert_that, all_of, is_not -from allure_commons_test.report import has_test_case -from allure_commons_test.label import has_severity - - -def test_decorated_class_not_decorated_method(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("TestDecoratedClass#test_not_decorated_method", - has_severity("trivial") - ) - ) - - -def test_decorated_class_decorated_method(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("TestDecoratedClass#test_decorated_method", - all_of(has_severity("minor"), - is_not(has_severity("trivial")) - ) - ) - ) - - -def test_not_decorated_sub_class_not_decorated_method(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("TestNotDecoratedSubClass#test_not_decorated_method", - has_severity("trivial") - ) - ) - - -def test_not_decorated_sub_class_decorated_method(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("TestNotDecoratedSubClass#test_decorated_method", - all_of(has_severity("critical"), - is_not(has_severity("trivial")) - ) - ) - ) diff --git a/allure-pytest/test/acceptance/label/severity/module_severity_test.py b/allure-pytest/test/acceptance/label/severity/module_severity_test.py deleted file mode 100644 index 9cde900a..00000000 --- a/allure-pytest/test/acceptance/label/severity/module_severity_test.py +++ /dev/null @@ -1,37 +0,0 @@ -""" ./examples/label/severity/module_severity.rst """ - -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.label import has_severity - - -def test_not_decorated_function(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_not_decorated_function", - has_severity("trivial") - ) - ) - - -def test_decorated_function(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_decorated_function", - has_severity("minor") - ) - ) - - -def test_method_of_not_decorated_class(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_method_of_not_decorated_class", - has_severity("trivial") - ) - ) - - -def test_method_of_decorated_class(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_method_of_decorated_class", - has_severity("normal") - ) - ) diff --git a/allure-pytest/test/acceptance/label/severity/severity_test.py b/allure-pytest/test/acceptance/label/severity/severity_test.py deleted file mode 100644 index effb79b3..00000000 --- a/allure-pytest/test/acceptance/label/severity/severity_test.py +++ /dev/null @@ -1,13 +0,0 @@ -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.label import has_severity - - -def test_severity(executed_docstring_path): - """ ./examples/label/severity/severity.rst """ - - assert_that(executed_docstring_path.allure_report, - has_test_case("test_severity", - has_severity("minor"), - ) - ) diff --git a/allure-pytest/test/acceptance/label/suite/custom_suite.py b/allure-pytest/test/acceptance/label/suite/custom_suite.py deleted file mode 100644 index cccb210c..00000000 --- a/allure-pytest/test/acceptance/label/suite/custom_suite.py +++ /dev/null @@ -1,15 +0,0 @@ -""" ./examples/label/suite/custom_suite.rst """ - -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.label import has_suite, has_parent_suite, has_sub_suite - - -def test_custom_suite(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_custom_suite", - has_suite("suite name"), - has_parent_suite("parent suite name"), - has_sub_suite("sub suite name") - ) - ) diff --git a/allure-pytest/test/acceptance/label/suite/default_suite_test.py b/allure-pytest/test/acceptance/label/suite/default_suite_test.py deleted file mode 100644 index daf1d588..00000000 --- a/allure-pytest/test/acceptance/label/suite/default_suite_test.py +++ /dev/null @@ -1,40 +0,0 @@ -import pytest -from hamcrest import assert_that, anything, not_ -from allure_commons_test.report import has_test_case -from allure_commons_test.label import has_parent_suite -from allure_commons_test.label import has_suite -from allure_commons_test.label import has_sub_suite - - -@pytest.mark.skip -def test_default_suite(executed_docstring_source): - """ - >>> def test_default_suite_example(): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_default_suite_example", - has_parent_suite(anything()), # path to testdir - has_suite("test_default_suite"), # created file name - not_(has_sub_suite(anything())) - ) - ) - - -@pytest.mark.skip -def test_default_class_suite(executed_docstring_source): - """ - >>> class TestSuiteClass: - ... def test_default_class_suite_example(self): - ... pass - - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_default_class_suite_example", - has_parent_suite(anything()), # path to testdir - has_suite("test_default_class_suite"), # created file name - has_sub_suite("TestSuiteClass") - ) - ) diff --git a/allure-pytest/test/acceptance/label/suite/module_level_custom_suite_test.py b/allure-pytest/test/acceptance/label/suite/module_level_custom_suite_test.py deleted file mode 100644 index 04e3fe7e..00000000 --- a/allure-pytest/test/acceptance/label/suite/module_level_custom_suite_test.py +++ /dev/null @@ -1,13 +0,0 @@ -""" ./examples/label/suite/module_level_custom_suite.rst """ - -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.label import has_suite - - -def test_module_custom_suite(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_module_level_custom_suite", - has_suite("module level suite name"), - ) - ) diff --git a/allure-pytest/test/acceptance/label/tag/tag_test.py b/allure-pytest/test/acceptance/label/tag/tag_test.py deleted file mode 100644 index 0636e5cb..00000000 --- a/allure-pytest/test/acceptance/label/tag/tag_test.py +++ /dev/null @@ -1,125 +0,0 @@ -from hamcrest import assert_that, not_ -from allure_commons_test.report import has_test_case -from allure_commons_test.label import has_tag - - -def test_pytest_marker(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.mark.cool - ... @pytest.mark.stuff - ... def test_pytest_marker_example(): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_pytest_marker_example", - has_tag("cool"), - has_tag("stuff") - ) - ) - - -def test_show_reserved_pytest_markers_full_decorator(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.mark.usermark1 - ... @pytest.mark.usermark2 - ... @pytest.mark.parametrize("param", ["foo"]) - ... @pytest.mark.skipif(False, reason="reason2") - ... @pytest.mark.skipif(False, reason="reason1") - ... def test_show_reserved_pytest_markers_full_decorator_example(param): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case('test_show_reserved_pytest_markers_full_decorator_example[foo]', - has_tag("usermark1"), - has_tag("usermark2"), - has_tag("@pytest.mark.skipif(False, reason='reason1')"), - not_(has_tag("@pytest.mark.skipif(False, reason='reason2')")), - not_(has_tag("@pytest.mark.parametrize('param', ['foo'])")) - ) - ) - - -def test_pytest_xfail_marker(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.mark.xfail(reason='this is unexpect pass') - ... def test_pytest_xfail_marker_example(): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case('test_pytest_xfail_marker_example', - has_tag("@pytest.mark.xfail(reason='this is unexpect pass')"), - ) - ) - - -def test_pytest_marker_with_args(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.mark.marker('cool', 'stuff') - ... def test_pytest_marker_with_args_example(): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_pytest_marker_with_args_example", - has_tag("marker('cool', 'stuff')") - ) - ) - - -def test_pytest_marker_with_kwargs(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.mark.marker(stuff='cool') - ... def test_pytest_marker_with_kwargs_example(): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_pytest_marker_with_kwargs_example", - has_tag("marker(stuff='cool')") - ) - ) - - -def test_pytest_marker_with_kwargs_native_encoding(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.mark.marker(stuff='я') - ... def test_pytest_marker_with_kwargs_native_encoding_example(): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_pytest_marker_with_kwargs_native_encoding_example", - has_tag("marker(stuff='я')") - ) - ) - - -def test_pytest_marker_with_kwargs_utf_encoding(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.mark.marker(stuff='я') - ... def test_pytest_marker_with_kwargs_utf_encoding_example(): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_pytest_marker_with_kwargs_utf_encoding_example", - has_tag("marker(stuff='я')") - ) - ) diff --git a/allure-pytest/test/acceptance/link/dynamic_link_test.py b/allure-pytest/test/acceptance/link/dynamic_link_test.py deleted file mode 100644 index 8fe6d610..00000000 --- a/allure-pytest/test/acceptance/link/dynamic_link_test.py +++ /dev/null @@ -1,46 +0,0 @@ -""" ./examples/link/dynamic_link.rst """ - -import pytest -from hamcrest import assert_that, equal_to -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_link -from allure_commons_test.result import has_issue_link - - -def test_dynamic_link(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_dynamic_link", - has_issue_link("issues/24") - ) - ) - - -@pytest.mark.parametrize("link", ["issues/24", "issues/132"]) -def test_parametrize_dynamic_link(executed_docstring_path, link): - assert_that(executed_docstring_path.allure_report, - has_test_case(f"test_parametrize_dynamic_link[{link}]", - has_issue_link(link), - ) - ) - - -def test_all_links_together(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_all_links_together", - has_issue_link("issues/24"), - has_issue_link("issues/132"), - has_link("allure", name="QAMETA", link_type="docs") - ) - ) - - -def test_unique_dynamic_links(executed_docstring_source): - """ - >>> import allure - - >>> def test_unique_dynamic_links_example(): - ... allure.dynamic.link("some/unique/dynamic/link") - ... allure.dynamic.link("some/unique/dynamic/link") - """ - assert_that(executed_docstring_source.allure_report.test_cases[0]['links'], - equal_to([{'url': 'some/unique/dynamic/link', 'type': 'link', 'name': 'some/unique/dynamic/link'}])) diff --git a/allure-pytest/test/acceptance/link/link_pattern_test.py b/allure-pytest/test/acceptance/link/link_pattern_test.py deleted file mode 100644 index 28d251b9..00000000 --- a/allure-pytest/test/acceptance/link/link_pattern_test.py +++ /dev/null @@ -1,22 +0,0 @@ -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_link, has_issue_link - - -def test_link_pattern(allured_testdir): - """ ./examples/link/dynamic_link.rst """ - - allured_testdir.parse_docstring_path() - - allured_testdir.run_with_allure("--allure-link-pattern", - "issue:https://github.com/allure-framework/allure-python2/{}", - "--allure-link-pattern", - "docs:https://docs.qameta.io/{}") - - assert_that(allured_testdir.allure_report, - has_test_case("test_all_links_together", - has_issue_link("https://github.com/allure-framework/allure-python2/issues/24"), - has_issue_link("https://github.com/allure-framework/allure-python2/issues/24"), - has_link("https://docs.qameta.io/allure") - ) - ) diff --git a/allure-pytest/test/acceptance/link/link_test.py b/allure-pytest/test/acceptance/link/link_test.py deleted file mode 100644 index 24f6868a..00000000 --- a/allure-pytest/test/acceptance/link/link_test.py +++ /dev/null @@ -1,39 +0,0 @@ -""" ./examples/link/link.rst """ - -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_link -from allure_commons_test.result import has_issue_link -from allure_commons_test.result import has_test_case_link - - -def test_link(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_link", - has_link("http://qameta.io") - ) - ) - - -def test_issue_link(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_issue_link", - has_issue_link("https://github.com/allure-framework/allure-python/issues/24") - ) - ) - - -def test_testcase_link(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_testcase_link", - has_test_case_link("issues/24#issuecomment-277330977") - ) - ) - - -def test_custom_link(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_custom_link", - has_link("http://qameta.io", name="QAMETA", link_type="homepage") - ) - ) diff --git a/allure-pytest/test/acceptance/parametrization/metafunc_test.py b/allure-pytest/test/acceptance/parametrization/metafunc_test.py deleted file mode 100644 index 620f133a..00000000 --- a/allure-pytest/test/acceptance/parametrization/metafunc_test.py +++ /dev/null @@ -1,43 +0,0 @@ -import pytest -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_parameter - - -@pytest.mark.parametrize("param", [True, False]) -def test_metafunc_param(executed_docstring_source, param): - """ - >>> def pytest_generate_tests(metafunc): - ... if "metafunc_param" in metafunc.fixturenames: - ... metafunc.parametrize("metafunc_param", [True, False]) - - - >>> def test_metafunc_param_example(metafunc_param): - ... assert metafunc_param - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case(f"test_metafunc_param_example[{param}]", - has_parameter("metafunc_param", str(param)) - ) - ) - - -@pytest.mark.parametrize("param", [True, False]) -def test_metafunc_param_with_ids(executed_docstring_source, param): - """ - >>> def pytest_generate_tests(metafunc): - ... if "metafunc_param_with_ids" in metafunc.fixturenames: - ... metafunc.parametrize("metafunc_param_with_ids", [True, False], ids=["pass", "fail"]) - - - >>> def test_metafunc_param_with_ids_example(metafunc_param_with_ids): - ... assert metafunc_param_with_ids - """ - - param_name = "pass" if param else "fail" - assert_that(executed_docstring_source.allure_report, - has_test_case(f"test_metafunc_param_with_ids_example[{param_name}]", - has_parameter("metafunc_param_with_ids", str(param)) - ) - ) diff --git a/allure-pytest/test/acceptance/parametrization/parametrization_test.py b/allure-pytest/test/acceptance/parametrization/parametrization_test.py deleted file mode 100644 index d03c14e5..00000000 --- a/allure-pytest/test/acceptance/parametrization/parametrization_test.py +++ /dev/null @@ -1,193 +0,0 @@ -import pytest -from hamcrest import assert_that, has_entry, ends_with -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_parameter, with_excluded, with_mode - - -def params_name(request): - node_id = request.node.nodeid - _, name = node_id.rstrip("]").split("[") - return name - - -@pytest.mark.parametrize("param", [True, False]) -def test_parametrization(executed_docstring_source, param): - """ - >>> import pytest - - >>> @pytest.mark.parametrize("param", [True, False]) - ... def test_parametrization_example(param): - ... assert param - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case(f"test_parametrization_example[{param}]", - has_parameter("param", str(param)) - ) - ) - - -@pytest.mark.xfail() -@pytest.mark.parametrize("param", [True, False], ids=["pass", "fail"]) -def test_parametrization_with_ids(executed_docstring_source, param): - """ - >>> import pytest - - >>> @pytest.mark.parametrize("param", [True, False], ids=["pass", "fail"]) - ... def test_parametrization_with_ids_example(param): - ... assert param - """ - - param_name = "pass" if param else "fail" - assert_that(executed_docstring_source.allure_report, - has_test_case( - f"test_parametrization_with_ids_example[{param_name}]", - has_parameter(param_name, str(param)) - ) - ) - - -@pytest.mark.parametrize("param1", [True, False]) -@pytest.mark.parametrize("param2", [True, True]) -def test_parametrization_many_decorators(executed_docstring_source, request, param1, param2): - """ - >>> import pytest - - >>> @pytest.mark.parametrize("param1", [True, False]) - ... @pytest.mark.parametrize("param2", [True, True]) - ... def test_parametrization_many_decorators_example(param1, param2): - ... pass - """ - - test_name = f"test_parametrization_many_decorators_example[{params_name(request)}]" - - assert_that(executed_docstring_source.allure_report, - has_test_case(test_name, - has_parameter("param1", str(param1)), - has_parameter("param2", str(param2)) - - ) - ) - - -@pytest.mark.xfail() -@pytest.mark.parametrize("param1", [True, False], ids=["pass", "fail"]) -@pytest.mark.parametrize("param2", [True, True]) -def test_parametrization_many_decorators_with_partial_ids(executed_docstring_source, request, param1, param2): - """ - >>> import pytest - - >>> @pytest.mark.parametrize("param1", [True, False], ids=["first_pass", "first_fail"]) - ... @pytest.mark.parametrize("param2", [True, True]) - ... def test_parametrization_many_decorators_with_partial_ids_example(param1, param2): - ... pass - """ - - test_name = f"test_parametrization_many_decorators_with_partial_ids_example[{params_name(request)}]" - - assert_that(executed_docstring_source.allure_report, - has_test_case(test_name, - has_parameter("pass" if param1 else "fail", str(param1)), - has_parameter("param2", str(param2)) - - ) - ) - - -def test_dynamic_parameter_add(executed_docstring_source): - """ - >>> import allure - - >>> def test_parameter_add(): - ... allure.dynamic.parameter("param1", "param-value") - """ - assert_that(executed_docstring_source.allure_report, - has_test_case("test_parameter_add", - has_parameter("param1", "'param-value'") - ) - ) - - -def test_dynamic_parameter_excluded(executed_docstring_source): - """ - >>> import allure - - >>> def test_parameter_excluded(): - ... allure.dynamic.parameter("param1", "param-value", excluded=True) - """ - assert_that(executed_docstring_source.allure_report, - has_test_case("test_parameter_excluded", - has_parameter("param1", "'param-value'", - with_excluded()) - ) - ) - - -def test_dynamic_parameter_mode(executed_docstring_source): - """ - >>> import allure - - >>> def test_parameter_mode(): - ... allure.dynamic.parameter("param1", "param-value", mode=allure.parameter_mode.MASKED) - """ - assert_that(executed_docstring_source.allure_report, - has_test_case("test_parameter_mode", - has_parameter("param1", "'param-value'", - with_mode('masked')) - ) - ) - - -def test_dynamic_parameter_override(executed_docstring_source): - """ - >>> import pytest - ... import allure - - >>> @pytest.mark.parametrize("param1", [object()], ids=["param-id"]) - ... def test_parameter_override(param1): - ... allure.dynamic.parameter("param1", "readable-value") - """ - assert_that(executed_docstring_source.allure_report, - has_test_case("test_parameter_override[param-id]", - has_parameter("param1", "'readable-value'") - ) - ) - - -def test_dynamic_parameter_override_from_fixture(executed_docstring_source): - """ - >>> import pytest - ... import allure - - - >>> @pytest.fixture() - ... def fixt(): - ... allure.dynamic.parameter("param1", "readable-value") - - >>> @pytest.mark.parametrize("param1", [object()], ids=["param-id"]) - ... def test_parameter_override_from_fixture(fixt, param1): - ... pass - """ - assert_that(executed_docstring_source.allure_report, - has_test_case("test_parameter_override_from_fixture[param-id]", - has_parameter("param1", "'readable-value'") - ) - ) - - -def test_fullname_with_braces(executed_docstring_source): - """ - >>> import pytest - ... import allure - - >>> class TestClass: - ... @pytest.mark.parametrize("param1", ["qwe]["]) - ... def test_with_braces(self, param1): - ... pass - """ - assert_that(executed_docstring_source.allure_report, - has_test_case("test_with_braces[qwe][]", - has_entry('fullName', ends_with(".TestClass#test_with_braces")), - has_parameter("param1", "'qwe]['") - ) - ) diff --git a/allure-pytest/test/acceptance/status/base_call_status_test.py b/allure-pytest/test/acceptance/status/base_call_status_test.py deleted file mode 100644 index a7f96364..00000000 --- a/allure-pytest/test/acceptance/status/base_call_status_test.py +++ /dev/null @@ -1,88 +0,0 @@ -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import with_status -from allure_commons_test.result import has_status_details -from allure_commons_test.result import with_message_contains -from allure_commons_test.result import with_trace_contains - - -def test_passed(executed_docstring_source): - """ - >>> def test_passed_example(): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_passed_example", - with_status("passed") - ) - ) - - -def test_failed(executed_docstring_source): - """ - >>> def test_failed_example(): - ... assert False - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_failed_example", - with_status("failed"), - has_status_details(with_message_contains("AssertionError"), - with_trace_contains("def test_failed_example():") - ) - ) - ) - - -def test_broken(executed_docstring_source): - """ - >>> def test_broken_example(): - ... raise IndentationError() - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_broken_example", - with_status("broken"), - has_status_details(with_message_contains("IndentationError"), - with_trace_contains("def test_broken_example():") - ) - ) - ) - - -def test_call_pytest_fail(executed_docstring_source): - """ - >>> import pytest - - >>> def test_call_pytest_fail_example(): - ... pytest.fail() - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_call_pytest_fail_example", - with_status("failed"), - has_status_details(with_message_contains("Failed"), - with_trace_contains("def test_call_pytest_fail_example():") - ) - ) - ) - - -def test_call_pytest_fail_with_reason(executed_docstring_source): - """ - >>> import pytest - - >>> def test_call_pytest_fail_with_reason_example(): - ... pytest.fail("Fail message") - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_call_pytest_fail_with_reason_example", - with_status("failed"), - has_status_details(with_message_contains("Fail message"), - with_trace_contains("def test_call_pytest_fail_with_reason_example():") - ) - ) - - ) diff --git a/allure-pytest/test/acceptance/status/base_setup_status_test.py b/allure-pytest/test/acceptance/status/base_setup_status_test.py deleted file mode 100644 index 9cec930c..00000000 --- a/allure-pytest/test/acceptance/status/base_setup_status_test.py +++ /dev/null @@ -1,159 +0,0 @@ -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import with_status -from allure_commons_test.result import has_status_details -from allure_commons_test.result import with_message_contains -from allure_commons_test.result import with_trace_contains -from allure_commons_test.container import has_container -from allure_commons_test.container import has_before - - -def test_failed_fixture(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.fixture - ... def failed_fixture(): - ... assert False - - >>> def test_failed_fixture_example(failed_fixture): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_failed_fixture_example", - with_status("failed"), - has_status_details(with_message_contains("AssertionError"), - with_trace_contains("def failed_fixture():") - ), - has_container(executed_docstring_source.allure_report, - has_before("failed_fixture", - with_status("failed"), - has_status_details(with_message_contains("AssertionError"), - with_trace_contains("failed_fixture") - ), - ), - ) - ) - ) - - -def test_broken_fixture(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.fixture - ... def broken_fixture(): - ... raise IndexError - - >>> def test_broken_fixture_example(broken_fixture): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_broken_fixture_example", - with_status("broken"), - has_status_details(with_message_contains("IndexError"), - with_trace_contains("def broken_fixture():") - ), - has_container(executed_docstring_source.allure_report, - has_before("broken_fixture", - with_status("broken"), - has_status_details(with_message_contains("IndexError"), - with_trace_contains("broken_fixture") - ), - ), - ) - ) - ) - - -def test_skip_fixture(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.fixture - ... def skip_fixture(): - ... pytest.skip() - - >>> def test_skip_fixture_example(skip_fixture): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_skip_fixture_example", - with_status("skipped"), - has_status_details(with_message_contains("Skipped")), - has_container(executed_docstring_source.allure_report, - has_before("skip_fixture", - with_status("skipped"), - has_status_details( - with_message_contains("Skipped"), - with_trace_contains("skip_fixture") - ), - ), - ) - ) - ) - - -def test_pytest_fail_fixture(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.fixture - ... def pytest_fail_fixture(): - ... pytest.fail() - - >>> def test_pytest_fail_fixture_example(pytest_fail_fixture): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_pytest_fail_fixture_example", - with_status("failed"), - has_status_details(with_message_contains("Failed"), - with_trace_contains("def pytest_fail_fixture():") - ), - has_container(executed_docstring_source.allure_report, - has_before("pytest_fail_fixture", - with_status("failed"), - has_status_details( - with_message_contains("Failed"), - with_trace_contains("pytest_fail_fixture") - ), - ), - ) - ) - ) - - -def test_pytest_fail_with_reason_fixture(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.fixture - ... def pytest_fail_with_reason_fixture(): - ... pytest.fail("Fail message") - - >>> def test_pytest_fail_with_reason_fixture_example(pytest_fail_with_reason_fixture): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_pytest_fail_with_reason_fixture_example", - with_status("failed"), - has_status_details(with_message_contains("Fail message"), - with_trace_contains("def pytest_fail_with_reason_fixture():") - ), - has_container(executed_docstring_source.allure_report, - has_before("pytest_fail_with_reason_fixture", - with_status("failed"), - has_status_details(with_message_contains("Fail message"), - with_trace_contains( - "pytest_fail_with_reason_fixture") - ), - ), - ) - ) - ) diff --git a/allure-pytest/test/acceptance/status/base_step_status_test.py b/allure-pytest/test/acceptance/status/base_step_status_test.py deleted file mode 100644 index 46aa6888..00000000 --- a/allure-pytest/test/acceptance/status/base_step_status_test.py +++ /dev/null @@ -1,84 +0,0 @@ -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_step -from allure_commons_test.result import with_status -from allure_commons_test.result import has_status_details -from allure_commons_test.result import with_message_contains -from allure_commons_test.result import with_trace_contains - - -def test_broken_step(executed_docstring_source): - """ - >>> import allure - - >>> def test_broken_step_example(): - ... with allure.step("Step"): - ... raise ZeroDivisionError - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_broken_step_example", - with_status("broken"), - has_status_details(with_message_contains("ZeroDivisionError"), - with_trace_contains("def test_broken_step_example():") - ), - has_step("Step", - with_status("broken"), - has_status_details(with_message_contains("ZeroDivisionError"), - with_trace_contains("test_broken_step_example") - ) - ) - ) - ) - - -def test_pytest_fail_in_step(executed_docstring_source): - """ - >>> import pytest - >>> import allure - - >>> def test_pytest_fail_in_step_example(): - ... with allure.step("Step"): - ... pytest.fail() - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_pytest_fail_in_step_example", - with_status("failed"), - has_status_details(with_message_contains("Failed"), - with_trace_contains("def test_pytest_fail_in_step_example():") - ), - has_step("Step", - with_status("failed"), - has_status_details(with_message_contains("Failed"), - with_trace_contains("test_pytest_fail_in_step_example") - ) - ) - ) - ) - - -def test_pytest_bytes_data_in_assert(executed_docstring_source): - """ - >>> import allure - - >>> def test_pytest_bytes_data_in_assert_example(): - ... with allure.step("Step"): - ... assert "0\\x82" == 1 - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_pytest_bytes_data_in_assert_example", - with_status("failed"), - has_status_details(with_message_contains("AssertionError: assert \'0\\x82\' == 1"), - with_trace_contains("def test_pytest_bytes_data_in_assert_example():") - ), - has_step("Step", - with_status("failed"), - has_status_details( - with_message_contains("AssertionError: assert \'0\\x82\' == 1"), - with_trace_contains("test_pytest_bytes_data_in_assert_example") - ) - ) - ) - ) diff --git a/allure-pytest/test/acceptance/status/skip_call_status_test.py b/allure-pytest/test/acceptance/status/skip_call_status_test.py deleted file mode 100644 index 70844f28..00000000 --- a/allure-pytest/test/acceptance/status/skip_call_status_test.py +++ /dev/null @@ -1,87 +0,0 @@ -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import with_status -from allure_commons_test.result import has_status_details -from allure_commons_test.result import with_message_contains - - -def test_skip(executed_docstring_source): - """ - >>> import pytest - - >>> def test_skip_example(): - ... pytest.skip() - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_skip_example", - with_status("skipped"), - has_status_details(with_message_contains("Skipped")) - ) - ) - - -def test_skip_with_reason(executed_docstring_source): - """ - >>> import pytest - - >>> def test_skip_with_reason_example(): - ... pytest.skip("Skip reason") - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_skip_with_reason_example", - with_status("skipped"), - has_status_details(with_message_contains("Skipped: Skip reason")) - ) - ) - - -def test_skip_decorator_and_reason(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.mark.skip(reason="Skip reason") - ... def test_skip_decorator_and_reason_example(): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_skip_decorator_and_reason_example", - with_status("skipped"), - has_status_details(with_message_contains("Skipped: Skip reason")) - ) - ) - - -def test_skipif_true(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.mark.skipif(True, reason="Skip reason") - ... def test_skipif_true_example(): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_skipif_true_example", - with_status("skipped"), - has_status_details(with_message_contains("Skipped: Skip reason")) - ) - ) - - -def test_skipif_false(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.mark.skipif(False, reason="Skip reason") - ... def test_skipif_false_example(): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_skipif_false_example", - with_status("passed") - ) - ) diff --git a/allure-pytest/test/acceptance/status/skip_setup_status_test.py b/allure-pytest/test/acceptance/status/skip_setup_status_test.py deleted file mode 100644 index 186bd601..00000000 --- a/allure-pytest/test/acceptance/status/skip_setup_status_test.py +++ /dev/null @@ -1,40 +0,0 @@ -import allure -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import with_status -from allure_commons_test.result import has_status_details -from allure_commons_test.result import with_message_contains -from allure_commons_test.result import with_trace_contains -from allure_commons_test.container import has_container -from allure_commons_test.container import has_before - - -@allure.feature("Fixture") -def test_skip_fixture(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.fixture - ... def skip_fixture(): - ... pytest.skip() - - >>> @pytest.mark.xfail() - ... def test_skip_fixture_example(skip_fixture): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_skip_fixture_example", - with_status("skipped"), - has_status_details(with_message_contains("Skipped")), - has_container(executed_docstring_source.allure_report, - has_before("skip_fixture", - with_status("skipped"), - has_status_details( - with_message_contains("Skipped"), - with_trace_contains("skip_fixture") - ), - ), - ) - ) - ) diff --git a/allure-pytest/test/acceptance/status/skip_step_status_test.py b/allure-pytest/test/acceptance/status/skip_step_status_test.py deleted file mode 100644 index 637ed838..00000000 --- a/allure-pytest/test/acceptance/status/skip_step_status_test.py +++ /dev/null @@ -1,31 +0,0 @@ -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_step -from allure_commons_test.result import with_status -from allure_commons_test.result import has_status_details -from allure_commons_test.result import with_message_contains -from allure_commons_test.result import with_trace_contains - - -def test_skip_in_step(executed_docstring_source): - """ - >>> import pytest - >>> import allure - - >>> def test_skip_in_step_example(): - ... with allure.step("Step"): - ... pytest.skip() - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_skip_in_step_example", - with_status("skipped"), - has_status_details(with_message_contains("Skipped")), - has_step("Step", - with_status("skipped"), - has_status_details(with_message_contains("Skipped"), - with_trace_contains("test_skip_in_step") - ) - ) - ) - ) diff --git a/allure-pytest/test/acceptance/status/xfail_call_status_test.py b/allure-pytest/test/acceptance/status/xfail_call_status_test.py deleted file mode 100644 index 5275723a..00000000 --- a/allure-pytest/test/acceptance/status/xfail_call_status_test.py +++ /dev/null @@ -1,105 +0,0 @@ -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import with_status -from allure_commons_test.result import has_status_details -from allure_commons_test.result import with_message_contains -from allure_commons_test.result import with_trace_contains - - -def test_xfail(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.mark.xfail() - ... def test_xfail_example(): - ... assert False - - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_xfail_example", - with_status("skipped"), - has_status_details(with_message_contains("XFAIL"), - with_message_contains("AssertionError"), - with_trace_contains("def test_xfail_example():") - ) - ) - ) - - -def test_xfail_with_reason_raise_mentioned_exception(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.mark.xfail(raises=AssertionError, reason='Some reason') - ... def test_xfail_with_reason_raise_mentioned_exception_example(): - ... assert False - - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_xfail_with_reason_raise_mentioned_exception_example", - with_status("skipped"), - has_status_details(with_message_contains("XFAIL Some reason"), - with_message_contains("AssertionError"), - with_trace_contains( - "def test_xfail_with_reason_raise_mentioned_exception_example():") - ) - ) - ) - - -def test_xfail_raise_not_mentioned_exception(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.mark.xfail(raises=AssertionError) - ... def test_xfail_raise_not_mentioned_exception_example(): - ... raise ZeroDivisionError - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_xfail_raise_not_mentioned_exception_example", - with_status("broken"), - has_status_details(with_message_contains("ZeroDivisionError"), - with_trace_contains( - "def test_xfail_raise_not_mentioned_exception_example():") - ) - ) - ) - - -def test_xfail_do_not_raise_mentioned_exception(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.mark.xfail(raises=AssertionError) - ... def test_xfail_do_not_raise_mentioned_exception_example(): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_xfail_do_not_raise_mentioned_exception_example", - with_status("passed"), - has_status_details(with_message_contains("XPASS"), - ) - ) - ) - - -def test_xfail_with_reason_do_not_raise_mentioned_exception(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.mark.xfail(raises=AssertionError, reason="Some reason") - ... def test_xfail_with_reason_do_not_raise_mentioned_exception_example(): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_xfail_with_reason_do_not_raise_mentioned_exception_example", - with_status("passed"), - has_status_details(with_message_contains("XPASS Some reason"), - ) - ) - ) diff --git a/allure-pytest/test/acceptance/status/xfail_setup_status_test.py b/allure-pytest/test/acceptance/status/xfail_setup_status_test.py deleted file mode 100644 index 28e8e092..00000000 --- a/allure-pytest/test/acceptance/status/xfail_setup_status_test.py +++ /dev/null @@ -1,73 +0,0 @@ -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import with_status -from allure_commons_test.result import has_status_details -from allure_commons_test.result import with_message_contains -from allure_commons_test.result import with_trace_contains -from allure_commons_test.container import has_container -from allure_commons_test.container import has_before - - -def test_xfail_with_run_false(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.mark.xfail(run=False) - ... def test_xfail_with_run_false_example(): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_xfail_with_run_false_example", - with_status("skipped"), - has_status_details(with_message_contains("Failed: [NOTRUN]")), - ) - ) - - -def test_xfail_with_run_false_and_with_reason(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.mark.xfail(run=False, reason="Some reason") - ... def test_xfail_with_run_false_and_with_reason_example(): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_xfail_with_run_false_and_with_reason_example", - with_status("skipped"), - has_status_details(with_message_contains("Failed: [NOTRUN] Some reason")) - ) - ) - - -def test_xfail_fixture(executed_docstring_source): - """ - >>> import pytest - - >>> @pytest.fixture - ... def broken_fixture(): - ... raise NotImplementedError - - >>> @pytest.mark.xfail() - ... def test_xfail_fixture_example(broken_fixture): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_xfail_fixture_example", - with_status("skipped"), - has_status_details(with_message_contains("NotImplementedError"), - with_trace_contains("def broken_fixture():") - ), - has_container(executed_docstring_source.allure_report, - has_before("broken_fixture", - with_status("broken"), - has_status_details(with_message_contains("NotImplementedError"), - with_trace_contains("broken_fixture") - ), - ), - ) - ) - ) diff --git a/allure-pytest/test/acceptance/status/xfail_step_status_test.py b/allure-pytest/test/acceptance/status/xfail_step_status_test.py deleted file mode 100644 index 1e57bd4a..00000000 --- a/allure-pytest/test/acceptance/status/xfail_step_status_test.py +++ /dev/null @@ -1,34 +0,0 @@ -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_step -from allure_commons_test.result import with_status -from allure_commons_test.result import has_status_details -from allure_commons_test.result import with_message_contains -from allure_commons_test.result import with_trace_contains - - -def test_xfail_step_failure(executed_docstring_source): - """ - >>> import pytest - >>> import allure - - >>> @pytest.mark.xfail() - ... def test_xfail_step_failure_example(): - ... with allure.step("Step"): - ... assert False - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_xfail_step_failure_example", - with_status("skipped"), - has_status_details(with_message_contains("AssertionError"), - with_trace_contains("def test_xfail_step_failure_example():") - ), - has_step("Step", - with_status("failed"), - has_status_details(with_message_contains("AssertionError"), - with_trace_contains("test_xfail_step_failure_example") - ) - ) - ) - ) diff --git a/allure-pytest/test/acceptance/step/outside_step_test.py b/allure-pytest/test/acceptance/step/outside_step_test.py deleted file mode 100644 index a724628b..00000000 --- a/allure-pytest/test/acceptance/step/outside_step_test.py +++ /dev/null @@ -1,83 +0,0 @@ -import allure -from hamcrest import assert_that, not_ -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_step -from allure_commons_test.container import has_container -from allure_commons_test.container import has_before - - -def test_step_from_init_py(allured_testdir): - allured_testdir.testdir.makepyfile(__init__=""" - import allure - - @allure.step("function in __init__ marked as step") - def step_from__init__(): - pass - """) - - allured_testdir.testdir.makepyfile(""" - from . import step_from__init__ - - def test_step_from_init_py_example(): - step_from__init__() - """) - - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_step_from_init_py_example", - has_step("function in __init__ marked as step") - ) - ) - - -def test_fixture_with_step_from_conftest(allured_testdir): - allured_testdir.testdir.makeconftest(""" - import allure - import pytest - - @allure.step("step in conftest.py") - def conftest_step(): - pass - - - @pytest.fixture - def fixture_with_conftest_step(): - conftest_step() - """) - - allured_testdir.testdir.makepyfile(""" - def test_fixture_with_step_from_conftest_example(fixture_with_conftest_step): - pass - """) - - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_fixture_with_step_from_conftest_example", - has_container(allured_testdir.allure_report, - has_before("fixture_with_conftest_step", - has_step("step in conftest.py") - ) - ) - ) - ) - - -@allure.issue("232") -def test_call_decorated_as_step_function(executed_docstring_source): - """ - >>> import allure - - >>> with allure.step("step outside"): - ... pass - - >>> def test_call_decorated_as_step_function_example(): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_call_decorated_as_step_function_example", - not_(has_step("step outside")) - ) - ) diff --git a/allure-pytest/test/acceptance/step/step_parameters.py b/allure-pytest/test/acceptance/step/step_parameters.py deleted file mode 100644 index 19e3bba8..00000000 --- a/allure-pytest/test/acceptance/step/step_parameters.py +++ /dev/null @@ -1,57 +0,0 @@ -import pytest -from hamcrest import assert_that -from allure_commons.utils import represent -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_step -from allure_commons_test.result import has_parameter - - -def params_name(request): - node_id = request.node.nodeid - _, name = node_id.rstrip("]").split("[") - return name - - -@pytest.mark.parametrize( - ["args", "kwargs"], - [ - ([True], {"kwarg": False}), - ([True], {"kwarg": False}), - (["hi"], {"kwarg": None}), - ([None], {"kwarg": 42}) - ] -) -def test_step_parameters(executed_docstring_source, request, args, kwargs): - """ - >>> import pytest - >>> import allure - - >>> @allure.step - ... def step(arg, kwarg=None): - ... pass - - >>> @pytest.mark.parametrize( - ... ["args", "kwargs"], - ... [ - ... ([True], {"kwarg": False}), - ... ([True], {"kwarg": False}), - ... (["hi"], {"kwarg": None}), - ... ([None], {"kwarg": 42}) - ... ] - ... ) - ... def test_args_less_than_placeholders_example(args, kwargs): - ... step(*args, **kwargs) - """ - - test_name = f"test_args_less_than_placeholders_example[{params_name(request)}]" - - assert_that(executed_docstring_source.allure_report, - has_test_case(test_name, - has_step("step", - *([has_parameter("arg", represent(arg)) for arg in args] + - [has_parameter("kwarg", represent(kwarg)) for kwarg in kwargs.values()] - ) - - ) - ) - ) diff --git a/allure-pytest/test/acceptance/step/step_placeholder_test.py b/allure-pytest/test/acceptance/step/step_placeholder_test.py deleted file mode 100644 index 6c4eda5f..00000000 --- a/allure-pytest/test/acceptance/step/step_placeholder_test.py +++ /dev/null @@ -1,51 +0,0 @@ -""" ./examples/step/step_placeholder.rst """ -import pytest -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_step -from allure_commons_test.result import has_status_details -from allure_commons_test.result import with_message_contains - - -def test_step_with_args_in_placeholder(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_step_with_args_in_placeholder", - has_step("Step with two args: 'first' and 'second'") - ) - ) - - -def test_step_with_kwargs_in_placeholder(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_step_with_kwargs_in_placeholder", - has_step("Step with two kwargs: '1' and 'second'") - ) - ) - - -def test_class_method_as_step(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_class_method_as_step", - has_step("Class method step with 'first' and 'second'") - ) - ) - - -@pytest.mark.skip() -def test_args_less_than_placeholders(executed_docstring_source): - """ - >>> import allure - - >>> @allure.step("{0} and {1}") - ... def step(arg): - ... pass - - >>> def test_args_less_than_placeholders_example(): - ... step(0) - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_args_less_than_placeholders_example", - has_status_details(with_message_contains("IndexError: tuple index out of range")) - ) - ) diff --git a/allure-pytest/test/acceptance/step/step_test.py b/allure-pytest/test/acceptance/step/step_test.py deleted file mode 100644 index 75bd1668..00000000 --- a/allure-pytest/test/acceptance/step/step_test.py +++ /dev/null @@ -1,42 +0,0 @@ -""" ./examples/step/step.rst """ - -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_step - - -def test_inline_step(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_inline_step", - has_step("inline step") - ) - ) - - -def test_reusable_step(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_reusable_step", - has_step("passed_step") - ) - ) - - -def test_nested_steps(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_nested_steps", - has_step("grand parent step", - has_step("parent step", - has_step("passed_step" - ) - ) - ) - ) - ) - - -def test_class_method_as_step(executed_docstring_path): - assert_that(executed_docstring_path.allure_report, - has_test_case("test_class_method_as_step", - has_step("class method as step") - ) - ) diff --git a/allure-pytest/test/acceptance/step/test_step_with_several_step_inside_thread.py b/allure-pytest/test/acceptance/step/test_step_with_several_step_inside_thread.py deleted file mode 100644 index 5fdc56fd..00000000 --- a/allure-pytest/test/acceptance/step/test_step_with_several_step_inside_thread.py +++ /dev/null @@ -1,74 +0,0 @@ -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_step -from hamcrest import assert_that - - -def test_step_with_thread(allured_testdir): - allured_testdir.testdir.makepyfile( - """ - from concurrent.futures import ThreadPoolExecutor - - import allure - - @allure.step("thread {x}") - def parallel_step(x=1): - with allure.step("Sub-step in thread"): - pass - - - def test_thread(): - with allure.step("Start in thread"): - with ThreadPoolExecutor(max_workers=2) as executor: - executor.map(parallel_step, [1, 2]) - """ - ) - - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_thread", - has_step("Start in thread", - has_step("thread 1", has_step("Sub-step in thread")), - has_step("thread 2") - ) - ) - ) - - -def test_step_with_reused_threads(allured_testdir): - allured_testdir.testdir.makepyfile( - """ - from concurrent.futures import ThreadPoolExecutor - - import allure - import random - from time import sleep - - @allure.step("thread {x}") - def parallel_step(x=1): - sleep(random.randint(0, 3)) - - def test_thread(): - with ThreadPoolExecutor(max_workers=2) as executor: - executor.map(parallel_step, range(1, 4)) - with allure.step("Reuse previous threads"): - with ThreadPoolExecutor(max_workers=2) as executor: - executor.map(parallel_step, range(1, 4)) - - """ - ) - - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_thread", - has_step("thread 1"), - has_step("thread 2"), - has_step("thread 3"), - has_step("Reuse previous threads", - has_step("thread 1"), - has_step("thread 2"), - has_step("thread 3"), - ), - ) - ) diff --git a/allure-pytest/test/acceptance/unicode_identifier/unicode_identifier_test.py b/allure-pytest/test/acceptance/unicode_identifier/unicode_identifier_test.py deleted file mode 100644 index abce0b4f..00000000 --- a/allure-pytest/test/acceptance/unicode_identifier/unicode_identifier_test.py +++ /dev/null @@ -1,37 +0,0 @@ -from hamcrest import assert_that -from allure_commons_test.report import has_test_case - - -def test_unicode_function_name(executed_docstring_source): - """ - >>> def test_unicode_func_déjà_vu(): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_unicode_func_déjà_vu") - ) - - -def test_unicode_method_name(executed_docstring_source): - """ - >>> class TestCase: - ... def test_unicode_method_例子(self): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("test_unicode_method_例子") - ) - - -def test_unicode_class_name(executed_docstring_source): - """ - >>> class TestCaseПервый: - ... def test_method(self): - ... pass - """ - - assert_that(executed_docstring_source.allure_report, - has_test_case("TestCaseПервый#test_method") - ) diff --git a/allure-pytest/test/conftest.py b/allure-pytest/test/conftest.py deleted file mode 100644 index a5f52417..00000000 --- a/allure-pytest/test/conftest.py +++ /dev/null @@ -1,80 +0,0 @@ -import pytest -from allure_commons_test.report import AllureReport -from doctest import script_from_examples -import mock -import allure_commons -from contextlib import contextmanager -from allure_commons.logger import AllureMemoryLogger - -pytest_plugins = "pytester" - - -def pytest_configure(config): - config.addinivalue_line( - "markers", "real_logger: mark test to run with a real allure logger" - ) - - -@contextmanager -def fake_logger(path, logger): - blocked_plugins = [] - for name, plugin in allure_commons.plugin_manager.list_name_plugin(): - allure_commons.plugin_manager.unregister(plugin=plugin, name=name) - blocked_plugins.append(plugin) - - with mock.patch(path) as ReporterMock: - ReporterMock.return_value = logger - yield - - for plugin in blocked_plugins: - allure_commons.plugin_manager.register(plugin) - - -class AlluredTestdir: - def __init__(self, testdir, request): - self.testdir = testdir - self.request = request - self.allure_report = None - - def parse_docstring_source(self): - docstring = self.request.node.function.__doc__ or self.request.node.module.__doc__ - source = script_from_examples(docstring).replace("#\n", "\n") - self.testdir.makepyfile(source) - - def parse_docstring_path(self): - doc_file = self.request.node.function.__doc__ or self.request.node.module.__doc__ - example_dir = self.request.config.rootdir.join(doc_file.strip()) - with open(example_dir, encoding="utf-8") as f: - content = f.read() - source = script_from_examples(content) - self.testdir.makepyfile(source) - - def run_with_allure(self, *args, **kwargs): - if self.request.node.get_closest_marker("real_logger"): - self.testdir.runpytest("--alluredir", self.testdir.tmpdir, *args, **kwargs) - self.allure_report = AllureReport(self.testdir.tmpdir.strpath) - else: - self.allure_report = AllureMemoryLogger() - with fake_logger("allure_pytest.plugin.AllureFileLogger", self.allure_report): - self.testdir.runpytest("--alluredir", self.testdir.tmpdir, *args, **kwargs) - - return self.allure_report - - -@pytest.fixture -def allured_testdir(testdir, request): - return AlluredTestdir(testdir, request) - - -@pytest.fixture -def executed_docstring_source(allured_testdir): - allured_testdir.parse_docstring_source() - allured_testdir.run_with_allure() - return allured_testdir - - -@pytest.fixture -def executed_docstring_path(allured_testdir): - allured_testdir.parse_docstring_path() - allured_testdir.run_with_allure() - return allured_testdir diff --git a/allure-pytest/test/integration/allure_ee/select_test_from_testplan_test.py b/allure-pytest/test/integration/allure_ee/select_test_from_testplan_test.py deleted file mode 100644 index f7dd303c..00000000 --- a/allure-pytest/test/integration/allure_ee/select_test_from_testplan_test.py +++ /dev/null @@ -1,102 +0,0 @@ -import pytest -import json -import os -from hamcrest import assert_that, contains_inanyorder, ends_with - - -@pytest.mark.parametrize( - ["planned_tests", "expected_tests"], - [ - # by ids only - ( - [{"id": 1}, {"id": 2}], - ["test_number_one", "test_number_two"] - ), - - # by ids for multiply decorated test - ( - [{"id": 1}, {"id": 3}, {"id": 4}], - ["test_number_one", "test_number_three"] - ), - - # by wrong id - ( - [{"id": 1234}], - [] - ), - - # by selectors only - ( - [{"selector": "test_number_one"}, {"selector": "test_number_three"}], - ["test_number_one", "test_number_three"] - ), - - # by selector for not decorated with id test - ( - [{"selector": "test_without_number"}], - ["test_without_number"] - ), - - # by id and selector for same test - ( - [{"id": 2, "selector": "test_number_two"}], - ["test_number_two"] - ), - - # by wrong selector - ( - [{"selector": "test_without_never"}], - [] - ), - - # without plan - ( - None, - ["test_number_one", "test_number_two", "test_number_three", "test_without_number"] - ), - ] -) -def test_select_by_testcase_id_test(planned_tests, expected_tests, allured_testdir, request): - """ - >>> import allure - - >>> @allure.id("1") - ... def test_number_one(): - ... pass - - >>> @allure.id("2") - ... def test_number_two(): - ... pass - - >>> @allure.id("3") - ... @allure.id("4") - ... def test_number_three(): - ... pass - - >>> def test_without_number(): - ... pass - """ - - root_dir = request.config.rootdir.strpath - test_dir = allured_testdir.testdir.tmpdir.strpath.replace(root_dir, "") - base_path = test_dir.strip(os.sep).replace(os.sep, ".") - full_name_base_template = f"{base_path}.test_select_by_testcase_id_test" - - if planned_tests: - for item in planned_tests: - if "selector" in item: - selector = item['selector'] - item["selector"] = f"{full_name_base_template}#{selector}" - - testplan = {"tests": planned_tests} - py_path = allured_testdir.testdir.makefile(".json", json.dumps(testplan)) - os.environ["ALLURE_TESTPLAN_PATH"] = py_path.strpath - else: - os.environ.pop("ALLURE_TESTPLAN_PATH", None) - - allured_testdir.parse_docstring_source() - allured_testdir.run_with_allure() - - executed_full_names = [test_case["fullName"] for test_case in allured_testdir.allure_report.test_cases] - - assert_that(executed_full_names, contains_inanyorder(*[ends_with(name) for name in expected_tests])) diff --git a/allure-pytest/test/integration/allure_ee/set_testcase_id_test.py b/allure-pytest/test/integration/allure_ee/set_testcase_id_test.py deleted file mode 100644 index 72e6b9b3..00000000 --- a/allure-pytest/test/integration/allure_ee/set_testcase_id_test.py +++ /dev/null @@ -1,32 +0,0 @@ -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.label import has_label - - -def test_set_testcase_id_label(executed_docstring_source): - """ - >>> import allure - - >>> @allure.id(123) - ... def test_allure_ee_id_label_example(): - ... pass - """ - assert_that(executed_docstring_source.allure_report, - has_test_case("test_allure_ee_id_label_example", - has_label("as_id", 123), - ) - ) - - -def test_set_dynamic_testcase_id_label(executed_docstring_source): - """ - >>> import allure - - >>> def test_allure_ee_id_dynamic_label_example(): - ... allure.dynamic.id(345) - """ - assert_that(executed_docstring_source.allure_report, - has_test_case("test_allure_ee_id_dynamic_label_example", - has_label("as_id", 345), - ) - ) diff --git a/allure-pytest/test/integration/pytest_check/pytest_check_test.py b/allure-pytest/test/integration/pytest_check/pytest_check_test.py deleted file mode 100644 index 96b8f7d9..00000000 --- a/allure-pytest/test/integration/pytest_check/pytest_check_test.py +++ /dev/null @@ -1,28 +0,0 @@ - -import allure -from allure_commons_test.report import has_test_case -from allure_commons_test.result import with_status, with_message_contains, has_status_details -from hamcrest import assert_that - - -@allure.issue("376") -@allure.feature("Integration") -def test_pytest_check(allured_testdir): - """ - >>> import pytest_check as check - >>> def test_pytest_check_example(): - ... check.equal(1, 2, msg="First failure") - ... check.equal(1, 2, msg="Second failure") - """ - - allured_testdir.parse_docstring_source() - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_pytest_check_example", - with_status("failed"), - has_status_details(with_message_contains("First failure"), - with_message_contains("Second failure")) - ), - - ) diff --git a/allure-pytest/test/integration/pytest_doctest/pytest_doctest_test.py b/allure-pytest/test/integration/pytest_doctest/pytest_doctest_test.py deleted file mode 100644 index ce33fbd2..00000000 --- a/allure-pytest/test/integration/pytest_doctest/pytest_doctest_test.py +++ /dev/null @@ -1,67 +0,0 @@ -import allure -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import with_status - - -@allure.feature("Integration") -def test_pytest_doctest(allured_testdir): - allured_testdir.testdir.makepyfile(''' - def some_func(): - """ - >>> some_func() - True - """ - return True - - ''') - - allured_testdir.run_with_allure("--doctest-modules") - - assert_that(allured_testdir.allure_report, - has_test_case("test_pytest_doctest.some_func", - with_status("passed")) - ) - - -@allure.feature("Integration") -def test_pytest_doctest_failed(allured_testdir): - allured_testdir.testdir.makepyfile(''' - def some_func(): - """ - >>> some_func() - True - """ - return not True - - ''') - - allured_testdir.run_with_allure("--doctest-modules") - - assert_that( - allured_testdir.allure_report, - has_test_case( - "test_pytest_doctest_failed.some_func", - with_status("failed") - ) - ) - - -@allure.feature("Integration") -def test_pytest_doctest_broken(allured_testdir): - allured_testdir.testdir.makepyfile(''' - def some_func(): - """ - >>> raise ValueError() - """ - ''') - - allured_testdir.run_with_allure("--doctest-modules") - - assert_that( - allured_testdir.allure_report, - has_test_case( - "test_pytest_doctest_broken.some_func", - with_status("broken") - ) - ) diff --git a/allure-pytest/test/integration/pytest_flakes/pytest_flakes_test.py b/allure-pytest/test/integration/pytest_flakes/pytest_flakes_test.py deleted file mode 100644 index 17a98d4a..00000000 --- a/allure-pytest/test/integration/pytest_flakes/pytest_flakes_test.py +++ /dev/null @@ -1,30 +0,0 @@ -import allure -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import with_status - - -@allure.issue("352") -def test_pytest_flakes(allured_testdir): - """ - >>> from os.path import * - >>> def test_pytest_flakes_example(): - ... assert True - """ - - allured_testdir.parse_docstring_source() - allured_testdir.run_with_allure("--flakes") - - assert_that(allured_testdir.allure_report, - has_test_case("flake-8", - with_status("broken") - ), - - ) - - assert_that(allured_testdir.allure_report, - has_test_case("test_pytest_flakes_example", - with_status("passed") - ) - - ) diff --git a/allure-pytest/test/integration/pytest_pluginmanager/pytest_get_allure_plugin_test.py b/allure-pytest/test/integration/pytest_pluginmanager/pytest_get_allure_plugin_test.py deleted file mode 100644 index 77d0a735..00000000 --- a/allure-pytest/test/integration/pytest_pluginmanager/pytest_get_allure_plugin_test.py +++ /dev/null @@ -1,19 +0,0 @@ -import allure -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import with_status - - -@allure.feature("Integration") -def test_pytest_get_allure_listener_plugin(allured_testdir): - allured_testdir.testdir.makepyfile(""" - def test_pytest_get_allure_listener_plugin(request): - assert request.config.pluginmanager.get_plugin('allure_listener') - """) - - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_pytest_get_allure_listener_plugin", - with_status("passed")) - ) diff --git a/allure-pytest/test/integration/pytest_rerunfailures/pytest_rerunfailures_test.py b/allure-pytest/test/integration/pytest_rerunfailures/pytest_rerunfailures_test.py deleted file mode 100644 index 2f9aea70..00000000 --- a/allure-pytest/test/integration/pytest_rerunfailures/pytest_rerunfailures_test.py +++ /dev/null @@ -1,31 +0,0 @@ -import allure -import pytest -from hamcrest import assert_that -from allure_commons_test.report import has_test_case -from allure_commons_test.result import with_status - - -@allure.issue("140") -@allure.feature("Integration") -@pytest.mark.parametrize("countdown", [2, 4]) -def test_pytest_rerunfailures(allured_testdir, countdown): - allured_testdir.testdir.makepyfile(f""" - import threading - import pytest - - back_to_normal = threading.local() - - @pytest.mark.flaky(reruns={countdown}) - def test_pytest_rerunfailures_example(): - countdown = getattr(back_to_normal, "countdown", 3) - back_to_normal.countdown = countdown - 1 - assert not countdown > 0 - - """) - - allured_testdir.run_with_allure() - - assert_that(allured_testdir.allure_report, - has_test_case("test_pytest_rerunfailures_example", - with_status("failed" if countdown == 2 else "passed")) - ) diff --git a/allure-pytest/test/integration/pytest_xdist/pytest_xdist_select_test.py b/allure-pytest/test/integration/pytest_xdist/pytest_xdist_select_test.py deleted file mode 100644 index 448eed81..00000000 --- a/allure-pytest/test/integration/pytest_xdist/pytest_xdist_select_test.py +++ /dev/null @@ -1,32 +0,0 @@ -import allure -import pytest -from hamcrest import assert_that, ends_with, has_entry -from allure_commons_test.report import has_only_testcases - - -@allure.issue("292") -@allure.feature("Integration") -@pytest.mark.real_logger -def test_xdist_and_select_test_by_bdd_label(allured_testdir): - """ - >>> import pytest - >>> import allure - - >>> @pytest.mark.foo - ... def test_with_mark_foo(): - ... print ("hello") - - >>> @allure.feature("boo") - ... def test_with_feature_boo(): - ... print ("hello") - """ - - allured_testdir.parse_docstring_source() - allured_testdir.run_with_allure("-v", "--allure-features=boo", "-n1") - - assert_that(allured_testdir.allure_report, - has_only_testcases( - has_entry("fullName", - ends_with("test_with_feature_boo") - ) - )) diff --git a/allure-python-commons-test/requirements.txt b/allure-python-commons-test/requirements.txt index ef1325ef..ca6d5b91 100644 --- a/allure-python-commons-test/requirements.txt +++ b/allure-python-commons-test/requirements.txt @@ -1,6 +1,2 @@ -# test requrements -pyhamcrest -poethepoet -# linters -flake8 -flake8-builtins \ No newline at end of file +-r ../requirements/testing.txt +-r ../requirements/linting.txt diff --git a/allure-python-commons-test/src/container.py b/allure-python-commons-test/src/container.py index 894bd60a..50aa1e6b 100644 --- a/allure-python-commons-test/src/container.py +++ b/allure-python-commons-test/src/container.py @@ -10,13 +10,14 @@ def __init__(self, report, *matchers): self.matchers = matchers def _matches(self, item): - return has_property('test_containers', - has_item( - all_of( - has_entry('children', has_item(item['uuid'])), - *self.matchers - ) - )).matches(self.report) + return has_property( + 'test_containers', + has_item( + all_of( + has_entry('children', has_item(item['uuid'])), + *self.matchers + ) + )).matches(self.report) def describe_to(self, description): description.append_text('describe me later').append_list('[', ', ', ']', self.matchers) @@ -151,13 +152,15 @@ def has_same_container(*args): def has_fixture(section, name, *matchers): - return has_entry(section, - has_item( - all_of( - has_entry('name', equal_to(name)), - *matchers - ) - )) + return has_entry( + section, + has_item( + all_of( + has_entry('name', equal_to(name)), + *matchers + ) + ) + ) def has_before(name, *matchers): diff --git a/allure-python-commons-test/src/label.py b/allure-python-commons-test/src/label.py index cfc82654..12782b06 100644 --- a/allure-python-commons-test/src/label.py +++ b/allure-python-commons-test/src/label.py @@ -1,15 +1,20 @@ from hamcrest import all_of +from hamcrest import anything from hamcrest import has_entry, has_item -def has_label(name, value): - return has_entry('labels', - has_item( - all_of( - has_entry('name', name), - has_entry('value', value) - ) - )) +def has_label(name, value=None): + if value is None: + value = anything() + return has_entry( + 'labels', + has_item( + all_of( + has_entry('name', name), + has_entry('value', value) + ) + ) + ) def has_severity(level): diff --git a/allure-python-commons-test/src/result.py b/allure-python-commons-test/src/result.py index 87ee0e0e..c9c3d18e 100644 --- a/allure-python-commons-test/src/result.py +++ b/allure-python-commons-test/src/result.py @@ -82,24 +82,35 @@ def has_description_html(*matchers): def has_step(name, *matchers): - return has_entry('steps', - has_item( - all_of( - has_entry('name', equal_to(name)), - *matchers - ) - )) + return has_entry( + 'steps', + has_item( + all_of( + has_entry('name', equal_to(name)), + *matchers + ) + ) + ) + + +def get_parameter_matcher(name, *matchers): + return has_entry( + 'parameters', + has_item( + all_of( + has_entry('name', equal_to(name)), + *matchers + ) + ) + ) def has_parameter(name, value, *matchers): - return has_entry('parameters', - has_item( - all_of( - has_entry('name', equal_to(name)), - has_entry('value', equal_to(value)), - *matchers - ) - )) + return get_parameter_matcher( + name, + has_entry('value', equal_to(value)), + *matchers + ) def doesnt_have_parameter(name): @@ -112,13 +123,19 @@ def doesnt_have_parameter(name): def has_link(url, link_type=None, name=None): - return has_entry('links', - has_item( - all_of( - *[has_entry(key, value) for key, value in - zip(('url', 'type', 'name'), (url, link_type, name)) if value is not None] - ) - )) + return has_entry( + 'links', + has_item( + all_of( + *[ + has_entry(key, value) for key, value in zip( + ('url', 'type', 'name'), + (url, link_type, name) + ) if value is not None + ] + ) + ) + ) def has_issue_link(url, name=None): @@ -126,21 +143,28 @@ def has_issue_link(url, name=None): def has_test_case_link(url, name=None): - return has_link(url, link_type='test_case', name=name) + return has_link(url, link_type='tms', name=name) def has_attachment(attach_type=None, name=None): - return has_entry('attachments', - has_item( - all_of( - has_entry('source', anything()), - has_entry('type', attach_type) if attach_type else anything(), - has_entry('name', name) if name else anything() - ) - )) + return has_entry( + 'attachments', + has_item( + all_of( + has_entry('source', anything()), + has_entry('type', attach_type) if attach_type else anything(), + has_entry('name', name) if name else anything() + ) + ) + ) -def has_attachment_with_content(attachments, content_matcher, attach_type=None, name=None): +def has_attachment_with_content( + attachments, + content_matcher, + attach_type=None, + name=None +): return has_entry( 'attachments', has_item( diff --git a/allure-python-commons/requirements.txt b/allure-python-commons/requirements.txt index 2f971461..ca6d5b91 100644 --- a/allure-python-commons/requirements.txt +++ b/allure-python-commons/requirements.txt @@ -1,7 +1,2 @@ -# test requrements -attr -pyhamcrest -pluggy -poethepoet -# linters -flake8 +-r ../requirements/testing.txt +-r ../requirements/linting.txt diff --git a/allure-python-commons/src/_allure.py b/allure-python-commons/src/_allure.py index e6dc2cf9..05e01dbd 100644 --- a/allure-python-commons/src/_allure.py +++ b/allure-python-commons/src/_allure.py @@ -66,7 +66,7 @@ def tag(*tags): return label(LabelType.TAG, *tags) -def id(id): +def id(id): # noqa: A001,A002 return label(LabelType.ID, id) @@ -125,7 +125,7 @@ def tag(*tags): Dynamic.label(LabelType.TAG, *tags) @staticmethod - def id(id): + def id(id): # noqa: A003,A002 Dynamic.label(LabelType.ID, id) @staticmethod diff --git a/allure-python-commons/src/logger.py b/allure-python-commons/src/logger.py index a3906343..c3a69299 100644 --- a/allure-python-commons/src/logger.py +++ b/allure-python-commons/src/logger.py @@ -1,6 +1,6 @@ -import errno import io import os +from pathlib import Path import json import uuid import shutil @@ -13,24 +13,21 @@ class AllureFileLogger: def __init__(self, report_dir, clean=False): - self._report_dir = report_dir - - try: - os.makedirs(report_dir) - except OSError as e: - if e.errno != errno.EEXIST: - raise - elif clean: - for f in os.listdir(report_dir): - f = os.path.join(report_dir, f) - if os.path.isfile(f): - os.unlink(f) + self._report_dir = Path(report_dir).absolute() + if self._report_dir.is_dir() and clean: + shutil.rmtree(self._report_dir) + self._report_dir.mkdir(parents=True, exist_ok=True) def _report_item(self, item): indent = INDENT if os.environ.get("ALLURE_INDENT_OUTPUT") else None filename = item.file_pattern.format(prefix=uuid.uuid4()) - data = asdict(item, filter=lambda attr, value: not (type(value) != bool and not bool(value))) - with io.open(os.path.join(self._report_dir, filename), 'w', encoding='utf8') as json_file: + data = asdict( + item, + filter=lambda attr, value: not ( + type(value) != bool and not bool(value) + ) + ) + with io.open(self._report_dir / filename, 'w', encoding='utf8') as json_file: json.dump(data, json_file, indent=indent, ensure_ascii=False) @hookimpl @@ -43,12 +40,12 @@ def report_container(self, container): @hookimpl def report_attached_file(self, source, file_name): - destination = os.path.join(self._report_dir, file_name) + destination = self._report_dir / file_name shutil.copy2(source, destination) @hookimpl def report_attached_data(self, body, file_name): - destination = os.path.join(self._report_dir, file_name) + destination = self._report_dir / file_name with open(destination, 'wb') as attached_file: if isinstance(body, str): attached_file.write(body.encode('utf-8')) @@ -75,7 +72,7 @@ def report_container(self, container): @hookimpl def report_attached_file(self, source, file_name): - pass + self.attachments[file_name] = source @hookimpl def report_attached_data(self, body, file_name): diff --git a/allure-python-commons/src/mapping.py b/allure-python-commons/src/mapping.py index 6f61c651..737d3390 100644 --- a/allure-python-commons/src/mapping.py +++ b/allure-python-commons/src/mapping.py @@ -8,8 +8,8 @@ TAG_PREFIX = "allure" -semi_sep = re.compile(r"allure[\.\w]+:") -eq_sep = re.compile(r"allure[\.\w]+=") +semi_sep = re.compile(r"allure[\.\w]+[^:=]*:") +eq_sep = re.compile(r"allure[\.\w]+[^:=]*=") def allure_tag_sep(tag): diff --git a/allure-python-commons/src/types.py b/allure-python-commons/src/types.py index 395ac70b..06b77dfa 100644 --- a/allure-python-commons/src/types.py +++ b/allure-python-commons/src/types.py @@ -14,7 +14,7 @@ class Severity(str, Enum): class LinkType: LINK = 'link' ISSUE = 'issue' - TEST_CASE = 'test_case' + TEST_CASE = 'tms' class LabelType(str): diff --git a/allure-robotframework/README.rst b/allure-robotframework/README.rst index a4b8ec64..0035e3b9 100644 --- a/allure-robotframework/README.rst +++ b/allure-robotframework/README.rst @@ -1,9 +1,9 @@ Allure Robot Framework Listener =============================== -.. image:: https://pypip.in/v/allure-robotframework/badge.png +.. image:: https://img.shields.io/pypi/v/allure-robotframework :alt: Release Status :target: https://pypi.python.org/pypi/allure-robotframework -.. image:: https://pypip.in/d/allure-robotframework/badge.png +.. image:: https://img.shields.io/pypi/dm/allure-robotframework :alt: Downloads :target: https://pypi.python.org/pypi/allure-robotframework @@ -25,7 +25,7 @@ Optional argument sets output directory. Example: .. code:: bash - $ robot --listener allure_robotframework;/set/your/path/here ./my_robot_test + $ robot --listener allure_robotframework:/set/your/path/here ./my_robot_test Default output directory is `output/allure`. @@ -39,6 +39,12 @@ Advanced listener settings: - ALLURE_MAX_STEP_MESSAGE_COUNT=5. If robotframework step contains less messages than specified in this setting, each message shows as substep. This reduces the number of attachments in large projects. The default value is zero - all messages are displayed as attachments. +Usage examples +-------------- + +See usage examples `here `_. + + Contributing to allure-robotframework ===================================== diff --git a/allure-robotframework/examples/attach/data_attach.rst b/allure-robotframework/examples/attach/data_attach.rst deleted file mode 100644 index 0a98be78..00000000 --- a/allure-robotframework/examples/attach/data_attach.rst +++ /dev/null @@ -1,21 +0,0 @@ - - -.. code:: robotframework - - *** Settings *** - Library AllureLibrary - - *** Test Cases *** - Data Attachment - Attach Hello world - - -.. code:: robotframework - - *** Settings *** - Library AllureLibrary - - *** Test Cases *** - Data Attachment With Name And Type - Attach https://github.com/allure-framework/allure2 https://github.com/allure-framework/allure-python - ... name=links attachment_type=URI_LIST \ No newline at end of file diff --git a/allure-robotframework/examples/attach/file_attach.rst b/allure-robotframework/examples/attach/file_attach.rst deleted file mode 100644 index 038335f7..00000000 --- a/allure-robotframework/examples/attach/file_attach.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. code:: robotframework - - *** Settings *** - Library AllureLibrary - - *** Test Cases *** - File Attachment - Attach File ${SUITE SOURCE} \ No newline at end of file diff --git a/allure-robotframework/examples/attach/foreign_library.py b/allure-robotframework/examples/attach/foreign_library.py deleted file mode 100644 index e1a5d3ef..00000000 --- a/allure-robotframework/examples/attach/foreign_library.py +++ /dev/null @@ -1,15 +0,0 @@ -import os -from tempfile import mkdtemp - - -class ForeignLibrary: - - def capture_page_screenshot(self): - tmp = mkdtemp() - screenshot_path = os.path.join(tmp, 'screenshot.txt') - with open(screenshot_path, 'w+') as screenshot: - screenshot.write("Grab some beer and be happy~(^o^)-c[~]") - return screenshot_path - - -foreign_library = ForeignLibrary diff --git a/allure-robotframework/examples/attach/foreign_library_attach.rst b/allure-robotframework/examples/attach/foreign_library_attach.rst deleted file mode 100644 index d7f3fabc..00000000 --- a/allure-robotframework/examples/attach/foreign_library_attach.rst +++ /dev/null @@ -1,22 +0,0 @@ - -For example, you have a something like a Selenium library. Lets define some stub for it: - -.. literalinclude:: ./foreign_library.py - - -make helper as you project scope library: - -.. literalinclude:: ./foreign_library_helper.py - - -and finally your test writen for foreign library works and makes attachments to allure report: - -.. code:: robotframework - - *** Settings *** - Library ./foreign_library.py - Library ./foreign_library_helper.py - - *** Test Cases *** - Override Library Keyword And Make Allure Attachment - Capture Page Screenshot \ No newline at end of file diff --git a/allure-robotframework/examples/attach/foreign_library_helper.py b/allure-robotframework/examples/attach/foreign_library_helper.py deleted file mode 100644 index a28146ec..00000000 --- a/allure-robotframework/examples/attach/foreign_library_helper.py +++ /dev/null @@ -1,22 +0,0 @@ -import allure -from robot.libraries.BuiltIn import BuiltIn - - -class ForeignLibraryHelper: - ROBOT_LIBRARY_SCOPE = "TEST SUITE" - ROBOT_LISTENER_API_VERSION = 2 - - def __init__(self): - self.ROBOT_LIBRARY_LISTENER = self - - def _start_suite(self, name, attrs): - BuiltIn().set_library_search_order('foreign_library_helper') - - def capture_page_screenshot(self): - helper_library = BuiltIn().get_library_instance('foreign_library') - path = helper_library.capture_page_screenshot() - allure.attach.file(path, name="screenshot", attachment_type=allure.attachment_type.TEXT) - return path - - -foreign_library_helper = ForeignLibraryHelper diff --git a/allure-robotframework/examples/attachment.rst b/allure-robotframework/examples/attachment.rst new file mode 100644 index 00000000..4a5f8043 --- /dev/null +++ b/allure-robotframework/examples/attachment.rst @@ -0,0 +1,138 @@ +==================================== +Attachments in allure_robotframework +==================================== + +You can attach data and files to a test result with the :code:`Attach` and +:code:`Attach File` keywords. + +--------------- +Data attachment +--------------- + +Use the :code:`Attach` to attach some textual data to your test: + +.. code:: robotframework + :name: data-attachment-default + + *** Settings *** + Library AllureLibrary + + *** Variables *** + ${log_message} This attachment was created using the allure_robotframework + ... library + + *** Test Cases *** + Data Attachment + Attach ${log_message} + +You can provide a name and a type of your attachments: + +.. code:: robotframework + :name: data-attachment-name-type + + *** Settings *** + Library AllureLibrary + + *** Variables *** + ${links} https://github.com/allure-framework/allure2 + ... https://github.com/allure-framework/allure-python + + *** Test Cases *** + Data Attachment + Attach ${links} + ... name=links attachment_type=URI_LIST + + +--------------- +File attachment +--------------- + +Use the :code:`Attach File` keyword to attach some file: + +.. code:: robotframework + :name: file-attachment-default + + *** Settings *** + Library AllureLibrary + + *** Test Cases *** + File Attachment + Attach File ./my_file.txt + +It's possible to specify a name and a type of the attachment: + +.. code:: robotframework + :name: file-attachment-name-type + + *** Settings *** + Library AllureLibrary + + *** Test Cases *** + File Attachment + Attach File ./my_file.txt + ... name=my-file attachment_type=TEXT + + +--------------------- +Automatic attachments +--------------------- + +If you want to automatically attach files, created by some library, you can use +the trick, described below. + +Lets say, we want to automatically attach screenshots, created by the +`SeleniumLibrary's Capture Page Screenshot`_ keyword. To achieve that, lets +create a wrapper over the SeleniumLibrary: + +selenium_wrapper.py: +^^^^^^^^^^^^^^^^^^^^ +.. code:: python + :name: selenium-wrapper + + import allure + from robot.libraries.BuiltIn import BuiltIn + + class SeleniumWrapper: + ROBOT_LIBRARY_SCOPE = "TEST SUITE" + ROBOT_LISTENER_API_VERSION = 2 + + def __init__(self): + self.ROBOT_LIBRARY_LISTENER = self + + def _start_suite(self, name, attrs): + BuiltIn().set_library_search_order(__name__) + + def capture_page_screenshot(self, *args, **kwargs): + target_lib = BuiltIn().get_library_instance('SeleniumLibrary') + path = target_lib.capture_page_screenshot(*args, **kwargs) + allure.attach.file( + path, + name="page", + attachment_type=allure.attachment_type.JPG + ) + return path + + selenium_wrapper = SeleniumWrapper + +The wrapper sets itself as the first library in the library resolution order of +the Robot Framework. It uses the SeleniumLibrary under the hood, attaching the +output file to the allure report. + +Import both the library and the wrapper in your .robot file: + +.. code:: robotframework + :name: selenium-suite + + *** Settings *** + Library SeleniumLibrary + Library ./selenium_wrapper.py + + *** Test Cases *** + Automatic Screenshot Attachment + Open Browser https://localhost:443 Chrome + Capture Page Screenshot + [Teardown] Close Browser + +All screenshots are now automatically attached to your allure report. + +.. _SeleniumLibrary's Capture Page Screenshot: https://robotframework.org/SeleniumLibrary/SeleniumLibrary.html#Capture%20Page%20Screenshot diff --git a/allure-robotframework/examples/description.rst b/allure-robotframework/examples/description.rst new file mode 100644 index 00000000..6a7270e1 --- /dev/null +++ b/allure-robotframework/examples/description.rst @@ -0,0 +1,43 @@ +========================== +Description of a test case +========================== + +Allure-robotframework automatically converts documentation of a Robot Framework +test case into allure test case description. The documentation can be set with +the :code:`[Documentation]` test setting: + +.. code:: robotframework + :name: setting-singleline-robot + + *** Test Cases *** + Single line doc from the setting + [Documentation] This documentation will appear as allure description + No Operation + +The documentation may span multiple lines: + +.. code:: robotframework + :name: setting-multiline-robot + + *** Test Cases *** + Multiline doc from the setting + [Documentation] This documentation contains multiple lines of text. + ... It will also appear as allure description. + No Operation + +------------------------------------------ +The :code:`Set Test Documentation` keyword +------------------------------------------ + +The documentation can also be set dynamically with the +`Set Test Documentation keyword`_: + +.. code:: robotframework + :name: keyword-robot + + *** Test Cases *** + Multiline doc from the keyword + Set Test Documentation This documentation will appear as allure description. + + +.. _Set Test Documentation keyword: https://robotframework.org/robotframework/latest/libraries/BuiltIn.html#Set%20Test%20Documentation \ No newline at end of file diff --git a/allure-robotframework/examples/description/testcase_description.rst b/allure-robotframework/examples/description/testcase_description.rst deleted file mode 100644 index eb23b34e..00000000 --- a/allure-robotframework/examples/description/testcase_description.rst +++ /dev/null @@ -1,34 +0,0 @@ - -Allure supports text case description. All next examples are valid: - -.. code:: robotframework - - *** Test Cases *** - Single Line Description - [Documentation] Single line description - No Operation - - -.. code:: robotframework - - *** Test Cases *** - Multi Line Description - [Documentation] Multi line - ... description - No Operation - - -.. code:: robotframework - - *** Test Cases *** - Dynamic Description - [Documentation] Static description - Set Test Documentation Dynamic description - - -.. code:: robotframework - - *** Test Cases *** - Append Dynamic Description - [Documentation] Static description - Set Test Documentation Dynamic description append=yes \ No newline at end of file diff --git a/allure-robotframework/examples/fixture/testcase_fixture.rst b/allure-robotframework/examples/fixture/testcase_fixture.rst deleted file mode 100644 index c47e8f8f..00000000 --- a/allure-robotframework/examples/fixture/testcase_fixture.rst +++ /dev/null @@ -1,46 +0,0 @@ - -Allure report contains all next fixtures: - - - -.. code:: robotframework - - *** Keywords *** - Passed Setup - No Operation - - Failed Setup - Fail - - Passed Teardown - No Operation - - Failed Teardown - Fail - - *** Test Cases *** - Test Case With Test Setup - [Setup] Passed Setup - No Operation - - Test Case With Failed Test Setup - [Setup] Failed Setup - No Operation - - Test Case With Test Teardown - [Teardown] Passed Teardown - No Operation - - Test Case With Failed Test Teardown - [Teardown] Failed Teardown - No Operation - - Test Case With Test Setup And Teardown - [Setup] Passed Setup - [Teardown] Passed Teardown - No Operation - - Test Case With Test Failed Setup And Teardown - [Setup] Failed Setup - [Teardown] Failed Teardown - No Operation \ No newline at end of file diff --git a/allure-robotframework/examples/label.rst b/allure-robotframework/examples/label.rst new file mode 100644 index 00000000..ab55fa4e --- /dev/null +++ b/allure-robotframework/examples/label.rst @@ -0,0 +1,91 @@ +======================================= +Allure labels for Robot Framework tests +======================================= + +You can attach allure labels to test results using the following mechanisms: + +#. From a test case file with robot framework tags +#. From a test library, i.e., directly from python code + +----------------------------------------- +Add an allure label from a test case file +----------------------------------------- + +Apply a :code:`allure.label.:` tag to your test case. Such a tag +will be automatically converted to the allure label: + +.. code:: robotframework + :name: tag-custom-robot + + *** Test Cases *** + Test authored by John Doe + [Tags] allure.label.author:John Doe + No Operation + +You can define any label that way, being it a built-in or a custom one. If you +want to add a built-in label, a shorter version of the syntax can be used: + +.. code:: robotframework + :name: tag-builtin-robot + + *** Test Cases *** + Test with the pinned ID + [Tags] allure.id:1008 + ... allure.story:RF tags as allure labels + No Operation + +Use the :code:`Test Tags` setting to automatically apply tags to all test cases: + +.. code:: robotframework + :name: tag-setting-robot + + *** Settings *** + Test Tags allure.feature:Allure labels support + + *** Test Cases *** + Test with two BDD-labels + [Tags] allure.story:RF tags as allure labels + No Operation + +You can read more about applying tags to test cases here: `Tagging test cases`_. + +--------------------------------------- +Add an allure label from a test library +--------------------------------------- + +To add a label from python code use the :code:`@allure.label` decorator, +the :code:`allure.dynamic.label` function or their specialized alternatives for +built-in allure labels: + +my_library.py: +^^^^^^^^^^^^^^ +.. code:: python + :name: code-labels-library + + import allure + import os + + @allure.label("layer", "API") + @allure.severity(allure.severity_level.CRITICAL) + def open_api(host, port): + allure.dynamic.label("endpoint", f"{host}:{port}") + allure.dynamic.suite(f"Testing API at {host}") + +Now, if you import this library in a test case file and invoke its +:code:`[Open API]` keyword, the test case receives four allure lables: layer, +severity, endpoint and suite: + +.. code:: robotframework + :name: code-labels-robot + + *** Settings *** + Library ./my_library.py + + *** Test Cases *** + Test backend API + [Documentation] Four labels should be attached to this test result. + Open API host=localhost + ... port=443 + + +.. _`Tagging test cases`: https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases \ No newline at end of file diff --git a/allure-robotframework/examples/label/__init__.rst b/allure-robotframework/examples/label/__init__.rst deleted file mode 100644 index 334faa45..00000000 --- a/allure-robotframework/examples/label/__init__.rst +++ /dev/null @@ -1,5 +0,0 @@ - -.. code:: robotframework - - *** Settings *** - Force Tags allure.epic:Tag diff --git a/allure-robotframework/examples/label/labels_library.py b/allure-robotframework/examples/label/labels_library.py deleted file mode 100644 index 7ac7c297..00000000 --- a/allure-robotframework/examples/label/labels_library.py +++ /dev/null @@ -1,11 +0,0 @@ - -import allure - - -@allure.label('layer', 'UI') -def open_browser_with_ui_layer(): - pass - - -def add_custom_label(label_type, *labels): - allure.dynamic.label(label_type, *labels) diff --git a/allure-robotframework/examples/label/testcase_bdd_label.rst b/allure-robotframework/examples/label/testcase_bdd_label.rst deleted file mode 100644 index f08ac8fa..00000000 --- a/allure-robotframework/examples/label/testcase_bdd_label.rst +++ /dev/null @@ -1,10 +0,0 @@ - -.. code:: robotframework - - *** Settings *** - Force Tags allure.feature:Label - - *** Test Case *** - Test Cases With BDD Labels - [Tags] allure.story:Test case BDD labels - No Operation diff --git a/allure-robotframework/examples/label/testcase_custom_labels.rst b/allure-robotframework/examples/label/testcase_custom_labels.rst deleted file mode 100644 index 5ea84940..00000000 --- a/allure-robotframework/examples/label/testcase_custom_labels.rst +++ /dev/null @@ -1,9 +0,0 @@ - -.. code:: robotframework - - *** Settings *** - Library ./labels_library.py - *** Test Case *** - Test Case With Custom Labels - [Setup] Open Browser With UI Layer - Add Custom Label stand Alpha Beta diff --git a/allure-robotframework/examples/link.rst b/allure-robotframework/examples/link.rst new file mode 100644 index 00000000..a443bd1e --- /dev/null +++ b/allure-robotframework/examples/link.rst @@ -0,0 +1,100 @@ +====================================== +Allure links for Robot Framework tests +====================================== + +You can add a link to a test result in a way, similar to +`allure labels `_, either + +#. in a test case definition as a Robot Framework tag, or +#. in a test library (in python code) + +--------------------------------------- +A Robot Framework tag as an allure link +--------------------------------------- + +Use a :code:`allure.[.]:` tag to associate a link with +the test case. The :code:`` should be one of :code:`link`, +:code:`issue` or :code:`tms`. The :code:`.` part is optional and may be +omitted. In that case the value of the link is used as the text. + +The following example contains a test case with a link to the allure-python +repository: + +.. code:: robotframework + :name: tag-unnamed-robot + + *** Test Cases *** + Allure Plain Link + [Tags] allure.link:https://github.com/allure-framework/allure-python + No Operation + +In the next example the exact same link will be shown as 'allure-python' in the +report: + +.. code:: robotframework + :name: tag-named-robot + + *** Test Cases *** + Allure Plain Link + [Tags] allure.link.allure-python:https://github.com/allure-framework/allure-python + No Operation + +To link a test case to an issue, follow the next example: + +.. code:: robotframework + :name: tag-issue-robot + + *** Test Cases *** + Allure Issue Link + [Tags] allure.issue.ISSUE-1:https://github.com/allure-framework/allure-python/issues/1 + No Operation + +And you can also link a test case to the corresponding item in your test +management system: + +.. code:: robotframework + :name: tag-tms-robot + + *** Test Cases *** + Allure TMS Link + [Tags] allure.tms.TESTCASE-1:https://my-tms/test-cases/1 + No Operation + +Read more about applying tags to Robot Framework test cases in this article: +`Tagging test cases`_. + +-------------------------------------- +Add an allure link from a test library +-------------------------------------- + +Use allure.dynamic.link, allure.dynamic.issue or allure.dynamic.testcase to add +a link of an appropriate type. + +The following example shows the usage of all those functions at once: + +**my_lib.py**: + +.. code:: python + :name: code-links-lib + + import allure + + def add_three_links(): + allure.dynamic.link("https://github.com/allure-framework/allure-python", name="allure-python") + allure.dynamic.issue("https://github.com/allure-framework/allure-python/issues/1", name="ISSUE-1") + allure.dynamic.testcase("https://my-tms/test-cases/1", name="TESTCASE-1") + +**The test data**: + +.. code:: robotframework + :name: code-links-robot + + *** Settings *** + Library ./my_lib.py + + *** Test Cases *** + Allure Link Decorators and Functions + Add Three Links + + +.. _`Tagging test cases`: https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases \ No newline at end of file diff --git a/allure-robotframework/examples/link/dynamic_link.rst b/allure-robotframework/examples/link/dynamic_link.rst deleted file mode 100644 index c12ae647..00000000 --- a/allure-robotframework/examples/link/dynamic_link.rst +++ /dev/null @@ -1,13 +0,0 @@ -Dynamic Links ------ - -.. code:: robotframework - - *** Test Cases *** - Test Case With Dynamic Link - Evaluate allure.dynamic.issue('https://jira.com/browse/ISSUE-1', 'ISSUE-1') - ... modules=allure - Evaluate allure.dynamic.testcase('https://testrail.com/browse/TEST-1', 'TEST-1') - ... modules=allure - Evaluate allure.dynamic.link('https://homepage.com/', name='homepage') - ... modules=allure diff --git a/allure-robotframework/examples/link/link.rst b/allure-robotframework/examples/link/link.rst deleted file mode 100644 index df4567ca..00000000 --- a/allure-robotframework/examples/link/link.rst +++ /dev/null @@ -1,54 +0,0 @@ -Links ------ - -Issues are supported via tags prefixed with :code:`issue:` : - -.. code:: robotframework - - *** Test Cases *** - Test Case With Issue Link Without URL - [Tags] issue:ISSUE-1 - No Operation - - -.. code:: robotframework - - *** Test Cases *** - Test Case With Issue Link With URL - [Tags] issue:https://jira.com/browse/ISSUE-1 - No Operation - -TMS links are supported via tags prefixed with :code:`test_case:` : - -.. code:: robotframework - - *** Test Cases *** - Test Case With TMS Link Without URL - [Tags] test_case:TEST-1 - No Operation - - -.. code:: robotframework - - *** Test Cases *** - Test Case With TMS Link With URL - [Tags] test_case:https://testrail.com/browse/TEST-1 - No Operation - -Ordinary links are supported via tags prefixed with :code:`link:` : - -.. code:: robotframework - - *** Test Cases *** - Test Case With Unlabeled Link - [Tags] link:https://homepage.com/ - No Operation - -Link label can be specified by text placed in :code:`[square brackets]` : - -.. code:: robotframework - - *** Test Cases *** - Test Case With Labeled Link - [Tags] link:[Home Page]https://homepage.com/ - No Operation diff --git a/allure-robotframework/examples/status/status.rst b/allure-robotframework/examples/status/status.rst deleted file mode 100644 index 416446dc..00000000 --- a/allure-robotframework/examples/status/status.rst +++ /dev/null @@ -1,21 +0,0 @@ - -.. code:: robotframework - - *** Settings *** - Library ./status_library.py - - *** Test Cases *** - Failed Test Case With Message - Fail msg=Failed Details - - Failed Test Case With Traceback - Set Log Level DEBUG - Fail msg=Failed Details - - Failed Test Case With Python Traceback - Set Log Level DEBUG - Fail With Traceback Fail message - - Failed Test Case With Not Executed Step - Fail - Log This step should be skipped diff --git a/allure-robotframework/examples/status/status_library.py b/allure-robotframework/examples/status/status_library.py deleted file mode 100644 index b14e7ef3..00000000 --- a/allure-robotframework/examples/status/status_library.py +++ /dev/null @@ -1,6 +0,0 @@ - -from robot.libraries.BuiltIn import BuiltIn - - -def fail_with_traceback(traceback_message): - BuiltIn().fail(traceback_message) diff --git a/allure-robotframework/examples/step.rst b/allure-robotframework/examples/step.rst new file mode 100644 index 00000000..ef3afcba --- /dev/null +++ b/allure-robotframework/examples/step.rst @@ -0,0 +1,37 @@ +================== +Steps and substeps +================== + +All keywords of a Robot Framework test case are automatically converted to +allure steps. + +To add nested steps apply the :code:`@allure.step` decorator to a step function +or use the :code:`allure.step` function in your test library: + +**my_lib.py**: + +.. code:: python + :name: steps-lib + + import allure + + @allure.step("Substep {parameter}") + def substep_with_decorator(parameter): + pass + + def substep(): + with allure.step("Library substep"): + substep_with_decorator("A") + pass + +**The test data**: + +.. code:: robotframework + :name: steps-robot + + *** Settings *** + Library ./my_lib.py + + *** Test Cases *** + Allure substeps + Substep \ No newline at end of file diff --git a/allure-robotframework/examples/step/builtin_step.rst b/allure-robotframework/examples/step/builtin_step.rst deleted file mode 100644 index 9bc2ecde..00000000 --- a/allure-robotframework/examples/step/builtin_step.rst +++ /dev/null @@ -1,6 +0,0 @@ -.. code:: robotframework - - *** Test Cases *** - Log Builtin Keyword - Log The rose is red - Log the violet's blue \ No newline at end of file diff --git a/allure-robotframework/examples/step/outside_step.rst b/allure-robotframework/examples/step/outside_step.rst deleted file mode 100644 index 0b05ac93..00000000 --- a/allure-robotframework/examples/step/outside_step.rst +++ /dev/null @@ -1,9 +0,0 @@ - -.. code:: robotframework - - *** Settings *** - Library ./outside_step_library.py - - *** Test Cases *** - Use Library Keyword With Allure Step - Keyword With Allure Step \ No newline at end of file diff --git a/allure-robotframework/examples/step/outside_step_library.py b/allure-robotframework/examples/step/outside_step_library.py deleted file mode 100644 index d7b34597..00000000 --- a/allure-robotframework/examples/step/outside_step_library.py +++ /dev/null @@ -1,6 +0,0 @@ -import allure - - -def keyword_with_allure_step(): - with allure.step("Passed Step Inside Keyword"): - pass diff --git a/allure-robotframework/examples/tag.rst b/allure-robotframework/examples/tag.rst new file mode 100644 index 00000000..caeb28bf --- /dev/null +++ b/allure-robotframework/examples/tag.rst @@ -0,0 +1,108 @@ +===================================== +Allure tags for Robot Framework tests +===================================== + +You can apply an allure tag to your Robot Framework tests either in Robot +Framework test data (.robot files) or in a test library (.py files). + +---------------------------------------- +Allure tags in Robot Framework test data +---------------------------------------- + +All Robot Framework tags (except those, started with ``allure.``) are +automatically converted into allure tags: + +.. code:: robotframework + :name: tags-static-robot + + *** Test Cases *** + Distributed Legacy Test + [Tags] distributed legacy + No Operation + +The conversion happens when a test case is completed, so any changes to the set +of tags are reflected: + +.. code:: robotframework + :name: tags-dynamic-robot + + *** Test Cases *** + Isolated Test + [Tags] distributed + Set Tags isolated + Remove Tags distributed + +Be careful, because any failed step stops subsequent tag modifications: + +.. code:: robotframework + :name: tags-partial-robot + + *** Test Cases *** + Supposed to Be an Isolated Test + [Documentation] But ends up being a distributed one. + [Tags] distributed + Fail Unexpected failure + Set Tags isolated + Remove Tags distributed + +You can apply an allure tag explicitly, with the +:code:`allure.label.tag:` Robot Framework tag or its shorter version, +:code:`allure.tag:`: + +.. code:: robotframework + :name: tags-explicit-robot + + *** Test Cases *** + Explicit External Test + [Tags] allure.label.tag:explicit allure.tag:extrenal + No Operation + +All other Robot Framework tags, starting with :code:`allure.` are not converted: + +.. code:: robotframework + :name: tags-noconv-robot + + *** Test Cases *** + No Allure Tags + [Tags] allure.label.as_id:1008 allure.feature:Allure tags support + No Operation + +Read more about applying tags to Robot Framework test cases in this article: +`Tagging test cases`_. + +------------------------------------------- +Allure tags in Robot Framework test library +------------------------------------------- + +Use the :code:`@allure.tag` decorator or the :code:`allure.dynamic.tag` function +to add an allure tag to the current test result. + +**my_lib.py***: + +.. code:: python + :name: tags-code-lib + + import allure + + @allure.tag("external") + def connect_to_external_api(): + pass + + @allure.tag("legacy") + def download_service_list(): + connect_to_external_api() + allure.dynamic.tag("stateful") + +**Robot Framework test data**: + +.. code:: robotframework + :name: tags-code-robot + + *** Settings *** + Library ./my_lib.py + + *** Test Cases *** + Stateful External Legacy Test + Download Service List + +.. _`Tagging test cases`: https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases \ No newline at end of file diff --git a/allure-robotframework/examples/tag/tag.rst b/allure-robotframework/examples/tag/tag.rst deleted file mode 100644 index 1f0a1afb..00000000 --- a/allure-robotframework/examples/tag/tag.rst +++ /dev/null @@ -1,32 +0,0 @@ -Tags ----- - -Allure supports robotframework tags: - -.. code:: robotframework - - *** Test Cases *** - Test Case With Tags - [Tags] alpha bravo - No Operation - - -уou can manipulate with tags: - -.. code:: robotframework - - *** Test Cases *** - Test Case With Dynamic Tags - [Tags] alpha - Set Tags bravo - - -.. code:: robotframework - - *** Test Cases *** - Test Case With Removed Tags - [Tags] alpha bravo - Set Tags charlie - Remove Tags bravo - -allure will track it and show actual tags set. diff --git a/allure-robotframework/examples/testplan.rst b/allure-robotframework/examples/testplan.rst new file mode 100644 index 00000000..372cfe30 --- /dev/null +++ b/allure-robotframework/examples/testplan.rst @@ -0,0 +1,101 @@ +========================================= +Allure testplan for Robot Framework tests +========================================= + +You can filter Robot Framework test cases by an ID or by a name with an allure +testplan. + +#. Create a testplan file. +#. Set the :code:`ALLURE_TESTPLAN_PATH` environment variable to the testplan + path. +#. Run the Robot Framework with the :code:`allure_robotframework.testplan` + pre-run modifier. + +------------------- +Creating a testplan +------------------- + +Lets say, we have the following Robot Framework test data in the +:code:`testplan.robot` file: + +.. code:: robotframework + :name: testdata + + *** Test Cases *** + Selected by Name + No Operation + + Selected by ID + [Tags] allure.id:1008 + No Operation + + Not Selected + [Tags] allure.id:1009 + No Operation + +And we want to select only two test cases: + +#. The test case :code:`Selected by Name`. +#. The test case with ID :code:`1008`. + +To achieve that, we need the following testplan (lets say, we put it in the +:code:`testplan.json` file): + +.. code:: json + :name: testplan + + { + "version":"1.0", + "tests": [ + { + "selector": "Testplan.Selected by Name" + }, + {"id": "1008"} + ] + } + +------------------------------------------------------------- +Setting the :code:`ALLURE_TESTPLAN_PATH` environment variable +------------------------------------------------------------- + +Refer to the docs on the environment you are working in on how to set up an +environment variable. + +If you are working in Linux or MacOS and use bash or a similar shell, the most +convinient way is to put :code:`ALLURE_TESTPLAN_PATH=./testplan.json` before the +:code:`robot` command, or use the +:code:`export ALLURE_TESTPLAN_PATH=./testplan.json` statement. + +If you are using PowerShell, set up the variable with the +:code:`$Env:ALLURE_TESTPLAN_PATH = "./testplan.json"` statement. + +--------------------------- +Running the Robot Framework +--------------------------- + +The following example shows how to execute the abovementioned test cases with +the testplan enabled (this is for Linux, bash; if you are using another +OS/Shell, the invocation may looks differently): + +.. code:: shell + + ALLURE_TESTPLAN_PATH=./testplan.json robot --log NONE --report NONE --output NONE --extension robot --loglevel DEBUG --listener allure_robotframework:./allure-results --prerunmodifier allure_robotframework.testplan ./testplan.robot + +The test cases, listed in the plan, will be executed:: + + ============================================================================== + Testplan + ============================================================================== + Selected by Name | PASS | + ------------------------------------------------------------------------------ + Selected by ID | PASS | + ------------------------------------------------------------------------------ + Testplan | PASS | + 2 tests, 2 passed, 0 failed + ============================================================================== + Output: None + +You can read more about the CLI arguments here: +`the Robot Framework command line options`_. + +.. _`the Robot Framework command line options`: https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-options \ No newline at end of file diff --git a/allure-robotframework/examples/testplan/testplan.rst b/allure-robotframework/examples/testplan/testplan.rst deleted file mode 100644 index 404d171d..00000000 --- a/allure-robotframework/examples/testplan/testplan.rst +++ /dev/null @@ -1,21 +0,0 @@ - -.. code:: robotframework - - *** Test Cases *** - First testcase - No Operation - - Second testcase - No Operation - - -.. code:: robotframework - - *** Test Cases *** - Test case with allure id - [Tags] allure.id=123 - No Operation - - One more case with allure id - [Tags] allure.id=777 - No Operation diff --git a/allure-robotframework/pyproject.toml b/allure-robotframework/pyproject.toml index 7b805fda..d869331e 100644 --- a/allure-robotframework/pyproject.toml +++ b/allure-robotframework/pyproject.toml @@ -1,8 +1,5 @@ [tool.poe.tasks] -linter = "flake8 ./src ./test" +linter = "flake8 ./src" tests = { shell = """python -m doctest ./src/listener/utils.py && - robot --log NONE --report NONE --output NONE \ - --extension robot --loglevel DEBUG \ - --listener allure_robotframework:allure-results \ - --outputdir allure-results ./test + pytest ../tests/allure_robotframework """ } diff --git a/allure-robotframework/requirements.txt b/allure-robotframework/requirements.txt index 999317b6..b2e49b0f 100644 --- a/allure-robotframework/requirements.txt +++ b/allure-robotframework/requirements.txt @@ -1,8 +1,3 @@ -# test requrements -robotframework-pabot -docutils -pyhamcrest -poethepoet -# linters -flake8 -flake8-builtins +-r ../requirements/testing.txt +-r ../requirements/linting.txt +-r ../requirements/testing/allure-robotframework.txt diff --git a/allure-robotframework/src/listener/allure_listener.py b/allure-robotframework/src/listener/allure_listener.py index a0ee14d3..7c8bccfa 100644 --- a/allure-robotframework/src/listener/allure_listener.py +++ b/allure-robotframework/src/listener/allure_listener.py @@ -17,7 +17,7 @@ from allure_robotframework.utils import get_allure_status from allure_robotframework.utils import get_allure_suites from allure_robotframework.utils import get_allure_parameters -from allure_robotframework.utils import allure_labels, allure_links, allure_tags +from allure_robotframework.utils import allure_labels, allure_links from allure_robotframework.types import RobotStatus, RobotLogLevel @@ -150,7 +150,6 @@ def stop_test(self, _, attributes, messages): test_result.labels.append(Label(name=LabelType.LANGUAGE, value=self._platform)) test_result.labels.append(Label(name=LabelType.HOST, value=self._host)) test_result.labels.append(Label(name=LabelType.THREAD, value=pool_id())) - test_result.labels.extend(allure_tags(attributes)) tags = attributes.get('tags', ()) test_result.labels.extend(allure_labels(tags)) test_result.statusDetails = StatusDetails(message=attributes.get('message'), diff --git a/allure-robotframework/src/listener/allure_testplan.py b/allure-robotframework/src/listener/allure_testplan.py index 865a5950..70e399fa 100644 --- a/allure-robotframework/src/listener/allure_testplan.py +++ b/allure-robotframework/src/listener/allure_testplan.py @@ -8,8 +8,12 @@ class allure_testplan(SuiteVisitor): def __init__(self): self.testplan = get_testplan() - self.allure_ids = [test["id"] for test in self.testplan] if self.testplan else [] - self.selectors = [test["selector"] for test in self.testplan] if self.testplan else [] + self.allure_ids = self.__to_set_by_item_key(self.testplan, "id") + self.selectors = self.__to_set_by_item_key(self.testplan, "selector") + + @staticmethod + def __to_set_by_item_key(items, key): + return {item[key] for item in items if key in item} def start_suite(self, suite): if self.testplan: diff --git a/allure-robotframework/src/listener/utils.py b/allure-robotframework/src/listener/utils.py index 18e6512a..8b308d81 100644 --- a/allure-robotframework/src/listener/utils.py +++ b/allure-robotframework/src/listener/utils.py @@ -2,7 +2,7 @@ from allure_commons.model2 import Status, Label, Parameter, Link from allure_commons.types import LabelType from allure_robotframework.types import RobotStatus -from allure_commons.mapping import parse_tag, labels_set, allure_tag_sep +from allure_commons.mapping import parse_tag, labels_set def get_allure_status(status): @@ -44,36 +44,46 @@ def get_allure_suites(longname): return labels -def allure_tags(attributes): - return [Label(LabelType.TAG, tag) for tag in attributes.get('tags', ()) if not allure_tag_sep(tag)] +def get_items_of_type_from_tags(tags, item_type): + return [ + item for item in map( + parse_tag, + tags + ) if isinstance(item, item_type) + ] def allure_labels(tags): - parsed = [parse_tag(item) for item in tags] - return labels_set(list(filter(lambda x: isinstance(x, Label), parsed))) + return labels_set( + get_items_of_type_from_tags(tags, Label) + ) def allure_links(attributes, prefix): tags = attributes.get('tags', ()) - def is_link(link): - return link.startswith(f"{prefix}:") - - return [ + general_syntax_links = [ + link for link in get_items_of_type_from_tags( + tags, + Link + ) if link.type == prefix + ] + rf_specific_syntax_links = [ _create_link_from_tag( prefix, tag - ) for tag in tags if is_link(tag) + ) for tag in tags if tag.startswith(f"{prefix}:") ] + return general_syntax_links + rf_specific_syntax_links + def _parse_link(link): lnk_val = link.split(':', 1)[1] or 'unknown' - lnk_label = search(r'\[.+\]', lnk_val) + lnk_label = search(r'^\[(.+)\]', lnk_val) if lnk_label: - lnk_label = lnk_label.group(0) - lnk_val = lnk_val.strip(lnk_label) - lnk_label = lnk_label.strip('[]') + lnk_val = lnk_val[lnk_label.end():] + lnk_label = lnk_label.group(1) else: lnk_label = lnk_val diff --git a/allure-robotframework/test/attach/data_attach.robot b/allure-robotframework/test/attach/data_attach.robot deleted file mode 100644 index e7d8a266..00000000 --- a/allure-robotframework/test/attach/data_attach.robot +++ /dev/null @@ -1,22 +0,0 @@ -*** Settings *** -Library ../run_robot_library.py -Library ../test_allure_library.py -Suite Setup Run exampe - - -*** Keywords *** -Run exampe - ${allure_report} Run Robot With Allure examples/attach/data_attach.rst - Set Suite Variable ${report} ${allure_report} - - -*** Test Case *** -Data Attachment - ${test_case} Should Has Test Case ${report} Data Attachment - ${step} Should Has Step ${test_case} AllureLibrary.Attach - Should Has Attachment ${step} - -Data Attachment With Name And Type - ${test_case} Should Has Test Case ${report} Data Attachment With Name And Type - ${step} Should Has Step ${test_case} AllureLibrary.Attach - Should Has Attachment ${step} name=links \ No newline at end of file diff --git a/allure-robotframework/test/attach/file_attach.robot b/allure-robotframework/test/attach/file_attach.robot deleted file mode 100644 index 5f2c1563..00000000 --- a/allure-robotframework/test/attach/file_attach.robot +++ /dev/null @@ -1,11 +0,0 @@ -*** Settings *** -Library ../run_robot_library.py -Library ../test_allure_library.py - - -*** Test Case *** -Data Attachment - ${allure_report} Run Robot With Allure examples/attach/file_attach.rst - ${test_case} Should Has Test Case ${allure_report} File Attachment - ${step} Should Has Step ${test_case} AllureLibrary.Attach File - Should Has Attachment ${step} \ No newline at end of file diff --git a/allure-robotframework/test/attach/foreign_library_attach.robot b/allure-robotframework/test/attach/foreign_library_attach.robot deleted file mode 100644 index e77931f6..00000000 --- a/allure-robotframework/test/attach/foreign_library_attach.robot +++ /dev/null @@ -1,11 +0,0 @@ -*** Settings *** -Library ../run_robot_library.py -Library ../test_allure_library.py - - -*** Test Case *** -Override Library Keyword And Make Allure Attachment - ${allure_report} Run Robot With Allure examples/attach/foreign_library_attach.rst - ${test_case} Should Has Test Case ${allure_report} Override Library Keyword And Make Allure Attachment - ${step} Should Has Step ${test_case} foreign_library_helper.Capture Page Screenshot - Should Has Attachment ${step} name=screenshot \ No newline at end of file diff --git a/allure-robotframework/test/description/testcase_description.robot b/allure-robotframework/test/description/testcase_description.robot deleted file mode 100644 index 18567a85..00000000 --- a/allure-robotframework/test/description/testcase_description.robot +++ /dev/null @@ -1,28 +0,0 @@ -*** Settings *** -Library ../run_robot_library.py -Library ../test_allure_library.py -Suite Setup Run exampe - - -*** Keywords *** -Run exampe - ${allure_report} Run Robot With Allure examples/description/testcase_description.rst - Set Suite Variable ${report} ${allure_report} - - -*** Test Cases *** -Single Line Description - ${test_case} Should Has Test Case ${report} Single Line Description - Should Has Description ${test_case} Single line description - -Multi Line Description - ${test_case} Should Has Test Case ${report} Multi Line Description - Should Has Description ${test_case} Multi line\ndescription - -Dynamic Description - ${test_case} Should Has Test Case ${report} Dynamic Description - Should Has Description ${test_case} Dynamic description - -Append Dynamic Description - ${test_case} Should Has Test Case ${report} Append Dynamic Description - Should Has Description ${test_case} Static description Dynamic description \ No newline at end of file diff --git a/allure-robotframework/test/fixture/suite_fixture.robot b/allure-robotframework/test/fixture/suite_fixture.robot deleted file mode 100644 index bc1a95ac..00000000 --- a/allure-robotframework/test/fixture/suite_fixture.robot +++ /dev/null @@ -1,10 +0,0 @@ -#*** Settings *** -#Suite Teardown Suite Setup Keyword -# -#*** Test Cases *** -#Demo Test Case With Suite Setup -# No Operation -# -#*** Keywords *** -#Suite Setup Keyword -# Fail msg=Failed Details \ No newline at end of file diff --git a/allure-robotframework/test/fixture/testcase_fixture.robot b/allure-robotframework/test/fixture/testcase_fixture.robot deleted file mode 100644 index 6e73f2bb..00000000 --- a/allure-robotframework/test/fixture/testcase_fixture.robot +++ /dev/null @@ -1,57 +0,0 @@ -#*** Settings *** -#Library ../run_robot_library.py -#Library ../test_allure_library.py -#Suite Setup Run exampe -# -# -#*** Keywords *** -#Run exampe -# ${allure_report} Run Robot With Allure examples/fixture/sf2/ -# Set Suite Variable ${report} ${allure_report} -# -# -#*** Test Cases *** -#Test Case With Test Setup -# ${test_case} Should Has Test Case ${report} Test Case With Test Setup -# ${fixture} Should Has Before Fixture ${test_case} Passed Setup -# Should Has Step ${fixture} BuiltIn.No Operation -# -#Test Case With Failed Test Setup -# ${test_case} Should Has Test Case ${report} Test Case With Failed Test Setup -# Should Has Status ${test_case} failed -# ${fixture} Should Has Before Fixture ${test_case} Failed Setup -# Should Has Status ${fixture} failed -# ${step} Should Has Step ${fixture} BuiltIn.Fail -# Should Has Status ${step} failed -# -#Test Case With Test Teardown -# ${test_case} Should Has Test Case ${report} Test Case With Test Teardown -# ${fixture} Should Has After Fixture ${test_case} Passed Teardown -# Should Has Step ${fixture} BuiltIn.No Operation -# -#Test Case With Failed Test Teardown -# ${test_case} Should Has Test Case ${report} Test Case With Failed Test Teardown -# Should Has Status ${test_case} failed -# ${fixture} Should Has After Fixture ${test_case} Failed Teardown -# Should Has Status ${fixture} failed -# ${step} Should Has Step ${fixture} BuiltIn.Fail -# Should Has Status ${step} failed -# -#Test Case With Test Setup And Teardown -# ${test_case} Should Has Test Case ${report} Test Case With Test Setup And Teardown -# ${fixture} Should Has Before Fixture ${test_case} Passed Setup -# Should Has Step ${fixture} BuiltIn.No Operation -# ${fixture} Should Has After Fixture ${test_case} Passed Teardown -# Should Has Step ${fixture} BuiltIn.No Operation -# -#Test Case With Test Failed Setup And Teardown -# ${test_case} Should Has Test Case ${report} Test Case With Test Failed Setup And Teardown -# Should Has Status ${test_case} failed -# ${fixture} Should Has Before Fixture ${test_case} Failed Setup -# Should Has Status ${fixture} failed -# ${step} Should Has Step ${fixture} BuiltIn.Fail -# Should Has Status ${step} failed -# ${fixture} Should Has After Fixture ${test_case} Failed Teardown -# Should Has Status ${fixture} failed -# ${step} Should Has Step ${fixture} BuiltIn.Fail -# Should Has Status ${step} failed diff --git a/allure-robotframework/test/label/testcase_bdd_label.robot b/allure-robotframework/test/label/testcase_bdd_label.robot deleted file mode 100644 index 5cb1c90a..00000000 --- a/allure-robotframework/test/label/testcase_bdd_label.robot +++ /dev/null @@ -1,12 +0,0 @@ -*** Settings *** -Library ../run_robot_library.py -Library ../test_allure_library.py - - -*** Test Case *** -Run Without options - ${allure_report} Run Robot With Allure examples/label - ${test_case} Should Has Test Case ${allure_report} Test Cases With BDD Labels - Should Has Label ${test_case} epic Tag - Should Has Label ${test_case} feature Label - Should Has Label ${test_case} story Test case BDD labels diff --git a/allure-robotframework/test/label/testcase_custom_labels.robot b/allure-robotframework/test/label/testcase_custom_labels.robot deleted file mode 100644 index 1a0d9bb1..00000000 --- a/allure-robotframework/test/label/testcase_custom_labels.robot +++ /dev/null @@ -1,12 +0,0 @@ -*** Settings *** -Library ../run_robot_library.py -Library ../test_allure_library.py - - -*** Test Case *** -Run Without options - ${allure_report} Run Robot With Allure examples/label/testcase_custom_labels.rst - ${test_case} Should Has Test Case ${allure_report} Test Case With Custom Labels - Should Has Label ${test_case} layer UI - Should Has Label ${test_case} stand Alpha - Should Has Label ${test_case} stand Beta diff --git a/allure-robotframework/test/link/dynamic_link.robot b/allure-robotframework/test/link/dynamic_link.robot deleted file mode 100644 index 90ac2c41..00000000 --- a/allure-robotframework/test/link/dynamic_link.robot +++ /dev/null @@ -1,22 +0,0 @@ -*** Settings *** -Library ../run_robot_library.py -Library ../test_allure_library.py -Suite Setup Run test case with dynamic link - - -*** Keywords *** -Run test case with dynamic link - ${allure_report} Run Robot With Allure examples/link/dynamic_link.rst - ${test_case} Should Has Test Case ${allure_report} Test Case With Dynamic Link - Set Suite Variable ${test_case} - - -*** Test Case *** -Test Case With Dynamic Links - ${test case} Should Has issue To https://jira.com/browse/ISSUE-1 With Name ISSUE-1 - ${test case} Should Has test_case To https://testrail.com/browse/TEST-1 With Name TEST-1 - ${test case} Should Has link To https://homepage.com/ With Name homepage - -*** Keywords *** -${test case} Should Has ${link type} To ${url} With Name ${name} - Should Has Link ${test_case} ${url} ${link type} ${name} diff --git a/allure-robotframework/test/link/link.robot b/allure-robotframework/test/link/link.robot deleted file mode 100644 index 76ffb0bf..00000000 --- a/allure-robotframework/test/link/link.robot +++ /dev/null @@ -1,37 +0,0 @@ -*** Settings *** -Library ../run_robot_library.py -Library ../test_allure_library.py -Suite Setup Run example - - -*** Keywords *** -Run example - ${allure_report} Run Robot With Allure examples/link/link.rst - Set Suite Variable ${report} ${allure_report} - - -*** Test Case *** -Test Case With Issue Link Without URL - ${test_case} Should Has Test Case ${report} Test Case With Issue Link Without URL - Should Has Link ${test_case} ISSUE-1 issue - -Test Case With Issue Link With URL - ${test_case} Should Has Test Case ${report} Test Case With Issue Link With URL - Should Has Link ${test_case} https://jira.com/browse/ISSUE-1 issue - -Test Case With TMS Link Without URL - ${test_case} Should Has Test Case ${report} Test Case With TMS Link Without URL - Should Has Link ${test_case} TEST-1 test_case - -Test Case With TMS Link With URL - ${test_case} Should Has Test Case ${report} Test Case With TMS Link With URL - Should Has Link ${test_case} https://testrail.com/browse/TEST-1 test_case - -Test Case With Unlabeled Link - ${test_case} Should Has Test Case ${report} Test Case With Unlabeled Link - Should Has Link ${test_case} https://homepage.com/ link - -Test Case With Labeled Link - ${test_case} Should Has Test Case ${report} Test Case With Labeled Link - Should Has Link ${test_case} https://homepage.com/ link Home Page - diff --git a/allure-robotframework/test/link/suite_link.robot b/allure-robotframework/test/link/suite_link.robot deleted file mode 100644 index 19030a90..00000000 --- a/allure-robotframework/test/link/suite_link.robot +++ /dev/null @@ -1,26 +0,0 @@ -*** Settings *** -Library ../run_robot_library.py -Library ../test_allure_library.py - - -*** Variables *** -${TC_LOG} | *Settings* | | |\n -... | Metadata | Link | https://github.com/allure-framework |\n -... | | | |\n -... | *Test Cases* | | |\n -... | Demo Test Case In Suite With link | | |\n -... | | No Operation | |\n - - -*** Test Cases *** -Test Case In Suite With link - No Operation -# ToDo: deprecated, need to revove from code -# ${tmp_dir}= Make Temp Dir -# ${test_case_dir}= Make Dir ${tmp_dir} test -# ${test_case}= Make Test Case ${test_case_dir} link.robot ${TC_LOG} -# ${allure_report}= Robot Run With Allure ${tmp_dir} ${test_case} -# ${tc_matcher}= Should Has Test Case ${allure_report} Demo Test Case In Suite With link -# Should has link ${allure_report} ${tc_matcher} https://github.com/allure-framework - -# ToDo: other link types \ No newline at end of file diff --git a/allure-robotframework/test/run_robot_library.py b/allure-robotframework/test/run_robot_library.py deleted file mode 100644 index b23c3c2a..00000000 --- a/allure-robotframework/test/run_robot_library.py +++ /dev/null @@ -1,47 +0,0 @@ -import os -from tempfile import mkdtemp, mkstemp -from robot import run -from multiprocessing import Process -from allure_commons_test.report import AllureReport - - -def run_robot_with_allure(*args, **kwargs): - root = os.path.abspath(os.path.join(__file__, "..", "..")) - targets = map(lambda target: os.path.join(root, target), args) - tmp_path = mkdtemp(dir=os.environ.get('TEST_TMP', '/tmp')) - - if "testplan" in kwargs: - # kwargs.pop("testplan") - kwargs["prerunmodifier"] = "allure_robotframework.testplan" - file, filename = mkstemp(suffix=".json", dir=tmp_path) - os.environ["ALLURE_TESTPLAN_PATH"] = filename - with os.fdopen(file, 'w') as tmp: - tmp.write(kwargs["testplan"]) - - def run_robot(path, **kw): - - # ToDo: fix it (_core not works correctly with multiprocessing) - # import allure_commons - # import importlib - # importlib.reload(allure_commons._core) - # - # - - from allure_robotframework import allure_robotframework - - listener = allure_robotframework(logger_path=tmp_path) - stdout_file = os.path.abspath(os.path.join(tmp_path, "..", "stdout.txt")) - output_path = os.path.abspath(os.path.join(tmp_path, "..")) - - with open(stdout_file, 'w+') as stdout: - options = {"listener": listener, "outputdir": output_path, "stdout": stdout, "extension": "rst"} - options.update(kw) - run(path, **options) - - robot_process = Process(target=run_robot, args=targets, kwargs=kwargs) - robot_process.start() - robot_process.join() - - os.environ.pop("ALLURE_TESTPLAN_PATH", None) - - return AllureReport(tmp_path) diff --git a/allure-robotframework/test/status/status.robot b/allure-robotframework/test/status/status.robot deleted file mode 100644 index 273a8d9d..00000000 --- a/allure-robotframework/test/status/status.robot +++ /dev/null @@ -1,37 +0,0 @@ -*** Settings *** -Library ../run_robot_library.py -Library ../test_allure_library.py - - -*** Test Case *** -Failed Test Case With Message - ${allure_report} Run Robot With Allure examples/status/status.rst - ${test_case} Should Has Test Case ${allure_report} Failed Test Case With Message - Should Has Status ${test_case} failed - Should Has Status Detail With Message ${test_case} Failed Details - ${step} Should Has Step ${test_case} BuiltIn.Fail - Should Has Status ${step} failed - Should Has Status Detail With Message ${step} Failed Details - -Failed Test Case With Traceback - ${allure_report} Run Robot With Allure examples/status/status.rst - ${test_case} Should Has Test Case ${allure_report} Failed Test Case With Traceback - Should Has Status ${test_case} failed - Should Has Status Detail With Traceback ${test_case} Traceback (most recent call last):\n${SPACE * 2}None - ${step} Should Has Step ${test_case} BuiltIn.Fail - Should Has Status ${step} failed - -Failed Test Case With Python Traceback - ${allure_report} Run Robot With Allure examples/status/status.rst - ${test_case} Should Has Test Case ${allure_report} Failed Test Case With Python Traceback - Should Has Status ${test_case} failed - Should Has Status Detail With Traceback ${test_case} fail_with_traceback\n${SPACE * 4}BuiltIn().fail(traceback_message) - ${step} Should Has Step ${test_case} status_library.Fail With Traceback - Should Has Status ${step} failed - -Failed Test Case With Not Executed Step - ${allure_report} Run Robot With Allure examples/status/status.rst - ${test_case} Should Has Test Case ${allure_report} Failed Test Case With Not Executed Step - Should Has Status ${test_case} failed - ${step} Should Has Step ${test_case} BuiltIn.Log - Should Has Status ${step} skipped diff --git a/allure-robotframework/test/step/builtin_step.robot b/allure-robotframework/test/step/builtin_step.robot deleted file mode 100644 index 8d63945e..00000000 --- a/allure-robotframework/test/step/builtin_step.robot +++ /dev/null @@ -1,17 +0,0 @@ -*** Settings *** -Library ../run_robot_library.py -Library ../test_allure_library.py - - -*** Test Case *** -Use Library Keyword With Allure Step - ${allure_report} Run Robot With Allure examples/step/builtin_step.rst - ${test_case} Should Has Test Case ${allure_report} Log Builtin Keyword - ${step} Should Has Step ${test_case} BuiltIn.Log - Should Has Parameter ${step} arg1 The rose is red - ${step} Should Has Step ${test_case} BuiltIn.Log - Should Has Parameter ${step} arg1 the violet's blue - -# ToDo: loglevel -# ToDo: Log Many -# ToDo: Comment \ No newline at end of file diff --git a/allure-robotframework/test/step/outside_step.robot b/allure-robotframework/test/step/outside_step.robot deleted file mode 100644 index e7b6206a..00000000 --- a/allure-robotframework/test/step/outside_step.robot +++ /dev/null @@ -1,11 +0,0 @@ -*** Settings *** -Library ../run_robot_library.py -Library ../test_allure_library.py - - -*** Test Case *** -Use Library Keyword With Allure Step - ${allure_report} Run Robot With Allure examples/step/outside_step.rst - ${test_case} Should Has Test Case ${allure_report} Use Library Keyword With Allure Step - ${step} Should Has Step ${test_case} outside_step_library.Keyword With Allure Step - Should Has Step ${step} Passed Step Inside Keyword \ No newline at end of file diff --git a/allure-robotframework/test/tag/tag.robot b/allure-robotframework/test/tag/tag.robot deleted file mode 100644 index b1f10d64..00000000 --- a/allure-robotframework/test/tag/tag.robot +++ /dev/null @@ -1,27 +0,0 @@ -*** Settings *** -Library ../run_robot_library.py -Library ../test_allure_library.py -Suite Setup Run exampe - - -*** Keywords *** -Run exampe - ${allure_report} Run Robot With Allure examples/tag/tag.rst - Set Suite Variable ${report} ${allure_report} - - -*** Test Case *** -Test Case With Tags - ${test_case} Should Has Test Case ${report} Test Case With Tags - Should Has Tag ${test_case} alpha - Should Has Tag ${test_case} bravo - -Test Case With Dynamic Tags - ${test_case} Should Has Test Case ${report} Test Case With Dynamic Tags - Should Has Tag ${test_case} alpha - Should Has Tag ${test_case} bravo - -Test Case With Removed Tags - ${test_case} Should Has Test Case ${report} Test Case With Removed Tags - Should Has Tag ${test_case} alpha - Should Has Tag ${test_case} charlie \ No newline at end of file diff --git a/allure-robotframework/test/test_allure_library.py b/allure-robotframework/test/test_allure_library.py deleted file mode 100644 index 0dd97c27..00000000 --- a/allure-robotframework/test/test_allure_library.py +++ /dev/null @@ -1,133 +0,0 @@ -from functools import partial -from hamcrest import assert_that -from hamcrest import not_, anything -from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_description -from allure_commons_test.result import has_step -from allure_commons_test.result import with_status -from allure_commons_test.result import has_parameter -from allure_commons_test.result import has_link -from allure_commons_test.result import has_status_details -from allure_commons_test.result import with_message_contains -from allure_commons_test.result import with_trace_contains -from allure_commons_test.result import has_attachment -from allure_commons_test.label import has_severity -from allure_commons_test.label import has_tag -from allure_commons_test.label import has_label -from allure_commons_test.container import has_container -from allure_commons_test.container import has_before, has_after - - -def match(matcher, *args): - for i, arg in enumerate(args): - if not hasattr(arg, '__call__'): - matcher = partial(matcher, arg) - else: - matcher = partial(matcher, match(arg, *args[i+1:])) - break - return matcher() - - -def should_has_test_case(allure_report, test_case): - test_case_matcher = partial(match, has_test_case, test_case) - assert_that(allure_report, test_case_matcher()) - return allure_report, test_case_matcher - - -def should_has_tag(context, tag): - allure_report, test_case_matcher = context - tag_matcher = partial(test_case_matcher, has_tag, tag) - assert_that(allure_report, tag_matcher()) - - -def should_not_has_tag(conetxt, tag): - allure_report, test_case_matcher = conetxt - tag_matcher = partial(test_case_matcher, not_, has_tag, tag) - assert_that(allure_report, tag_matcher()) - - -def should_has_severity(context, severity): - allure_report, test_case_matcher = context - severity_matcher = partial(test_case_matcher, has_severity, severity) - assert_that(allure_report, severity_matcher()) - - -def should_not_has_severity(context): - allure_report, test_case_matcher = context - severity_matcher = partial(test_case_matcher, not_, has_severity, anything) - assert_that(allure_report, severity_matcher()) - - -def should_has_step(context, step): - allure_report, item_matcher = context - step_matcher = partial(item_matcher, has_step, step) - assert_that(allure_report, step_matcher()) - return allure_report, step_matcher - - -def should_not_has_step(context, step): - allure_report, item_matcher = context - step_matcher = partial(item_matcher, not_, has_step, step) - assert_that(allure_report, step_matcher()) - - -def should_has_attachment(context, attach_type=None, name=None): - allure_report, item_matcher = context - matcher = partial(item_matcher, has_attachment, attach_type, name) - assert_that(allure_report, matcher()) - - -def should_has_description(context, description): - allure_report, test_case_matcher = context - description_matcher = partial(test_case_matcher, has_description, description) - assert_that(allure_report, description_matcher()) - - -def should_has_before_fixture(context, fixture): - allure_report, test_case_matcher = context - fixture_matcher = partial(test_case_matcher, has_container, allure_report, has_before, fixture) - assert_that(allure_report, fixture_matcher()) - return allure_report, fixture_matcher - - -def should_has_after_fixture(context, fixture): - allure_report, test_case_matcher = context - fixture_matcher = partial(test_case_matcher, has_container, allure_report, has_after, fixture) - assert_that(allure_report, fixture_matcher()) - return allure_report, fixture_matcher - - -def should_has_status(context, status): - allure_report, item_matcher = context - status_matcher = partial(item_matcher, with_status, status) - assert_that(allure_report, status_matcher()) - - -def should_has_parameter(context, name, value): - allure_report, item_matcher = context - matcher = partial(item_matcher, has_parameter, name, value) - assert_that(allure_report, matcher()) - - -def should_has_status_detail_with_message(conext, message): - allure_report, item_matcher = conext - matcher = partial(item_matcher, has_status_details, with_message_contains, message) - assert_that(allure_report, matcher()) - - -def should_has_status_detail_with_traceback(conext, traceback): - allure_report, item_matcher = conext - matcher = partial(item_matcher, has_status_details, with_trace_contains, traceback) - assert_that(allure_report, matcher()) - - -def should_has_link(context, link, link_type=None, link_name=None): - allure_report, test_case_matcher = context - matcher = partial(test_case_matcher, has_link, link, link_type, link_name) - assert_that(allure_report, matcher()) - - -def should_has_label(context, name, value): - allure_report, test_case_matcher = context - matcher = partial(test_case_matcher, has_label, name, value) - assert_that(allure_report, matcher()) diff --git a/allure-robotframework/test/testplan/testplan.robot b/allure-robotframework/test/testplan/testplan.robot deleted file mode 100644 index 7ba18820..00000000 --- a/allure-robotframework/test/testplan/testplan.robot +++ /dev/null @@ -1,16 +0,0 @@ -*** Settings *** -Library ../run_robot_library.py -Library ../test_allure_library.py - - -*** Variables ** -${PLAN_A} \{ -... "version":"1.0", -... "tests": [ -... { "id": "123", "selector": "Second testcase"} -... ] -... \} - -*** Test Case *** -Failed Test Case With Message - ${allure_report} Run Robot With Allure examples/testplan/testplan.rst testplan=${PLAN_A} \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..5485c029 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,15 @@ +[tool.poe.tasks] +linter = "flake8 ./allure-*/src ./tests" +tests = "pytest" +allure-collect = "pytest -p allure_pytest --alluredir ./.allure-results --clean-alluredir --allure-link-pattern issue:https://github.com/allure-framework/allure-python/issues/{0}" +allure-generate = "allure generate --clean --output ./.allure-report ./.allure-results" +allure-open = "allure open ./.allure-report" + +[tool.pytest.ini_options] +testpaths = [ + "tests" +] +addopts = [ + "-p", "no:allure_pytest", + "-p", "no:allure_pytest_bdd" +] diff --git a/requirements/all.txt b/requirements/all.txt new file mode 100644 index 00000000..2c5fe0a7 --- /dev/null +++ b/requirements/all.txt @@ -0,0 +1,20 @@ +# Commons: +-r ./commons.txt + +# Allure integrations +-e allure-behave +-e allure-nose2 +-e allure-pytest +-e allure-pytest-bdd +-e allure-robotframework + +# Testing & linting +-r ./testing.txt +-r ./linting.txt + +# Allure per-package testing deps +-r ./testing/allure-behave.txt +-r ./testing/allure-nose2.txt +-r ./testing/allure-pytest.txt +-r ./testing/allure-pytest-bdd.txt +-r ./testing/allure-robotframework.txt diff --git a/requirements/commons.txt b/requirements/commons.txt new file mode 100644 index 00000000..eedfd669 --- /dev/null +++ b/requirements/commons.txt @@ -0,0 +1,2 @@ +-e allure-python-commons +-e allure-python-commons-test diff --git a/requirements/core.txt b/requirements/core.txt new file mode 100644 index 00000000..af8ea1ae --- /dev/null +++ b/requirements/core.txt @@ -0,0 +1,2 @@ +# Task runner +poethepoet diff --git a/requirements/linting.txt b/requirements/linting.txt new file mode 100644 index 00000000..fc08386d --- /dev/null +++ b/requirements/linting.txt @@ -0,0 +1,3 @@ +-r ./core.txt +flake8 +flake8-builtins diff --git a/requirements/testing.txt b/requirements/testing.txt new file mode 100644 index 00000000..09919cdf --- /dev/null +++ b/requirements/testing.txt @@ -0,0 +1,7 @@ +-r ./core.txt +docutils +mock +poethepoet +PyHamcrest +Pygments +pytest diff --git a/requirements/testing/allure-behave.txt b/requirements/testing/allure-behave.txt new file mode 100644 index 00000000..0de2f9a3 --- /dev/null +++ b/requirements/testing/allure-behave.txt @@ -0,0 +1 @@ +# allure_behave testing deps diff --git a/requirements/testing/allure-nose2.txt b/requirements/testing/allure-nose2.txt new file mode 100644 index 00000000..22c30d31 --- /dev/null +++ b/requirements/testing/allure-nose2.txt @@ -0,0 +1 @@ +# allure_nose2 testing deps diff --git a/requirements/testing/allure-pytest-bdd.txt b/requirements/testing/allure-pytest-bdd.txt new file mode 100644 index 00000000..19b9ce8f --- /dev/null +++ b/requirements/testing/allure-pytest-bdd.txt @@ -0,0 +1 @@ +# allure_pytest_bdd testing deps diff --git a/requirements/testing/allure-pytest.txt b/requirements/testing/allure-pytest.txt new file mode 100644 index 00000000..ca239ac7 --- /dev/null +++ b/requirements/testing/allure-pytest.txt @@ -0,0 +1,6 @@ +# allure_pytest testing deps +pytest-check +pytest-flakes +pytest-rerunfailures +pytest-xdist +pytest-lazy-fixture diff --git a/requirements/testing/allure-python-commons-test.txt b/requirements/testing/allure-python-commons-test.txt new file mode 100644 index 00000000..ff36d34a --- /dev/null +++ b/requirements/testing/allure-python-commons-test.txt @@ -0,0 +1 @@ +# allure_commons_test testing deps diff --git a/requirements/testing/allure-python-commons.txt b/requirements/testing/allure-python-commons.txt new file mode 100644 index 00000000..84ed3139 --- /dev/null +++ b/requirements/testing/allure-python-commons.txt @@ -0,0 +1 @@ +# allure_commons testing deps diff --git a/requirements/testing/allure-robotframework.txt b/requirements/testing/allure-robotframework.txt new file mode 100644 index 00000000..842589fe --- /dev/null +++ b/requirements/testing/allure-robotframework.txt @@ -0,0 +1,2 @@ +# allure_robotframework testing deps +robotframework-pabot diff --git a/allure-nose2/test/__init__.py b/tests/__init__.py similarity index 100% rename from allure-nose2/test/__init__.py rename to tests/__init__.py diff --git a/allure-nose2/test/labels/__init__.py b/tests/allure_behave/__init__.py similarity index 100% rename from allure-nose2/test/labels/__init__.py rename to tests/allure_behave/__init__.py diff --git a/allure-nose2/test/parametrized/__init__.py b/tests/allure_behave/acceptance/__init__.py similarity index 100% rename from allure-nose2/test/parametrized/__init__.py rename to tests/allure_behave/acceptance/__init__.py diff --git a/allure-nose2/test/result/__init__.py b/tests/allure_behave/acceptance/allure_api/__init__.py similarity index 100% rename from allure-nose2/test/result/__init__.py rename to tests/allure_behave/acceptance/allure_api/__init__.py diff --git a/allure-nose2/test/with_mp/__init__.py b/tests/allure_behave/acceptance/allure_api/attachment/__init__.py similarity index 100% rename from allure-nose2/test/with_mp/__init__.py rename to tests/allure_behave/acceptance/allure_api/attachment/__init__.py diff --git a/tests/allure_behave/acceptance/allure_api/attachment/attachment_test.py b/tests/allure_behave/acceptance/allure_api/attachment/attachment_test.py new file mode 100644 index 00000000..93029b0a --- /dev/null +++ b/tests/allure_behave/acceptance/allure_api/attachment/attachment_test.py @@ -0,0 +1,83 @@ +""" ./allure-behave/examples/attachment.rst """ + +from tests.allure_behave.behave_runner import AllureBehaveRunner +from hamcrest import assert_that, equal_to +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_attachment_with_content +from allure_commons_test.result import has_attachment +from allure_commons_test.result import has_step + + +def test_data_attachment_from_step(behave_runner: AllureBehaveRunner): + behave_runner.run_behave( + feature_rst_ids=["data-attachment-feature"], + step_rst_ids=["data-attachment-steps"] + ) + assert_that( + behave_runner.allure_results, + has_test_case( + "Data attachment from step definitions", + has_step( + "Given a step that adds a named attachment", + has_attachment_with_content( + behave_runner.allure_results.attachments, + equal_to("This is the attachment with the name 'step.txt'"), + name="step.txt" + ) + ), + has_step( + "And a step that adds a typed named attachment", + has_attachment_with_content( + behave_runner.allure_results.attachments, + equal_to( + "[DEBUG] This attachment is named 'trace.log' and has " + "TEXT document appearance" + ), + attach_type="text/plain", + name="trace.log" + ) + ) + ) + ) + + +def test_file_attachment_from_step(behave_runner: AllureBehaveRunner): + behave_runner.run_behave( + feature_rst_ids=["file-attachment-feature"], + step_rst_ids=["file-attachment-steps"] + ) + assert_that( + behave_runner.allure_results, + has_test_case( + "File attachment from a step definition", + has_step( + "Given a step that attaches a file", + has_attachment("text/plain", "web.log") + ) + ) + ) + + +def test_data_attachment_from_hook(behave_runner: AllureBehaveRunner): + feature = """ + Feature: Allure attachments in behave tests + Scenario: Attachment from after_scenario hook + Given noop + """ + behave_runner.run_behave( + feature_literals=[feature], + step_literals=["given('noop')(lambda _:0)"], + environment_rst_id="attach-hook" + ) + assert_that( + behave_runner.allure_results, + has_test_case( + "Attachment from after_scenario hook", + has_attachment_with_content( + behave_runner.allure_results.attachments, + equal_to("This attachment will appear on a scenario level"), + attach_type="text/plain", + name="attachment.txt" + ) + ) + ) diff --git a/allure-pytest-bdd/test/__init__.py b/tests/allure_behave/acceptance/allure_api/description/__init__.py similarity index 100% rename from allure-pytest-bdd/test/__init__.py rename to tests/allure_behave/acceptance/allure_api/description/__init__.py diff --git a/tests/allure_behave/acceptance/allure_api/description/description_test.py b/tests/allure_behave/acceptance/allure_api/description/description_test.py new file mode 100644 index 00000000..49152daa --- /dev/null +++ b/tests/allure_behave/acceptance/allure_api/description/description_test.py @@ -0,0 +1,80 @@ +""" ./allure-behave/examples/description.rst """ + +from tests.allure_behave.behave_runner import AllureBehaveRunner +from hamcrest import assert_that +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_description +from allure_commons_test.result import with_status + + +def test_descriptions_from_feature_file(behave_runner: AllureBehaveRunner): + behave_runner.run_behave( + feature_rst_ids=["description-in-feature-feature"], + step_rst_ids=["description-in-feature-steps"] + ) + assert_that( + behave_runner.allure_results, + has_test_case( + "Description from a .feature file", + with_status("passed"), + has_description( + "This scenario has a description.\nThis description spans " + "across multiple lines." + ) + ) + ) + + +def test_descriptions_from_step(behave_runner: AllureBehaveRunner): + behave_runner.run_behave( + feature_rst_ids=["description-in-step-feature"], + step_rst_ids=["description-in-step-steps"] + ) + assert_that( + behave_runner.allure_results, + has_test_case( + "Description from a step definition", + with_status("passed"), + has_description( + "This scenario has a description specified by the step " + "definition" + ) + ) + ) + + +def test_descriptions_before_scenario(behave_runner: AllureBehaveRunner): + behave_runner.run_behave( + feature_rst_ids=["description-in-hook-feature"], + step_rst_ids=["description-in-feature-steps"], + environment_rst_id="description-in-hook-env" + ) + assert_that( + behave_runner.allure_results, + has_test_case( + "Description from the before_scenario hook", + with_status("passed"), + has_description( + "This scenario has a description specified in the before_scenario hook" + ) + ) + ) + + +def test_descriptions_after_scenario(behave_runner: AllureBehaveRunner): + behave_runner.run_behave( + feature_rst_ids=["description-in-hook-feature"], + step_rst_ids=["description-in-feature-steps"], + environment_rst_id="description-in-hook-env" + ) + assert_that( + behave_runner.allure_results, + has_test_case( + "Description from the after_scenario hook", + with_status("passed"), + has_description( + "This scenario has a description specified in the " + "after_scenario hook" + ) + ) + ) diff --git a/allure-pytest/test/__init__.py b/tests/allure_behave/acceptance/allure_api/labels/__init__.py similarity index 100% rename from allure-pytest/test/__init__.py rename to tests/allure_behave/acceptance/allure_api/labels/__init__.py diff --git a/tests/allure_behave/acceptance/allure_api/labels/label_test.py b/tests/allure_behave/acceptance/allure_api/labels/label_test.py new file mode 100644 index 00000000..3bbf0022 --- /dev/null +++ b/tests/allure_behave/acceptance/allure_api/labels/label_test.py @@ -0,0 +1,22 @@ +""" ./allure-behave/examples/label.rst """ + +from tests.allure_behave.behave_runner import AllureBehaveRunner +from hamcrest import assert_that +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status +from allure_commons_test.label import has_label + + +def test_label_from_feature_file(behave_runner: AllureBehaveRunner): + behave_runner.run_behave( + feature_rst_ids=["label-feature"], + step_literals=["given('noop')(lambda c:None)"] + ) + assert_that( + behave_runner.allure_results, + has_test_case( + "Scenario marked with an author label", + with_status("passed"), + has_label("author", "John-Doe") + ) + ) diff --git a/allure-pytest/test/acceptance/__init__.py b/tests/allure_behave/acceptance/allure_api/links/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/__init__.py rename to tests/allure_behave/acceptance/allure_api/links/__init__.py diff --git a/tests/allure_behave/acceptance/allure_api/links/link_test.py b/tests/allure_behave/acceptance/allure_api/links/link_test.py new file mode 100644 index 00000000..c9628b98 --- /dev/null +++ b/tests/allure_behave/acceptance/allure_api/links/link_test.py @@ -0,0 +1,98 @@ +""" ./allure-behave/examples/link.rst """ + +from tests.allure_behave.behave_runner import AllureBehaveRunner +from hamcrest import assert_that, all_of +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status +from allure_commons_test.result import has_link +from allure_commons_test.result import has_issue_link +from allure_commons_test.result import has_test_case_link + + +def test_link_on_scenario_level(behave_runner: AllureBehaveRunner): + behave_runner.run_behave( + feature_rst_ids=["link-scenario-feature"], + step_literals=["given('noop')(lambda c:None)"] + ) + assert_that( + behave_runner.allure_results, + has_test_case( + "Scenario with the link to the allure report website", + with_status("passed"), + has_link("https://qameta.io/allure-report/", "link", "report") + ) + ) + + +def test_link_on_feature_level(behave_runner: AllureBehaveRunner): + behave_runner.run_behave( + feature_rst_ids=["link-feature-feature"], + step_literals=["given('noop')(lambda c:None)"] + ) + assert_that( + behave_runner.allure_results, + all_of( + has_test_case( + "Scenario with the link to the homepage", + with_status("passed"), + has_link("https://qameta.io", "link", "homepage") + ), + has_test_case( + "Another scenario with the link to the homepage", + with_status("passed"), + has_link("https://qameta.io", "link", "homepage") + ) + ) + ) + + +def test_specialized_links(behave_runner: AllureBehaveRunner): + behave_runner.run_behave( + feature_rst_ids=["specialized-links-feature"], + step_literals=["given('noop')(lambda c:None)"] + ) + assert_that( + behave_runner.allure_results, + all_of( + has_test_case( + "Scenario associated with the issue", + with_status("passed"), + has_issue_link( + "https://github.com/allure-framework/allure-python/issues/1", + "https://github.com/allure-framework/allure-python/issues/1" + ) + ), + has_test_case( + "Scenario associated with the TMS test case", + with_status("passed"), + has_test_case_link( + "https://qameta.io/#features", + "https://qameta.io/#features" + ) + ) + ) + ) + + +def test_dynamic_links(behave_runner: AllureBehaveRunner): + behave_runner.run_behave( + feature_rst_ids=["dynamic-links-feature"], + step_rst_ids=["dynamic-links-steps"], + environment_rst_id="dynamic-links-hooks" + ) + assert_that( + behave_runner.allure_results, + has_test_case( + "Issue from the step definition and link from the hook", + with_status("passed"), + has_issue_link( + "https://github.com/allure-framework/allure-python/issues/1", + "Skip None and empty values in json" + ), + has_link( + "https://qameta.io/allure-report/", + "link", + "Allure Report" + ) + ) + ) diff --git a/allure-pytest/test/acceptance/attachment/__init__.py b/tests/allure_behave/acceptance/allure_api/severities/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/attachment/__init__.py rename to tests/allure_behave/acceptance/allure_api/severities/__init__.py diff --git a/tests/allure_behave/acceptance/allure_api/severities/severity_test.py b/tests/allure_behave/acceptance/allure_api/severities/severity_test.py new file mode 100644 index 00000000..9ad562bd --- /dev/null +++ b/tests/allure_behave/acceptance/allure_api/severities/severity_test.py @@ -0,0 +1,74 @@ +""" ./allure-behave/examples/severity.rst """ + +import pytest +from tests.allure_behave.behave_runner import AllureBehaveRunner +from hamcrest import assert_that, all_of +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status +from allure_commons_test.label import has_severity + + +@pytest.mark.parametrize(["name", "sev"], [ + pytest.param("Blocking scenario", "blocker", id="blocker"), + pytest.param("Critical scenario", "critical", id="critical"), + pytest.param("Normal scenario", "normal", id="normal"), + pytest.param("Minor scenario", "minor", id="minor"), + pytest.param("Trivial scenario", "trivial", id="trivial") +]) +def test_severity_on_scenario(name, sev, behave_runner: AllureBehaveRunner): + behave_runner.run_behave( + feature_rst_ids=["severity-on-scenario"], + step_literals=["given('noop')(lambda c:None)"] + ) + assert_that( + behave_runner.allure_results, + has_test_case( + name, + with_status("passed"), + has_severity(sev) + ) + ) + + +def test_severity_on_feature(behave_runner: AllureBehaveRunner): + behave_runner.run_behave( + feature_rst_ids=["severity-on-feature"], + step_literals=["given('noop')(lambda c:None)"] + ) + assert_that( + behave_runner.allure_results, + all_of( + has_test_case( + "This scenario inherits the @cricial tag", + with_status("passed"), + has_severity("critical") + ), + has_test_case( + "This scenario also inherits the @cricial tag", + with_status("passed"), + has_severity("critical") + ) + ) + ) + + +def test_multiple_severity_tags(behave_runner: AllureBehaveRunner): + behave_runner.run_behave( + feature_rst_ids=["multiple-severities"], + step_literals=["given('noop')(lambda c:None)"] + ) + assert_that( + behave_runner.allure_results, + all_of( + has_test_case( + "This is a trivial scenario", + with_status("passed"), + has_severity("trivial") + ), + has_test_case( + "While this one is a blocker", + with_status("passed"), + has_severity("blocker") + ) + ) + ) diff --git a/allure-pytest/test/acceptance/capture/__init__.py b/tests/allure_behave/acceptance/allure_api/tags/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/capture/__init__.py rename to tests/allure_behave/acceptance/allure_api/tags/__init__.py diff --git a/tests/allure_behave/acceptance/allure_api/tags/tag_test.py b/tests/allure_behave/acceptance/allure_api/tags/tag_test.py new file mode 100644 index 00000000..6c9b3e6a --- /dev/null +++ b/tests/allure_behave/acceptance/allure_api/tags/tag_test.py @@ -0,0 +1,46 @@ +""" ./allure-behave/examples/tag.rst """ + +import pytest +from tests.allure_behave.behave_runner import AllureBehaveRunner +from hamcrest import assert_that +from allure_commons_test.report import has_test_case +from allure_commons_test.label import has_tag + + +@pytest.mark.parametrize(["feature_id", "scenario", "tags"], [ + pytest.param( + "tag-scenario-feature", + "Applying a tag directly to a scenario", + ["distributed"], + id="scenario-tag" + ), + pytest.param( + "tag-feature-feature", + "Applying a tag to a feature", + ["isolated"], + id="feature-tag" + ), + pytest.param( + "tag-multiple-feature", + "Applying multiple tags", + ["node-1", "node-2", "node-3", "node-4"], + id="multiple-tags" + ) +]) +def test_behave_tags_as_allure_tags( + feature_id, + scenario, + tags, + behave_runner: AllureBehaveRunner +): + behave_runner.run_behave( + feature_rst_ids=[feature_id], + step_literals=["given('noop')(lambda c:None)"] + ) + assert_that( + behave_runner.allure_results, + has_test_case( + scenario, + *(has_tag(tag) for tag in tags) + ) + ) diff --git a/allure-pytest/test/acceptance/description/__init__.py b/tests/allure_behave/acceptance/allure_api/testplan/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/description/__init__.py rename to tests/allure_behave/acceptance/allure_api/testplan/__init__.py diff --git a/tests/allure_behave/acceptance/allure_api/testplan/testplan_test.py b/tests/allure_behave/acceptance/allure_api/testplan/testplan_test.py new file mode 100644 index 00000000..444d8b7d --- /dev/null +++ b/tests/allure_behave/acceptance/allure_api/testplan/testplan_test.py @@ -0,0 +1,95 @@ +""" ./allure-behave/examples/testplan.rst """ + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status +from hamcrest import assert_that, all_of, not_ +from tests.allure_behave.behave_runner import AllureBehaveRunner + + +def test_testplan_fullname_selection(behave_runner: AllureBehaveRunner): + behave_runner.run_behave( + feature_rst_ids=["fullname-feature-1", "fullname-feature-2"], + step_rst_ids=["steps"], + testplan_rst_id="fullname-testplan" + ) + + assert_that( + behave_runner.allure_results, + all_of( + has_test_case( + "Scenario selection", + with_status("passed") + ), + has_test_case( + "Scenario deselection", + with_status("skipped") + ), + has_test_case( + "Scenario selection 2", + with_status("passed") + ), + has_test_case( + "Scenario deselection 2", + with_status("skipped") + ) + ) + ) + + +def test_testplan_id_selection(behave_runner: AllureBehaveRunner): + behave_runner.run_behave( + feature_rst_ids=["id-feature-1", "id-feature-2"], + step_rst_ids=["steps"], + testplan_rst_id="id-testplan" + ) + + assert_that( + behave_runner.allure_results, + all_of( + has_test_case( + "Scenario selection", + with_status("passed") + ), + has_test_case( + "Scenario deselection", + with_status("skipped") + ), + has_test_case( + "Scenario selection 2", + with_status("passed") + ), + has_test_case( + "Scenario deselection 2", + with_status("skipped") + ) + ) + ) + + +def test_skipping_of_tests_missing_in_testplan(behave_runner: AllureBehaveRunner): + behave_runner.run_behave( + feature_rst_ids=["fullname-feature-1", "fullname-feature-2"], + step_rst_ids=["steps"], + testplan_rst_id="fullname-testplan", + options=["-D", "AllureFormatter.hide_excluded=True"] + ) + + assert_that( + behave_runner.allure_results, + all_of( + has_test_case( + "Scenario selection", + with_status("passed") + ), + not_( + has_test_case("Scenario deselection") + ), + has_test_case( + "Scenario selection 2", + with_status("passed") + ), + not_( + has_test_case("Scenario deselection 2") + ) + ) + ) diff --git a/allure-pytest/test/acceptance/display_name/__init__.py b/tests/allure_behave/acceptance/behave_support/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/display_name/__init__.py rename to tests/allure_behave/acceptance/behave_support/__init__.py diff --git a/allure-pytest/test/acceptance/duration/__init__.py b/tests/allure_behave/acceptance/behave_support/background/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/duration/__init__.py rename to tests/allure_behave/acceptance/behave_support/background/__init__.py diff --git a/tests/allure_behave/acceptance/behave_support/background/background_steps.py b/tests/allure_behave/acceptance/behave_support/background/background_steps.py new file mode 100644 index 00000000..a2865174 --- /dev/null +++ b/tests/allure_behave/acceptance/behave_support/background/background_steps.py @@ -0,0 +1,20 @@ +from behave import given + +@given("the first background step that is passed") +def step_impl(_): + pass + +@given("the first background step that is failed") +def step_impl(_): + assert False, "Failed assertion message" + +@given("the first background step that is broken") +def step_impl(_): + raise ValueError("Something is broken") + +@given("the second background step with no failures") +@given("the first step with no failures") +@given("the second step with no failures") +@given("the step with no failures") +def step_impl(_): + pass diff --git a/tests/allure_behave/acceptance/behave_support/background/background_test.py b/tests/allure_behave/acceptance/behave_support/background/background_test.py new file mode 100644 index 00000000..0a3a0eee --- /dev/null +++ b/tests/allure_behave/acceptance/behave_support/background/background_test.py @@ -0,0 +1,84 @@ +import pytest +from hamcrest import assert_that, all_of +from tests.allure_behave.behave_runner import AllureBehaveRunner +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status +from allure_commons_test.result import has_step + + +@pytest.mark.parametrize( + ["step_outcome", "status", "remained_steps_status"], + [ + pytest.param("passed", "passed", "passed", id="passed"), + pytest.param("failed", "failed", "skipped", id="failed"), + pytest.param("broken", "broken", "skipped", id="broken"), + pytest.param("undefined", "broken", "skipped", id="undefined"), + ] +) +def test_background( + docstring: str, + behave_runner: AllureBehaveRunner, + step_outcome: str, + status: str, + remained_steps_status: str +): + """ + Feature: Allure-behave compatibility with feature backgrounds + Background: A background with {step_outcome} step + Given the first background step that is {step_outcome} + And the second background step with no failures + + Scenario: Scenario with background containing {step_outcome} step + Given the first step with no failures + And the second step with no failures + + Scenario: Another scenario with background containing {step_outcome} step + Given the step with no failures + """ + behave_runner.run_behave( + feature_literals=[ + docstring.format(step_outcome=step_outcome) + ], + step_paths=["./background_steps.py"] + ) + assert_that( + behave_runner.allure_results, + all_of( + has_test_case( + f"Scenario with background containing {step_outcome} step", + with_status(status), + has_step( + f"Given the first background step that is {step_outcome}", + with_status(status) + ), + has_step( + "And the second background step with no failures", + with_status(remained_steps_status) + ), + has_step( + "Given the first step with no failures", + with_status(remained_steps_status) + ), + has_step( + "And the second step with no failures", + with_status(remained_steps_status) + ) + ), + has_test_case( + f"Another scenario with background containing {step_outcome} step", + with_status(status), + has_step( + f"Given the first background step that is {step_outcome}", + with_status(status) + ), + has_step( + "And the second background step with no failures", + with_status(remained_steps_status) + ), + has_step( + "Given the step with no failures", + with_status(remained_steps_status) + ) + ) + ) + ) diff --git a/allure-pytest/test/acceptance/fixture/__init__.py b/tests/allure_behave/acceptance/behave_support/behave_cmd/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/fixture/__init__.py rename to tests/allure_behave/acceptance/behave_support/behave_cmd/__init__.py diff --git a/tests/allure_behave/acceptance/behave_support/behave_cmd/behave_cmd_test.py b/tests/allure_behave/acceptance/behave_support/behave_cmd/behave_cmd_test.py new file mode 100644 index 00000000..6e3fe849 --- /dev/null +++ b/tests/allure_behave/acceptance/behave_support/behave_cmd/behave_cmd_test.py @@ -0,0 +1,64 @@ +from hamcrest import assert_that, all_of, not_ +from tests.allure_behave.behave_runner import AllureBehaveRunner +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status + + +def test_behave_tags_filter(docstring: str, behave_runner: AllureBehaveRunner): + """Feature: Behave --tags CLI argument support + + @tag + Scenario: Scenario with tag + Given noop + + Scenario: Scenario without tag + Given noop + """ + + behave_runner.run_behave( + feature_literals=[docstring], + step_literals=["given('noop')(lambda c:None)"], + options=["--tags=tag"] + ) + assert_that( + behave_runner.allure_results, + all_of( + has_test_case( + "Scenario with tag", + with_status("passed") + ), + has_test_case( + "Scenario without tag", + with_status("skipped") + ) + ) + ) + + +def test_behave_no_skipped_support(docstring: str, behave_runner: AllureBehaveRunner): + """Feature: Behave --tags CLI argument support + + @tag + Scenario: Scenario with tag + Given noop + + Scenario: Scenario without tag + Given noop + """ + behave_runner.run_behave( + feature_literals=[docstring], + step_literals=["given('noop')(lambda c:None)"], + options=["--tags=tag", "--no-skipped"] + ) + assert_that( + behave_runner.allure_results, + all_of( + has_test_case( + "Scenario with tag", + with_status("passed") + ), + not_( + has_test_case("Scenario without tag") + ) + ) + ) diff --git a/allure-pytest/test/acceptance/fixture/function_scope/__init__.py b/tests/allure_behave/acceptance/behave_support/hooks/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/fixture/function_scope/__init__.py rename to tests/allure_behave/acceptance/behave_support/hooks/__init__.py diff --git a/tests/allure_behave/acceptance/behave_support/hooks/hook_test.py b/tests/allure_behave/acceptance/behave_support/hooks/hook_test.py new file mode 100644 index 00000000..197ed5a1 --- /dev/null +++ b/tests/allure_behave/acceptance/behave_support/hooks/hook_test.py @@ -0,0 +1,232 @@ +import allure +from tests.allure_behave.behave_runner import AllureBehaveRunner as Runner +from hamcrest import assert_that, all_of, not_, equal_to +from allure_commons_test.container import has_container, has_before, has_after +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status +from allure_commons_test.result import has_attachment_with_content +from allure_commons_test.result import has_step + + +def test_global_hooks(behave_runner: Runner): + behave_runner.run_behave( + feature_paths=["./test-data/global-hooks.feature"], + step_paths=["./test-data/steps.py"], + environment_path="./test-data/global-hooks.py" + ) + assert_that( + behave_runner.allure_results, + has_test_case( + "Global hooks as fixtures", + with_status("passed"), + has_container( + behave_runner.allure_results, + has_before("before all", with_status("passed")) + ), + has_container( + behave_runner.allure_results, + has_before("before feature", with_status("passed")) + ), + has_container( + behave_runner.allure_results, + has_before("before scenario", with_status("passed")) + ), + has_container( + behave_runner.allure_results, + has_before("before step", with_status("passed")) + ), + has_container( + behave_runner.allure_results, + has_after("after all", with_status("passed")) + ), + has_container( + behave_runner.allure_results, + has_after("after feature", with_status("passed")) + ), + has_container( + behave_runner.allure_results, + has_after("after scenario", with_status("passed")) + ), + has_container( + behave_runner.allure_results, + has_after("after step", with_status("passed")) + ) + ) + ) + + +def test_tag_hooks(behave_runner: Runner): + behave_runner.run_behave( + feature_paths=[ + "./test-data/tag-hook.feature", + "./test-data/feature-tag-hook.feature" + ], + step_paths=["./test-data/steps.py"], + environment_path="./test-data/tag-hooks.py" + ) + assert_that( + behave_runner.allure_results, + all_of( + has_test_case( + "Tag hooks as fixture - this scenario is affected", + with_status("passed"), + has_container( + behave_runner.allure_results, + has_before("before tag @hook_target", with_status("passed")) + ), + has_container( + behave_runner.allure_results, + has_after("after tag @hook_target", with_status("passed")) + ) + ), + has_test_case( + "Tag hooks as fixture - this scenario is not affected", + with_status("passed"), + not_( + has_container( + behave_runner.allure_results, + has_before("before tag @hook_target") + ) + ), + not_( + has_container( + behave_runner.allure_results, + has_after("after tag @hook_target") + ) + ) + ), + has_test_case( + "Feature-level tag hooks as fixtures", + with_status("passed"), + has_container( + behave_runner.allure_results, + has_before("before tag @hook_target", with_status("passed")) + ), + has_container( + behave_runner.allure_results, + has_after("after tag @hook_target", with_status("passed")) + ) + ) + ) + ) + + +def test_attachment_before_feature(behave_runner: Runner): + behave_runner.run_behave( + feature_paths=["./test-data/attachment-hook.feature"], + step_paths=["./test-data/steps.py"], + environment_path="./test-data/attachment-hooks.py" + ) + assert_that( + behave_runner.allure_results, + all_of( + has_test_case( + "Attachment from before_feature fixture-hook", + with_status("passed"), + has_container( + behave_runner.allure_results, + has_before( + "before feature", + with_status("passed"), + has_attachment_with_content( + behave_runner.allure_results.attachments, + equal_to("Attachment from before_feature"), + allure.attachment_type.TEXT.mime_type, + "Dynamic attachment" + ) + ), + ) + ), + has_test_case( + "One more scenario with same attachment in fixture-hook", + with_status("passed"), + has_container( + behave_runner.allure_results, + has_before( + "before feature", + with_status("passed"), + has_attachment_with_content( + behave_runner.allure_results.attachments, + equal_to("Attachment from before_feature"), + allure.attachment_type.TEXT.mime_type, + "Dynamic attachment" + ) + ) + ) + ) + ) + ) + + +def test_context_step_in_scenario_hooks(behave_runner: Runner): + behave_runner.run_behave( + feature_paths=["./test-data/step-hook.feature"], + step_paths=["./test-data/steps.py"], + environment_path="./test-data/context-step-hooks.py" + ) + assert_that( + behave_runner.allure_results, + has_test_case( + "Hook with steps", + with_status("passed"), + has_container( + behave_runner.allure_results, + has_before( + "before scenario", + with_status("passed"), + has_step( + "Step in before_scenario", + with_status("passed") + ) + ), + ), + has_container( + behave_runner.allure_results, + has_after( + "after scenario", + with_status("passed"), + has_step( + "Step in after_scenario", + with_status("passed") + ) + ) + ) + ) + ) + + +def test_func_step_in_scenario_hooks(behave_runner: Runner): + behave_runner.run_behave( + feature_paths=["./test-data/step-hook.feature"], + step_paths=["./test-data/steps.py"], + environment_path="./test-data/func-step-hooks.py" + ) + assert_that( + behave_runner.allure_results, + has_test_case( + "Hook with steps", + with_status("passed"), + has_container( + behave_runner.allure_results, + has_before( + "before all", + with_status("passed"), + has_step( + "Step in 'before_all'", + with_status("passed") + ) + ), + ), + has_container( + behave_runner.allure_results, + has_after( + "after all", + with_status("passed"), + has_step( + "Step in 'after_all'", + with_status("passed") + ) + ) + ) + ) + ) diff --git a/tests/allure_behave/acceptance/behave_support/hooks/test-data/attachment-hook.feature b/tests/allure_behave/acceptance/behave_support/hooks/test-data/attachment-hook.feature new file mode 100644 index 00000000..6b66a2c6 --- /dev/null +++ b/tests/allure_behave/acceptance/behave_support/hooks/test-data/attachment-hook.feature @@ -0,0 +1,6 @@ +Feature: Behave hook support + Scenario: Attachment from before_feature fixture-hook + Given noop + + Scenario: One more scenario with same attachment in fixture-hook + Given noop diff --git a/tests/allure_behave/acceptance/behave_support/hooks/test-data/attachment-hooks.py b/tests/allure_behave/acceptance/behave_support/hooks/test-data/attachment-hooks.py new file mode 100644 index 00000000..fb9a84f8 --- /dev/null +++ b/tests/allure_behave/acceptance/behave_support/hooks/test-data/attachment-hooks.py @@ -0,0 +1,11 @@ +import allure +import allure_commons + + +@allure_commons.fixture +def before_feature(context, feature): + allure.attach( + "Attachment from before_feature", + name="Dynamic attachment", + attachment_type=allure.attachment_type.TEXT + ) diff --git a/tests/allure_behave/acceptance/behave_support/hooks/test-data/context-step-hooks.py b/tests/allure_behave/acceptance/behave_support/hooks/test-data/context-step-hooks.py new file mode 100644 index 00000000..215add9b --- /dev/null +++ b/tests/allure_behave/acceptance/behave_support/hooks/test-data/context-step-hooks.py @@ -0,0 +1,12 @@ +import allure +import allure_commons + +@allure_commons.fixture +def before_scenario(context, scenario): + with allure.step("Step in before_scenario"): + pass + +@allure_commons.fixture +def after_scenario(context, scenario): + with allure.step("Step in after_scenario"): + pass diff --git a/tests/allure_behave/acceptance/behave_support/hooks/test-data/feature-tag-hook.feature b/tests/allure_behave/acceptance/behave_support/hooks/test-data/feature-tag-hook.feature new file mode 100644 index 00000000..d1bc54ee --- /dev/null +++ b/tests/allure_behave/acceptance/behave_support/hooks/test-data/feature-tag-hook.feature @@ -0,0 +1,4 @@ +@hook_target +Feature: Behave hook support + Scenario: Feature-level tag hooks as fixtures + Given noop diff --git a/tests/allure_behave/acceptance/behave_support/hooks/test-data/func-step-hooks.py b/tests/allure_behave/acceptance/behave_support/hooks/test-data/func-step-hooks.py new file mode 100644 index 00000000..303485b4 --- /dev/null +++ b/tests/allure_behave/acceptance/behave_support/hooks/test-data/func-step-hooks.py @@ -0,0 +1,16 @@ +import allure +import allure_commons + +@allure.step("Step in {caller}") +def step(caller): + pass + + +@allure_commons.fixture +def before_all(context): + step("before_all") + + +@allure_commons.fixture +def after_all(context): + step("after_all") diff --git a/tests/allure_behave/acceptance/behave_support/hooks/test-data/global-hooks.feature b/tests/allure_behave/acceptance/behave_support/hooks/test-data/global-hooks.feature new file mode 100644 index 00000000..441f10e7 --- /dev/null +++ b/tests/allure_behave/acceptance/behave_support/hooks/test-data/global-hooks.feature @@ -0,0 +1,3 @@ +Feature: Behave hooks support + Scenario: Global hooks as fixtures + Given noop \ No newline at end of file diff --git a/tests/allure_behave/acceptance/behave_support/hooks/test-data/global-hooks.py b/tests/allure_behave/acceptance/behave_support/hooks/test-data/global-hooks.py new file mode 100644 index 00000000..1eb703c0 --- /dev/null +++ b/tests/allure_behave/acceptance/behave_support/hooks/test-data/global-hooks.py @@ -0,0 +1,33 @@ +import allure_commons + +@allure_commons.fixture +def before_all(context): + pass + +@allure_commons.fixture +def after_all(context): + pass + +@allure_commons.fixture +def before_feature(context, feature): + pass + +@allure_commons.fixture +def after_feature(context, feature): + pass + +@allure_commons.fixture +def before_scenario(context, scenario): + pass + +@allure_commons.fixture +def after_scenario(context, scenario): + pass + +@allure_commons.fixture +def before_step(context, step): + pass + +@allure_commons.fixture +def after_step(context, step): + pass diff --git a/tests/allure_behave/acceptance/behave_support/hooks/test-data/step-hook.feature b/tests/allure_behave/acceptance/behave_support/hooks/test-data/step-hook.feature new file mode 100644 index 00000000..03e5f216 --- /dev/null +++ b/tests/allure_behave/acceptance/behave_support/hooks/test-data/step-hook.feature @@ -0,0 +1,3 @@ +Feature: Behave hook support + Scenario: Hook with steps + Given noop diff --git a/tests/allure_behave/acceptance/behave_support/hooks/test-data/steps.py b/tests/allure_behave/acceptance/behave_support/hooks/test-data/steps.py new file mode 100644 index 00000000..254950d7 --- /dev/null +++ b/tests/allure_behave/acceptance/behave_support/hooks/test-data/steps.py @@ -0,0 +1,5 @@ +from behave import given + +@given("noop") +def step_impl(context): + pass diff --git a/tests/allure_behave/acceptance/behave_support/hooks/test-data/tag-hook.feature b/tests/allure_behave/acceptance/behave_support/hooks/test-data/tag-hook.feature new file mode 100644 index 00000000..c537b7c6 --- /dev/null +++ b/tests/allure_behave/acceptance/behave_support/hooks/test-data/tag-hook.feature @@ -0,0 +1,8 @@ +Feature: Behave hooks support + + @hook_target + Scenario: Tag hooks as fixture - this scenario is affected + Given noop + + Scenario: Tag hooks as fixture - this scenario is not affected + Given noop diff --git a/tests/allure_behave/acceptance/behave_support/hooks/test-data/tag-hooks.py b/tests/allure_behave/acceptance/behave_support/hooks/test-data/tag-hooks.py new file mode 100644 index 00000000..81048c1e --- /dev/null +++ b/tests/allure_behave/acceptance/behave_support/hooks/test-data/tag-hooks.py @@ -0,0 +1,9 @@ +import allure_commons + +@allure_commons.fixture +def before_tag(context, tag): + pass + +@allure_commons.fixture +def after_tag(context, tag): + pass diff --git a/allure-pytest/test/acceptance/history_id/__init__.py b/tests/allure_behave/acceptance/behave_support/scenario_outlines/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/history_id/__init__.py rename to tests/allure_behave/acceptance/behave_support/scenario_outlines/__init__.py diff --git a/tests/allure_behave/acceptance/behave_support/scenario_outlines/scenario_outline_test.py b/tests/allure_behave/acceptance/behave_support/scenario_outlines/scenario_outline_test.py new file mode 100644 index 00000000..e6e73593 --- /dev/null +++ b/tests/allure_behave/acceptance/behave_support/scenario_outlines/scenario_outline_test.py @@ -0,0 +1,137 @@ +from hamcrest import assert_that, all_of, has_entry +from tests.allure_behave.behave_runner import AllureBehaveRunner +from allure_commons_test.report import has_only_testcases +from allure_commons_test.result import with_status +from allure_commons_test.result import has_parameter + + +def test_outline_with_single_table(behave_runner: AllureBehaveRunner): + behave_runner.run_behave( + feature_paths=["./test-data/outline.feature"], + step_paths=["./test-data/steps.py"], + options=["--tags=1", "--no-skipped"] + ) + + assert_that( + behave_runner.allure_results, + has_only_testcases( + all_of( + has_entry( + "name", + "Scenario outline with one table -- @1.1 Customers" + ), + with_status("passed"), + has_parameter("name", "Alice"), + has_parameter("surname", "Johnson") + ), + all_of( + has_entry( + "name", + "Scenario outline with one table -- @1.2 Customers" + ), + with_status("passed"), + has_parameter("name", "Bob"), + has_parameter("surname", "Smith") + ) + ) + ) + + +def test_outline_with_multiple_tables(behave_runner: AllureBehaveRunner): + behave_runner.run_behave( + feature_paths=["./test-data/outline.feature"], + step_paths=["./test-data/steps.py"], + options=["--tags=multiple-tables", "--no-skipped"] + ) + + assert_that( + behave_runner.allure_results, + has_only_testcases( + all_of( + has_entry( + "name", + "Scenario outline with multiple tables -- @1.1 Customers" + ), + with_status("passed"), + has_parameter("name", "Alice"), + has_parameter("surname", "Johnson") + ), + all_of( + has_entry( + "name", + "Scenario outline with multiple tables -- @1.2 Customers" + ), + with_status("passed"), + has_parameter("name", "Bob"), + has_parameter("surname", "Smith") + ), + all_of( + has_entry( + "name", + "Scenario outline with multiple tables -- @2.1 Employees" + ), + with_status("passed"), + has_parameter("name", "Jane"), + has_parameter("surname", "Watson") + ), + all_of( + has_entry( + "name", + "Scenario outline with multiple tables -- @2.2 Employees" + ), + with_status("passed"), + has_parameter("name", "Mark"), + has_parameter("surname", "Nickson") + ) + ) + ) + + +def test_multiple_outlines_each_with_one_table(behave_runner: AllureBehaveRunner): + behave_runner.run_behave( + feature_paths=["./test-data/outline.feature"], + step_paths=["./test-data/steps.py"], + options=["--tags=single-table", "--no-skipped"] + ) + + assert_that( + behave_runner.allure_results, + has_only_testcases( + all_of( + has_entry( + "name", + "Scenario outline with one table -- @1.1 Customers" + ), + with_status("passed"), + has_parameter("name", "Alice"), + has_parameter("surname", "Johnson") + ), + all_of( + has_entry( + "name", + "Scenario outline with one table -- @1.2 Customers" + ), + with_status("passed"), + has_parameter("name", "Bob"), + has_parameter("surname", "Smith") + ), + all_of( + has_entry( + "name", + "Another scenario outline with one table -- @1.1 Employees" + ), + with_status("passed"), + has_parameter("name", "Jane"), + has_parameter("surname", "Watson") + ), + all_of( + has_entry( + "name", + "Another scenario outline with one table -- @1.2 Employees" + ), + with_status("passed"), + has_parameter("name", "Mark"), + has_parameter("surname", "Nickson") + ) + ) + ) diff --git a/tests/allure_behave/acceptance/behave_support/scenario_outlines/test-data/outline.feature b/tests/allure_behave/acceptance/behave_support/scenario_outlines/test-data/outline.feature new file mode 100644 index 00000000..99518f81 --- /dev/null +++ b/tests/allure_behave/acceptance/behave_support/scenario_outlines/test-data/outline.feature @@ -0,0 +1,34 @@ +Feature: Scenario Outline + @single-table + @1 + Scenario Outline: Scenario outline with one table + Given a user + + Examples: Customers + | name | surname | + | Alice | Johnson | + | Bob | Smith | + + @single-table + @2 + Scenario Outline: Another scenario outline with one table + Given a user + + Examples: Employees + | name | surname | + | Jane | Watson | + | Mark | Nickson | + + @multiple-tables + Scenario Outline: Scenario outline with multiple tables + Given a user + + Examples: Customers + | name | surname | + | Alice | Johnson | + | Bob | Smith | + + Examples: Employees + | name | surname | + | Jane | Watson | + | Mark | Nickson | diff --git a/tests/allure_behave/acceptance/behave_support/scenario_outlines/test-data/steps.py b/tests/allure_behave/acceptance/behave_support/scenario_outlines/test-data/steps.py new file mode 100644 index 00000000..d80a758b --- /dev/null +++ b/tests/allure_behave/acceptance/behave_support/scenario_outlines/test-data/steps.py @@ -0,0 +1,5 @@ +from behave import given + +@given("a user {name} {surname}") +def step_impl(context, name, surname): + pass diff --git a/allure-pytest/test/acceptance/label/__init__.py b/tests/allure_behave/acceptance/behave_support/scenarios/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/label/__init__.py rename to tests/allure_behave/acceptance/behave_support/scenarios/__init__.py diff --git a/tests/allure_behave/acceptance/behave_support/scenarios/scenario_test.py b/tests/allure_behave/acceptance/behave_support/scenarios/scenario_test.py new file mode 100644 index 00000000..28b3f696 --- /dev/null +++ b/tests/allure_behave/acceptance/behave_support/scenarios/scenario_test.py @@ -0,0 +1,142 @@ +import pytest +from hamcrest import assert_that +from tests.allure_behave.behave_runner import AllureBehaveRunner +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status +from allure_commons_test.result import has_step + + +@pytest.mark.parametrize(["step", "status"], [ + pytest.param( + "given('a step')(lambda c:None)", + "passed", + id="passed" + ), + pytest.param( + "@given('a step')\ndef step_impl(_):assert False", + "failed", + id="failed" + ), + pytest.param( + "@given('a step')\ndef step_impl(_):raise ValueError", + "broken", + id="broken" + ), + pytest.param( + "", + "broken", + id="undefined" + ) +]) +def test_scenario_with_one_step( + docstring, + behave_runner: AllureBehaveRunner, + step, + status +): + """ + Feature: Behave scenario support + Scenario: Scenario with single step + Given a step + """ + + behave_runner.run_behave( + feature_literals=[docstring], + step_literals=[step] + ) + assert_that( + behave_runner.allure_results, + has_test_case( + "Scenario with single step", + with_status(status), + has_step( + "Given a step", + with_status(status) + ) + ) + ) + + +@pytest.mark.parametrize(["trigger_step", "status"], [ + pytest.param( + "@given('trigger')\ndef _(_):assert False", + "failed", + id="failed" + ), + pytest.param( + "@given('trigger')\ndef _(_):raise ValueError", + "broken", + id="broken" + ), + pytest.param( + "", + "broken", + id="undefined" + ) +]) +def test_when_not_passed_remaining_steps_are_skipped( + docstring, + behave_runner: AllureBehaveRunner, + trigger_step, + status +): + """ + Feature: Behave scenario support + Scenario: Scenario with four steps + Given step 1 + And trigger + And step 3 + And step 4 + """ + + behave_runner.run_behave( + feature_literals=[docstring], + step_literals=[ + "given('step {n}')(lambda c,**_:None)", + trigger_step + ] + ) + assert_that( + behave_runner.allure_results, + has_test_case( + "Scenario with four steps", + with_status(status), + has_step( + "Given step 1", + with_status("passed") + ), + has_step( + "And trigger", + with_status(status) + ), + has_step( + "And step 3", + with_status("skipped") + ), + has_step( + "And step 4", + with_status("skipped") + ) + ) + ) + + +def test_nameless_scenario(docstring, behave_runner: AllureBehaveRunner): + """ + Feature: Behave scenario support + Scenario: + Given noop + """ + + behave_runner.run_behave( + feature_literals=[docstring], + step_literals=["given('noop')(lambda c:None)"] + ) + + assert_that( + behave_runner.allure_results, + has_test_case( + "Scenario", + with_status("passed") + ) + ) diff --git a/allure-pytest/test/acceptance/label/bdd/__init__.py b/tests/allure_behave/acceptance/behave_support/steps/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/label/bdd/__init__.py rename to tests/allure_behave/acceptance/behave_support/steps/__init__.py diff --git a/tests/allure_behave/acceptance/behave_support/steps/behave_step_test.py b/tests/allure_behave/acceptance/behave_support/steps/behave_step_test.py new file mode 100644 index 00000000..1a601053 --- /dev/null +++ b/tests/allure_behave/acceptance/behave_support/steps/behave_step_test.py @@ -0,0 +1,136 @@ +from tests.allure_behave.behave_runner import AllureBehaveRunner +from hamcrest import assert_that, equal_to + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status +from allure_commons_test.result import has_step +from allure_commons_test.result import has_status_details +from allure_commons_test.result import with_message_contains +from allure_commons_test.result import has_attachment_with_content +from allure_commons_test.content import csv_equivalent + + +def test_failed_behave_step(docstring: str, behave_runner: AllureBehaveRunner): + """ + Feature: Bheave step support + Scenario: Scenario with failed step + Given a step failed + """ + + behave_runner.run_behave( + feature_literals=[docstring], + step_literals=["@given('a step failed')\ndef _(_):assert False,'Fail message'"] + ) + + assert_that( + behave_runner.allure_results, + has_test_case( + "Scenario with failed step", + with_status("failed"), + has_step( + "Given a step failed", + with_status("failed"), + has_status_details( + with_message_contains("AssertionError: Fail message") + ) + ) + ) + ) + + +def test_broken_behave_step(docstring, behave_runner: AllureBehaveRunner): + """ + Feature: Bheave step support + Scenario: Scenario with broken step + Given a broken step + """ + + behave_runner.run_behave( + feature_literals=[docstring], + step_literals=["@given('a broken step')\ndef _(_):raise ValueError('Reason')"] + ) + + assert_that( + behave_runner.allure_results, + has_test_case( + "Scenario with broken step", + with_status("broken"), + has_step( + "Given a broken step", + with_status("broken"), + has_status_details( + with_message_contains("ValueError: Reason") + ) + ) + ) + ) + + +def test_step_text_data(docstring, behave_runner: AllureBehaveRunner): + """ + Feature: Bheave step support + Scenario: Scenario with step which contains text data + Given a step with text data + ''' + Textual information attached to the step. + ''' + """ + + behave_runner.run_behave( + feature_literals=[docstring], + step_literals=["given('a step with text data')(lambda _:0)"] + ) + + assert_that( + behave_runner.allure_results, + has_test_case( + "Scenario with step which contains text data", + with_status("passed"), + has_step( + "Given a step with text data", + with_status("passed"), + has_attachment_with_content( + behave_runner.allure_results.attachments, + equal_to("Textual information attached to the step."), + "text/plain" + ) + ) + ) + ) + + +def test_step_table_data(docstring, behave_runner: AllureBehaveRunner): + """ + Feature: Bheave step support + Scenario: Scenario with step which contains a table + Given a step with table data + | id | name | + | 1 | John | + | 2 | Jane | + """ + + behave_runner.run_behave( + feature_literals=[docstring], + step_literals=["given('a step with table data')(lambda _:0)"] + ) + + assert_that( + behave_runner.allure_results, + has_test_case( + "Scenario with step which contains a table", + with_status("passed"), + has_step( + "Given a step with table data", + with_status("passed"), + has_attachment_with_content( + behave_runner.allure_results.attachments, + csv_equivalent([ + ["id", "name"], + ["1", "John"], + ["2", "Jane"] + ]), + "text/csv" + ) + ) + ) + ) diff --git a/tests/allure_behave/behave_runner.py b/tests/allure_behave/behave_runner.py new file mode 100644 index 00000000..34a3561f --- /dev/null +++ b/tests/allure_behave/behave_runner.py @@ -0,0 +1,194 @@ +import behave.step_registry +import sys + +from behave import matchers +from behave.configuration import Configuration +from behave.formatter.base import StreamOpener +from behave.formatter.pretty import PrettyFormatter +from behave.parser import parse_feature +from behave.runner import Context, Runner +from behave.step_registry import setup_step_decorators +from behave.step_registry import StepRegistry +from pytest import FixtureRequest, Pytester +from typing import Sequence +from tests.e2e import AllureFrameworkRunner, PathlikeT + +from allure_behave.formatter import AllureFormatter + + +def __fix_behave_in_memory_run(): + # Behave has poor support for consecutive prigrammatic runs. This is due to + # how step decorators are cached. + # There are three ways to introduce behave step decorators (i.e., @given) + # into a step definition module: + # 1. from behave import given (most common use) + # 2. Without any import (just as if they are globally defined, less + # common) + # 3. from behave.step_regostry import given (rarely) + # The decorators are associated with a StepRegistry instance. This + # association is first created when behave.step_registry module is imported. + # They are then introduced as the behave package attributes and basically + # are cached on a package level. Even if we replace the decorators from + # behave.step_registry with new ones associated with a new StepRegistry with + # the behave.step_registry.setup_step_decorators function, the decorators in + # the behave package remains the same and remains attached to the old step + # registry. + # We need to create a new StepRegistry before a run to prevent step + # duplication error, but if step definitions are created with the decorators + # introduced with (1), they will be added to the old registry and will be + # never matched. + # To fix that we force decorators to use the global instance of the + # StepRegistry. + original_add_step_definition = StepRegistry.add_step_definition + + def __fixed_add_step_definition(self, *args, **kwargs): + return original_add_step_definition( + behave.step_registry.registry, + *args, + **kwargs + ) + + StepRegistry.add_step_definition = __fixed_add_step_definition + + +class _InMemoryBehaveRunner(Runner): + def __init__(self, features, steps, environment, args=None): + if args is None: + args = [] + config = Configuration( + ["--no-snippets"] + list(args), + load_config=False + ) + super().__init__(config) + self.__features = features + self.__steps = steps + self.__environment = environment + + def load_hooks(self, filename=None): + if self.__environment: + exec(self.__environment, self.hooks) + if "before_all" not in self.hooks: + self.hooks["before_all"] = self.before_all_default_hook + + def load_step_definitions(self, extra_step_paths=None): + behave.step_registry.registry = self.step_registry = StepRegistry() + step_globals = { + "use_step_matcher": matchers.use_step_matcher, + "step_matcher": matchers.step_matcher, + } + + # To support the decorators (i.e., @given) with no imports + setup_step_decorators(step_globals, self.step_registry) + + default_matcher = matchers.current_matcher + for step in self.__steps: + step_module_globals = step_globals.copy() + exec(step, step_module_globals) + matchers.current_matcher = default_matcher + + def load_features(self): + self.features.extend( + parse_feature(f) for f in self.__features + ) + + def load_formatter(self): + opener = StreamOpener(stream=sys.stdout) + allure_formatter = AllureFormatter(opener, self.config) + pretty_formatter = PrettyFormatter(opener, self.config) + self.formatters.append(allure_formatter) + self.formatters.append(pretty_formatter) + + def run(self): + self.context = Context(self) + self.load_hooks() + self.load_step_definitions() + self.load_features() + self.load_formatter() + self.run_model() + + +class AllureBehaveRunner(AllureFrameworkRunner): + """The runner to test allure-behave integration.""" + + LOGGER_PATH = "allure_behave.formatter.AllureFileLogger" + + def __init__(self, request: FixtureRequest, pytester: Pytester): + super().__init__(request, pytester) + + def run_behave( + self, + feature_paths: Sequence[PathlikeT] = None, + feature_literals: Sequence[str] = None, + feature_rst_ids: Sequence[str] = None, + step_paths: Sequence[PathlikeT] = None, + step_literals: Sequence[str] = None, + step_rst_ids: Sequence[str] = None, + environment_path: PathlikeT = None, + environment_literal: str = None, + environment_rst_id: str = None, + testplan_content: dict = None, + testplan_path: PathlikeT = None, + testplan_rst_id: str = None, + options: Sequence[str] = None, + ): + """Executes behave in memory and returns the allure results of the run. + + Arguments: + feature_paths (Sequence[str | Path]): paths to feature files + relative to the current test module folder. + feature_literals (Sequence[str]): content of feature files. + feature_rst_ids (Sequence[str]): IDs of .rst code blocks containing + feature file content. + step_paths (Sequence[str | Path]): paths to step definition files + relative to the current test module folder. + step_literals (Sequence[str]): content of step definition files. + step_rst_ids (Sequence[str]): IDs of .rst code blocks containing + step definitions. + environment_path (str | Path): a path to en environment file + relative to the current test module folder. + environment_literal (str): content of an environment file. + environment_rst_id (str): an ID of a .rst code block containing an + environment file content. + testplan_content (dict): an allure testplan content. + testplan_path (str | Path): a path to an allure testplan file + relative to the current test module folder. + testplan_rst_id (str): an ID of a .rst code block containing an + allure testplan. + options (Sequence[str]): behave CLI options + + Returns: + allure_commons.logger.AllureMemoryLogger: the allure results of the + run. The results of the last run are also accessible through the + :attr:`allure_results` attribute. + + """ + return self._run( + self._get_all_content( + paths=feature_paths, + literals=feature_literals, + rst_ids=feature_rst_ids + ), + self._get_all_content( + paths=step_paths, + literals=step_literals, + rst_ids=step_rst_ids + ), + self._resolve_content( + path=environment_path, + literal=environment_literal, + rst_id=environment_rst_id + ), + testplan_content=testplan_content, + testplan_path=testplan_path, + testplan_rst_id=testplan_rst_id, + logger_path=AllureBehaveRunner.LOGGER_PATH, + options=options + ) + + def _run_framework(self, features, steps, environment, options): + _InMemoryBehaveRunner(features, steps, environment, options).run() + + +__fix_behave_in_memory_run() + +__all__ = ["AllureBehaveRunner"] diff --git a/tests/allure_behave/conftest.py b/tests/allure_behave/conftest.py new file mode 100644 index 00000000..d0a99e13 --- /dev/null +++ b/tests/allure_behave/conftest.py @@ -0,0 +1,7 @@ +from pytest import fixture +from .behave_runner import AllureBehaveRunner + + +@fixture +def behave_runner(request, pytester): + return AllureBehaveRunner(request, pytester) diff --git a/allure-pytest/test/acceptance/label/custom/__init__.py b/tests/allure_behave/defects/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/label/custom/__init__.py rename to tests/allure_behave/defects/__init__.py diff --git a/tests/allure_behave/defects/issue717_test.py b/tests/allure_behave/defects/issue717_test.py new file mode 100644 index 00000000..cfd5f371 --- /dev/null +++ b/tests/allure_behave/defects/issue717_test.py @@ -0,0 +1,75 @@ +import allure +import pytest + +from allure_behave.utils import step_table +from allure_commons_test.content import csv_equivalent +from hamcrest import assert_that + + +class RowStub: + def __init__(self, cells): + self.cells = cells + + def __iter__(self): + return iter(self.cells) + + +class TableStub: + def __init__(self, headings, rows): + self.headings = headings + self.rows = [RowStub(cells) for cells in rows] + + +class StepStub: + def __init__(self, content): + headings, *rows = content + table = TableStub(headings, rows) + self.table = table + + +class CsvTestData: + def __init__(self, content): + self.step = StepStub(content) + self.content = content + + +@pytest.fixture(params=[ + pytest.param( + [ + ["a"], + [","] + ], + id="comma" + ), + pytest.param( + [ + ["a"], + ["\""] + ], + id="quote" + ), + pytest.param( + [ + ["a", "b"], + ["1,2", "3,4"] + ], + id="2c-commas" + ), + pytest.param( + [ + ["a", "b"], + ["\"1\",2", "3\",4"] + ], + id="mix" + ) +]) +def csv_testdata(request): + yield CsvTestData(request.param) + + +@allure.issue("717") +def test_step_table_data_escaping(csv_testdata): + assert_that( + step_table(csv_testdata.step), + csv_equivalent(csv_testdata.content) + ) diff --git a/allure-pytest/test/acceptance/label/manual/__init__.py b/tests/allure_nose2/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/label/manual/__init__.py rename to tests/allure_nose2/__init__.py diff --git a/allure-pytest/test/acceptance/label/package/__init__.py b/tests/allure_nose2/acceptance/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/label/package/__init__.py rename to tests/allure_nose2/acceptance/__init__.py diff --git a/allure-pytest/test/acceptance/label/severity/__init__.py b/tests/allure_nose2/acceptance/allure_api/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/label/severity/__init__.py rename to tests/allure_nose2/acceptance/allure_api/__init__.py diff --git a/allure-pytest/test/acceptance/label/suite/__init__.py b/tests/allure_nose2/acceptance/allure_api/labels/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/label/suite/__init__.py rename to tests/allure_nose2/acceptance/allure_api/labels/__init__.py diff --git a/tests/allure_nose2/acceptance/allure_api/labels/test_bdd_labels.py b/tests/allure_nose2/acceptance/allure_api/labels/test_bdd_labels.py new file mode 100644 index 00000000..40576aec --- /dev/null +++ b/tests/allure_nose2/acceptance/allure_api/labels/test_bdd_labels.py @@ -0,0 +1,102 @@ +from hamcrest import assert_that +from tests.allure_nose2.nose2_runner import AllureNose2Runner + +from allure_commons_test.report import has_test_case +from allure_commons_test.label import has_epic +from allure_commons_test.label import has_feature + + +def test_method_label(nose2_runner: AllureNose2Runner): + """ + >>> import unittest + >>> import allure + + >>> class TestBDDLabelExample(unittest.TestCase): + ... @allure.epic("Label", "Bdd") + ... @allure.feature("Method label") + ... def test_method_label_example(self): + ... pass + """ + + allure_report = nose2_runner.run_docstring() + + assert_that( + allure_report, + has_test_case( + "test_method_label_example", + has_epic("Label"), + has_epic("Bdd"), + has_feature("Method label") + ) + ) + + +def test_class_label(nose2_runner: AllureNose2Runner): + """ + >>> import unittest + >>> import allure + + >>> @allure.epic("Label", "Bdd") + ... class TestBDDLabelExample(unittest.TestCase): + ... def test_class_label_example(self): + ... pass + """ + + allure_report = nose2_runner.run_docstring() + + assert_that( + allure_report, + has_test_case( + "test_class_label_example", + has_epic("Label"), + has_epic("Bdd"), + ) + ) + + +def test_class_method_label(nose2_runner: AllureNose2Runner): + """ + >>> import unittest + >>> import allure + + >>> @allure.epic("Label", "Bdd") + ... class TestBDDLabelExample(unittest.TestCase): + ... @allure.feature("Method label") + ... def test_class_and_method_label_example(self): + ... pass + """ + + allure_report = nose2_runner.run_docstring() + + assert_that( + allure_report, + has_test_case( + "test_class_and_method_label_example", + has_epic("Label"), + has_epic("Bdd"), + has_feature("Method label") + ) + ) + + +def test_func_label(nose2_runner: AllureNose2Runner): + """ + >>> import allure + + >>> @allure.epic("Label", "Bdd") + ... @allure.feature("Function label") + ... def test_func_label_example(): + ... pass + """ + + allure_report = nose2_runner.run_docstring() + + assert_that( + allure_report, + has_test_case( + "test_func_label_example", + has_epic("Label"), + has_epic("Bdd"), + has_feature("Function label") + ) + ) diff --git a/allure-pytest/test/acceptance/label/tag/__init__.py b/tests/allure_nose2/acceptance/nose2_support/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/label/tag/__init__.py rename to tests/allure_nose2/acceptance/nose2_support/__init__.py diff --git a/allure-pytest/test/acceptance/link/__init__.py b/tests/allure_nose2/acceptance/nose2_support/parametrized/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/link/__init__.py rename to tests/allure_nose2/acceptance/nose2_support/parametrized/__init__.py diff --git a/tests/allure_nose2/acceptance/nose2_support/parametrized/test_parametrized.py b/tests/allure_nose2/acceptance/nose2_support/parametrized/test_parametrized.py new file mode 100644 index 00000000..556bc52e --- /dev/null +++ b/tests/allure_nose2/acceptance/nose2_support/parametrized/test_parametrized.py @@ -0,0 +1,58 @@ +from hamcrest import assert_that, all_of +from tests.allure_nose2.nose2_runner import AllureNose2Runner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_parameter + + +def test_parametrized_func(nose2_runner: AllureNose2Runner): + """ + >>> from nose2.tools import params + + >>> @params(("hello", 42), ("world", 777)) + ... def test_parametrized_func_example(alpha, betta): + ... pass + """ + + allure_report = nose2_runner.run_docstring() + + assert_that( + allure_report, + all_of( + has_test_case( + "test_parametrized_func_example", + has_parameter("alpha", "'hello'"), + has_parameter("betta", "42") + ), + has_test_case( + "test_parametrized_func_example", + has_parameter("alpha", "'world'"), + has_parameter("betta", "777") + ) + ) + ) + + +def test_parametrized_method(nose2_runner: AllureNose2Runner): + """ + >>> import unittest + >>> from nose2.tools import params + + >>> class TestParametrizedExample(unittest.TestCase): + ... @params(({"hello": 4}, [4, 2]), ({"wold": 2}, [7, 7, 7])) + ... def test_parametrized_method_example(self, bravo, charlie): + ... pass + """ + + allure_report = nose2_runner.run_docstring() + + assert_that( + allure_report, + all_of( + has_test_case( + "test_parametrized_method_example", + has_parameter("bravo", "{'hello': 4}"), + has_parameter("charlie", "[4, 2]") + ) + ) + ) diff --git a/allure-pytest/test/acceptance/parametrization/__init__.py b/tests/allure_nose2/acceptance/nose2_support/result/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/parametrization/__init__.py rename to tests/allure_nose2/acceptance/nose2_support/result/__init__.py diff --git a/tests/allure_nose2/acceptance/nose2_support/result/test_fullname.py b/tests/allure_nose2/acceptance/nose2_support/result/test_fullname.py new file mode 100644 index 00000000..83fae6a9 --- /dev/null +++ b/tests/allure_nose2/acceptance/nose2_support/result/test_fullname.py @@ -0,0 +1,50 @@ +from hamcrest import assert_that +from tests.allure_nose2.nose2_runner import AllureNose2Runner +from hamcrest import has_entry, has_item, has_property + + +def test_func_fullname(nose2_runner: AllureNose2Runner): + """ + >>> def test_func_fullname_example(): + ... pass + """ + + allure_report = nose2_runner.run_docstring() + + assert_that( + allure_report, + has_property( + "test_cases", + has_item( + has_entry( + "fullName", + "test_func_fullname.test_func_fullname_example" + ) + ) + ) + ) + + +def test_method_fullname(nose2_runner: AllureNose2Runner): + """ + >>> import unittest + + >>> class TestFullnameExample(unittest.TestCase): + ... def test_method_fullname_example(self): + ... pass + """ + + allure_report = nose2_runner.run_docstring() + + assert_that( + allure_report, + has_property( + "test_cases", + has_item( + has_entry( + "fullName", + "test_method_fullname.TestFullnameExample.test_method_fullname_example" + ) + ) + ) + ) diff --git a/tests/allure_nose2/acceptance/nose2_support/result/test_status.py b/tests/allure_nose2/acceptance/nose2_support/result/test_status.py new file mode 100644 index 00000000..62c4b6e3 --- /dev/null +++ b/tests/allure_nose2/acceptance/nose2_support/result/test_status.py @@ -0,0 +1,96 @@ +from hamcrest import assert_that +from tests.allure_nose2.nose2_runner import AllureNose2Runner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status +from allure_commons_test.result import has_status_details +from allure_commons_test.result import with_message_contains + + +def test_passed_status(nose2_runner: AllureNose2Runner): + """ + >>> import unittest + + >>> class TestStatusExample(unittest.TestCase): + ... def test_passed_example(self): + ... assert True + """ + + allure_report = nose2_runner.run_docstring() + + assert_that( + allure_report, + has_test_case( + "test_passed_example", + with_status("passed") + ) + ) + + +def test_failed_status(nose2_runner: AllureNose2Runner): + """ + >>> import unittest + + >>> class TestStatusExample(unittest.TestCase): + ... def test_failed_example(self): + ... assert False, "my message" + """ + + allure_report = nose2_runner.run_docstring() + + assert_that( + allure_report, + has_test_case( + "test_failed_example", + with_status("failed"), + has_status_details( + with_message_contains("my message") + ) + ) + ) + + +def test_broken_status(nose2_runner: AllureNose2Runner): + """ + >>> import unittest + + >>> class TestStatusExample(unittest.TestCase): + ... def test_broken_example(self): + ... raise Exception("my error") + """ + + allure_report = nose2_runner.run_docstring() + + assert_that( + allure_report, + has_test_case( + "test_broken_example", + with_status("broken"), + has_status_details( + with_message_contains("my error") + ) + ) + ) + + +def test_skipped_status(nose2_runner: AllureNose2Runner): + """ + >>> import unittest + + >>> class TestStatusExample(unittest.TestCase): + ... def test_skipped_example(self): + ... self.skipTest('my skip reason') + """ + + allure_report = nose2_runner.run_docstring() + + assert_that( + allure_report, + has_test_case( + "test_skipped_example", + with_status("skipped"), + has_status_details( + with_message_contains("my skip reason") + ) + ) + ) diff --git a/allure-pytest/test/acceptance/status/__init__.py b/tests/allure_nose2/acceptance/nose2_support/with_mp/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/status/__init__.py rename to tests/allure_nose2/acceptance/nose2_support/with_mp/__init__.py diff --git a/allure-nose2/test/with_mp/test_pm.py b/tests/allure_nose2/acceptance/nose2_support/with_mp/test_mp.py similarity index 58% rename from allure-nose2/test/with_mp/test_pm.py rename to tests/allure_nose2/acceptance/nose2_support/with_mp/test_mp.py index 794f85e0..501b5c06 100644 --- a/allure-nose2/test/with_mp/test_pm.py +++ b/tests/allure_nose2/acceptance/nose2_support/with_mp/test_mp.py @@ -1,8 +1,8 @@ # Todo test mp -from test.example_runner import run_docstring_example +from tests.allure_nose2.nose2_runner import AllureNose2Runner -def test_func_fullname(): +def test_func_fullname(nose2_runner: AllureNose2Runner): """ >>> def test_func_fullname_example1(): ... pass @@ -11,4 +11,4 @@ def test_func_fullname(): >>> def test_func_fullname_example3(): ... pass """ - run_docstring_example() + nose2_runner.run_docstring() diff --git a/tests/allure_nose2/conftest.py b/tests/allure_nose2/conftest.py new file mode 100644 index 00000000..ce355c89 --- /dev/null +++ b/tests/allure_nose2/conftest.py @@ -0,0 +1,7 @@ +from .nose2_runner import AllureNose2Runner +from pytest import fixture + + +@fixture +def nose2_runner(request, pytester): + yield AllureNose2Runner(request, pytester) diff --git a/tests/allure_nose2/nose2_runner.py b/tests/allure_nose2/nose2_runner.py new file mode 100644 index 00000000..5829e442 --- /dev/null +++ b/tests/allure_nose2/nose2_runner.py @@ -0,0 +1,39 @@ +import importlib.machinery +import importlib.util +from doctest import script_from_examples +from nose2 import main +from pytest import FixtureRequest, Pytester +from tests.e2e import AllureFrameworkRunner + + +class AllureNose2Runner(AllureFrameworkRunner): + LOGGER_PATH = "allure_nose2.plugin.AllureFileLogger" + + def __init__(self, request: FixtureRequest, pytester: Pytester): + super().__init__(request, pytester) + + def run_docstring(self): + docstring = self._find_docstring() + example_code = script_from_examples(docstring) + spec = importlib.machinery.ModuleSpec(self.request.node.name, None) + module = importlib.util.module_from_spec(spec) + return self._run( + module, + example_code, + logger_path=AllureNose2Runner.LOGGER_PATH + ) + + def _run_framework(self, module, example): + # We execute the example here because the _run_framework runs in a + # nested allure context. Otherwise, all allure decorators used in the + # example would affect allure results of the testing system itself. + exec(example, module.__dict__) + main( + module=module, + argv=["nose2", "--allure"], + plugins=["allure_nose2.plugin"], + exit=False + ) + + +__all__ = ["AllureNose2Runner"] diff --git a/allure-pytest/test/acceptance/step/__init__.py b/tests/allure_pytest/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/step/__init__.py rename to tests/allure_pytest/__init__.py diff --git a/allure-pytest/test/acceptance/unicode_identifier/__init__.py b/tests/allure_pytest/acceptance/__init__.py similarity index 100% rename from allure-pytest/test/acceptance/unicode_identifier/__init__.py rename to tests/allure_pytest/acceptance/__init__.py diff --git a/allure-pytest/test/integration/__init__.py b/tests/allure_pytest/acceptance/attachment/__init__.py similarity index 100% rename from allure-pytest/test/integration/__init__.py rename to tests/allure_pytest/acceptance/attachment/__init__.py diff --git a/tests/allure_pytest/acceptance/attachment/attachment_class_test.py b/tests/allure_pytest/acceptance/attachment/attachment_class_test.py new file mode 100644 index 00000000..0137e898 --- /dev/null +++ b/tests/allure_pytest/acceptance/attachment/attachment_class_test.py @@ -0,0 +1,24 @@ +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_attachment + + +def test_class_method_attachment(allure_pytest_runner: AllurePytestRunner): + """ + >>> import allure + + >>> class TestClass: + ... def test_class_method_attachment(self): + ... allure.attach("text", "failed", allure.attachment_type.TEXT) + """ + + allure_report = allure_pytest_runner.run_docstring() + + assert_that( + allure_report, + has_test_case( + "test_class_method_attachment", + has_attachment(name="failed") + ) + ) diff --git a/tests/allure_pytest/acceptance/attachment/attachment_fixture_test.py b/tests/allure_pytest/acceptance/attachment/attachment_fixture_test.py new file mode 100644 index 00000000..c14f18eb --- /dev/null +++ b/tests/allure_pytest/acceptance/attachment/attachment_fixture_test.py @@ -0,0 +1,45 @@ +""" ./allure-pytest/examples/attachment/attachment_fixture.rst """ + +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_attachment +from allure_commons_test.container import has_container +from allure_commons_test.container import has_before +from allure_commons_test.container import has_after + + +def test_fixture_attachment(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_fixture_attachment", + has_container( + allure_results, + has_before( + "fixture_with_attachment", + has_attachment() + ) + ) + ) + ) + + +def test_fixture_finalizer_attachment(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_fixture_finalizer_attachment", + has_container( + allure_results, + has_after( + "fixture_with_attachment_in_finalizer::finalizer", + has_attachment() + ) + ) + ) + ) diff --git a/tests/allure_pytest/acceptance/attachment/attachment_hook_test.py b/tests/allure_pytest/acceptance/attachment/attachment_hook_test.py new file mode 100644 index 00000000..40999e62 --- /dev/null +++ b/tests/allure_pytest/acceptance/attachment/attachment_hook_test.py @@ -0,0 +1,57 @@ +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_attachment + + +def test_attach_from_runtest_teardown(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_pytest( + """ + def test_attach_from_runtest_teardown(): + pass + """, + conftest_literal=( + """ + import allure + + + def pytest_runtest_teardown(*args, **kwargs): + allure.attach(body="body", name="attachment from teardown") + """ + ) + ) + + assert_that( + allure_results, + has_test_case( + "test_attach_from_runtest_teardown", + has_attachment(name="attachment from teardown") + ) + ) + + +def test_attach_from_runtest_logfinish(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_pytest( + """ + def test_attach_from_runtest_logfinish(): + pass + """, + conftest_literal=( + """ + import allure + + + def pytest_runtest_logfinish(*args, **kwargs): + allure.attach(body="body", name="attachment from logfinish") + """ + ) + ) + + assert_that( + allure_results, + has_test_case( + "test_attach_from_runtest_logfinish", + has_attachment(name="attachment from logfinish") + ) + ) diff --git a/tests/allure_pytest/acceptance/attachment/attachment_parametrized_test.py b/tests/allure_pytest/acceptance/attachment/attachment_parametrized_test.py new file mode 100644 index 00000000..0016e2df --- /dev/null +++ b/tests/allure_pytest/acceptance/attachment/attachment_parametrized_test.py @@ -0,0 +1,40 @@ +from hamcrest import assert_that +from hamcrest import all_of +from hamcrest import equal_to +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_attachment_with_content + + +def test_parametrized_attachment(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + >>> import allure + + >>> @pytest.mark.parametrize("param", ["first", "second"]) + ... def test_parametrized_attachment_example(param): + ... allure.attach(param) + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + all_of( + has_test_case( + "test_parametrized_attachment_example[first]", + has_attachment_with_content( + allure_results.attachments, + content_matcher=equal_to("first") + ) + ), + has_test_case( + "test_parametrized_attachment_example[second]", + has_attachment_with_content( + allure_results.attachments, + content_matcher=equal_to("second") + ) + ) + ) + ) diff --git a/tests/allure_pytest/acceptance/attachment/attachment_step_test.py b/tests/allure_pytest/acceptance/attachment/attachment_step_test.py new file mode 100644 index 00000000..0ffa7d6f --- /dev/null +++ b/tests/allure_pytest/acceptance/attachment/attachment_step_test.py @@ -0,0 +1,64 @@ +""" ./allure-pytest/examples/attachment/attachment_step.rst """ + +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_step +from allure_commons_test.result import has_attachment + + +def test_step_with_attachment(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples() + + assert_that( + allure_results, + has_test_case( + "test_step_with_attachment", + has_step( + "step_with_attachment", + has_attachment() + ), + ) + ) + + +def test_step_with_thread_and_attachment(allure_pytest_runner: AllurePytestRunner): + testfile_content = ( + """ + from concurrent.futures import ThreadPoolExecutor + + import allure + import pytest + + @allure.step("thread {x}") + def parallel_step(x=1): + allure.attach("text", str(x), allure.attachment_type.TEXT) + + + def test_thread(): + with allure.step("Start in thread"): + with ThreadPoolExecutor(max_workers=2) as executor: + f_result = executor.map(parallel_step, [1, 2]) + """ + ) + + allure_results = allure_pytest_runner.run_pytest(testfile_content) + + assert_that( + allure_results, + has_test_case( + "test_thread", + has_step( + "Start in thread", + has_step( + "thread 1", + has_attachment(name="1") + ), + has_step( + "thread 2", + has_attachment(name="2") + ) + ) + ) + ) diff --git a/tests/allure_pytest/acceptance/attachment/attachment_test.py b/tests/allure_pytest/acceptance/attachment/attachment_test.py new file mode 100644 index 00000000..3c2015ba --- /dev/null +++ b/tests/allure_pytest/acceptance/attachment/attachment_test.py @@ -0,0 +1,46 @@ +""" ./allure-pytest/examples/attachment/attachment.rst """ + +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_attachment + + +def test_attach_body_with_default_kwargs(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_attach_body_with_default_kwargs", + has_attachment() + ) + ) + + +def test_attach_body(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_attach_body", + has_attachment( + attach_type="application/xml", + name="some attachment name" + ) + ) + ) + + +def test_attach_file(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_attach_file", + has_attachment() + ) + ) diff --git a/allure-pytest/test/integration/allure_ee/__init__.py b/tests/allure_pytest/acceptance/capture/__init__.py similarity index 100% rename from allure-pytest/test/integration/allure_ee/__init__.py rename to tests/allure_pytest/acceptance/capture/__init__.py diff --git a/tests/allure_pytest/acceptance/capture/capture_attach_test.py b/tests/allure_pytest/acceptance/capture/capture_attach_test.py new file mode 100644 index 00000000..64f538f4 --- /dev/null +++ b/tests/allure_pytest/acceptance/capture/capture_attach_test.py @@ -0,0 +1,134 @@ +import pytest +from hamcrest import assert_that +from hamcrest import all_of, is_, is_not, empty +from hamcrest import has_property, has_value +from hamcrest import contains_string +from tests.allure_pytest.pytest_runner import AllurePytestRunner + + +@pytest.mark.parametrize("capture", ["sys", "fd", "no"]) +def test_capture_stdout(allure_pytest_runner: AllurePytestRunner, capture): + """ + >>> import pytest + >>> import allure + + >>> @pytest.fixture + ... def fixture(request): + ... print ("Start fixture") + ... def finalizer(): + ... print ("Stop fixture") + ... request.addfinalizer(finalizer) + + >>> def test_capture_stdout_example(fixture): + ... print ("Start test") + ... with allure.step("Step"): + ... print ("Start step") + """ + + allure_results = allure_pytest_runner.run_docstring(f"--capture={capture}") + + if_pytest_capture_ = is_not if capture == "no" else is_ + + assert_that( + allure_results, + has_property( + "attachments", + all_of( + if_pytest_capture_(has_value(contains_string("Start fixture"))), + if_pytest_capture_(has_value(contains_string("Stop fixture"))), + if_pytest_capture_(has_value(contains_string("Start test"))), + if_pytest_capture_(has_value(contains_string("Start step"))) + ) + ) + ) + + +@pytest.mark.parametrize("capture", ["sys", "fd"]) +def test_capture_empty_stdout(allure_pytest_runner: AllurePytestRunner, capture): + """ + >>> import pytest + >>> import allure + + >>> @pytest.fixture + ... def fixture(request): + ... def finalizer(): + ... pass + ... request.addfinalizer(finalizer) + + >>> def test_capture_stdout_example(fixture): + ... with allure.step("Step"): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring(f"--capture={capture}") + + assert_that( + allure_results, + has_property("attachments", empty()) + ) + + +@pytest.mark.parametrize("logging", [True, False]) +def test_capture_log(allure_pytest_runner: AllurePytestRunner, logging): + """ + >>> import logging + >>> import pytest + >>> import allure + + >>> logger = logging.getLogger(__name__) + + >>> @pytest.fixture + ... def fixture(request): + ... logger.info("Start fixture") + ... def finalizer(): + ... logger.info("Stop fixture") + ... request.addfinalizer(finalizer) + + >>> def test_capture_log_example(fixture): + ... logger.info("Start test") + ... with allure.step("Step"): + ... logger.info("Start step") + """ + + params = [] if logging else ["-p", "no:logging"] + allure_results = allure_pytest_runner.run_docstring( + "--log-level=INFO", + *params + ) + + if_logging_ = is_ if logging else is_not + + assert_that( + allure_results, + has_property( + "attachments", + all_of( + if_logging_(has_value(contains_string("Start fixture"))), + if_logging_(has_value(contains_string("Stop fixture"))), + if_logging_(has_value(contains_string("Start test"))), + if_logging_(has_value(contains_string("Start step"))) + ) + ) + ) + + +def test_capture_disabled(allure_pytest_runner: AllurePytestRunner): + """ + >>> import logging + >>> logger = logging.getLogger(__name__) + + >>> def test_capture_disabled_example(): + ... logger.info("Start logging") + ... #print ("Start printing") + + """ + + allure_results = allure_pytest_runner.run_docstring( + "--log-level=INFO", + "--allure-no-capture" + ) + + assert_that( + allure_results, + has_property("attachments", empty()) + ) diff --git a/allure-pytest/test/integration/pytest_check/__init__.py b/tests/allure_pytest/acceptance/description/__init__.py similarity index 100% rename from allure-pytest/test/integration/pytest_check/__init__.py rename to tests/allure_pytest/acceptance/description/__init__.py diff --git a/tests/allure_pytest/acceptance/description/description_test.py b/tests/allure_pytest/acceptance/description/description_test.py new file mode 100644 index 00000000..195538a9 --- /dev/null +++ b/tests/allure_pytest/acceptance/description/description_test.py @@ -0,0 +1,49 @@ +""" ./allure-pytest/examples/description/description.rst """ + +from hamcrest import assert_that, contains_string +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_description, has_description_html + + +def test_description(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_description", + has_description( + contains_string("Test description") + ) + ) + ) + + +def test_description_html(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_description_html", + has_description_html( + contains_string("

Html test description

") + ) + ) + ) + + +def test_docstring_description(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_docstring_description", + has_description( + contains_string("Docstring") + ) + ) + ) diff --git a/tests/allure_pytest/acceptance/description/dynamic_description_test.py b/tests/allure_pytest/acceptance/description/dynamic_description_test.py new file mode 100644 index 00000000..5af57321 --- /dev/null +++ b/tests/allure_pytest/acceptance/description/dynamic_description_test.py @@ -0,0 +1,35 @@ +"""./allure-pytest/examples/description/dynamic_description.rst""" + +from hamcrest import assert_that, contains_string +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_description, has_description_html + + +def test_dynamic_description(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_dynamic_description", + has_description( + contains_string("Actual description") + ) + ) + ) + + +def test_dynamic_description_html(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_dynamic_description_html", + has_description_html( + contains_string("

Actual HTML description

") + ) + ) + ) diff --git a/allure-pytest/test/integration/pytest_doctest/__init__.py b/tests/allure_pytest/acceptance/display_name/__init__.py similarity index 100% rename from allure-pytest/test/integration/pytest_doctest/__init__.py rename to tests/allure_pytest/acceptance/display_name/__init__.py diff --git a/tests/allure_pytest/acceptance/display_name/display_name_test.py b/tests/allure_pytest/acceptance/display_name/display_name_test.py new file mode 100644 index 00000000..a0985b1d --- /dev/null +++ b/tests/allure_pytest/acceptance/display_name/display_name_test.py @@ -0,0 +1,107 @@ +""" ./allure-pytest/examples/display_name/display_name.rst""" + +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_title +from allure_commons_test.label import has_label + + +def test_display_name(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_display_name", + has_title("A some test title") + ) + ) + + +def test_display_name_template(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_display_name_template", + has_title("A some test title with param False") + ) + ) + + +def test_fixture_value_in_display_name(allure_pytest_runner: AllurePytestRunner): + """ + >>> import allure + >>> import pytest + + >>> @pytest.fixture + ... def fix(): + ... return 'fixture value' + + >>> @allure.title('title with {fix}') + ... def test_fixture_value_name(fix): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_fixture_value_name", + has_title("title with fixture value") + ) + ) + + +def test_display_name_with_features(allure_pytest_runner: AllurePytestRunner): + """ + >>> import allure + >>> import pytest + + >>> @allure.feature('Feature 1') + ... @allure.title('Titled test with features') + ... @allure.feature('Feature 2') + ... def test_feature_label_for_titled_test(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_feature_label_for_titled_test", + has_label("feature", "Feature 1"), + has_label("feature", "Feature 2"), + has_title("Titled test with features") + ) + ) + + +def test_failed_fixture_value_in_display_name(allure_pytest_runner: AllurePytestRunner): + """ + >>> import allure + >>> import pytest + + >>> @pytest.fixture + ... def fix(): + ... raise AssertionError("Fixture failed for some reason") + + >>> @allure.title('title with {fix}') + ... def test_fixture_value_name(fix): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_fixture_value_name", + has_title("title with {fix}") + ) + ) diff --git a/tests/allure_pytest/acceptance/display_name/dynamic_display_name_test.py b/tests/allure_pytest/acceptance/display_name/dynamic_display_name_test.py new file mode 100644 index 00000000..20289c88 --- /dev/null +++ b/tests/allure_pytest/acceptance/display_name/dynamic_display_name_test.py @@ -0,0 +1,19 @@ +""" ./allure-pytest/examples/display_name/dynamic_display_name.rst """ + +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_title + + +def test_dynamic_display_name(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples() + + assert_that( + allure_results, + has_test_case( + "test_dynamic_display_name", + has_title("It is renamed test") + ) + ) diff --git a/allure-pytest/test/integration/pytest_flakes/__init__.py b/tests/allure_pytest/acceptance/duration/__init__.py similarity index 100% rename from allure-pytest/test/integration/pytest_flakes/__init__.py rename to tests/allure_pytest/acceptance/duration/__init__.py diff --git a/tests/allure_pytest/acceptance/duration/duration_time_test.py b/tests/allure_pytest/acceptance/duration/duration_time_test.py new file mode 100644 index 00000000..9d201824 --- /dev/null +++ b/tests/allure_pytest/acceptance/duration/duration_time_test.py @@ -0,0 +1,149 @@ +import allure +import pytest +from hamcrest import assert_that, has_entry, greater_than, all_of, less_than +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status +from allure_commons.utils import now + + +snippets = [ + "pass", + pytest.param("assert False", id="assert-fail"), + pytest.param("raise RuntimeError()", id="break"), + pytest.param("pytest.skip()", id="skip"), + pytest.param("pytest.fail()", id="pytest-fail"), + pytest.param("pytest.xfail()", id="xfail"), + pytest.param("pytest.exit('msg')", id="exit"), +] + + +@pytest.mark.parametrize("snippet", snippets) +def test_duration(allure_pytest_runner: AllurePytestRunner, snippet): + testfile_content = ( + f""" + def test_duration_example(): + {snippet} + """ + ) + + before = now() + allure_results = allure_pytest_runner.run_pytest(testfile_content) + after = now() + + assert_that( + allure_results, + has_test_case( + "test_duration_example", + all_of( + has_entry("start", greater_than(before)), + has_entry("stop", all_of( + greater_than(before), + less_than(after) + )) + ) + ) + ) + + +@allure.issue("244") +@pytest.mark.parametrize("snippet", snippets) +def test_with_fixture_duration(allure_pytest_runner: AllurePytestRunner, snippet): + testfile_content = ( + f""" + import pytest + + @pytest.fixture + def fixture(): + {snippet} + + def test_with_fixture_duration_example(fixture): + pass + """ + ) + + before = now() + allure_results = allure_pytest_runner.run_pytest(testfile_content) + after = now() + + assert_that( + allure_results, + has_test_case( + "test_with_fixture_duration_example", + all_of( + has_entry("start", greater_than(before)), + has_entry("stop", all_of( + greater_than(before), + less_than(after) + )) + ) + ) + ) + + +@allure.issue("244") +@pytest.mark.parametrize("snippet", snippets) +def test_with_fixture_finalizer_duration( + allure_pytest_runner: AllurePytestRunner, + snippet +): + testfile_content = ( + f""" + import pytest + + @pytest.fixture + def fixture(request): + def finalizer(): + {snippet} + request.addfinalizef(finalizer) + + def test_with_fixture_finalizer_duration(fixture): + pass + """ + ) + + before = now() + allure_results = allure_pytest_runner.run_pytest(testfile_content) + after = now() + + assert_that( + allure_results, + has_test_case( + "test_with_fixture_finalizer_duration", + all_of( + has_entry("start", greater_than(before)), + has_entry("stop", all_of( + greater_than(before), + less_than(after) + )) + ) + ) + ) + + +def test_test_skipped_if_fixture_exits(allure_pytest_runner: AllurePytestRunner): + """Test should be market as skipped: pytest reports it as 'not run'""" + + testfile_content = ( + """ + import pytest + + @pytest.fixture + def fixture(): + pytest.exit("Reason") + + def test_with_fixture_duration_example(fixture): + pass + """ + ) + + allure_results = allure_pytest_runner.run_pytest(testfile_content) + + assert_that( + allure_results, + has_test_case( + "test_with_fixture_duration_example", + with_status("skipped") + ) + ) diff --git a/allure-pytest/test/integration/pytest_lazy_fixture/__init__.py b/tests/allure_pytest/acceptance/fixture/__init__.py similarity index 100% rename from allure-pytest/test/integration/pytest_lazy_fixture/__init__.py rename to tests/allure_pytest/acceptance/fixture/__init__.py diff --git a/allure-pytest/test/acceptance/fixture/fixture_finalized_test.py b/tests/allure_pytest/acceptance/fixture/fixture_finalized_test.py similarity index 52% rename from allure-pytest/test/acceptance/fixture/fixture_finalized_test.py rename to tests/allure_pytest/acceptance/fixture/fixture_finalized_test.py index a5cab436..2b1f9737 100644 --- a/allure-pytest/test/acceptance/fixture/fixture_finalized_test.py +++ b/tests/allure_pytest/acceptance/fixture/fixture_finalized_test.py @@ -1,5 +1,7 @@ import allure from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + from allure_commons_test.report import has_test_case from allure_commons_test.container import has_container from allure_commons_test.container import has_before, has_after @@ -7,7 +9,7 @@ @allure.feature("Fixture") @allure.story("Fixture finalizer") -def test_fixture_finalizer(executed_docstring_source): +def test_fixture_finalizer(allure_pytest_runner: AllurePytestRunner): """ >>> import pytest @@ -23,19 +25,24 @@ def test_fixture_finalizer(executed_docstring_source): ... pass """ - assert_that(executed_docstring_source.allure_report, - has_test_case("test_fixture_with_finalizer_example", - has_container(executed_docstring_source.allure_report, - has_before("fixture_with_finalizer"), - has_after("fixture_with_finalizer::finalizer") - ) - ) - ) + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_fixture_with_finalizer_example", + has_container( + allure_results, + has_before("fixture_with_finalizer"), + has_after("fixture_with_finalizer::finalizer") + ) + ) + ) @allure.feature("Fixture") @allure.story("Fixture finalizer") -def test_fixture_finalizers(executed_docstring_source): +def test_fixture_finalizers(allure_pytest_runner: AllurePytestRunner): """ >>> import pytest @@ -55,12 +62,17 @@ def test_fixture_finalizers(executed_docstring_source): ... pass """ - assert_that(executed_docstring_source.allure_report, - has_test_case("test_fixture_with_finalizers_example", - has_container(executed_docstring_source.allure_report, - has_before("fixture_with_finalizers"), - has_after("fixture_with_finalizers::first_finalizer"), - has_after("fixture_with_finalizers::second_finalizer") - ) - ) - ) + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_fixture_with_finalizers_example", + has_container( + allure_results, + has_before("fixture_with_finalizers"), + has_after("fixture_with_finalizers::first_finalizer"), + has_after("fixture_with_finalizers::second_finalizer") + ) + ) + ) diff --git a/tests/allure_pytest/acceptance/fixture/fixture_test.py b/tests/allure_pytest/acceptance/fixture/fixture_test.py new file mode 100644 index 00000000..68562282 --- /dev/null +++ b/tests/allure_pytest/acceptance/fixture/fixture_test.py @@ -0,0 +1,497 @@ +import pytest +from hamcrest import assert_that, not_, all_of +from itertools import combinations_with_replacement +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +import allure +from allure_commons_test.report import has_test_case +from allure_commons_test.container import has_container, has_before, has_after +from allure_commons_test.result import has_step + +fixture_scopes = ["session", "module", "class", "function"] + + +@allure.feature("Fixture") +@pytest.mark.parametrize("first_scope", fixture_scopes) +@pytest.mark.parametrize("second_scope", fixture_scopes) +def test_fixture(allure_pytest_runner: AllurePytestRunner, first_scope, second_scope): + testfile_content = ( + f""" + import pytest + + @pytest.fixture(scope="{first_scope}") + def first_fixture(): + pass + + @pytest.fixture(scope="{second_scope}") + def second_fixture(): + pass + + def test_fixture_example(first_fixture, second_fixture): + pass + """ + ) + + allure_results = allure_pytest_runner.run_pytest(testfile_content) + + assert_that( + allure_results, + has_test_case( + "test_fixture_example", + has_container(allure_results, has_before("first_fixture")), + has_container(allure_results, has_before("second_fixture")) + ) + ) + + +@pytest.mark.parametrize( + ["parent_scope", "child_scope"], + list(combinations_with_replacement(fixture_scopes, 2)) +) +def test_nested_fixture(allure_pytest_runner: AllurePytestRunner, parent_scope, child_scope): + testfile_content = ( + f""" + import pytest + + @pytest.fixture(scope="{parent_scope}") + def parent_fixture(): + pass + + @pytest.fixture(scope="{child_scope}") + def child_fixture(parent_fixture): + pass + + def test_nested_fixture_example(child_fixture): + pass + + def test_fixture_used_in_other_fixtures_example(parent_fixture): + pass + """ + ) + + allure_results = allure_pytest_runner.run_pytest(testfile_content) + + assert_that( + allure_results, + has_test_case( + "test_nested_fixture_example", + has_container(allure_results, has_before("parent_fixture")), + has_container(allure_results, has_before("child_fixture")) + ) + ) + + assert_that( + allure_results, + has_test_case( + "test_fixture_used_in_other_fixtures_example", + has_container(allure_results, has_before("parent_fixture")), + not_(has_container(allure_results, has_before("child_fixture"))) + ) + ) + + +@allure.feature("Fixture") +def test_nested_fixtures(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + If we have two fixtures: + >>> @pytest.fixture + ... def first_fixture(): + ... pass + + + >>> @pytest.fixture + ... def second_fixture(): + ... pass + + And one that uses both previous: + >>> @pytest.fixture + ... def child_fixture(first_fixture, second_fixture): + ... pass + + For next test, allure report will contain all tree fixtures: + >>> def test_nested_fixtures_example(child_fixture): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_nested_fixtures_example", + has_container(allure_results, has_before("first_fixture")), + has_container(allure_results, has_before("second_fixture")), + has_container(allure_results, has_before("child_fixture")) + ) + ) + + +@allure.feature("Fixture") +def test_fixture_allure_title(allure_pytest_runner: AllurePytestRunner): + testfile_content = ( + """ + import pytest + import allure + + @pytest.fixture + @allure.title("Allure fixture title") + def first_fixture(): + pass + + def test_titled_fixture_example(first_fixture): + pass + """ + ) + + allure_results = allure_pytest_runner.run_pytest(testfile_content) + + assert_that( + allure_results, + has_test_case( + "test_titled_fixture_example", + has_container( + allure_results, + has_before("Allure fixture title") + ) + ) + ) + + +@allure.feature("Fixture") +def test_fixture_allure_title_before(allure_pytest_runner: AllurePytestRunner): + testfile_content = ( + """ + import pytest + import allure + + @allure.title("Allure fixture title") + @pytest.fixture + def first_fixture(): + pass + + def test_titled_before_fixture_example(first_fixture): + pass + """ + ) + + allure_results = allure_pytest_runner.run_pytest(testfile_content) + + assert_that( + allure_results, + has_test_case( + "test_titled_before_fixture_example", + has_container( + allure_results, + has_before("Allure fixture title") + ) + ) + ) + + +def test_titled_fixture_from_conftest(allure_pytest_runner: AllurePytestRunner): + conftest_content = ( + """ + import allure + import pytest + + @allure.title('Titled fixture before pytest.fixture') + @pytest.fixture + def first_fixture(): + pass + + @pytest.fixture + @allure.title('Titled fixture after pytest.fixture') + def second_fixture(): + pass + """ + ) + + testfile_content = ( + """ + def test_with_titled_conftest_fixtures(first_fixture, second_fixture): + pass + """ + ) + + allure_results = allure_pytest_runner.run_pytest( + testfile_content, + conftest_literal=conftest_content + ) + + assert_that( + allure_results, + has_test_case( + "test_with_titled_conftest_fixtures", + has_container( + allure_results, + has_before("Titled fixture before pytest.fixture") + ), + has_container( + allure_results, + has_before("Titled fixture after pytest.fixture") + ) + ) + ) + + +def test_fixture_override(allure_pytest_runner: AllurePytestRunner): + conftest_content = ( + """ + import pytest + import allure + + @pytest.fixture + def my_fixture(): + with allure.step('Step in before in original fixture'): + pass + yield + with allure.step('Step in after in original fixture'): + pass + + """ + ) + + testfile_content = ( + """ + import pytest + import allure + + @pytest.fixture + def my_fixture(my_fixture): + with allure.step('Step in before in redefined fixture'): + pass + yield + with allure.step('Step in after in redefined fixture'): + pass + + def test_with_redefined_fixture(my_fixture): + pass + """ + ) + + allure_results = allure_pytest_runner.run_pytest( + testfile_content, + conftest_literal=conftest_content + ) + + assert_that( + allure_results, + has_test_case( + "test_with_redefined_fixture", + has_container( + allure_results, + has_before( + "my_fixture", + has_step("Step in before in original fixture") + ), + has_after( + "my_fixture::0", + has_step("Step in after in original fixture") + ) + ), + has_container( + allure_results, + has_before( + "my_fixture", + has_step("Step in before in redefined fixture") + ), + has_after( + "my_fixture::0", + has_step("Step in after in redefined fixture") + ) + ) + ) + ) + + +@pytest.mark.parametrize( + ["parent_scope", "child_scope"], + list(combinations_with_replacement(fixture_scopes, 2)) +) +def test_dynamically_called_fixture( + allure_pytest_runner: AllurePytestRunner, + parent_scope, + child_scope +): + testfile_content = ( + f""" + import pytest + + @pytest.fixture(scope="{parent_scope}", autouse=True) + def parent_auto_call_fixture(): + yield + + @pytest.fixture(scope="{child_scope}") + def child_manual_call_fixture(): + yield + + @pytest.fixture(scope="{parent_scope}") + def parent_dyn_call_fixture(): + yield + + @pytest.fixture(scope="{child_scope}") + def child_dyn_call_fixture(request): + request.getfixturevalue('parent_dyn_call_fixture') + + def test_one(child_manual_call_fixture): + pass + + def test_two(request): + request.getfixturevalue('child_dyn_call_fixture') + + def test_three(request): + request.getfixturevalue('parent_dyn_call_fixture') + """ + ) + + allure_results = allure_pytest_runner.run_pytest(testfile_content) + + assert_that( + allure_results, + all_of( + has_test_case( + "test_one", + has_container( + allure_results, + has_before("parent_auto_call_fixture"), + has_after("parent_auto_call_fixture::0") + ), + has_container( + allure_results, + has_before("child_manual_call_fixture"), + has_after("child_manual_call_fixture::0") + ), + not_( + has_container( + allure_results, + has_before("parent_dyn_call_fixture"), + has_after("parent_dyn_call_fixture::0") + ), + ), + not_( + has_container( + allure_results, + has_before("child_dyn_call_fixture") + ), + ) + ), + has_test_case( + "test_two", + has_container( + allure_results, + has_before("parent_auto_call_fixture"), + has_after("parent_auto_call_fixture::0") + ), + not_( + has_container( + allure_results, + has_before("child_manual_call_fixture"), + has_after("child_manual_call_fixture::0") + ), + ), + has_container( + allure_results, + has_before("parent_dyn_call_fixture"), + has_after("parent_dyn_call_fixture::0") + ), + has_container( + allure_results, + has_before("child_dyn_call_fixture") + ) + ), + has_test_case( + "test_three", + has_container( + allure_results, + has_before("parent_auto_call_fixture"), + has_after("parent_auto_call_fixture::0") + ), + not_( + has_container( + allure_results, + has_before("child_manual_call_fixture"), + has_after("child_manual_call_fixture::0") + ), + ), + has_container( + allure_results, + has_before("parent_dyn_call_fixture"), + has_after("parent_dyn_call_fixture::0") + ), + not_( + has_container( + allure_results, + has_before("child_dyn_call_fixture") + ) + ) + ) + ) + ) + + +def test_one_fixture_on_two_tests(allure_pytest_runner: AllurePytestRunner): + testfile_content = ( + """ + import pytest + import allure + + @pytest.fixture + def fixture(request): + with allure.step(request.node.name): + pass + + class TestClass: + def test_first(self, fixture): + pass + + def test_second(self, fixture): + pass + """ + ) + allure_results = allure_pytest_runner.run_pytest(testfile_content) + + assert_that( + allure_results, + all_of( + has_test_case( + "test_first", + has_container( + allure_results, + has_before( + "fixture", + has_step("test_first") + ) + ), + not_( + has_container( + allure_results, + has_before( + "fixture", + has_step("test_second") + ) + ) + ) + ), + has_test_case( + "test_second", + has_container( + allure_results, + has_before( + "fixture", + has_step("test_second") + ) + ), + not_( + has_container( + allure_results, + has_before( + "fixture", + has_step("test_first") + ) + ) + ) + ) + ) + ) diff --git a/tests/allure_pytest/acceptance/fixture/parametrized_fixture_test.py b/tests/allure_pytest/acceptance/fixture/parametrized_fixture_test.py new file mode 100644 index 00000000..66bcf56a --- /dev/null +++ b/tests/allure_pytest/acceptance/fixture/parametrized_fixture_test.py @@ -0,0 +1,95 @@ +from hamcrest import assert_that, all_of +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.container import has_container +from allure_commons_test.container import has_before +from allure_commons_test.result import has_parameter + + +def params_name(request): + node_id = request.node.nodeid + _, name = node_id.rstrip("]").split("[") + return name + + +def test_function_scope_parametrized_fixture(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.fixture(params=[True, False]) + ... def parametrized_fixture(request): + ... pass + + >>> def test_function_scope_parametrized_fixture_example(parametrized_fixture): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + all_of( + has_test_case( + "test_function_scope_parametrized_fixture_example[True]", + has_parameter( + "parametrized_fixture", + "True" + ), + has_container( + allure_results, + has_before("parametrized_fixture") + ) + ), + has_test_case( + "test_function_scope_parametrized_fixture_example[False]", + has_parameter( + "parametrized_fixture", + "False" + ), + has_container( + allure_results, + has_before("parametrized_fixture") + ) + ) + ) + ) + + +def test_function_scope_parametrized_fixture_with_ids( + allure_pytest_runner: AllurePytestRunner +): + """ + >>> import pytest + + >>> @pytest.fixture(params=[True, False], ids=["param_true", "param_false"]) + ... def parametrized_fixture(request): + ... pass + + >>> def test_function(parametrized_fixture): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + all_of( + has_test_case( + "test_function[param_true]", + has_parameter("parametrized_fixture", "True"), + has_container( + allure_results, + has_before("parametrized_fixture") + ) + ), + has_test_case( + "test_function[param_false]", + has_parameter("parametrized_fixture", "False"), + has_container( + allure_results, + has_before("parametrized_fixture") + ) + ) + ) + ) diff --git a/allure-pytest/test/acceptance/fixture/yield_fixture_test.py b/tests/allure_pytest/acceptance/fixture/yield_fixture_test.py similarity index 66% rename from allure-pytest/test/acceptance/fixture/yield_fixture_test.py rename to tests/allure_pytest/acceptance/fixture/yield_fixture_test.py index e2ac5d92..d64126f5 100644 --- a/allure-pytest/test/acceptance/fixture/yield_fixture_test.py +++ b/tests/allure_pytest/acceptance/fixture/yield_fixture_test.py @@ -1,13 +1,16 @@ + +from hamcrest import assert_that, not_, all_of +from tests.allure_pytest.pytest_runner import AllurePytestRunner + import allure from allure_commons_test.container import has_before from allure_commons_test.container import has_container from allure_commons_test.report import has_test_case from allure_commons_test.result import has_step -from hamcrest import assert_that, not_, all_of @allure.feature("Fixture") -def test_yield_fixture(executed_docstring_source): +def test_yield_fixture(allure_pytest_runner: AllurePytestRunner): """ >>> import pytest @@ -19,16 +22,21 @@ def test_yield_fixture(executed_docstring_source): ... pass """ - assert_that(executed_docstring_source.allure_report, - has_test_case("test_yield_fixture_example", - has_container(executed_docstring_source.allure_report, - has_before("yield_fixture") - ) - ) - ) + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_yield_fixture_example", + has_container( + allure_results, + has_before("yield_fixture") + ) + ) + ) -def test_opened_step_function(executed_docstring_source): +def test_opened_step_function(allure_pytest_runner: AllurePytestRunner): """ >>> import allure >>> import pytest @@ -43,14 +51,16 @@ def test_opened_step_function(executed_docstring_source): ... pass """ + allure_results = allure_pytest_runner.run_docstring() + assert_that( - executed_docstring_source.allure_report, + allure_results, has_test_case( "test_opened_step", all_of( has_step("Body step"), has_container( - executed_docstring_source.allure_report, + allure_results, has_before( "yield_fixture", has_step( diff --git a/allure-pytest/test/integration/pytest_pluginmanager/__init__.py b/tests/allure_pytest/acceptance/history_id/__init__.py similarity index 100% rename from allure-pytest/test/integration/pytest_pluginmanager/__init__.py rename to tests/allure_pytest/acceptance/history_id/__init__.py diff --git a/tests/allure_pytest/acceptance/history_id/history_id_test.py b/tests/allure_pytest/acceptance/history_id/history_id_test.py new file mode 100644 index 00000000..55c2ea13 --- /dev/null +++ b/tests/allure_pytest/acceptance/history_id/history_id_test.py @@ -0,0 +1,42 @@ +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_history_id + + +def test_history_id(allure_pytest_runner: AllurePytestRunner): + """ + >>> def test_history_id_example(): + ... assert True + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_history_id_example", + has_history_id() + ) + ) + + +def test_history_id_for_skipped(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.mark.skip + ... def test_history_id_for_skipped_example(): + ... assert True + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_history_id_for_skipped_example", + has_history_id() + ) + ) diff --git a/allure-pytest/test/integration/pytest_rerunfailures/__init__.py b/tests/allure_pytest/acceptance/label/__init__.py similarity index 100% rename from allure-pytest/test/integration/pytest_rerunfailures/__init__.py rename to tests/allure_pytest/acceptance/label/__init__.py diff --git a/allure-pytest/test/integration/pytest_xdist/__init__.py b/tests/allure_pytest/acceptance/label/bdd/__init__.py similarity index 100% rename from allure-pytest/test/integration/pytest_xdist/__init__.py rename to tests/allure_pytest/acceptance/label/bdd/__init__.py diff --git a/tests/allure_pytest/acceptance/label/bdd/bdd_label_test.py b/tests/allure_pytest/acceptance/label/bdd/bdd_label_test.py new file mode 100644 index 00000000..6c638fc2 --- /dev/null +++ b/tests/allure_pytest/acceptance/label/bdd/bdd_label_test.py @@ -0,0 +1,41 @@ +""" ./allure-pytest/examples/label/bdd/bdd_label.rst """ + +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.label import has_epic +from allure_commons_test.label import has_feature +from allure_commons_test.label import has_story + + +def test_single_bdd_label(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_single_bdd_label", + has_epic("My epic"), + has_feature("My feature"), + has_story("My story") + ) + ) + + +def test_multiple_bdd_label(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_multiple_bdd_label", + has_epic("My epic"), + has_epic("Another epic"), + has_feature("My feature"), + has_feature("Another feature"), + has_feature("One more feature"), + has_story("My story"), + has_story("Alternative story") + ) + ) diff --git a/tests/allure_pytest/acceptance/label/bdd/dynamic_bdd_label_test.py b/tests/allure_pytest/acceptance/label/bdd/dynamic_bdd_label_test.py new file mode 100644 index 00000000..66c30a30 --- /dev/null +++ b/tests/allure_pytest/acceptance/label/bdd/dynamic_bdd_label_test.py @@ -0,0 +1,65 @@ +""" ./allure-pytest/examples/label/bdd/dynamic_bdd_label.rst """ + +import pytest +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.label import has_feature, has_epic, has_story + + +def test_dynamic_labels(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_dynamic_labels", + has_feature("first feature"), + has_feature("second feature"), + has_epic("first epic"), + has_epic("second epic"), + has_story("first story"), + has_story("second story") + ) + ) + + +@pytest.mark.parametrize("feature, epic, story", [ + pytest.param("first feature", "first epic", "first story", id="first"), + pytest.param("second feature", "second epic", "second story", id="second") +]) +def test_parametrized_dynamic_labels( + allure_pytest_runner: AllurePytestRunner, + feature, + epic, + story +): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + f"test_parametrized_dynamic_labels[{feature}-{epic}-{story}]", + has_feature(feature), + has_epic(epic), + has_story(story) + ) + ) + + +def test_multiple_dynamic_labels(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_multiple_dynamic_labels", + has_feature("first feature"), + has_feature("second feature"), + has_epic("first epic"), + has_epic("second epic"), + has_story("first story"), + has_story("second story") + ) + ) diff --git a/tests/allure_pytest/acceptance/label/bdd/select_bdd_test.py b/tests/allure_pytest/acceptance/label/bdd/select_bdd_test.py new file mode 100644 index 00000000..dfa4befc --- /dev/null +++ b/tests/allure_pytest/acceptance/label/bdd/select_bdd_test.py @@ -0,0 +1,62 @@ +""" ./allure-pytest/examples/label/bdd/select_tests_by_bdd.rst """ + +import pytest +from hamcrest import assert_that, only_contains, any_of, ends_with +from tests.allure_pytest.pytest_runner import AllurePytestRunner + + +@pytest.mark.parametrize( + ["options", "expected_tests"], + [ + pytest.param( + {"epics": ["Another Epic"]}, + ["test_with_another_epic_feature_story"], + id="epics" + ), + + pytest.param( + {"features": ["My Feature"]}, + [ + "test_with_epic_feature_story", + "test_with_epic_feature" + ], + id="features" + ), + + pytest.param( + {"stories": ["My Story", "Another Story"]}, + [ + "test_with_epic_feature_story", + "test_with_another_epic_feature_story" + ], + id="stories" + ), + + pytest.param( + {"stories": ["My Story"], "epics": ["Another Epic"]}, + [ + "test_with_epic_feature_story", + "test_with_another_epic_feature_story" + ], + id="story-or-epic" + ) + + ] +) +def test_select_by_bdd_label( + allure_pytest_runner: AllurePytestRunner, + options, + expected_tests +): + bdd_filter_args = ( + f"--allure-{k}=" + ",".join(v) for k, v in options.items() + ) + + allure_results = allure_pytest_runner.run_docpath_examples(*bdd_filter_args) + + test_cases = [test_case["fullName"] for test_case in allure_results.test_cases] + assert_that(test_cases, only_contains( + any_of( + *(ends_with(name) for name in expected_tests) + ) + )) diff --git a/tests/allure_pytest/acceptance/label/custom/__init__.py b/tests/allure_pytest/acceptance/label/custom/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_pytest/acceptance/label/custom/custom_label_test.py b/tests/allure_pytest/acceptance/label/custom/custom_label_test.py new file mode 100644 index 00000000..e3b2ae9e --- /dev/null +++ b/tests/allure_pytest/acceptance/label/custom/custom_label_test.py @@ -0,0 +1,20 @@ +""" ./allure-pytest/examples/label/custom/custom_label.rst """ + +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.label import has_label + + +def test_custom_label(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples() + + assert_that( + allure_results, + has_test_case( + "test_custom_label", + has_label("Application", "desktop"), + has_label("Application", "mobile") + ) + ) diff --git a/tests/allure_pytest/acceptance/label/custom/select_custom_label_test.py b/tests/allure_pytest/acceptance/label/custom/select_custom_label_test.py new file mode 100644 index 00000000..db4c643b --- /dev/null +++ b/tests/allure_pytest/acceptance/label/custom/select_custom_label_test.py @@ -0,0 +1,64 @@ +""" ./allure-pytest/examples/label/custom/select_tests_by_label.rst """ + +import pytest +from hamcrest import assert_that, all_of +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case + + +@pytest.mark.parametrize( + ["labels", "expected_tests"], + [ + pytest.param( + {"Application": ["desktop"]}, + [ + "test_custom_label_one", + "test_custom_label_both" + ], + id="desktop" + ), + pytest.param( + {"Application": ["mobile"]}, + [ + "test_custom_label_another", + "test_custom_label_both" + ], + id="mobile" + ), + pytest.param( + {"Application": ["desktop", "mobile"]}, + [ + "test_custom_label_one", + "test_custom_label_another", + "test_custom_label_both" + ], + id="desktop-or-mobile" + ), + pytest.param( + {"Application": ["mobile"], "layer": ["api"]}, + [ + "test_custom_label_another", + "test_custom_label_both", + "test_layer_label" + ], + id="mobile-or-api" + ) + ] +) +def test_select_by_custom_label( + allure_pytest_runner: AllurePytestRunner, + labels, + expected_tests +): + label_filters = ( + f"--allure-label={k}=" + ",".join(v) for k, v in labels.items() + ) + allure_results = allure_pytest_runner.run_docpath_examples(*label_filters) + + assert_that( + allure_results, + all_of( + *map(has_test_case, expected_tests) + ) + ) diff --git a/tests/allure_pytest/acceptance/label/id/set_testcase_id_test.py b/tests/allure_pytest/acceptance/label/id/set_testcase_id_test.py new file mode 100644 index 00000000..2dccfc20 --- /dev/null +++ b/tests/allure_pytest/acceptance/label/id/set_testcase_id_test.py @@ -0,0 +1,44 @@ +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.label import has_label + + +def test_set_testcase_id_label(allure_pytest_runner: AllurePytestRunner): + """ + >>> import allure + + >>> @allure.id(123) + ... def test_allure_ee_id_label_example(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_allure_ee_id_label_example", + has_label("as_id", 123), + ) + ) + + +def test_set_dynamic_testcase_id_label(allure_pytest_runner: AllurePytestRunner): + """ + >>> import allure + + >>> def test_allure_ee_id_dynamic_label_example(): + ... allure.dynamic.id(345) + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_allure_ee_id_dynamic_label_example", + has_label("as_id", 345), + ) + ) diff --git a/tests/allure_pytest/acceptance/label/manual/__init__.py b/tests/allure_pytest/acceptance/label/manual/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_pytest/acceptance/label/manual/manual_test.py b/tests/allure_pytest/acceptance/label/manual/manual_test.py new file mode 100644 index 00000000..2752cc5d --- /dev/null +++ b/tests/allure_pytest/acceptance/label/manual/manual_test.py @@ -0,0 +1,31 @@ +""" ./allure-pytest/examples/label/manual/allure_manual.rst """ + +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.label import has_label + + +def test_allure_manual_label(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_manual", + has_label("ALLURE_MANUAL", True), + ) + ) + + +def test_allure_manual_label_dynamic(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_manual_dynamic", + has_label("ALLURE_MANUAL", True), + ) + ) diff --git a/tests/allure_pytest/acceptance/label/package/__init__.py b/tests/allure_pytest/acceptance/label/package/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_pytest/acceptance/label/package/regression_test.py b/tests/allure_pytest/acceptance/label/package/regression_test.py new file mode 100644 index 00000000..42c90d31 --- /dev/null +++ b/tests/allure_pytest/acceptance/label/package/regression_test.py @@ -0,0 +1,47 @@ +import textwrap +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.label import has_package + + +def test_path_with_dots_test(allure_pytest_runner: AllurePytestRunner): + package_path = allure_pytest_runner.pytester.mkpydir("path.with.dots") + package_path.joinpath("test_path.py").write_text( + textwrap.dedent( + """ + def test_path_with_dots_test_example(): + pass + """ + ) + ) + + allure_results = allure_pytest_runner.run_pytest() + + assert_that( + allure_results, + has_test_case( + "test_path_with_dots_test_example", + has_package("path.with.dots.test_path") + ) + ) + + +def test_with_no_package(allure_pytest_runner: AllurePytestRunner): + """ + >>> def test_package_less(request): + ... pass + """ + + allure_pytest_runner.pytester.makeini("""[pytest]""") + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_package_less", + has_package("test_with_no_package") + ) + ) diff --git a/tests/allure_pytest/acceptance/label/severity/__init__.py b/tests/allure_pytest/acceptance/label/severity/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_pytest/acceptance/label/severity/class_severity_test.py b/tests/allure_pytest/acceptance/label/severity/class_severity_test.py new file mode 100644 index 00000000..6708385d --- /dev/null +++ b/tests/allure_pytest/acceptance/label/severity/class_severity_test.py @@ -0,0 +1,71 @@ +"""./allure-pytest/examples/label/severity/class_severity.rst""" + +from hamcrest import assert_that, all_of, is_not +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.label import has_severity + + +def test_decorated_class_not_decorated_method( + allure_pytest_runner: AllurePytestRunner +): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "TestDecoratedClass#test_not_decorated_method", + has_severity("trivial") + ) + ) + + +def test_decorated_class_decorated_method( + allure_pytest_runner: AllurePytestRunner +): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "TestDecoratedClass#test_decorated_method", + all_of( + has_severity("minor"), + is_not(has_severity("trivial")) + ) + ) + ) + + +def test_not_decorated_sub_class_not_decorated_method( + allure_pytest_runner: AllurePytestRunner +): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "TestNotDecoratedSubClass#test_not_decorated_method", + has_severity("trivial") + ) + ) + + +def test_not_decorated_sub_class_decorated_method( + allure_pytest_runner: AllurePytestRunner +): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "TestNotDecoratedSubClass#test_decorated_method", + all_of( + has_severity("critical"), + is_not( + has_severity("trivial") + ) + ) + ) + ) diff --git a/tests/allure_pytest/acceptance/label/severity/module_severity_test.py b/tests/allure_pytest/acceptance/label/severity/module_severity_test.py new file mode 100644 index 00000000..606633a4 --- /dev/null +++ b/tests/allure_pytest/acceptance/label/severity/module_severity_test.py @@ -0,0 +1,55 @@ +""" ./allure-pytest/examples/label/severity/module_severity.rst """ + +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.label import has_severity + + +def test_not_decorated_function(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_not_decorated_function", + has_severity("trivial") + ) + ) + + +def test_decorated_function(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_decorated_function", + has_severity("minor") + ) + ) + + +def test_method_of_not_decorated_class(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_method_of_not_decorated_class", + has_severity("trivial") + ) + ) + + +def test_method_of_decorated_class(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_method_of_decorated_class", + has_severity("normal") + ) + ) diff --git a/allure-pytest/test/acceptance/label/severity/select_severity_test.py b/tests/allure_pytest/acceptance/label/severity/select_severity_test.py similarity index 65% rename from allure-pytest/test/acceptance/label/severity/select_severity_test.py rename to tests/allure_pytest/acceptance/label/severity/select_severity_test.py index baed93fc..3cd3878c 100644 --- a/allure-pytest/test/acceptance/label/severity/select_severity_test.py +++ b/tests/allure_pytest/acceptance/label/severity/select_severity_test.py @@ -1,7 +1,8 @@ -""" ./examples/label/severity/select_tests_by_severity.rst """ +""" ./allure-pytest/examples/label/severity/select_tests_by_severity.rst """ import pytest from hamcrest import assert_that, only_contains, any_of, ends_with +from tests.allure_pytest.pytest_runner import AllurePytestRunner @pytest.mark.parametrize( @@ -33,11 +34,19 @@ ) ] ) -def test_select_by_severity_level(allured_testdir, severities, expected_tests): - allured_testdir.parse_docstring_path() +def test_select_by_severity_level( + allure_pytest_runner: AllurePytestRunner, + severities, + expected_tests +): + allure_results = allure_pytest_runner.run_docpath_examples( + "--allure-severities", + ",".join(severities) + ) - allured_testdir.run_with_allure("--allure-severities", ",".join(severities)) - test_cases = [test_case["fullName"] for test_case in allured_testdir.allure_report.test_cases] + test_cases = [ + test_case["fullName"] for test_case in allure_results.test_cases + ] assert_that(test_cases, only_contains( any_of( diff --git a/tests/allure_pytest/acceptance/label/severity/severity_test.py b/tests/allure_pytest/acceptance/label/severity/severity_test.py new file mode 100644 index 00000000..42665734 --- /dev/null +++ b/tests/allure_pytest/acceptance/label/severity/severity_test.py @@ -0,0 +1,19 @@ +""" ./allure-pytest/examples/label/severity/severity.rst """ + +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.label import has_severity + + +def test_severity(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples() + + assert_that( + allure_results, + has_test_case( + "test_severity", + has_severity("minor"), + ) + ) diff --git a/tests/allure_pytest/acceptance/label/suite/__init__.py b/tests/allure_pytest/acceptance/label/suite/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_pytest/acceptance/label/suite/custom_suite_test.py b/tests/allure_pytest/acceptance/label/suite/custom_suite_test.py new file mode 100644 index 00000000..98abfc57 --- /dev/null +++ b/tests/allure_pytest/acceptance/label/suite/custom_suite_test.py @@ -0,0 +1,21 @@ +""" ./allure-pytest/examples/label/suite/custom_suite.rst """ + +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.label import has_suite, has_parent_suite, has_sub_suite + + +def test_custom_suite(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples() + + assert_that( + allure_results, + has_test_case( + "test_custom_suite", + has_suite("suite name"), + has_parent_suite("parent suite name"), + has_sub_suite("sub suite name") + ) + ) diff --git a/tests/allure_pytest/acceptance/label/suite/default_suite_test.py b/tests/allure_pytest/acceptance/label/suite/default_suite_test.py new file mode 100644 index 00000000..92a71fbe --- /dev/null +++ b/tests/allure_pytest/acceptance/label/suite/default_suite_test.py @@ -0,0 +1,111 @@ +from doctest import script_from_examples +from hamcrest import assert_that, anything, not_ +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.label import has_parent_suite +from allure_commons_test.label import has_suite +from allure_commons_test.label import has_sub_suite + + +def test_no_parent_module( + allure_pytest_runner: AllurePytestRunner +): + """ + >>> def test_default_suite_example(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_default_suite_example", + not_(has_parent_suite(anything())), + has_suite("test_no_parent_module"), + not_(has_sub_suite(anything())) + ) + ) + + +def test_class_no_parent_module( + allure_pytest_runner: AllurePytestRunner +): + """ + >>> class TestSuiteClass: + ... def test_default_class_suite_example(self): + ... pass + + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_default_class_suite_example", + not_(has_parent_suite(anything())), + has_suite("test_class_no_parent_module"), + has_sub_suite("TestSuiteClass") + ) + ) + + +def test_with_parent_module( + allure_pytest_runner: AllurePytestRunner, + docstring +): + """ + >>> def test_default_suite_example(): + ... pass + + """ + + content = script_from_examples(docstring) + module = "test_default_suites_with_parent_module" + filename = module + ".py" + fullname = "parent_module/" + filename + allure_pytest_runner.pytester.makepyfile(**{fullname: content}) + + allure_results = allure_pytest_runner.run_pytest() + + assert_that( + allure_results, + has_test_case( + "test_default_suite_example", + has_parent_suite("parent_module"), + has_suite(module), + not_(has_sub_suite(anything())) + ) + ) + + +def test_with_class_and_parent_module( + allure_pytest_runner: AllurePytestRunner, + docstring +): + """ + >>> class TestSuiteClass: + ... def test_default_class_suite_example(self): + ... pass + + """ + + content = script_from_examples(docstring) + module = "test_default_suites_with_class_and_parent_module" + filename = module + ".py" + fullname = "parent_module/" + filename + allure_pytest_runner.pytester.makepyfile(**{fullname: content}) + + allure_results = allure_pytest_runner.run_pytest() + + assert_that( + allure_results, + has_test_case( + "test_default_class_suite_example", + has_parent_suite("parent_module"), + has_suite(module), + has_sub_suite("TestSuiteClass") + ) + ) diff --git a/tests/allure_pytest/acceptance/label/suite/module_level_custom_suite_test.py b/tests/allure_pytest/acceptance/label/suite/module_level_custom_suite_test.py new file mode 100644 index 00000000..edf1d1ec --- /dev/null +++ b/tests/allure_pytest/acceptance/label/suite/module_level_custom_suite_test.py @@ -0,0 +1,19 @@ +""" ./allure-pytest/examples/label/suite/module_level_custom_suite.rst """ + +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.label import has_suite + + +def test_module_custom_suite(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples() + + assert_that( + allure_results, + has_test_case( + "test_module_level_custom_suite", + has_suite("module level suite name"), + ) + ) diff --git a/tests/allure_pytest/acceptance/label/tag/__init__.py b/tests/allure_pytest/acceptance/label/tag/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_pytest/acceptance/label/tag/tag_test.py b/tests/allure_pytest/acceptance/label/tag/tag_test.py new file mode 100644 index 00000000..3f32475b --- /dev/null +++ b/tests/allure_pytest/acceptance/label/tag/tag_test.py @@ -0,0 +1,165 @@ +from hamcrest import assert_that, not_ +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.label import has_tag + + +def test_pytest_marker(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.mark.cool + ... @pytest.mark.stuff + ... def test_pytest_marker_example(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_pytest_marker_example", + has_tag("cool"), + has_tag("stuff") + ) + ) + + +def test_show_reserved_pytest_markers_full_decorator( + allure_pytest_runner: AllurePytestRunner +): + """ + >>> import pytest + + >>> @pytest.mark.usermark1 + ... @pytest.mark.usermark2 + ... @pytest.mark.parametrize("param", ["foo"]) + ... @pytest.mark.skipif(False, reason="reason2") + ... @pytest.mark.skipif(False, reason="reason1") + ... def test_show_reserved_pytest_markers_full_decorator_example(param): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_show_reserved_pytest_markers_full_decorator_example[foo]", + has_tag("usermark1"), + has_tag("usermark2"), + has_tag("@pytest.mark.skipif(False, reason='reason1')"), + not_( + has_tag("@pytest.mark.skipif(False, reason='reason2')") + ), + not_( + has_tag("@pytest.mark.parametrize('param', ['foo'])") + ) + ) + ) + + +def test_pytest_xfail_marker(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.mark.xfail(reason='this is unexpect pass') + ... def test_pytest_xfail_marker_example(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_pytest_xfail_marker_example", + has_tag("@pytest.mark.xfail(reason='this is unexpect pass')") + ) + ) + + +def test_pytest_marker_with_args(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.mark.marker('cool', 'stuff') + ... def test_pytest_marker_with_args_example(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_pytest_marker_with_args_example", + has_tag("marker('cool', 'stuff')") + ) + ) + + +def test_pytest_marker_with_kwargs(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.mark.marker(stuff='cool') + ... def test_pytest_marker_with_kwargs_example(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_pytest_marker_with_kwargs_example", + has_tag("marker(stuff='cool')") + ) + ) + + +def test_pytest_marker_with_kwargs_native_encoding( + allure_pytest_runner: AllurePytestRunner +): + """ + >>> import pytest + + >>> @pytest.mark.marker(stuff='я') + ... def test_pytest_marker_with_kwargs_native_encoding_example(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_pytest_marker_with_kwargs_native_encoding_example", + has_tag("marker(stuff='я')") + ) + ) + + +def test_pytest_marker_with_kwargs_utf_encoding( + allure_pytest_runner: AllurePytestRunner +): + """ + >>> import pytest + + >>> @pytest.mark.marker(stuff='я') + ... def test_pytest_marker_with_kwargs_utf_encoding_example(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_pytest_marker_with_kwargs_utf_encoding_example", + has_tag("marker(stuff='я')") + ) + ) diff --git a/tests/allure_pytest/acceptance/link/__init__.py b/tests/allure_pytest/acceptance/link/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_pytest/acceptance/link/dynamic_link_test.py b/tests/allure_pytest/acceptance/link/dynamic_link_test.py new file mode 100644 index 00000000..d8390a77 --- /dev/null +++ b/tests/allure_pytest/acceptance/link/dynamic_link_test.py @@ -0,0 +1,73 @@ +""" ./allure-pytest/examples/link/dynamic_link.rst """ + +from hamcrest import assert_that, equal_to, all_of +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_link +from allure_commons_test.result import has_issue_link + + +def test_dynamic_link(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_dynamic_link", + has_issue_link("issues/24") + ) + ) + + +def test_parametrize_dynamic_link(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + all_of( + has_test_case( + "test_parametrize_dynamic_link[issues/24]", + has_issue_link("issues/24"), + ), + has_test_case( + "test_parametrize_dynamic_link[issues/132]", + has_issue_link("issues/132"), + ) + ) + ) + + +def test_all_links_together(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_all_links_together", + has_issue_link("issues/24"), + has_issue_link("issues/132"), + has_link("allure", name="QAMETA", link_type="docs") + ) + ) + + +def test_unique_dynamic_links(allure_pytest_runner: AllurePytestRunner): + """ + >>> import allure + + >>> def test_unique_dynamic_links_example(): + ... allure.dynamic.link("some/unique/dynamic/link") + ... allure.dynamic.link("some/unique/dynamic/link") + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results.test_cases[0]['links'], + equal_to([{ + 'url': 'some/unique/dynamic/link', + 'type': 'link', + 'name': 'some/unique/dynamic/link' + }]) + ) diff --git a/tests/allure_pytest/acceptance/link/link_pattern_test.py b/tests/allure_pytest/acceptance/link/link_pattern_test.py new file mode 100644 index 00000000..d1fa6bc8 --- /dev/null +++ b/tests/allure_pytest/acceptance/link/link_pattern_test.py @@ -0,0 +1,26 @@ +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_link, has_issue_link + + +def test_link_pattern(allure_pytest_runner: AllurePytestRunner): + """ ./allure-pytest/examples/link/dynamic_link.rst """ + + allure_results = allure_pytest_runner.run_docpath_examples( + "--allure-link-pattern", + "issue:https://github.com/allure-framework/allure-python2/{}", + "--allure-link-pattern", + "docs:https://docs.qameta.io/{}" + ) + + assert_that( + allure_results, + has_test_case( + "test_all_links_together", + has_issue_link("https://github.com/allure-framework/allure-python2/issues/24"), + has_issue_link("https://github.com/allure-framework/allure-python2/issues/24"), + has_link("https://docs.qameta.io/allure") + ) + ) diff --git a/tests/allure_pytest/acceptance/link/link_test.py b/tests/allure_pytest/acceptance/link/link_test.py new file mode 100644 index 00000000..1994dd31 --- /dev/null +++ b/tests/allure_pytest/acceptance/link/link_test.py @@ -0,0 +1,57 @@ +""" ./allure-pytest/examples/link/link.rst """ + +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_link +from allure_commons_test.result import has_issue_link +from allure_commons_test.result import has_test_case_link + + +def test_link(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_link", + has_link("http://qameta.io") + ) + ) + + +def test_issue_link(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_issue_link", + has_issue_link("https://github.com/allure-framework/allure-python/issues/24") + ) + ) + + +def test_testcase_link(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_testcase_link", + has_test_case_link("issues/24#issuecomment-277330977") + ) + ) + + +def test_custom_link(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_custom_link", + has_link("http://qameta.io", name="QAMETA", link_type="homepage") + ) + ) diff --git a/tests/allure_pytest/acceptance/parametrization/__init__.py b/tests/allure_pytest/acceptance/parametrization/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_pytest/acceptance/parametrization/dynamic_parameter_test.py b/tests/allure_pytest/acceptance/parametrization/dynamic_parameter_test.py new file mode 100644 index 00000000..d4186f55 --- /dev/null +++ b/tests/allure_pytest/acceptance/parametrization/dynamic_parameter_test.py @@ -0,0 +1,70 @@ +""" ./allure-pytest/examples/parameter/dynamic_parameter.rst """ + +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import ( + has_parameter, + get_parameter_matcher, + with_excluded, + with_mode +) + + +def test_dynamic_parameter(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_dynamic_parameter", + has_parameter("username", "'John Doe'") + ) + ) + + +def test_masked_dynamic_parameter(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_masked_dynamic_parameter", + has_parameter( + "password", + "'qwerty'", + with_mode("masked") + ) + ) + ) + + +def test_hidden_dynamic_parameter(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_hidden_dynamic_parameter", + get_parameter_matcher( + "hostname", + with_mode("hidden") + ) + ) + ) + + +def test_excluded_dynamic_parameter(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_excluded_dynamic_parameter", + get_parameter_matcher( + "work-dir", + with_excluded() + ) + ) + ) diff --git a/tests/allure_pytest/acceptance/parametrization/metafunc_test.py b/tests/allure_pytest/acceptance/parametrization/metafunc_test.py new file mode 100644 index 00000000..3e63b4cf --- /dev/null +++ b/tests/allure_pytest/acceptance/parametrization/metafunc_test.py @@ -0,0 +1,65 @@ +from hamcrest import assert_that, all_of +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_parameter + + +def test_metafunc_param(allure_pytest_runner: AllurePytestRunner): + """ + >>> def pytest_generate_tests(metafunc): + ... if "metafunc_param" in metafunc.fixturenames: + ... metafunc.parametrize("metafunc_param", [True, False]) + + + >>> def test_metafunc_param_example(metafunc_param): + ... assert metafunc_param + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + all_of( + has_test_case( + "test_metafunc_param_example[True]", + has_parameter("metafunc_param", "True") + ), + has_test_case( + "test_metafunc_param_example[False]", + has_parameter("metafunc_param", "False") + ) + ) + ) + + +def test_metafunc_param_with_ids(allure_pytest_runner: AllurePytestRunner): + """ + >>> def pytest_generate_tests(metafunc): + ... if "metafunc_param_with_ids" in metafunc.fixturenames: + ... metafunc.parametrize( + ... "metafunc_param_with_ids", + ... [True, False], + ... ids=["pass", "fail"] + ... ) + + + >>> def test_metafunc_param_with_ids_example(metafunc_param_with_ids): + ... assert metafunc_param_with_ids + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + all_of( + has_test_case( + "test_metafunc_param_with_ids_example[pass]", + has_parameter("metafunc_param_with_ids", "True") + ), + has_test_case( + "test_metafunc_param_with_ids_example[fail]", + has_parameter("metafunc_param_with_ids", "False") + ) + ) + ) diff --git a/tests/allure_pytest/acceptance/parametrization/parametrization_test.py b/tests/allure_pytest/acceptance/parametrization/parametrization_test.py new file mode 100644 index 00000000..07d7ac3b --- /dev/null +++ b/tests/allure_pytest/acceptance/parametrization/parametrization_test.py @@ -0,0 +1,279 @@ +from hamcrest import assert_that, has_entry, ends_with, all_of +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_parameter +from allure_commons_test.result import with_excluded +from allure_commons_test.result import with_mode + + +def test_parametrization(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.mark.parametrize("n", [1, 2]) + ... def test_parametrization_example(n): + ... assert param + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + all_of( + has_test_case( + "test_parametrization_example[1]", + has_parameter("n", "1") + ), + has_test_case( + "test_parametrization_example[2]", + has_parameter("n", "2") + ) + ) + ) + + +def test_parametrization_with_ids(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.mark.parametrize("v", [1, 2], ids=["a", "b"]) + ... def test_parametrization_with_ids_example(v): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + all_of( + has_test_case( + "test_parametrization_with_ids_example[a]", + has_parameter("v", "1") + ), + has_test_case( + "test_parametrization_with_ids_example[b]", + has_parameter("v", "2") + ) + ) + ) + + +def test_parametrization_many_decorators(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.mark.parametrize("s", ["a", "b"]) + ... @pytest.mark.parametrize("n", [1, 2]) + ... def test_parametrization_many_decorators_example(n, s): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + all_of( + has_test_case( + "test_parametrization_many_decorators_example[1-a]", + has_parameter("n", "1"), + has_parameter("s", "'a'") + ), + has_test_case( + "test_parametrization_many_decorators_example[1-b]", + has_parameter("n", "1"), + has_parameter("s", "'b'") + ), + has_test_case( + "test_parametrization_many_decorators_example[2-a]", + has_parameter("n", "2"), + has_parameter("s", "'a'") + ), + has_test_case( + "test_parametrization_many_decorators_example[2-b]", + has_parameter("n", "2"), + has_parameter("s", "'b'") + ) + ) + ) + + +def test_parametrization_decorators_with_partial_ids( + allure_pytest_runner: AllurePytestRunner +): + """ + >>> import pytest + + >>> @pytest.mark.parametrize("s", ["a", "b"], ids=["A", "B"]) + ... @pytest.mark.parametrize("n", [1, 2]) + ... def test_two_marks_one_with_ids(n, s): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + all_of( + has_test_case( + "test_two_marks_one_with_ids[1-A]", + has_parameter("n", "1"), + has_parameter("s", "'a'") + ), + has_test_case( + "test_two_marks_one_with_ids[1-B]", + has_parameter("n", "1"), + has_parameter("s", "'b'") + ), + has_test_case( + "test_two_marks_one_with_ids[2-A]", + has_parameter("n", "2"), + has_parameter("s", "'a'") + ), + has_test_case( + "test_two_marks_one_with_ids[2-B]", + has_parameter("n", "2"), + has_parameter("s", "'b'") + ) + ) + ) + + +def test_dynamic_parameter_add(allure_pytest_runner: AllurePytestRunner): + """ + >>> import allure + + >>> def test_parameter_add(): + ... allure.dynamic.parameter("param1", "param-value") + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_parameter_add", + has_parameter("param1", "'param-value'") + ) + ) + + +def test_dynamic_parameter_excluded(allure_pytest_runner: AllurePytestRunner): + """ + >>> import allure + + >>> def test_parameter_excluded(): + ... allure.dynamic.parameter("param1", "param-value", excluded=True) + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_parameter_excluded", + has_parameter( + "param1", + "'param-value'", + with_excluded() + ) + ) + ) + + +def test_dynamic_parameter_mode(allure_pytest_runner: AllurePytestRunner): + """ + >>> import allure + + >>> def test_parameter_mode(): + ... allure.dynamic.parameter("param1", "param-value", mode=allure.parameter_mode.MASKED) + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_parameter_mode", + has_parameter( + "param1", + "'param-value'", + with_mode('masked') + ) + ) + ) + + +def test_dynamic_parameter_override(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + ... import allure + + >>> @pytest.mark.parametrize("param1", [object()], ids=["param-id"]) + ... def test_parameter_override(param1): + ... allure.dynamic.parameter("param1", "readable-value") + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_parameter_override[param-id]", + has_parameter("param1", "'readable-value'") + ) + ) + + +def test_dynamic_parameter_override_from_fixture( + allure_pytest_runner: AllurePytestRunner +): + """ + >>> import pytest + ... import allure + + + >>> @pytest.fixture() + ... def fixt(): + ... allure.dynamic.parameter("param1", "readable-value") + + >>> @pytest.mark.parametrize("param1", [object()], ids=["param-id"]) + ... def test_parameter_override_from_fixture(fixt, param1): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_parameter_override_from_fixture[param-id]", + has_parameter("param1", "'readable-value'") + ) + ) + + +def test_fullname_with_braces(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + ... import allure + + >>> class TestClass: + ... @pytest.mark.parametrize("param1", ["qwe]["]) + ... def test_with_braces(self, param1): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_with_braces[qwe][]", + has_entry( + 'fullName', + ends_with(".TestClass#test_with_braces") + ), + has_parameter("param1", "'qwe]['") + ) + ) diff --git a/tests/allure_pytest/acceptance/pytest_pluginmanager/__init__.py b/tests/allure_pytest/acceptance/pytest_pluginmanager/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_pytest/acceptance/pytest_pluginmanager/pytest_get_allure_plugin_test.py b/tests/allure_pytest/acceptance/pytest_pluginmanager/pytest_get_allure_plugin_test.py new file mode 100644 index 00000000..24d0cf81 --- /dev/null +++ b/tests/allure_pytest/acceptance/pytest_pluginmanager/pytest_get_allure_plugin_test.py @@ -0,0 +1,26 @@ +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +import allure +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status + + +@allure.feature("Integration") +def test_pytest_get_allure_listener_plugin( + allure_pytest_runner: AllurePytestRunner +): + """ + >>> def test_pytest_get_allure_listener_plugin(request): + ... assert request.config.pluginmanager.get_plugin('allure_listener') + """ + + output = allure_pytest_runner.run_docstring() + + assert_that( + output, + has_test_case( + "test_pytest_get_allure_listener_plugin", + with_status("passed") + ) + ) diff --git a/tests/allure_pytest/acceptance/status/__init__.py b/tests/allure_pytest/acceptance/status/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_pytest/acceptance/status/base_call_status_test.py b/tests/allure_pytest/acceptance/status/base_call_status_test.py new file mode 100644 index 00000000..81f3a338 --- /dev/null +++ b/tests/allure_pytest/acceptance/status/base_call_status_test.py @@ -0,0 +1,113 @@ +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status +from allure_commons_test.result import has_status_details +from allure_commons_test.result import with_message_contains +from allure_commons_test.result import with_trace_contains + + +def test_passed(allure_pytest_runner: AllurePytestRunner): + """ + >>> def test_passed_example(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_passed_example", + with_status("passed") + ) + ) + + +def test_failed(allure_pytest_runner: AllurePytestRunner): + """ + >>> def test_failed_example(): + ... assert False + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_failed_example", + with_status("failed"), + has_status_details( + with_message_contains("AssertionError"), + with_trace_contains("def test_failed_example():") + ) + ) + ) + + +def test_broken(allure_pytest_runner: AllurePytestRunner): + """ + >>> def test_broken_example(): + ... raise IndentationError() + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_broken_example", + with_status("broken"), + has_status_details( + with_message_contains("IndentationError"), + with_trace_contains("def test_broken_example():") + ) + ) + ) + + +def test_call_pytest_fail(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> def test_call_pytest_fail_example(): + ... pytest.fail() + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_call_pytest_fail_example", + with_status("failed"), + has_status_details( + with_message_contains("Failed"), + with_trace_contains("def test_call_pytest_fail_example():") + ) + ) + ) + + +def test_call_pytest_fail_with_reason(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> def test_call_pytest_fail_with_reason_example(): + ... pytest.fail("Fail message") + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_call_pytest_fail_with_reason_example", + with_status("failed"), + has_status_details( + with_message_contains("Fail message"), + with_trace_contains("def test_call_pytest_fail_with_reason_example():") + ) + ) + ) diff --git a/tests/allure_pytest/acceptance/status/base_setup_status_test.py b/tests/allure_pytest/acceptance/status/base_setup_status_test.py new file mode 100644 index 00000000..cf2468bc --- /dev/null +++ b/tests/allure_pytest/acceptance/status/base_setup_status_test.py @@ -0,0 +1,199 @@ +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status +from allure_commons_test.result import has_status_details +from allure_commons_test.result import with_message_contains +from allure_commons_test.result import with_trace_contains +from allure_commons_test.container import has_container +from allure_commons_test.container import has_before + + +def test_failed_fixture(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.fixture + ... def failed_fixture(): + ... assert False + + >>> def test_failed_fixture_example(failed_fixture): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_failed_fixture_example", + with_status("failed"), + has_status_details( + with_message_contains("AssertionError"), + with_trace_contains("def failed_fixture():") + ), + has_container( + allure_results, + has_before( + "failed_fixture", + with_status("failed"), + has_status_details( + with_message_contains("AssertionError"), + with_trace_contains("failed_fixture") + ) + ) + ) + ) + ) + + +def test_broken_fixture(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.fixture + ... def broken_fixture(): + ... raise IndexError + + >>> def test_broken_fixture_example(broken_fixture): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_broken_fixture_example", + with_status("broken"), + has_status_details( + with_message_contains("IndexError"), + with_trace_contains("def broken_fixture():") + ), + has_container( + allure_results, + has_before( + "broken_fixture", + with_status("broken"), + has_status_details( + with_message_contains("IndexError"), + with_trace_contains("broken_fixture") + ), + ) + ) + ) + ) + + +def test_skip_fixture(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.fixture + ... def skip_fixture(): + ... pytest.skip() + + >>> def test_skip_fixture_example(skip_fixture): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_skip_fixture_example", + with_status("skipped"), + has_status_details( + with_message_contains("Skipped") + ), + has_container( + allure_results, + has_before( + "skip_fixture", + with_status("skipped"), + has_status_details( + with_message_contains("Skipped"), + with_trace_contains("skip_fixture") + ) + ) + ) + ) + ) + + +def test_pytest_fail_fixture(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.fixture + ... def pytest_fail_fixture(): + ... pytest.fail() + + >>> def test_pytest_fail_fixture_example(pytest_fail_fixture): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_pytest_fail_fixture_example", + with_status("failed"), + has_status_details( + with_message_contains("Failed"), + with_trace_contains("def pytest_fail_fixture():") + ), + has_container( + allure_results, + has_before( + "pytest_fail_fixture", + with_status("failed"), + has_status_details( + with_message_contains("Failed"), + with_trace_contains("pytest_fail_fixture") + ) + ) + ) + ) + ) + + +def test_pytest_fail_with_reason_fixture(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.fixture + ... def pytest_fail_with_reason_fixture(): + ... pytest.fail("Fail message") + + >>> def test_pytest_fail_with_reason_fixture_example(pytest_fail_with_reason_fixture): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_pytest_fail_with_reason_fixture_example", + with_status("failed"), + has_status_details( + with_message_contains("Fail message"), + with_trace_contains("def pytest_fail_with_reason_fixture():") + ), + has_container( + allure_results, + has_before( + "pytest_fail_with_reason_fixture", + with_status("failed"), + has_status_details( + with_message_contains("Fail message"), + with_trace_contains("pytest_fail_with_reason_fixture") + ) + ) + ) + ) + ) diff --git a/tests/allure_pytest/acceptance/status/base_step_status_test.py b/tests/allure_pytest/acceptance/status/base_step_status_test.py new file mode 100644 index 00000000..c5cb1a06 --- /dev/null +++ b/tests/allure_pytest/acceptance/status/base_step_status_test.py @@ -0,0 +1,106 @@ +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_step +from allure_commons_test.result import with_status +from allure_commons_test.result import has_status_details +from allure_commons_test.result import with_message_contains +from allure_commons_test.result import with_trace_contains + + +def test_broken_step(allure_pytest_runner: AllurePytestRunner): + """ + >>> import allure + + >>> def test_broken_step_example(): + ... with allure.step("Step"): + ... raise ZeroDivisionError + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_broken_step_example", + with_status("broken"), + has_status_details( + with_message_contains("ZeroDivisionError"), + with_trace_contains("def test_broken_step_example():") + ), + has_step( + "Step", + with_status("broken"), + has_status_details( + with_message_contains("ZeroDivisionError"), + with_trace_contains("test_broken_step_example") + ) + ) + ) + ) + + +def test_pytest_fail_in_step(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + >>> import allure + + >>> def test_pytest_fail_in_step_example(): + ... with allure.step("Step"): + ... pytest.fail() + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_pytest_fail_in_step_example", + with_status("failed"), + has_status_details( + with_message_contains("Failed"), + with_trace_contains("def test_pytest_fail_in_step_example():") + ), + has_step( + "Step", + with_status("failed"), + has_status_details( + with_message_contains("Failed"), + with_trace_contains("test_pytest_fail_in_step_example") + ) + ) + ) + ) + + +def test_pytest_bytes_data_in_assert(allure_pytest_runner: AllurePytestRunner): + """ + >>> import allure + + >>> def test_pytest_bytes_data_in_assert_example(): + ... with allure.step("Step"): + ... assert "0\\x82" == 1 + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_pytest_bytes_data_in_assert_example", + with_status("failed"), + has_status_details( + with_message_contains("AssertionError: assert \'0\\x82\' == 1"), + with_trace_contains("def test_pytest_bytes_data_in_assert_example():") + ), + has_step( + "Step", + with_status("failed"), + has_status_details( + with_message_contains("AssertionError: assert \'0\\x82\' == 1"), + with_trace_contains("test_pytest_bytes_data_in_assert_example") + ) + ) + ) + ) diff --git a/allure-pytest/test/acceptance/status/base_teardown_status_test.py b/tests/allure_pytest/acceptance/status/base_teardown_status_test.py similarity index 84% rename from allure-pytest/test/acceptance/status/base_teardown_status_test.py rename to tests/allure_pytest/acceptance/status/base_teardown_status_test.py index 683ff1de..0194b458 100644 --- a/allure-pytest/test/acceptance/status/base_teardown_status_test.py +++ b/tests/allure_pytest/acceptance/status/base_teardown_status_test.py @@ -1,4 +1,6 @@ from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + from allure_commons_test.report import has_test_case from allure_commons_test.result import with_status from allure_commons_test.result import has_status_details @@ -8,7 +10,7 @@ from allure_commons_test.container import has_after -def test_failed_finalizer_fixture(executed_docstring_source): +def test_failed_finalizer_fixture(allure_pytest_runner: AllurePytestRunner): """ >>> import pytest @@ -22,8 +24,10 @@ def test_failed_finalizer_fixture(executed_docstring_source): ... pass """ + allure_results = allure_pytest_runner.run_docstring() + assert_that( - executed_docstring_source.allure_report, + allure_results, has_test_case( "test_failed_finalizer_fixture_example", with_status("failed"), @@ -32,7 +36,7 @@ def test_failed_finalizer_fixture(executed_docstring_source): with_trace_contains("def fixture_finalizer():") ), has_container( - executed_docstring_source.allure_report, + allure_results, has_after( "failed_finalizer_fixture::fixture_finalizer", with_status("failed"), @@ -46,7 +50,7 @@ def test_failed_finalizer_fixture(executed_docstring_source): ) -def test_pytest_failed_finalizer_fixture(executed_docstring_source): +def test_pytest_failed_finalizer_fixture(allure_pytest_runner: AllurePytestRunner): """ >>> import pytest @@ -60,8 +64,10 @@ def test_pytest_failed_finalizer_fixture(executed_docstring_source): ... pass """ + allure_results = allure_pytest_runner.run_docstring() + assert_that( - executed_docstring_source.allure_report, + allure_results, has_test_case( "test_pytest_failed_finalizer_fixture_example", with_status("failed"), @@ -70,7 +76,7 @@ def test_pytest_failed_finalizer_fixture(executed_docstring_source): with_trace_contains("def fixture_finalizer():") ), has_container( - executed_docstring_source.allure_report, + allure_results, has_after( "pytest_failed_finalizer_fixture::fixture_finalizer", with_status("failed"), diff --git a/tests/allure_pytest/acceptance/status/skip_call_status_test.py b/tests/allure_pytest/acceptance/status/skip_call_status_test.py new file mode 100644 index 00000000..7138f17d --- /dev/null +++ b/tests/allure_pytest/acceptance/status/skip_call_status_test.py @@ -0,0 +1,117 @@ +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status +from allure_commons_test.result import has_status_details +from allure_commons_test.result import with_message_contains + + +def test_skip(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> def test_skip_example(): + ... pytest.skip() + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_skip_example", + with_status("skipped"), + has_status_details( + with_message_contains("Skipped") + ) + ) + ) + + +def test_skip_with_reason(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> def test_skip_with_reason_example(): + ... pytest.skip("Skip reason") + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_skip_with_reason_example", + with_status("skipped"), + has_status_details( + with_message_contains("Skipped: Skip reason") + ) + ) + ) + + +def test_skip_decorator_and_reason(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.mark.skip(reason="Skip reason") + ... def test_skip_decorator_and_reason_example(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_skip_decorator_and_reason_example", + with_status("skipped"), + has_status_details( + with_message_contains("Skipped: Skip reason") + ) + ) + ) + + +def test_skipif_true(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.mark.skipif(True, reason="Skip reason") + ... def test_skipif_true_example(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_skipif_true_example", + with_status("skipped"), + has_status_details( + with_message_contains("Skipped: Skip reason") + ) + ) + ) + + +def test_skipif_false(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.mark.skipif(False, reason="Skip reason") + ... def test_skipif_false_example(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_skipif_false_example", + with_status("passed") + ) + ) diff --git a/tests/allure_pytest/acceptance/status/skip_setup_status_test.py b/tests/allure_pytest/acceptance/status/skip_setup_status_test.py new file mode 100644 index 00000000..436e8755 --- /dev/null +++ b/tests/allure_pytest/acceptance/status/skip_setup_status_test.py @@ -0,0 +1,50 @@ +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +import allure +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status +from allure_commons_test.result import has_status_details +from allure_commons_test.result import with_message_contains +from allure_commons_test.result import with_trace_contains +from allure_commons_test.container import has_container +from allure_commons_test.container import has_before + + +@allure.feature("Fixture") +def test_skip_fixture(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.fixture + ... def skip_fixture(): + ... pytest.skip() + + >>> @pytest.mark.xfail() + ... def test_skip_fixture_example(skip_fixture): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_skip_fixture_example", + with_status("skipped"), + has_status_details( + with_message_contains("Skipped") + ), + has_container( + allure_results, + has_before( + "skip_fixture", + with_status("skipped"), + has_status_details( + with_message_contains("Skipped"), + with_trace_contains("skip_fixture") + ) + ) + ) + ) + ) diff --git a/tests/allure_pytest/acceptance/status/skip_step_status_test.py b/tests/allure_pytest/acceptance/status/skip_step_status_test.py new file mode 100644 index 00000000..78dd10ea --- /dev/null +++ b/tests/allure_pytest/acceptance/status/skip_step_status_test.py @@ -0,0 +1,41 @@ +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_step +from allure_commons_test.result import with_status +from allure_commons_test.result import has_status_details +from allure_commons_test.result import with_message_contains +from allure_commons_test.result import with_trace_contains + + +def test_skip_in_step(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + >>> import allure + + >>> def test_skip_in_step_example(): + ... with allure.step("Step"): + ... pytest.skip() + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_skip_in_step_example", + with_status("skipped"), + has_status_details( + with_message_contains("Skipped") + ), + has_step( + "Step", + with_status("skipped"), + has_status_details( + with_message_contains("Skipped"), + with_trace_contains("test_skip_in_step") + ) + ) + ) + ) diff --git a/allure-pytest/test/acceptance/status/skip_teardown_status_test.py b/tests/allure_pytest/acceptance/status/skip_teardown_status_test.py similarity index 83% rename from allure-pytest/test/acceptance/status/skip_teardown_status_test.py rename to tests/allure_pytest/acceptance/status/skip_teardown_status_test.py index 0ec758ce..531056c1 100644 --- a/allure-pytest/test/acceptance/status/skip_teardown_status_test.py +++ b/tests/allure_pytest/acceptance/status/skip_teardown_status_test.py @@ -1,4 +1,6 @@ from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + from allure_commons_test.report import has_test_case from allure_commons_test.result import with_status from allure_commons_test.result import has_status_details @@ -8,7 +10,7 @@ from allure_commons_test.container import has_after -def test_skip_finalizer_fixture(executed_docstring_source): +def test_skip_finalizer_fixture(allure_pytest_runner: AllurePytestRunner): """ >>> import pytest @@ -22,13 +24,15 @@ def test_skip_finalizer_fixture(executed_docstring_source): ... pass """ + allure_results = allure_pytest_runner.run_docstring() + assert_that( - executed_docstring_source.allure_report, + allure_results, has_test_case( "test_skip_finalizer_fixture_example", with_status("passed"), has_container( - executed_docstring_source.allure_report, + allure_results, has_after( "skip_finalizer_fixture::fixture_finalizer", with_status("skipped"), diff --git a/tests/allure_pytest/acceptance/status/xfail_call_status_test.py b/tests/allure_pytest/acceptance/status/xfail_call_status_test.py new file mode 100644 index 00000000..88b17689 --- /dev/null +++ b/tests/allure_pytest/acceptance/status/xfail_call_status_test.py @@ -0,0 +1,142 @@ +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status +from allure_commons_test.result import has_status_details +from allure_commons_test.result import with_message_contains +from allure_commons_test.result import with_trace_contains + + +def test_xfail(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.mark.xfail() + ... def test_xfail_example(): + ... assert False + + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_xfail_example", + with_status("skipped"), + has_status_details( + with_message_contains("XFAIL"), + with_message_contains("AssertionError"), + with_trace_contains("def test_xfail_example():") + ) + ) + ) + + +def test_xfail_with_reason_raise_mentioned_exception( + allure_pytest_runner: AllurePytestRunner +): + """ + >>> import pytest + + >>> @pytest.mark.xfail(raises=AssertionError, reason='Some reason') + ... def test_xfail_with_reason_raise_mentioned_exception_example(): + ... assert False + + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_xfail_with_reason_raise_mentioned_exception_example", + with_status("skipped"), + has_status_details( + with_message_contains("XFAIL Some reason"), + with_message_contains("AssertionError"), + with_trace_contains( + "def test_xfail_with_reason_raise_mentioned_exception_example():" + ) + ) + ) + ) + + +def test_xfail_raise_not_mentioned_exception( + allure_pytest_runner: AllurePytestRunner +): + """ + >>> import pytest + + >>> @pytest.mark.xfail(raises=AssertionError) + ... def test_xfail_raise_not_mentioned_exception_example(): + ... raise ZeroDivisionError + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_xfail_raise_not_mentioned_exception_example", + with_status("broken"), + has_status_details( + with_message_contains("ZeroDivisionError"), + with_trace_contains( + "def test_xfail_raise_not_mentioned_exception_example():" + ) + ) + ) + ) + + +def test_xfail_do_not_raise_mentioned_exception( + allure_pytest_runner: AllurePytestRunner +): + """ + >>> import pytest + + >>> @pytest.mark.xfail(raises=AssertionError) + ... def test_xfail_do_not_raise_mentioned_exception_example(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_xfail_do_not_raise_mentioned_exception_example", + with_status("passed"), + has_status_details( + with_message_contains("XPASS"), + ) + ) + ) + + +def test_xfail_with_reason_do_not_raise_mentioned_exception( + allure_pytest_runner: AllurePytestRunner +): + """ + >>> import pytest + + >>> @pytest.mark.xfail(raises=AssertionError, reason="Some reason") + ... def test_xfail_with_reason_do_not_raise_mentioned_exception_example(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_xfail_with_reason_do_not_raise_mentioned_exception_example", + with_status("passed"), + has_status_details( + with_message_contains("XPASS Some reason"), + ) + ) + ) diff --git a/tests/allure_pytest/acceptance/status/xfail_setup_status_test.py b/tests/allure_pytest/acceptance/status/xfail_setup_status_test.py new file mode 100644 index 00000000..97006842 --- /dev/null +++ b/tests/allure_pytest/acceptance/status/xfail_setup_status_test.py @@ -0,0 +1,95 @@ +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status +from allure_commons_test.result import has_status_details +from allure_commons_test.result import with_message_contains +from allure_commons_test.result import with_trace_contains +from allure_commons_test.container import has_container +from allure_commons_test.container import has_before + + +def test_xfail_with_run_false(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.mark.xfail(run=False) + ... def test_xfail_with_run_false_example(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_xfail_with_run_false_example", + with_status("skipped"), + has_status_details( + with_message_contains("Failed: [NOTRUN]") + ) + ) + ) + + +def test_xfail_with_run_false_and_with_reason(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.mark.xfail(run=False, reason="Some reason") + ... def test_xfail_with_run_false_and_with_reason_example(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_xfail_with_run_false_and_with_reason_example", + with_status("skipped"), + has_status_details( + with_message_contains("Failed: [NOTRUN] Some reason") + ) + ) + ) + + +def test_xfail_fixture(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + + >>> @pytest.fixture + ... def broken_fixture(): + ... raise NotImplementedError + + >>> @pytest.mark.xfail() + ... def test_xfail_fixture_example(broken_fixture): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_xfail_fixture_example", + with_status("skipped"), + has_status_details( + with_message_contains("NotImplementedError"), + with_trace_contains("def broken_fixture():") + ), + has_container( + allure_results, + has_before( + "broken_fixture", + with_status("broken"), + has_status_details( + with_message_contains("NotImplementedError"), + with_trace_contains("broken_fixture") + ), + ), + ) + ) + ) diff --git a/tests/allure_pytest/acceptance/status/xfail_step_status_test.py b/tests/allure_pytest/acceptance/status/xfail_step_status_test.py new file mode 100644 index 00000000..1ea66511 --- /dev/null +++ b/tests/allure_pytest/acceptance/status/xfail_step_status_test.py @@ -0,0 +1,43 @@ +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_step +from allure_commons_test.result import with_status +from allure_commons_test.result import has_status_details +from allure_commons_test.result import with_message_contains +from allure_commons_test.result import with_trace_contains + + +def test_xfail_step_failure(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + >>> import allure + + >>> @pytest.mark.xfail() + ... def test_xfail_step_failure_example(): + ... with allure.step("Step"): + ... assert False + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_xfail_step_failure_example", + with_status("skipped"), + has_status_details( + with_message_contains("AssertionError"), + with_trace_contains("def test_xfail_step_failure_example():") + ), + has_step( + "Step", + with_status("failed"), + has_status_details( + with_message_contains("AssertionError"), + with_trace_contains("test_xfail_step_failure_example") + ) + ) + ) + ) diff --git a/allure-pytest/test/acceptance/status/xfail_teardown_status_test.py b/tests/allure_pytest/acceptance/status/xfail_teardown_status_test.py similarity index 84% rename from allure-pytest/test/acceptance/status/xfail_teardown_status_test.py rename to tests/allure_pytest/acceptance/status/xfail_teardown_status_test.py index 0b295c06..23b3bf03 100644 --- a/allure-pytest/test/acceptance/status/xfail_teardown_status_test.py +++ b/tests/allure_pytest/acceptance/status/xfail_teardown_status_test.py @@ -1,4 +1,6 @@ from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + from allure_commons_test.report import has_test_case from allure_commons_test.result import with_status from allure_commons_test.result import has_status_details @@ -8,7 +10,7 @@ from allure_commons_test.container import has_after -def test_xfail_failed_finalizer_fixture(executed_docstring_source): +def test_xfail_failed_finalizer_fixture(allure_pytest_runner: AllurePytestRunner): """ >>> import pytest @@ -23,8 +25,10 @@ def test_xfail_failed_finalizer_fixture(executed_docstring_source): ... pass """ + allure_results = allure_pytest_runner.run_docstring() + assert_that( - executed_docstring_source.allure_report, + allure_results, has_test_case( "test_xfail_failed_finalizer_fixture_example", with_status("passed"), @@ -32,7 +36,7 @@ def test_xfail_failed_finalizer_fixture(executed_docstring_source): with_message_contains("XPASS") ), has_container( - executed_docstring_source.allure_report, + allure_results, has_after( "failed_finalizer_fixture::fixture_finalizer", with_status("failed"), diff --git a/tests/allure_pytest/acceptance/step/__init__.py b/tests/allure_pytest/acceptance/step/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_pytest/acceptance/step/outside_step_test.py b/tests/allure_pytest/acceptance/step/outside_step_test.py new file mode 100644 index 00000000..e6cb2e78 --- /dev/null +++ b/tests/allure_pytest/acceptance/step/outside_step_test.py @@ -0,0 +1,106 @@ +import allure +from hamcrest import assert_that, not_ +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_step +from allure_commons_test.container import has_container +from allure_commons_test.container import has_before + + +def test_step_from_init_py(allure_pytest_runner: AllurePytestRunner): + allure_pytest_runner.pytester.makepyfile(__init__=( + """ + import allure + + @allure.step("function in __init__ marked as step") + def step_from__init__(): + pass + """ + )) + + allure_results = allure_pytest_runner.run_pytest( + """ + from . import step_from__init__ + + def test_step_from_init_py_example(): + step_from__init__() + """ + ) + + assert_that( + allure_results, + has_test_case( + "test_step_from_init_py_example", + has_step("function in __init__ marked as step") + ) + ) + + +def test_fixture_with_step_from_conftest(allure_pytest_runner: AllurePytestRunner): + conftest_content = ( + """ + import allure + import pytest + + @allure.step("step in conftest.py") + def conftest_step(): + pass + + + @pytest.fixture + def fixture_with_conftest_step(): + conftest_step() + """ + ) + + testfile_content = ( + """ + def test_fixture_with_step_from_conftest_example(fixture_with_conftest_step): + pass + """ + ) + + allure_results = allure_pytest_runner.run_pytest( + testfile_content, + conftest_literal=conftest_content + ) + + assert_that( + allure_results, + has_test_case( + "test_fixture_with_step_from_conftest_example", + has_container( + allure_results, + has_before( + "fixture_with_conftest_step", + has_step("step in conftest.py") + ) + ) + ) + ) + + +@allure.issue("232") +def test_call_decorated_as_step_function(allure_pytest_runner: AllurePytestRunner): + """ + >>> import allure + + >>> with allure.step("step outside"): + ... pass + + >>> def test_call_decorated_as_step_function_example(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_call_decorated_as_step_function_example", + not_( + has_step("step outside") + ) + ) + ) diff --git a/tests/allure_pytest/acceptance/step/step_parameters_test.py b/tests/allure_pytest/acceptance/step/step_parameters_test.py new file mode 100644 index 00000000..98c9b6b6 --- /dev/null +++ b/tests/allure_pytest/acceptance/step/step_parameters_test.py @@ -0,0 +1,42 @@ +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_step +from allure_commons_test.result import has_parameter + + +def test_step_parameters(allure_pytest_runner: AllurePytestRunner): + """ + >>> import pytest + >>> import allure + + >>> @allure.step + ... def step(arg, kwarg=None): + ... pass + + >>> @pytest.mark.parametrize( + ... ["args", "kwargs"], + ... [ + ... ([True], {"kwarg": False}), + ... (["hi"], {"kwarg": None}), + ... ([None], {"kwarg": 42}) + ... ] + ... ) + ... def test_step_parameters(args, kwargs): + ... step(*args, **kwargs) + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_step_parameters[args0-kwargs0]", + has_step( + "step", + has_parameter("arg", "True"), + has_parameter("kwarg", "False") + ) + ) + ) diff --git a/tests/allure_pytest/acceptance/step/step_placeholder_test.py b/tests/allure_pytest/acceptance/step/step_placeholder_test.py new file mode 100644 index 00000000..7f93b175 --- /dev/null +++ b/tests/allure_pytest/acceptance/step/step_placeholder_test.py @@ -0,0 +1,72 @@ +""" ./allure-pytest/examples/step/step_placeholder.rst """ + +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_step +from allure_commons_test.result import has_status_details +from allure_commons_test.result import with_status +from allure_commons_test.result import with_message_contains + + +def test_step_with_args_in_placeholder(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_step_with_args_in_placeholder", + has_step("Step with two args: 'first' and 'second'") + ) + ) + + +def test_step_with_kwargs_in_placeholder(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_step_with_kwargs_in_placeholder", + has_step("Step with two kwargs: '1' and 'second'") + ) + ) + + +def test_class_method_as_step(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_class_method_as_step", + has_step("Class method step with 'first' and 'second'") + ) + ) + + +def test_args_less_than_placeholders(allure_pytest_runner: AllurePytestRunner): + """ + >>> import allure + + >>> @allure.step("{0} and {1}") + ... def step(arg): + ... pass + + >>> def test_args_less_than_placeholders_example(): + ... step(0) + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_args_less_than_placeholders_example", + with_status("broken"), + has_status_details( + with_message_contains("IndexError") + ) + ) + ) diff --git a/tests/allure_pytest/acceptance/step/step_test.py b/tests/allure_pytest/acceptance/step/step_test.py new file mode 100644 index 00000000..9addf92c --- /dev/null +++ b/tests/allure_pytest/acceptance/step/step_test.py @@ -0,0 +1,61 @@ +""" ./allure-pytest/examples/step/step.rst """ + +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_step + + +def test_inline_step(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_inline_step", + has_step("inline step") + ) + ) + + +def test_reusable_step(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_reusable_step", + has_step("passed_step") + ) + ) + + +def test_nested_steps(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_nested_steps", + has_step( + "grand parent step", + has_step( + "parent step", + has_step("passed_step") + ) + ) + ) + ) + + +def test_class_method_as_step(allure_pytest_runner: AllurePytestRunner): + allure_results = allure_pytest_runner.run_docpath_examples(cache=True) + + assert_that( + allure_results, + has_test_case( + "test_class_method_as_step", + has_step("class method as step") + ) + ) diff --git a/tests/allure_pytest/acceptance/step/test_step_with_several_step_inside_thread.py b/tests/allure_pytest/acceptance/step/test_step_with_several_step_inside_thread.py new file mode 100644 index 00000000..88304eee --- /dev/null +++ b/tests/allure_pytest/acceptance/step/test_step_with_several_step_inside_thread.py @@ -0,0 +1,86 @@ +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_step + + +def test_step_with_thread(allure_pytest_runner: AllurePytestRunner): + """ + >>> from concurrent.futures import ThreadPoolExecutor + >>> import allure + + >>> @allure.step("thread {x}") + ... def parallel_step(x=1): + ... with allure.step("Sub-step in thread"): + ... pass + + >>> def test_thread(): + ... with allure.step("Start in thread"): + ... with ThreadPoolExecutor(max_workers=2) as executor: + ... executor.map(parallel_step, [1, 2]) + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_thread", + has_step( + "Start in thread", + has_step( + "thread 1", + has_step("Sub-step in thread") + ), + has_step("thread 2") + ) + ) + ) + + +def test_step_with_reused_threads(allure_pytest_runner: AllurePytestRunner): + """ + >>> from concurrent.futures import ThreadPoolExecutor + >>> from threading import Event + >>> from random import shuffle + >>> from time import sleep + >>> import allure + + >>> def parallel_step(data): + ... event, index = data + ... with allure.step(f"thread {index}"): + ... event.wait() + + >>> def __execute_randomly(executor): + ... events = [Event() for i in range(1, 4)] + ... executor.map(parallel_step, zip(events, range(1, 4))) + ... shuffle(events) + ... for e in events: + ... e.set() + + >>> def test_thread(): + ... with ThreadPoolExecutor(max_workers=2) as executor: + ... __execute_randomly(executor) + ... with allure.step("Reuse previous threads"): + ... with ThreadPoolExecutor(max_workers=2) as executor: + ... __execute_randomly(executor) + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_thread", + has_step("thread 1"), + has_step("thread 2"), + has_step("thread 3"), + has_step( + "Reuse previous threads", + has_step("thread 1"), + has_step("thread 2"), + has_step("thread 3"), + ) + ) + ) diff --git a/tests/allure_pytest/acceptance/testplan/select_test_from_testplan_test.py b/tests/allure_pytest/acceptance/testplan/select_test_from_testplan_test.py new file mode 100644 index 00000000..bb8679a4 --- /dev/null +++ b/tests/allure_pytest/acceptance/testplan/select_test_from_testplan_test.py @@ -0,0 +1,116 @@ +import pytest +from hamcrest import assert_that, contains_inanyorder, ends_with +from tests.allure_pytest.pytest_runner import AllurePytestRunner + + +@pytest.mark.parametrize( + ["testplan", "expected_tests"], + [ + pytest.param( + {"tests": [{"id": 1}, {"id": 2}]}, + ["test_number_one", "test_number_two"], + id="ids-only" + ), + + pytest.param( + {"tests": [{"id": 1}, {"id": 3}, {"id": 4}]}, + ["test_number_one", "test_number_three"], + id="id-for-test-with-two-ids" + ), + + pytest.param( + {"tests": [{"id": 1234}]}, + [], + id="id-nomatch" + ), + + pytest.param( + {"tests": [ + {"selector": "testplan_test#test_number_one"}, + {"selector": "testplan_test#test_number_three"} + ]}, + ["test_number_one", "test_number_three"], + id="selectors-only" + ), + + pytest.param( + {"tests": [{"selector": "testplan_test#test_without_number"}]}, + ["test_without_number"], + id="selector-for-test-with-noid" + ), + + pytest.param( + {"tests": [{"id": 2, "selector": "testplan_test#test_number_two"}]}, + ["test_number_two"], + id="id-selector-same-test" + ), + + pytest.param( + {"tests": [{"selector": "testplan_test#test_without_never"}]}, + [], + id="selector-nomatch" + ), + + pytest.param( + {"tests": []}, + [ + "test_number_one", + "test_number_two", + "test_number_three", + "test_without_number" + ], + id="no-tests-in-plan" + ), + + pytest.param( + {}, + [ + "test_number_one", + "test_number_two", + "test_number_three", + "test_without_number" + ], + id="empty-plan" + ) + ] +) +def test_select_by_testcase_id_test( + allure_pytest_runner: AllurePytestRunner, + testplan, + expected_tests +): + """ + >>> import allure + + >>> @allure.id("1") + ... def test_number_one(): + ... pass + + >>> @allure.id("2") + ... def test_number_two(): + ... pass + + >>> @allure.id("3") + ... @allure.id("4") + ... def test_number_three(): + ... pass + + >>> def test_without_number(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring( + filename="testplan_test", + testplan=testplan + ) + + executed_full_names = [ + tc["fullName"] for tc in allure_results.test_cases + ] + + assert_that( + executed_full_names, + contains_inanyorder( + * [ends_with(name) for name in expected_tests] + ) + ) diff --git a/tests/allure_pytest/conftest.py b/tests/allure_pytest/conftest.py new file mode 100644 index 00000000..d179255b --- /dev/null +++ b/tests/allure_pytest/conftest.py @@ -0,0 +1,7 @@ +from pytest import fixture +from .pytest_runner import AllurePytestRunner + + +@fixture +def allure_pytest_runner(request, pytester): + yield AllurePytestRunner(request, pytester) diff --git a/tests/allure_pytest/externals/__init__.py b/tests/allure_pytest/externals/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_pytest/externals/pytest_check/__init__.py b/tests/allure_pytest/externals/pytest_check/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_pytest/externals/pytest_check/pytest_check_test.py b/tests/allure_pytest/externals/pytest_check/pytest_check_test.py new file mode 100644 index 00000000..d569fb5f --- /dev/null +++ b/tests/allure_pytest/externals/pytest_check/pytest_check_test.py @@ -0,0 +1,38 @@ +import pytest +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +import allure +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status, with_message_contains, has_status_details + + +@pytest.fixture +def check_runner(allure_pytest_runner: AllurePytestRunner): + allure_pytest_runner.enable_plugins("check") + yield allure_pytest_runner + + +@allure.issue("376") +@allure.feature("Integration") +def test_pytest_check(check_runner: AllurePytestRunner): + """ + >>> import pytest_check as check + >>> def test_pytest_check_example(): + ... check.equal(1, 2, msg="First failure") + ... check.equal(1, 2, msg="Second failure") + """ + + output = check_runner.run_docstring() + + assert_that( + output, + has_test_case( + "test_pytest_check_example", + with_status("failed"), + has_status_details( + with_message_contains("First failure"), + with_message_contains("Second failure") + ) + ) + ) diff --git a/tests/allure_pytest/externals/pytest_doctest/__init__.py b/tests/allure_pytest/externals/pytest_doctest/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_pytest/externals/pytest_doctest/pytest_doctest_test.py b/tests/allure_pytest/externals/pytest_doctest/pytest_doctest_test.py new file mode 100644 index 00000000..92945cba --- /dev/null +++ b/tests/allure_pytest/externals/pytest_doctest/pytest_doctest_test.py @@ -0,0 +1,63 @@ +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +import allure +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status + + +@allure.feature("Integration") +def test_pytest_doctest(allure_pytest_runner: AllurePytestRunner): + """ + >>> def some_func(): + ... ''' + ... >>> some_func() + ... True + ... ''' + ... return True + + """ + + output = allure_pytest_runner.run_docstring("--doctest-modules") + + assert_that(output, has_test_case( + "test_pytest_doctest.some_func", + with_status("passed") + )) + + +@allure.feature("Integration") +def test_pytest_doctest_failed(allure_pytest_runner: AllurePytestRunner): + """ + >>> def some_func(): + ... ''' + ... >>> some_func() + ... True + ... ''' + ... return not True + + """ + + output = allure_pytest_runner.run_docstring("--doctest-modules") + + assert_that(output, has_test_case( + "test_pytest_doctest_failed.some_func", + with_status("failed") + )) + + +@allure.feature("Integration") +def test_pytest_doctest_broken(allure_pytest_runner: AllurePytestRunner): + """ + >>> def some_func(): + ... ''' + ... >>> raise ValueError() + ... ''' + """ + + output = allure_pytest_runner.run_docstring("--doctest-modules") + + assert_that(output, has_test_case( + "test_pytest_doctest_broken.some_func", + with_status("broken") + )) diff --git a/tests/allure_pytest/externals/pytest_flakes/__init__.py b/tests/allure_pytest/externals/pytest_flakes/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_pytest/externals/pytest_flakes/pytest_flakes_test.py b/tests/allure_pytest/externals/pytest_flakes/pytest_flakes_test.py new file mode 100644 index 00000000..7358b660 --- /dev/null +++ b/tests/allure_pytest/externals/pytest_flakes/pytest_flakes_test.py @@ -0,0 +1,35 @@ +import pytest +from hamcrest import assert_that, all_of +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +import allure +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status + + +@pytest.fixture +def flakes_runner(allure_pytest_runner: AllurePytestRunner): + allure_pytest_runner.enable_plugins("flakes") + yield allure_pytest_runner + + +@allure.issue("352") +def test_pytest_flakes(flakes_runner: AllurePytestRunner): + """ + >>> from os.path import * + >>> def test_pytest_flakes_example(): + ... assert True + """ + + output = flakes_runner.run_docstring("--flakes") + + assert_that(output, all_of( + has_test_case( + "flake-8", + with_status("broken") + ), + has_test_case( + "test_pytest_flakes_example", + with_status("passed") + ) + )) diff --git a/tests/allure_pytest/externals/pytest_lazy_fixture/__init__.py b/tests/allure_pytest/externals/pytest_lazy_fixture/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/allure-pytest/test/integration/pytest_lazy_fixture/pytest_lazy_fixture_test.py b/tests/allure_pytest/externals/pytest_lazy_fixture/pytest_lazy_fixture_test.py similarity index 50% rename from allure-pytest/test/integration/pytest_lazy_fixture/pytest_lazy_fixture_test.py rename to tests/allure_pytest/externals/pytest_lazy_fixture/pytest_lazy_fixture_test.py index 809107a2..cdb3bb08 100644 --- a/allure-pytest/test/integration/pytest_lazy_fixture/pytest_lazy_fixture_test.py +++ b/tests/allure_pytest/externals/pytest_lazy_fixture/pytest_lazy_fixture_test.py @@ -1,12 +1,21 @@ -import allure +import pytest from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +import allure from allure_commons_test.report import has_test_case from allure_commons_test.container import has_container from allure_commons_test.container import has_before +@pytest.fixture +def lazy_fixture_runner(allure_pytest_runner: AllurePytestRunner): + allure_pytest_runner.enable_plugins("lazy-fixture") + yield allure_pytest_runner + + @allure.feature("Integration") -def test_lazy_fixture(executed_docstring_source): +def test_lazy_fixture(lazy_fixture_runner: AllurePytestRunner): """ >>> import pytest ... from pytest_lazyfixture import lazy_fixture @@ -20,17 +29,22 @@ def test_lazy_fixture(executed_docstring_source): ... pass """ - assert_that(executed_docstring_source.allure_report, - has_test_case("test_lazy_fixture_example", - has_container(executed_docstring_source.allure_report, - has_before("my_lazy_fixture") - ), - ) - ) + output = lazy_fixture_runner.run_docstring() + + assert_that( + output, + has_test_case( + "test_lazy_fixture_example", + has_container( + output, + has_before("my_lazy_fixture") + ) + ) + ) @allure.feature("Integration") -def test_nested_lazy_fixture(executed_docstring_source): +def test_nested_lazy_fixture(lazy_fixture_runner: AllurePytestRunner): """ >>> import pytest ... from pytest_lazyfixture import lazy_fixture @@ -47,10 +61,15 @@ def test_nested_lazy_fixture(executed_docstring_source): ... pass """ - assert_that(executed_docstring_source.allure_report, - has_test_case("test_nested_lazy_fixture_example", - has_container(executed_docstring_source.allure_report, - has_before("my_lazy_fixture") - ), - ) - ) + output = lazy_fixture_runner.run_docstring() + + assert_that( + output, + has_test_case( + "test_nested_lazy_fixture_example", + has_container( + output, + has_before("my_lazy_fixture") + ) + ) + ) diff --git a/tests/allure_pytest/externals/pytest_rerunfailures/__init__.py b/tests/allure_pytest/externals/pytest_rerunfailures/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_pytest/externals/pytest_rerunfailures/pytest_rerunfailures_test.py b/tests/allure_pytest/externals/pytest_rerunfailures/pytest_rerunfailures_test.py new file mode 100644 index 00000000..f2611788 --- /dev/null +++ b/tests/allure_pytest/externals/pytest_rerunfailures/pytest_rerunfailures_test.py @@ -0,0 +1,43 @@ +import pytest +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +import allure +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status + + +@pytest.fixture +def rerunfailures_runner(allure_pytest_runner: AllurePytestRunner): + allure_pytest_runner.enable_plugins("rerunfailures") + yield allure_pytest_runner + + +@allure.issue("140") +@allure.feature("Integration") +@pytest.mark.parametrize("countdown, status", [(2, "failed"), (4, "passed")]) +def test_pytest_rerunfailures( + rerunfailures_runner: AllurePytestRunner, + countdown, + status +): + testfile_content = ( + f""" + import pytest + + @pytest.mark.flaky(reruns={countdown}) + def test_pytest_rerunfailures_example(request): + run = request.node.execution_count + assert run == 4 + """ + ) + + output = rerunfailures_runner.run_pytest(testfile_content) + + assert_that( + output, + has_test_case( + "test_pytest_rerunfailures_example", + with_status(status) + ) + ) diff --git a/tests/allure_pytest/externals/pytest_xdist/__init__.py b/tests/allure_pytest/externals/pytest_xdist/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_pytest/externals/pytest_xdist/pytest_xdist_select_test.py b/tests/allure_pytest/externals/pytest_xdist/pytest_xdist_select_test.py new file mode 100644 index 00000000..d9984fc1 --- /dev/null +++ b/tests/allure_pytest/externals/pytest_xdist/pytest_xdist_select_test.py @@ -0,0 +1,39 @@ +import pytest +from hamcrest import assert_that, ends_with, has_entry +from tests.allure_pytest.pytest_runner import AllurePytestRunner + +import allure +from allure_commons_test.report import has_only_testcases + + +@pytest.fixture +def xdist_runner(allure_pytest_runner: AllurePytestRunner): + allure_pytest_runner.in_memory = False + allure_pytest_runner.enable_plugins("xdist") + yield allure_pytest_runner + + +@allure.issue("292") +@allure.feature("Integration") +def test_xdist_and_select_test_by_bdd_label(xdist_runner: AllurePytestRunner): + """ + >>> import pytest + >>> import allure + + >>> @pytest.mark.foo + ... def test_with_mark_foo(): + ... print ("hello") + + >>> @allure.feature("boo") + ... def test_with_feature_boo(): + ... print ("hello") + """ + + output = xdist_runner.run_docstring("-v", "--allure-features=boo", "-n1") + + assert_that(output, has_only_testcases( + has_entry( + "fullName", + ends_with("test_with_feature_boo") + ) + )) diff --git a/tests/allure_pytest/pytest_runner.py b/tests/allure_pytest/pytest_runner.py new file mode 100644 index 00000000..334b09dc --- /dev/null +++ b/tests/allure_pytest/pytest_runner.py @@ -0,0 +1,209 @@ +from doctest import script_from_examples +from pathlib import Path +from pytest import FixtureRequest, Pytester, StashKey +from tests.e2e import AllureFrameworkRunner, altered_env, PathlikeT +from typing import Sequence, Tuple, Union + +from allure_commons.logger import AllureMemoryLogger + + +class AllurePytestRunner(AllureFrameworkRunner): + """A runner for allure_pytest integration. + + Note: + Automatic plugin loading is disabled for all test runs initiated using + an instance of this class. If you need to test allure compatibility with + some pytest plugin, use :method:`AllurePytestRunner` or + :method:`AllurePytestRunner` to explicitly request its loading. + + """ + + LOGGER_PATH = "allure_pytest.plugin.AllureFileLogger" + DOCTEST_RESULT_KEY = StashKey() + + def __init__(self, request: FixtureRequest, pytester: Pytester): + self.logger_path = AllurePytestRunner.LOGGER_PATH + super().__init__(request, pytester) + self.select_plugins("allure_pytest") + + def enable_plugins(self, *plugins: str) -> None: + """Request loading of pytest plugins on subsequent runs. Those plugins + are added into the list of the previously requested ones. + + """ + + self.enabled_plugins.update(plugins) + + def select_plugins(self, *plugins: str) -> None: + """Request loading of pytest plugins on subsequent runs. All other + plugins will not be loaded. + + Note: + Don't forget to add an allure integration plugin as well (i.e., + allure_pytest). + + """ + + self.enabled_plugins = set(plugins) + + def run_docstring( + self, + *cli_args: str, + filename: PathlikeT = None, + testplan: dict = None + ) -> AllureMemoryLogger: + """Runs a doctest from a docstring of the current test node (or one of its + parents). + + Arguments: + *cli_args (str): pytest CLI arguments + + Keyword Arguments: + filename (str | Path): an optional file name where the doctest is + saved before pytest is run. This should be a relative name. + testplan (dict): an optional allure testplan data. + + Returns: + allure_commons.logger.AllureMemoryLogger: allure results that were + collected during the test run. + """ + docstring = self._find_docstring() + testfile_content = script_from_examples(docstring) + return self.run_pytest( + (filename, testfile_content), + cli_args=cli_args, + testplan=testplan + ) + + def run_docpath_examples( + self, + *cli_args: str, + filename: PathlikeT = None, + testplan: dict = None, + cache: bool = False + ) -> AllureMemoryLogger: + """Runs a doctest from a document denoted by a path in docstring of + the current test node (or one of its parents). + + If the path is relative, it is prepended with the rootdir. + + Arguments: + *cli_args (str): pytest CLI arguments. + + Keyword Arguments: + filename (str | Path): an optional file name where the doctest is + saved before pytest is run. This should be a relative name. + testplan (dict): an optional allure testplan data. + cache (bool): set this flag if the allure results should be cached + on a node which docstring was originally used as the path. This + improves the performance if you have multiple tests on the same + document. Be careful though, this may lead to unexpected results + if the tests are relied upon different environments (i.e., the + CLI arguments are different). Only one run can be cached for + any given test. + + Returns: + allure_commons.logger.AllureMemoryLogger: allure results that were + collected during the test run. + """ + + if cache: + return self._cache_docstring_test_result( + AllurePytestRunner.DOCTEST_RESULT_KEY, + self.__test_docpath_examples, + filename, + cli_args, + testplan + ) + return self.__test_docpath_examples( + filename=filename, + cli_args=cli_args, + testplan=testplan, + docpath=self._find_docstring() + ) + + def run_pytest( + self, + *testfile_literals: Union[str, Tuple[PathlikeT, str]], + conftest_literal: str = None, + cli_args: Sequence[str] = None, + testplan: dict = None + ) -> AllureMemoryLogger: + """Runs a nested pytest session in an isolated allure context. + + Arguments: + *testfile_literals (str | Tuple[str | Path, str]): test files to + run. Each test file is represented either as a content string or + as a tuple of a path and a string. The path should be relative + to the pytester's path. + + Keyword arguments: + conftest_literal (str): an optional conftest.py content. + cli_args (Sequence[str]): pytest CLI arguments. + testplan (dict): an optional allure testplan data. + + Returns: + allure_commons.logger.AllureMemoryLogger: allure results that were + collected during the test run. + """ + + if conftest_literal: + self.pytester.makeconftest(conftest_literal) + if cli_args is None: + cli_args = () + plugin_args = self.__iter_plugin_args() + pytest_args = [ + "--alluredir", + self.pytester.path, + *plugin_args, + *cli_args + ] + self.__generate_testfiles(testfile_literals) + return self._run( + pytest_args, + testplan_content=testplan, + logger_path=self.logger_path + ) + + def _run_framework(self, options): + with altered_env(PYTEST_DISABLE_PLUGIN_AUTOLOAD="true"): + self.pytester.runpytest(*options) + + def __generate_testfiles(self, testfiles): + for testfile in testfiles: + filepath = None + content = testfile + if not isinstance(testfile, str): + filepath, content = testfile + if filepath: + extension = Path(filepath).suffix or ".py" + self.pytester.makefile( + extension, + **{str(filepath): content} + ) + else: + self.pytester.makepyfile(content) + + def __test_docpath_examples( + self, + filename, + cli_args, + testplan, + docpath, + ): + docpath = docpath.strip() + doc_content = self._read_file(docpath, self.request.config.rootpath) + testfile_content = script_from_examples(doc_content) + return self.run_pytest( + (filename, testfile_content), + cli_args=cli_args, + testplan=testplan + ) + + def __iter_plugin_args(self): + for plugin_package in self.enabled_plugins: + yield "-p" + yield plugin_package + + +__all__ = ["AllurePytestRunner"] diff --git a/tests/allure_pytest_bdd/__init__.py b/tests/allure_pytest_bdd/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_pytest_bdd/acceptance/__init__.py b/tests/allure_pytest_bdd/acceptance/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_pytest_bdd/acceptance/scenario_outline_test.py b/tests/allure_pytest_bdd/acceptance/scenario_outline_test.py new file mode 100644 index 00000000..ccf20611 --- /dev/null +++ b/tests/allure_pytest_bdd/acceptance/scenario_outline_test.py @@ -0,0 +1,76 @@ +""" ./allure-pytest-bdd/examples/scenario-outline """ + +from hamcrest import assert_that, all_of +from tests.allure_pytest.pytest_runner import AllurePytestRunner +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status +from allure_commons_test.result import has_step +from allure_commons_test.result import has_parameter + + +def test_scenario_outline(allure_pytest_bdd_runner: AllurePytestRunner): + feature_content = ( + """ + Feature: Allure report for scenario outline + Scenario Outline: Two examples with two parameters each + Given first step for value + When something is done with the value + Then check postconditions using and + + Examples: + | first | second | + | Alpha | 1 | + | Bravo | 2 | + """ + ) + steps_content = ( + """ + from pytest_bdd import scenario, given, when, then + from pytest_bdd import parsers + + @scenario("outline.feature", "Two examples with two parameters each") + def test_scenario_outline(): + pass + + @given(parsers.parse("first step for {first} value")) + def given_first_step_for_first_value(first): + pass + + @when(parsers.parse("something is done with the value {second}")) + def when_something_is_done_with_the_value_second(second): + pass + + @then(parsers.parse("check postconditions using {first} and {second}")) + def then_check_postconditions_using_first_and_second(first, second): + pass + """ + ) + + output = allure_pytest_bdd_runner.run_pytest( + ("outline.feature", feature_content), + steps_content, + ) + + assert_that( + output, + all_of( + has_test_case( + "Two examples with two parameters each", + with_status("passed"), + has_step("Given first step for Alpha value"), + has_step("When something is done with the value 1"), + has_step("Then check postconditions using Alpha and 1"), + has_parameter("first", "Alpha"), + has_parameter("second", "1") + ), + has_test_case( + "Two examples with two parameters each", + with_status("passed"), + has_step("Given first step for Bravo value"), + has_step("When something is done with the value 2"), + has_step("Then check postconditions using Bravo and 2"), + has_parameter("first", "Bravo"), + has_parameter("second", "2") + ) + ) + ) diff --git a/tests/allure_pytest_bdd/acceptance/scenario_test.py b/tests/allure_pytest_bdd/acceptance/scenario_test.py new file mode 100644 index 00000000..a381f088 --- /dev/null +++ b/tests/allure_pytest_bdd/acceptance/scenario_test.py @@ -0,0 +1,58 @@ +""" ./allure-pytest-bdd/examples/simple-scenario """ + +from hamcrest import assert_that +from tests.allure_pytest.pytest_runner import AllurePytestRunner +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status +from allure_commons_test.result import has_step +from allure_commons_test.result import has_history_id + + +def test_simple_passed_scenario(allure_pytest_bdd_runner: AllurePytestRunner): + feature_content = ( + """ + Feature: Basic allure-pytest-bdd usage + Scenario: Simple passed example + Given the preconditions are satisfied + When the action is invoked + Then the postconditions are held + """ + ) + steps_content = ( + """ + from pytest_bdd import scenario, given, when, then + + @scenario("scenario.feature", "Simple passed example") + def test_scenario_passes(): + pass + + @given("the preconditions are satisfied") + def given_the_preconditions_are_satisfied(): + pass + + @when("the action is invoked") + def when_the_action_is_invoked(): + pass + + @then("the postconditions are held") + def then_the_postconditions_are_held(): + pass + """ + ) + + output = allure_pytest_bdd_runner.run_pytest( + ("scenario.feature", feature_content), + steps_content + ) + + assert_that( + output, + has_test_case( + "Simple passed example", + with_status("passed"), + has_step("Given the preconditions are satisfied"), + has_step("When the action is invoked"), + has_step("Then the postconditions are held"), + has_history_id() + ) + ) diff --git a/tests/allure_pytest_bdd/conftest.py b/tests/allure_pytest_bdd/conftest.py new file mode 100644 index 00000000..ba247cab --- /dev/null +++ b/tests/allure_pytest_bdd/conftest.py @@ -0,0 +1,10 @@ +import pytest +from tests.allure_pytest.pytest_runner import AllurePytestRunner + + +@pytest.fixture +def allure_pytest_bdd_runner(request, pytester): + runner = AllurePytestRunner(request, pytester) + runner.logger_path = "allure_pytest_bdd.plugin.AllureFileLogger" + runner.select_plugins("pytest-bdd", "allure_pytest_bdd") + yield runner diff --git a/tests/allure_robotframework/__init__.py b/tests/allure_robotframework/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_robotframework/acceptance/__init__.py b/tests/allure_robotframework/acceptance/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_robotframework/acceptance/allure_api/__init__.py b/tests/allure_robotframework/acceptance/allure_api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_robotframework/acceptance/allure_api/attachment/__init__.py b/tests/allure_robotframework/acceptance/allure_api/attachment/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_robotframework/acceptance/allure_api/attachment/attachment_test.py b/tests/allure_robotframework/acceptance/allure_api/attachment/attachment_test.py new file mode 100644 index 00000000..7f016402 --- /dev/null +++ b/tests/allure_robotframework/acceptance/allure_api/attachment/attachment_test.py @@ -0,0 +1,146 @@ +""" ./allure-robotframework/examples/attachment.rst """ + +from pytest import MonkeyPatch +from hamcrest import assert_that, equal_to +from tests.allure_robotframework.robot_runner import AllureRobotRunner +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_attachment_with_content +from allure_commons_test.result import has_step +from allure_commons_test.result import with_status + + +def test_data_attachment_with_default_name_and_type( + robot_runner: AllureRobotRunner +): + robot_runner.run_robotframework( + suite_rst_ids={"attach-data.robot": "data-attachment-default"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Attach-Data.Data Attachment", + has_step( + "AllureLibrary.Attach", + has_attachment_with_content( + robot_runner.allure_results.attachments, + equal_to( + "This attachment was created using the " + "allure_robotframework library" + ) + ) + ) + ) + ) + + +def test_data_attachment_with_name_and_type( + robot_runner: AllureRobotRunner +): + robot_runner.run_robotframework( + suite_rst_ids={"attach-data.robot": "data-attachment-name-type"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Attach-Data.Data Attachment", + has_step( + "AllureLibrary.Attach", + has_attachment_with_content( + robot_runner.allure_results.attachments, + equal_to( + "https://github.com/allure-framework/allure2 " + "https://github.com/allure-framework/allure-python" + ), + "text/uri-list", + "links" + ) + ) + ) + ) + + +def test_file_attachment_with_default_name_and_type( + robot_runner: AllureRobotRunner +): + robot_runner.run_robotframework( + suite_rst_ids={"attach-file.robot": "file-attachment-default"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Attach-File.File Attachment", + has_step( + "AllureLibrary.Attach File", + has_attachment_with_content( + robot_runner.allure_results.attachments, + equal_to("./my_file.txt") + ) + ) + ) + ) + + +def test_file_attachment_with_name_and_type( + robot_runner: AllureRobotRunner +): + robot_runner.run_robotframework( + suite_rst_ids={"attach-file.robot": "file-attachment-name-type"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Attach-File.File Attachment", + has_step( + "AllureLibrary.Attach File", + has_attachment_with_content( + robot_runner.allure_results.attachments, + equal_to("./my_file.txt"), + "text/plain", + "my-file" + ) + ) + ) + ) + + +def test_autoattach_wrapper( + robot_runner: AllureRobotRunner, + monkeypatch: MonkeyPatch +): + monkeypatch.syspath_prepend(".") + + robot_runner.run_robotframework( + suite_rst_ids={"selenium-wrapper.robot": "selenium-suite"}, + library_literals={ + "SeleniumLibrary": ( + """ + def open_browser(*_):pass + def capture_page_screenshot(*_):return "./screenshot.jpg" + def close_browser(*_):pass + """ + ) + }, + library_rst_ids={"selenium_wrapper": "selenium-wrapper"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Selenium-Wrapper.Automatic Screenshot Attachment", + with_status("passed"), + has_step( + "selenium_wrapper.Capture Page Screenshot", + with_status("passed"), + has_attachment_with_content( + robot_runner.allure_results.attachments, + equal_to("./screenshot.jpg"), + "image/jpg", + "page" + ) + ) + ) + ) diff --git a/tests/allure_robotframework/acceptance/allure_api/description/__init__.py b/tests/allure_robotframework/acceptance/allure_api/description/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_robotframework/acceptance/allure_api/description/description_test.py b/tests/allure_robotframework/acceptance/allure_api/description/description_test.py new file mode 100644 index 00000000..e3a8fb76 --- /dev/null +++ b/tests/allure_robotframework/acceptance/allure_api/description/description_test.py @@ -0,0 +1,61 @@ +""" ./allure-robotframework/examples/description.rst """ + +from hamcrest import assert_that +from tests.allure_robotframework.robot_runner import AllureRobotRunner +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_description + + +def test_single_line_description_from_setting( + robot_runner: AllureRobotRunner +): + robot_runner.run_robotframework( + suite_rst_ids={"description.robot": "setting-singleline-robot"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Description.Single line doc from the setting", + has_description( + "This documentation will appear as allure description" + ) + ) + ) + + +def test_miltiline_description_from_setting( + robot_runner: AllureRobotRunner +): + robot_runner.run_robotframework( + suite_rst_ids={"description.robot": "setting-multiline-robot"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Description.Multiline doc from the setting", + has_description( + "This documentation contains multiple lines of text.\n" + "It will also appear as allure description." + ) + ) + ) + + +def test_miltiline_description_from_keyword( + robot_runner: AllureRobotRunner +): + robot_runner.run_robotframework( + suite_rst_ids={"description.robot": "keyword-robot"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Description.Multiline doc from the keyword", + has_description( + "This documentation will appear as allure description." + ) + ) + ) diff --git a/tests/allure_robotframework/acceptance/allure_api/labels/__init__.py b/tests/allure_robotframework/acceptance/allure_api/labels/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_robotframework/acceptance/allure_api/labels/labels_test.py b/tests/allure_robotframework/acceptance/allure_api/labels/labels_test.py new file mode 100644 index 00000000..e5f1782d --- /dev/null +++ b/tests/allure_robotframework/acceptance/allure_api/labels/labels_test.py @@ -0,0 +1,73 @@ +""" ./allure-robotframework/examples/label.rst """ + +from allure import severity_level +from hamcrest import assert_that +from tests.allure_robotframework.robot_runner import AllureRobotRunner +from allure_commons_test.report import has_test_case +from allure_commons_test.label import has_label +from allure_commons_test.label import has_feature +from allure_commons_test.label import has_story +from allure_commons_test.label import has_severity +from allure_commons_test.label import has_suite + + +def test_custom_label_from_robot_tag(robot_runner: AllureRobotRunner): + robot_runner.run_robotframework( + suite_rst_ids={"labels.robot": "tag-custom-robot"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Labels.Test authored by John Doe", + has_label("author", "John Doe") + ) + ) + + +def test_builtin_label_from_robot_tag(robot_runner: AllureRobotRunner): + robot_runner.run_robotframework( + suite_rst_ids={"labels.robot": "tag-builtin-robot"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Labels.Test with the pinned ID", + has_label("as_id", "1008"), + has_story("RF tags as allure labels") + ) + ) + + +def test_robot_tag_from_settings(robot_runner: AllureRobotRunner): + robot_runner.run_robotframework( + suite_rst_ids={"labels.robot": "tag-setting-robot"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Labels.Test with two BDD-labels", + has_feature("Allure labels support"), + has_story("RF tags as allure labels") + ) + ) + + +def test_labels_from_test_library(robot_runner: AllureRobotRunner): + robot_runner.run_robotframework( + suite_rst_ids={"labels.robot": "code-labels-robot"}, + library_rst_ids={"my_library.py": "code-labels-library"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Labels.Test backend API", + has_label("layer", "API"), + has_severity(severity_level.CRITICAL), + has_label("endpoint", "localhost:443"), + has_suite("Testing API at localhost") + ) + ) diff --git a/tests/allure_robotframework/acceptance/allure_api/links/__init__.py b/tests/allure_robotframework/acceptance/allure_api/links/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_robotframework/acceptance/allure_api/links/links_test.py b/tests/allure_robotframework/acceptance/allure_api/links/links_test.py new file mode 100644 index 00000000..8bcac5c7 --- /dev/null +++ b/tests/allure_robotframework/acceptance/allure_api/links/links_test.py @@ -0,0 +1,142 @@ +""" ./allure-robotframework/examples/link.rst """ + +from hamcrest import assert_that +from tests.allure_robotframework.robot_runner import AllureRobotRunner +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_link +from allure_commons_test.result import has_issue_link +from allure_commons_test.result import has_test_case_link + + +def test_link_from_robot_tag(robot_runner: AllureRobotRunner): + robot_runner.run_robotframework( + suite_rst_ids={"links.robot": "tag-unnamed-robot"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Links.Allure Plain Link", + has_link( + "https://github.com/allure-framework/allure-python", + "link", + "https://github.com/allure-framework/allure-python" + ) + ) + ) + + +def test_named_link_from_robot_tag(robot_runner: AllureRobotRunner): + robot_runner.run_robotframework( + suite_rst_ids={"links.robot": "tag-named-robot"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Links.Allure Plain Link", + has_link( + "https://github.com/allure-framework/allure-python", + "link", + "allure-python" + ) + ) + ) + + +def test_issue_from_robot_tag(robot_runner: AllureRobotRunner): + robot_runner.run_robotframework( + suite_rst_ids={"links.robot": "tag-issue-robot"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Links.Allure Issue Link", + has_issue_link( + "https://github.com/allure-framework/allure-python/issues/1", + "ISSUE-1" + ) + ) + ) + + +def test_tms_from_robot_tag(robot_runner: AllureRobotRunner): + robot_runner.run_robotframework( + suite_rst_ids={"links.robot": "tag-tms-robot"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Links.Allure TMS Link", + has_test_case_link( + "https://my-tms/test-cases/1", + "TESTCASE-1" + ) + ) + ) + + +def test_links_from_code(robot_runner: AllureRobotRunner): + robot_runner.run_robotframework( + suite_rst_ids={"links.robot": "code-links-robot"}, + library_rst_ids={"my_lib.py": "code-links-lib"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Links.Allure Link Decorators and Functions", + has_link( + "https://github.com/allure-framework/allure-python", + "link", + "allure-python" + ), + has_issue_link( + "https://github.com/allure-framework/allure-python/issues/1", + "ISSUE-1" + ), + has_test_case_link( + "https://my-tms/test-cases/1", + "TESTCASE-1" + ) + ) + ) + + +def test_rf_specific_tag_syntax(docstring, robot_runner: AllureRobotRunner): + """ + *** Test Cases *** + RF-Specific Tag Syntax + [Tags] link:[allure-python]https://github.com/allure-framework/allure-python + ... link:https://github.com/allure-framework/allure-python/issues + ... issue:ISSUE-1 + ... issue:https://github.com/allure-framework/allure-python/issues/1 + ... issue:[ISSUE-1]https://github.com/allure-framework/allure-python/issues/1 + ... tms:TESTCASE-1 + ... tms:https://my-tms/test-cases/1 + ... tms:[TESTCASE-1]https://my-tms/test-cases/1 + No Operation + """ + + robot_runner.run_robotframework( + suite_literals={"links.robot": docstring} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Links.RF-Specific Tag Syntax", + has_link( + "https://github.com/allure-framework/allure-python", + "link", + "allure-python" + ), + has_link( + "https://github.com/allure-framework/allure-python/issues", + "link", + "https://github.com/allure-framework/allure-python/issues" + ) + ) + ) diff --git a/tests/allure_robotframework/acceptance/allure_api/steps/__init__.py b/tests/allure_robotframework/acceptance/allure_api/steps/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_robotframework/acceptance/allure_api/steps/steps_test.py b/tests/allure_robotframework/acceptance/allure_api/steps/steps_test.py new file mode 100644 index 00000000..2daeee49 --- /dev/null +++ b/tests/allure_robotframework/acceptance/allure_api/steps/steps_test.py @@ -0,0 +1,27 @@ +""" ./allure-robotframework/examples/step.rst """ + +from hamcrest import assert_that +from tests.allure_robotframework.robot_runner import AllureRobotRunner +from allure_commons_test.report import has_test_case +from allure_commons_test.result import has_step + + +def test_library_steps(robot_runner: AllureRobotRunner): + robot_runner.run_robotframework( + suite_rst_ids={"steps.robot": "steps-robot"}, + library_rst_ids={"my_lib.py": "steps-lib"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Steps.Allure substeps", + has_step( + "my_lib.Substep", + has_step( + "Library substep", + has_step("Substep 'A'") + ) + ) + ) + ) diff --git a/tests/allure_robotframework/acceptance/allure_api/tags/__init__.py b/tests/allure_robotframework/acceptance/allure_api/tags/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_robotframework/acceptance/allure_api/tags/tags_test.py b/tests/allure_robotframework/acceptance/allure_api/tags/tags_test.py new file mode 100644 index 00000000..1504630d --- /dev/null +++ b/tests/allure_robotframework/acceptance/allure_api/tags/tags_test.py @@ -0,0 +1,112 @@ +""" ./allure-robotframework/examples/tag.rst """ + +from hamcrest import assert_that, all_of, not_ +from tests.allure_robotframework.robot_runner import AllureRobotRunner +from allure_commons_test.report import has_test_case +from allure_commons_test.label import has_tag +from allure_commons_test.label import has_label + + +def test_robot_tags(robot_runner: AllureRobotRunner): + robot_runner.run_robotframework( + suite_rst_ids={"tags.robot": "tags-static-robot"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Tags.Distributed Legacy Test", + has_tag("distributed"), + has_tag("legacy") + ) + ) + + +def test_modified_robot_tags(robot_runner: AllureRobotRunner): + robot_runner.run_robotframework( + suite_rst_ids={"tags.robot": "tags-dynamic-robot"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Tags.Isolated Test", + all_of( + has_tag("isolated"), + not_( + has_tag("distributed") + ) + ) + ) + ) + + +def test_robot_tags_not_modified_because_of_failure(robot_runner: AllureRobotRunner): + robot_runner.run_robotframework( + suite_rst_ids={"tags.robot": "tags-partial-robot"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Tags.Supposed to Be an Isolated Test", + all_of( + has_tag("distributed"), + not_( + has_tag("isolated") + ) + ) + ) + ) + + +def test_explicit_tags(robot_runner: AllureRobotRunner): + robot_runner.run_robotframework( + suite_rst_ids={"tags.robot": "tags-explicit-robot"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Tags.Explicit External Test", + all_of( + has_tag("explicit"), + has_tag("extrenal") + ) + ) + ) + + +def test_rf_tags_starting_with_allure_not_added(robot_runner: AllureRobotRunner): + robot_runner.run_robotframework( + suite_rst_ids={"tags.robot": "tags-noconv-robot"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Tags.No Allure Tags", + not_( + has_label("tag") + ) + ) + ) + + +def test_tags_from_library(robot_runner: AllureRobotRunner): + robot_runner.run_robotframework( + suite_rst_ids={"tags.robot": "tags-code-robot"}, + library_rst_ids={"my_lib.py": "tags-code-lib"} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Tags.Stateful External Legacy Test", + all_of( + has_tag("stateful"), + has_tag("external"), + has_tag("legacy") + ) + ) + ) diff --git a/tests/allure_robotframework/acceptance/allure_api/testplan/__init__.py b/tests/allure_robotframework/acceptance/allure_api/testplan/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_robotframework/acceptance/allure_api/testplan/testplan_test.py b/tests/allure_robotframework/acceptance/allure_api/testplan/testplan_test.py new file mode 100644 index 00000000..e464c79c --- /dev/null +++ b/tests/allure_robotframework/acceptance/allure_api/testplan/testplan_test.py @@ -0,0 +1,24 @@ +""" ./allure-robotframework/examples/testplan.rst """ + +from allure_commons_test.report import has_test_case +from hamcrest import assert_that, all_of, not_ +from tests.allure_robotframework.robot_runner import AllureRobotRunner + + +def test_testplan(robot_runner: AllureRobotRunner): + robot_runner.run_robotframework( + suite_rst_ids={"testplan.robot": "testdata"}, + testplan_rst_id="testplan", + options={"prerunmodifier": "allure_robotframework.testplan"} + ) + + assert_that( + robot_runner.allure_results, + all_of( + has_test_case("Testplan.Selected by Name"), + has_test_case("Selected by ID"), + not_( + has_test_case("Testplan.Not Selected") + ) + ) + ) diff --git a/tests/allure_robotframework/acceptance/robotframework_support/__init__.py b/tests/allure_robotframework/acceptance/robotframework_support/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_robotframework/acceptance/robotframework_support/fixtures/__init__.py b/tests/allure_robotframework/acceptance/robotframework_support/fixtures/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_robotframework/acceptance/robotframework_support/fixtures/fixture_test.py b/tests/allure_robotframework/acceptance/robotframework_support/fixtures/fixture_test.py new file mode 100644 index 00000000..d20e266e --- /dev/null +++ b/tests/allure_robotframework/acceptance/robotframework_support/fixtures/fixture_test.py @@ -0,0 +1,223 @@ +from hamcrest import assert_that +from tests.allure_robotframework.robot_runner import AllureRobotRunner +from allure_commons_test.report import has_test_case +from allure_commons_test.container import has_container +from allure_commons_test.container import has_before +from allure_commons_test.container import has_after +from allure_commons_test.result import with_status +from allure_commons_test.result import has_status_details +from allure_commons_test.result import with_message_contains + + +def test_setup(docstring, robot_runner: AllureRobotRunner): + """ + *** Keywords *** + Fixture + No Operation + + *** Test Cases *** + Test Under Test + [Setup] Fixture + No Operation + """ + + robot_runner.run_robotframework( + suite_literals={"fixture.robot": docstring} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Fixture.Test Under Test", + has_container( + robot_runner.allure_results, + has_before( + "Fixture", + with_status("passed") + ) + ) + ) + ) + + +def test_failed_setup(docstring, robot_runner: AllureRobotRunner): + """ + *** Keywords *** + Fixture + Fail Reason + + *** Test Cases *** + Test Under Test + [Setup] Fixture + No Operation + """ + + robot_runner.run_robotframework( + suite_literals={"fixture.robot": docstring} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Fixture.Test Under Test", + has_container( + robot_runner.allure_results, + has_before( + "Fixture", + with_status("failed"), + has_status_details( + with_message_contains("Reason") + ) + ) + ) + ) + ) + + +def test_teardown(docstring, robot_runner: AllureRobotRunner): + """ + *** Keywords *** + Fixture + No Operation + + *** Test Cases *** + Test Under Test + [Teardown] Fixture + No Operation + """ + + robot_runner.run_robotframework( + suite_literals={"fixture.robot": docstring} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Fixture.Test Under Test", + has_container( + robot_runner.allure_results, + has_after( + "Fixture", + with_status("passed") + ) + ) + ) + ) + + +def test_failed_teardown(docstring, robot_runner: AllureRobotRunner): + """ + *** Keywords *** + Fixture + Fail Reason + + *** Test Cases *** + Test Under Test + [Teardown] Fixture + No Operation + """ + + robot_runner.run_robotframework( + suite_literals={"fixture.robot": docstring} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Fixture.Test Under Test", + has_container( + robot_runner.allure_results, + has_after( + "Fixture", + with_status("failed"), + has_status_details( + with_message_contains("Reason") + ) + ) + ) + ) + ) + + +def test_setup_teardown(docstring, robot_runner: AllureRobotRunner): + """ + *** Keywords *** + Setup Fixture + No Operation + + Teardown Fixture + No Operation + + *** Test Cases *** + Test Under Test + [Setup] Setup Fixture + [Teardown] Teardown Fixture + No Operation + """ + + robot_runner.run_robotframework( + suite_literals={"fixture.robot": docstring} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Fixture.Test Under Test", + has_container( + robot_runner.allure_results, + has_before( + "Setup Fixture", + with_status("passed") + ), + has_after( + "Teardown Fixture", + with_status("passed") + ) + ) + ) + ) + + +def test_failed_setup_teardown(docstring, robot_runner: AllureRobotRunner): + """ + *** Keywords *** + Setup Fixture + Fail Setup fail reason + + Teardown Fixture + Fail Teardown fail reason + + *** Test Cases *** + Test Under Test + [Setup] Setup Fixture + [Teardown] Teardown Fixture + No Operation + """ + + robot_runner.run_robotframework( + suite_literals={"fixture.robot": docstring} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Fixture.Test Under Test", + has_container( + robot_runner.allure_results, + has_before( + "Setup Fixture", + with_status("failed"), + has_status_details( + with_message_contains("Setup fail reason") + ) + ), + has_after( + "Teardown Fixture", + with_status("failed"), + has_status_details( + with_message_contains("Teardown fail reason") + ) + ) + ) + ) + ) diff --git a/tests/allure_robotframework/acceptance/robotframework_support/statuses/__init__.py b/tests/allure_robotframework/acceptance/robotframework_support/statuses/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/allure_robotframework/acceptance/robotframework_support/statuses/statuses_test.py b/tests/allure_robotframework/acceptance/robotframework_support/statuses/statuses_test.py new file mode 100644 index 00000000..2f65fd48 --- /dev/null +++ b/tests/allure_robotframework/acceptance/robotframework_support/statuses/statuses_test.py @@ -0,0 +1,101 @@ +from hamcrest import assert_that +from doctest import script_from_examples +from tests.allure_robotframework.robot_runner import AllureRobotRunner +from allure_commons_test.report import has_test_case +from allure_commons_test.result import with_status +from allure_commons_test.result import has_status_details +from allure_commons_test.result import with_message_contains +from allure_commons_test.result import with_trace_contains +from allure_commons_test.result import has_step + + +def test_failed_test(docstring, robot_runner: AllureRobotRunner): + """ + *** Test Cases *** + Failed Test Case + Fail msg=Reason + """ + + robot_runner.run_robotframework( + suite_literals={"status.robot": docstring} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Status.Failed Test Case", + with_status("failed"), + has_status_details( + with_message_contains("Reason"), + with_trace_contains("AssertionError: Reason") + ) + ) + ) + + +def test_failed_in_library(docstring, robot_runner: AllureRobotRunner): + """ + *** Settings *** + Library ./library.py + + *** Test Cases *** + Failed Test Case + Fail In Library + """ + + library = script_from_examples( + """ + >>> from robot.libraries.BuiltIn import BuiltIn + >>> def fail_in_library(): + ... BuiltIn().fail("Reason") + """ + ) + + robot_runner.run_robotframework( + suite_literals={"status.robot": docstring}, + library_literals={"library.py": library} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Status.Failed Test Case", + with_status("failed"), + has_status_details( + with_message_contains("Reason"), + with_trace_contains("library.py\", line 3, in fail_in_library") + ), + has_step( + "library.Fail In Library", + with_status("failed"), + has_status_details( + with_message_contains("Reason"), + with_trace_contains("library.py\", line 3, in fail_in_library") + ) + ) + ) + ) + + +def test_steps_after_failed_are_skipped(docstring, robot_runner: AllureRobotRunner): + """ + *** Test Cases *** + Failed Test Case + Fail + Log This step is skipped + """ + + robot_runner.run_robotframework( + suite_literals={"status.robot": docstring} + ) + + assert_that( + robot_runner.allure_results, + has_test_case( + "Status.Failed Test Case", + has_step( + "BuiltIn.Log", + with_status("skipped") + ) + ) + ) diff --git a/tests/allure_robotframework/conftest.py b/tests/allure_robotframework/conftest.py new file mode 100644 index 00000000..3bccc8fd --- /dev/null +++ b/tests/allure_robotframework/conftest.py @@ -0,0 +1,7 @@ +from pytest import fixture +from .robot_runner import AllureRobotRunner + + +@fixture +def robot_runner(request, pytester): + return AllureRobotRunner(request, pytester) diff --git a/tests/allure_robotframework/robot_runner.py b/tests/allure_robotframework/robot_runner.py new file mode 100644 index 00000000..c601f4a4 --- /dev/null +++ b/tests/allure_robotframework/robot_runner.py @@ -0,0 +1,121 @@ +import robot +from pytest import FixtureRequest, Pytester +from tests.e2e import AllureFrameworkRunner, PathlikeT +from typing import Sequence, Mapping +from allure_robotframework import allure_robotframework + + +class AllureRobotRunner(AllureFrameworkRunner): + """The runner to test allure-robotframework integration.""" + + LOGGER_PATH = "allure_robotframework.robot_listener.AllureFileLogger" + + def __init__(self, request: FixtureRequest, pytester: Pytester): + super().__init__(request, pytester) + + def run_robotframework( + self, + suite_paths: Sequence[PathlikeT] = None, + suite_literals: Mapping[str, str] = None, + suite_rst_ids: Sequence[str] = None, + library_paths: Sequence[PathlikeT] = None, + library_literals: Mapping[str, str] = None, + library_rst_ids: Sequence[str] = None, + testplan_content: dict = None, + testplan_path: PathlikeT = None, + testplan_rst_id: str = None, + options: Mapping[str, any] = None + ) -> None: + """Runs the robotframework against an example. + + The example consists of suite(s), i.e., .robot files, libraries, + i.e., .py files and, optionaly, a testplan. All types of files can be + specified either as paths or as a mapping from a file name to its content + or as a mapping from a file name to an ID in the associated .rst + document. + + Arguments: + suite_paths (Sequence[str | Path]): a sequence of path-like objects + pointing to .robot files relative to the current test`s folder. + suite_literals (Mapping[str, str]): a mapping from a file name to + the content of a .robot file (.robot extension can be omitted). + suite_rst_ids (Mapping[str, str]): a mapping from a file name to an + ID of a .robot file content from the .rst document, associated + with current node. + library_paths (Sequence[str | Path]): a sequence of path-like + objects pointing to .py library files relative to the current + test`s folder. + library_literals (Mapping[str, str]): a mapping from a file name to + the content of a .py library file (.py extension can be + omitted). + library_rst_ids (Mapping[str, str]): a mapping from a file name to + an IDs of a .py library file content from the .rst document, + associated with current node. + testplan (dict): a testplan content. + testplan_path (str | Path): a path to a testplan relative to the + current test`s folder. + testplan_rst_id (str): a testplan ID from the .rst document, + associated with current node. + options (Mapping[str, any]): robot framework options. + + Returns: + allure_commons.logger.AllureMemoryLogger: the allure results of the + run. The results of the last run are also accessible through the + :attr:`allure_results` attribute. + """ + return self._run( + self.__prepare_example( + suite_literals=suite_literals, + suite_paths=suite_paths, + suite_rst_ids=suite_rst_ids, + library_literals=library_literals, + library_paths=library_paths, + library_rst_ids=library_rst_ids + ), + testplan_content=testplan_content, + testplan_path=testplan_path, + testplan_rst_id=testplan_rst_id, + logger_path=AllureRobotRunner.LOGGER_PATH, + options=self.__resolve_options(options) + ) + + def _run_framework(self, suites, options): + robot.run(*suites, listener=allure_robotframework(None), **options) + + def __resolve_options(self, options): + return { + ** { + "log": None, + "loglevel": "DEBUG", + "report": None, + "output": None, + "extension": "robot", + "outputdir": str(self.pytester.path) + }, + ** (options or {}) + } + + def __prepare_example( + self, + suite_literals, + suite_paths, + suite_rst_ids, + library_literals, + library_paths, + library_rst_ids + ): + suites = self._create_files( + extension=".robot", + paths=suite_paths, + literals=suite_literals, + rst_examples=suite_rst_ids + ) + self._create_files( + paths=library_paths, + literals=library_literals, + rst_examples=library_rst_ids + ) + return suites + + +__all__ = ["AllureRobotRunner"] diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 00000000..efd47e01 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,15 @@ +import pytest +from pytest import FixtureRequest +from .e2e import find_node_with_docstring_or_throw, RstExampleTable + +pytest_plugins = "pytester" + + +@pytest.fixture +def rst_examples(request: FixtureRequest) -> RstExampleTable: + return RstExampleTable.find_examples(request) + + +@pytest.fixture +def docstring(request: FixtureRequest) -> str: + return find_node_with_docstring_or_throw(request)[1] diff --git a/tests/e2e.py b/tests/e2e.py new file mode 100644 index 00000000..cce35ee7 --- /dev/null +++ b/tests/e2e.py @@ -0,0 +1,618 @@ +"""Utility functions and classes for end-to-end testing of allure integrations +with python testing frameworks. + +""" + +import docutils +import docutils.nodes +import docutils.parsers.rst +import json +import mock +import pytest +import shutil +import warnings +from abc import abstractmethod +from contextlib import contextmanager +from pathlib import Path +from pytest import FixtureRequest, Pytester, MonkeyPatch +from typing import Tuple, Mapping, TypeVar, Generator, Callable, Union + +import allure_commons +from allure_commons.logger import AllureMemoryLogger +from allure_commons_test.report import AllureReport + + +PathlikeT = Union[str, Path] + + +@contextmanager +def altered_env(**kwargs) -> Generator[MonkeyPatch, None, None]: + mp = MonkeyPatch() + for n, v in kwargs.items(): + if v is None: + mp.delenv(n, False) + else: + mp.setenv(n, str(v)) + yield mp + mp.undo() + + +@contextmanager +def allure_plugin_context(): + """Separates an allure integration under test from currently active + allure integration (if eny). + + """ + + outer_context_plugins = __pop_all_allure_plugins() + + yield + + __pop_all_allure_plugins() + __restore_allure_plugins(outer_context_plugins) + + +@contextmanager +def allure_in_memory_context( + path: str = None +) -> Generator[AllureMemoryLogger, None, None]: + """Creates a context to test an allure integration. + + While a testing context is active the following conditions hold: + + #. Allure's output is stored in memory instead of being written to the file + system. + #. Allure plugins of an integration under test are isolated from the + allure plugins of the executing environment (if allure is active). + + When the testing context is deactivated, all allure plugins registered + during the test are removed and the plugins of the execution environment are + restored. + + Arguments: + path (str): a path to a class to replace. + Defaults to :code:`"allure_commons.logger.AllureFileLogger"`. + Provide this argument if the integration under test imports the + logger using the + :code:`from allure_commons.logger import AllureFileLogger` syntax. + + Yields: + AllureMemoryLogger: an instance of the in-memory logger, where an output + will be collected. + + """ + + if path is None: + path = "allure_commons.logger.AllureFileLogger" + + # Plugin context must be set first, because mock patching may cause + # module loading, thus, side effects, including allure decorators evaluation + # (and that requires all plugins of nested allure to already be in place). + with allure_plugin_context(): + with mock.patch(path) as ReporterMock: + ReporterMock.return_value = AllureMemoryLogger() + yield ReporterMock.return_value + + +class AllureFileContextValue: + def __init__(self): + self.allure_results = None + + +@contextmanager +def allure_file_context( + alluredir: PathlikeT +) -> Generator[AllureFileContextValue, None, None]: + """Creates a context to test an allure integration. + + It behaves in a way similar to :func:`allure_in_memory_context` except that + the result is created from the actual allure output files. It is useful + if the result files are generated in a separate process. + + Arguments: + alluredir (str | Path): a path to allure results directory. + + The report can be accessed through the :attr:`AllureFileContextValue.output` + attribute once the context is exited. + + Example: + + >>> with allure_file_context("./allure-results") as v: + ... # run framework with allure integration + >>> # use v.allure_results to access the results + + """ + + with allure_plugin_context(): + value = AllureFileContextValue() + yield value + value.allure_results = AllureReport(alluredir) + + +def find_node_with_docstring( + request: FixtureRequest +) -> Union[Tuple[pytest.Item, str], Tuple[None, None]]: + """Find a docstring associated with a test function. + + It first checks the function itself and then, if no docstring was found, + moves up the hierarchy until either a docstring is found or no parent nodes + left. + + Returns: + A tuple of a node and its docstring or :code:`(None, None)` if no + docstring is found. + + """ + + node = request.node + while node: + docstring = node.obj.__doc__ + if docstring: + break + node = node.parent + return node, docstring + + +def find_node_with_docstring_or_throw( + request: FixtureRequest +) -> Tuple[pytest.Item, str]: + """Find a docstring associated with a test function. + + It first checks the function itself and then, if no docstring was found, + moves up the hierarchy until either a docstring is found or no parent nodes + left. + + Raises: + ValueError: if the docstring doesn't exist. + + Returns: + A tuple of a node and its docstring. + + """ + node, docstring = find_node_with_docstring(request) + if node is None: + nodeid = request.node.nodeid + raise ValueError(f"Unable to get docstring for node {nodeid}") + return node, docstring + + +def get_path_from_docstring(request: FixtureRequest) -> Path: + """Extract a path to a file or folder from a docstring of a test function or + one of its parents. + + The path is joined to the rootpath. + + Raises: + ValueError: if no docstring specified. + + Returns: + Path: a full path path denoted by the docstring. + + """ + return request.config.rootpath.joinpath( + find_node_with_docstring_or_throw(request)[1].strip() + ) + + +RstExampleTableT = TypeVar("RstExampleTableT", bound="RstExampleTable") + + +class RstExampleTable: + """Examples from a .rst document associated with a test. + + Attributes: + STASH_KEY (pytest.StashKey): (class attribute) a pytest stash key to + cache an instance of this class on node, that established the + association with the document. + source (str | Path): a path to a document the table was created from. + examples (Mapping[str, str]): a mapping from an example name to its + content. + + """ + + STASH_KEY = pytest.StashKey() + + def __init__(self, filepath: PathlikeT) -> None: + """Create a table of examples from a .rst document. + + Arguments: + filepath (str | Path): a path to a .rst document to parse. + + """ + self.source = filepath + self.examples = self.__load_examples(filepath) + + def __getitem__(self, name: str) -> str: + """Find an example in the document by its name. + + An example is represented by a code block in the original document. The + name of the example is specified using the :code:`:name:` option of the + code block. + + Arguments: + name (str): a name of an example. + + Raises: + KeyError: the required example doesn't exist in the document. + + Returns: + str: the content of the example. + """ + if name not in self.examples: + raise KeyError(f"Code block {name!r} not found in {self.source}") + return self.examples[name] + + @staticmethod + def find_examples(request: FixtureRequest) -> RstExampleTableT: + """Loads code examples, associated with the test node or one of its + parents. + + Arguments: + request (FixtureRequest): the request fixture. + + Returns (RstExampleTable): A table containing the examples, indexed by + their names from the .rst document + + Notes: + It first finds a docstring defined on the function, class, module or + package associated with the node. If multiple docstrings exist, + the one defined on a lower level wins. + + The docstring content is used then as the path to the + reStructuredText document. The document is parsed and all its code + blocks are combined in a dictionary that maps their names to the + code block content. The mapping can be accessed through the returned + instance of RstExampleTable class. + + The table is then cached in a stash of the same node from which the + original docstring was loaded. This prevents from parsing the same + document several times if multiple tests from the same module/package + (or parametrizations of the same metafunc) are testing the examples + from the same document. + """ + + node, docstring = find_node_with_docstring_or_throw( + request + ) + examples = RstExampleTable.__get_from_cache(node) + if examples is None: + examples = RstExampleTable.__create_and_cache(node, docstring) + return examples + + @staticmethod + def __load_examples(filepath: PathlikeT) -> Mapping[str, str]: + document = RstExampleTable.parse_rst(filepath) + return { + name: code_block.astext() + for code_block in document.findall( + RstExampleTable.__filter + ) for name in code_block["names"] + } + + @staticmethod + def parse_rst(filepath: PathlikeT) -> docutils.nodes.document: + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + parser = docutils.parsers.rst.Parser() + components = (docutils.parsers.rst.Parser,) + settings = docutils.frontend.OptionParser( + components=components + ).get_default_values() + document = docutils.utils.new_document( + str(filepath), + settings=settings + ) + with open(filepath, encoding="utf-8") as f: + content = f.read() + parser.parse(content, document) + return document + + @staticmethod + def __get_from_cache(node): + if RstExampleTable.STASH_KEY in node.stash: + return node.stash[RstExampleTable.STASH_KEY] + + @staticmethod + def __create_and_cache(node, path): + filepath = node.config.rootpath.joinpath(path.strip()) + if not filepath.exists() or filepath.is_dir(): + raise ValueError( + f"Document, referred by {node.nodeid}, " + f"doesn't exist at {filepath}" + ) + table = RstExampleTable(filepath) + node.stash[RstExampleTable.STASH_KEY] = table + return table + + @staticmethod + def __filter(node): + return isinstance( + node, + docutils.nodes.literal_block + ) and "code" in node["classes"] and node["names"] + + +class AllureFrameworkRunner: + """An abstract base class for framework test runners to test allure + integrations. + + """ + def __init__(self, request: FixtureRequest, pytester: Pytester): + self.request = request + self.pytester = pytester + self.allure_results = None + self.in_memory = True + + def _run( + self, + *args, + testplan_content: dict = None, + testplan_path: PathlikeT = None, + testplan_rst_id: str = None, + logger_path: str = None, + **kwargs + ) -> AllureMemoryLogger: + """Runs the framework and collect the allure results. + + Prepares the testplan (if any), replace the allure file logger with the + in-memory logger and runs the :method:`_run_framework` method. + + Arguments: + *args: positional arguments for the underlying call. + + Keyword arguments: + testplan_content (dict): the content of the allure testplan. + testplan_path (str | Path): the path to the allure testplan + relative to the current test folder. + testplan_rst_id (str): the ID of the allure testplan code block. + **kwargs: keyword arguments for the underlying call. + + Returns: + AllureMemoryLogger: the collected allure results. The results of the + last call are also available in the :attr:`allure_results` + attribute. + + """ + testplan_path = self.__prepare_testplan( + content=testplan_content, + path=testplan_path, + rst_id=testplan_rst_id + ) + with altered_env(ALLURE_TESTPLAN_PATH=testplan_path): + output = self.__run_and_collect_results_in_memory( + logger_path, + args, + kwargs + ) if self.in_memory else self.__run_and_collect_results_from_fs( + args, + kwargs + ) + self.allure_results = output + return output + + @abstractmethod + def _run_framework(self, *args, **kwargs): + """Override this method and invoke the actual framework. + + This method is invoked by the :method:`_run`. Arguments (args and kwargs + are the same as were provided to the :method:`_run`. + + """ + + def _find_docstring(self): + """Find a docstring, associated with the test ot throw.""" + return find_node_with_docstring_or_throw(self.request)[1] + + def _get_all_content(self, paths=None, literals=None, rst_ids=None): + """Return a list of content denoted by files, literals and IDs of the + .rst document code blocks. + + Arguments: + paths (Sequence[str | Path]): a sequence of file paths (relative to + the current test's directory) to load content from. + literals (Sequence[str]): a sequence of literals to use as content. + rst_ids (Sequence[str]): a sequence of code blocks from the .rst + document. + + Returns: + List[str]: a list of strings, each representing a file content. + + """ + + return [ + self._read_file(p) for p in (paths or []) + ] + list(literals or []) + [ + self.__get_from_rst(rst_id) for rst_id in (rst_ids or []) + ] + + def _resolve_content(self, path=None, literal=None, rst_id=None): + """Return content denoted either by a literal or a path (relative to + the test folder) or an ID of the .rst document code block in that + order. The first content source wins. + + """ + if literal: + return literal + if path: + return self._read_file(path) + if rst_id: + return self.__get_from_rst(rst_id) + + def _create_files( + self, + extension=".py", + paths=None, + literals=None, + rst_examples=None + ): + """Create and/or copy files in the pytester directory. + + Arguments: + extension (str): an output files extension. + paths (Sequence[str | Path]): a sequence of paths to copy, + relative to the current test directory. + literals (Mapping[str, str]): a mapping from a name of a file to + its content (an extension can be omitted). + rst_examples (Mapping[str, str]): a mapping from a file name (an + extension may be omitted) to its ID in the .rst document. + + Returns: + List[Path]: a list of the newly created file paths. + """ + return self._copy_files(paths) + self._make_files_from_literals( + extension, + literals + ) + self._make_files_from_rst(extension, rst_examples) + + def _make_files_from_literals(self, extension, literals): + """Create files in the pytester directory. + + Arguments: + extension (str): an output files extension. + literals (Mapping[str, str]): a mapping from a name of a file to + its content (an extension can be omitted). + + Returns: + List[Path]: a list of the newly created file paths. + """ + + return [ + self.pytester.makefile( + extension, + **{name: content} + ) for name, content in (literals or {}).items() + ] + + def _copy_files(self, src_paths): + """Copy files denoted by paths into the pytester directory. + + Arguments: + src_paths (Sequence[str | Path]): a sequence of paths to copy, + relative to the current test directory. + + Returns: + List[Path]: a list of the newly created file paths. + """ + dst_paths = [] + for p in src_paths or []: + src = self.request.path.parent / p + dst = self.pytester.path / Path(p).name + shutil.copyfile(src, dst) + dst_paths.append(dst) + return dst_paths + + def _make_files_from_rst( + self, + extension: str, + rst_name_to_id: Mapping[str, str] + ): + """Copy code blocks from the .rst document to the pytester dir. + + Arguments: + extension (str): an output files extension. + rst_name_to_id (Mapping[str, str]): a mapping from a file name (an + extension may be omitted) to its ID in the .rst document. + + Returns: + List[Path]: a list of the newly created file paths. + """ + + return [ + self.__make_single_file_from_rst( + extension, + name, rst_id + ) for name, rst_id in (rst_name_to_id or {}).items() + ] + + def _read_file(self, path: PathlikeT, basepath: PathlikeT = None): + """Read file content. + + Arguments: + path (str | Path): a path to a file. If it's a relative path, it's + prepended by the basepath. + basepath (str | Path): a basepath. The path to the folder of the + current test by default. + + """ + if basepath is None: + basepath = self.request.path.parent + path = basepath / path + with open(path, mode="r", encoding="utf-8") as f: + return f.read() + + def _cache_docstring_test_result( + self, + cache_key: pytest.StashKey, + test_fn: Callable, + *args: any, + **kwargs: any + ): + """Gets docstring run results from the cache of the node associated with + the docstring. In case of a cache miss, returns + :code:`run_fn(*args, docstring, **kwargs)`. The result is cached to + avoid future calls. + + Arguments: + cache_key (pytest.StashKey): a pytest stash key used to cache the + result. + run_fn (Callable): a function to call in case of a cache miss. The + docstring is appended to the positional arguments. + *args: positional arguments of the :param:`run_fn`. + **kwargs: keyword arguments of the :param:`run_fn`. + + Returns: + The result of the :code:`run_fn(*args, docstring, **kwargs)` call, + either from the cache or from the actual call. + """ + + node, docstring = find_node_with_docstring_or_throw(self.request) + if cache_key in node.stash: + return node.stash[cache_key] + result = test_fn(*args, docstring, **kwargs) + node.stash[cache_key] = result + return result + + def __run_and_collect_results_in_memory(self, logger_path, args, kwargs): + with allure_in_memory_context(logger_path) as output: + self._run_framework(*args, **kwargs) + return output + + def __run_and_collect_results_from_fs(self, args, kwargs): + with allure_file_context(self.pytester.path) as v: + self._run_framework(*args, **kwargs) + return v.allure_results + + def __make_single_file_from_rst(self, extension, name, rst_id): + return self.pytester.makefile( + extension, **{ + name: self.__get_from_rst(rst_id) + } + ) + + def __get_from_rst(self, rst_id): + return RstExampleTable.find_examples(self.request)[rst_id] + + def __prepare_testplan(self, content, path, rst_id): + if content: + path = self.pytester.makefile( + ".json", + json.dumps(content) + ) + elif rst_id: + path = self.pytester.makefile( + ".json", + self.__get_from_rst(rst_id) + ) + return path + + +def __pop_all_allure_plugins(): + name_plugin_tuples = allure_commons.plugin_manager.list_name_plugin() + for name, plugin in name_plugin_tuples: + allure_commons.plugin_manager.unregister(plugin=plugin, name=name) + return name_plugin_tuples + + +def __restore_allure_plugins(name_plugin_tuples): + for name, plugin in name_plugin_tuples: + allure_commons.plugin_manager.register(plugin, name)