Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions examples/behave/tests/features/attachments.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
Feature: Test Attachments
As a test developer
I want to attach files and content to my test results
So that I can provide additional context for test failures

@qase.id:10
Scenario: Attach file to test
Given I have a test with attachments
When I attach a file to the test
Then the attachments should be included in the test result

@qase.id:20
Scenario: Attach text content
Given I have a test with attachments
When I attach content as text
Then the attachments should be included in the test result

@qase.id:30
Scenario: Attach JSON data
Given I have a test with attachments
When I attach JSON data
Then the attachments should be included in the test result

@qase.id:40
Scenario: Attach screenshot
Given I want to attach a screenshot
When I attach the screenshot
Then the attachments should be included in the test result

@qase.id:50
Scenario: Add comments to test
Given I have a test with attachments
When I add a comment about the test
Then the attachments should be included in the test result

@qase.id:60
Scenario: Add debug information
Given I have a test with attachments
When I add debug information
Then the attachments should be included in the test result
72 changes: 72 additions & 0 deletions examples/behave/tests/features/steps/attachment_steps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
from behave import *
from qase.behave import qase
import tempfile
import os


@given('I have a test with attachments')
def step_impl(context):
# Create a temporary file for testing
with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
f.write("This is a test attachment content")
context.temp_file_path = f.name



@when('I attach a file to the test')
def step_impl(context):
# Attach the temporary file
qase.attach(file_path=context.temp_file_path)


@when('I attach content as text')
def step_impl(context):
# Attach text content directly
qase.attach(content="This is some text content", file_name="text_content.txt")


@when('I attach JSON data')
def step_impl(context):
# Attach JSON content
json_data = '{"test": "data", "value": 123}'
qase.attach(content=json_data, file_name="test_data.json", mime_type="application/json")


@then('the attachments should be included in the test result')
def step_impl(context):
# # Clean up temporary file
if hasattr(context, 'temp_file_path') and os.path.exists(context.temp_file_path):
os.unlink(context.temp_file_path)



@given('I want to attach a screenshot')
def step_impl(context):
# Simulate creating a screenshot (in real scenario, this would be actual screenshot data)
context.screenshot_data = b"fake_screenshot_data"
pass


@when('I attach the screenshot')
def step_impl(context):
# Attach binary data (screenshot)
qase.attach(
content=context.screenshot_data,
file_name="screenshot.png",
mime_type="image/png"
)


@when('I add a comment about the test')
def step_impl(context):
# Add a comment to the test result
qase.comment("Screenshot captured successfully")
qase.comment("User was logged in at the time of capture")


@when('I add debug information')
def step_impl(context):
# Add debug information as comments
import datetime
qase.comment(f"Debug: Current timestamp is {datetime.datetime.now()}")
qase.comment("Debug: All elements were found and interacted with")
3 changes: 2 additions & 1 deletion qase-behave/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ parameterize your tests.

For detailed instructions on using annotations and methods, refer to [Usage](docs/usage.md).

For information about attaching files and content or adding comments to test results, see [Attachments](docs/ATTACHMENTS.md).

For example:

```gherkin
Expand Down Expand Up @@ -106,4 +108,3 @@ We maintain the reporter on [LTS versions of Python](https://devguide.python.org

<!-- references -->

[auth]: https://developers.qase.io/#authentication
34 changes: 34 additions & 0 deletions qase-behave/changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,37 @@
# qase-behave 1.1.3

## What's new

- Added support for file and content attachments to test results using `qase.attach()` method.
- Added support for adding comments to test results using `qase.comment()` method.
- Improved MIME type detection for attachments.
- Updated documentation with examples and usage instructions.

### Attachment Usage

```python
from qase.behave import qase

# Attach a file
qase.attach(file_path="/path/to/file.txt")

# Attach content directly
qase.attach(content="test data", file_name="data.txt")

# Attach binary data
qase.attach(content=b"binary data", file_name="screenshot.png", mime_type="image/png")
```

### Comment Usage

```python
from qase.behave import qase

# Add comments to test results
qase.comment("Test completed successfully")
qase.comment("Debug info: user logged in")
```

# qase-behave 1.1.2

## What's new
Expand Down
155 changes: 155 additions & 0 deletions qase-behave/docs/ATTACHMENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# Attachments in Qase Behave

Qase Behave supports attaching files and content to test results. This allows you to provide additional context for test failures, such as screenshots, logs, or data files.

## Usage

### Import the qase object

```python
from qase.behave import qase
```

### Attach a file

```python
@given('I have a test with a file')
def step_impl(context):
# Attach an existing file
qase.attach(file_path="/path/to/your/file.txt")
```

### Attach content directly

```python
@when('I attach text content')
def step_impl(context):
# Attach text content
qase.attach(content="This is some text content", file_name="content.txt")
```

### Attach binary data

```python
@when('I attach a screenshot')
def step_impl(context):
# Attach binary data (e.g., screenshot)
screenshot_data = b"binary_screenshot_data"
qase.attach(
content=screenshot_data,
file_name="screenshot.png",
mime_type="image/png"
)
```

### Attach JSON data

```python
@when('I attach JSON data')
def step_impl(context):
json_data = '{"test": "data", "value": 123}'
qase.attach(
content=json_data,
file_name="test_data.json",
mime_type="application/json"
)
```

## Method Signature

```python
qase.attach(
file_path: Optional[str] = None,
content: Optional[Union[str, bytes]] = None,
file_name: Optional[str] = None,
mime_type: Optional[str] = None
) -> None
```

### Parameters

- **file_path**: Path to the file to attach (mutually exclusive with `content`)
- **content**: Content to attach as string or bytes (mutually exclusive with `file_path`)
- **file_name**: Name for the attachment (auto-detected from `file_path` if not provided)
- **mime_type**: MIME type of the attachment (auto-detected if not provided)

### Notes

- Either `file_path` or `content` must be provided, but not both
- If `file_name` is not provided, it will be derived from `file_path` or default to "attachment.txt"
- If `mime_type` is not provided, it will be auto-detected from the file extension or default to "text/plain"
- Attachments are automatically included in the test result when the scenario completes

## Examples

### Complete Example

```python
from behave import *
from qase.behave import qase
import tempfile
import os

@given('I have a test with attachments')
def step_impl(context):
# Create a temporary file for testing
with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
f.write("This is a test attachment content")
context.temp_file_path = f.name

@when('I attach multiple items')
def step_impl(context):
# Attach the temporary file
qase.attach(file_path=context.temp_file_path)

# Attach text content
qase.attach(content="Additional text content", file_name="additional.txt")

# Attach JSON data
json_data = '{"status": "success", "timestamp": "2024-01-01T00:00:00Z"}'
qase.attach(content=json_data, file_name="status.json", mime_type="application/json")

@then('clean up temporary files')
def step_impl(context):
if hasattr(context, 'temp_file_path') and os.path.exists(context.temp_file_path):
os.unlink(context.temp_file_path)
```

### Error Handling

The `qase.attach()` method will raise appropriate exceptions:

- `RuntimeError`: If called outside of an active scenario
- `ValueError`: If both `file_path` and `content` are provided, or if neither is provided
- `FileNotFoundError`: If the specified file path doesn't exist (when using `file_path`)

## Adding Comments

You can also add comments to your test scenarios using the `qase.comment()` method:

```python
@when('I add a comment')
def step_impl(context):
qase.comment("This is a test comment")
qase.comment("Another comment with additional context")
```

### Comment Method Signature

```python
qase.comment(message: str) -> None
```

### Parameters

- **message**: The comment message to add to the scenario

### Notes

- Comments are automatically included in the test result when the scenario completes
- Multiple comments are concatenated with newlines
- If no active scenario is available, a RuntimeError will be raised

## Integration with Qase TestOps

Attachments and comments added using `qase.attach()` and `qase.comment()` will be automatically uploaded to Qase TestOps when the test results are submitted. The attachments and comments will be associated with the corresponding test case and will be available in the Qase TestOps interface.
9 changes: 7 additions & 2 deletions qase-behave/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "qase-behave"
version = "1.1.2"
version = "1.1.3"
description = "Qase Behave Plugin for Qase TestOps and Qase Report"
readme = "README.md"
keywords = ["qase", "behave", "plugin", "testops", "report", "qase reporting", "test observability"]
Expand Down Expand Up @@ -70,9 +70,14 @@ extras =
where = ["src"]

[tool.pytest.ini_options]
addopts = "--cov-report=term-missing --verbose"
addopts = "--cov-report=term-missing --verbose --tb=short --strict-markers"
norecursedirs = ["dist", "build", ".tox"]
testpaths = ["tests"]
markers = [
"unit: Unit tests",
"integration: Integration tests",
"slow: Slow running tests"
]

[tool.flake8]
exclude = [".tox", "build", "dist", ".eggs"]
Expand Down
3 changes: 2 additions & 1 deletion qase-behave/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
attrs==23.2.0
behave>=1.2.6
qase-python-commons~=3.5.0
qase-python-commons~=3.5.1
pytest>=7.0.0
4 changes: 4 additions & 0 deletions qase-behave/src/qase/behave/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .formatter import QaseFormatter
from .qase_global import qase

__all__ = ['QaseFormatter', 'qase']
3 changes: 3 additions & 0 deletions qase-behave/src/qase/behave/formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from qase.commons.reporters import QaseCoreReporter

from qase.behave.utils import filter_scenarios, parse_scenario, parse_step
from qase.behave.qase_global import qase


class QaseFormatter(Formatter):
Expand Down Expand Up @@ -38,6 +39,8 @@ def scenario(self, scenario: Scenario):
self.reporter.add_result(self.__current_scenario)
self.__current_scenario = None
self.__current_scenario = parse_scenario(scenario)
# Update global qase object with current scenario
qase._set_current_scenario(self.__current_scenario)
pass

def result(self, result: Step):
Expand Down
Loading