feat(yamlreaders): Added YamlReader for custom YAML format
Parses custom YAML test specifications: - Steps with requests - Extract variables from responses - Assert response status and fields
This commit is contained in:
1 parent
37053a5d8e
commit
0f7dd83b33
1 file changed
+108
@@ -0,0 +1,108 @@
|
||||
from pathlib import Path
|
||||
|
||||
from models import (
|
||||
AssertModel,
|
||||
ExtractModel,
|
||||
RequestModel,
|
||||
StepModel,
|
||||
TestModel,
|
||||
)
|
||||
|
||||
from .base import BaseReader, ParseError
|
||||
|
||||
|
||||
class YamlReader(BaseReader):
|
||||
def validate(self, source: str | Path) -> bool:
|
||||
try:
|
||||
data = self.load_yaml(source)
|
||||
|
||||
if "steps" not in data:
|
||||
return False
|
||||
|
||||
if not isinstance(data["steps"], list):
|
||||
return False
|
||||
|
||||
for step in data["steps"]:
|
||||
if "name" not in step or "request" not in step:
|
||||
return False
|
||||
|
||||
request = step["request"]
|
||||
if "method" not in request:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def parse(self, source: str | Path) -> TestModel:
|
||||
data = self.load_yaml(source)
|
||||
|
||||
return TestModel(
|
||||
name=data.get("name", "Unnamed Test"),
|
||||
base_url=data.get("base_url", ""),
|
||||
variables=data.get("variables", {}),
|
||||
steps=self._parse_steps(data.get("steps", [])),
|
||||
)
|
||||
|
||||
def _parse_steps(self, steps: list[dict]) -> list[StepModel]:
|
||||
result = []
|
||||
|
||||
for i, step in enumerate(steps):
|
||||
if "name" not in step:
|
||||
raise ParseError(f"Step {i} missing 'name'")
|
||||
if "request" not in step:
|
||||
raise ParseError(f"Step {i} missing 'request'")
|
||||
|
||||
result.append(StepModel(
|
||||
name=step["name"],
|
||||
request=self._parse_request(step["request"]),
|
||||
extract=self._parse_extract(step.get("extract", [])),
|
||||
assert_=self._parse_assert(step.get("assert", [])),
|
||||
))
|
||||
|
||||
return result
|
||||
|
||||
def _parse_request(self, request: dict) -> RequestModel:
|
||||
return RequestModel(
|
||||
method=request.get("method", "GET").upper(),
|
||||
path=request.get("url", request.get("path", "/")),
|
||||
headers=request.get("headers", {}),
|
||||
query=request.get("query", {}),
|
||||
body=request.get("body"),
|
||||
body_type=request.get("body_type", "json"),
|
||||
timeout=request.get("timeout", 30),
|
||||
)
|
||||
|
||||
def _parse_extract(self, extract: list[dict]) -> list[ExtractModel]:
|
||||
result = []
|
||||
|
||||
for item in extract:
|
||||
if "name" not in item:
|
||||
raise ParseError("Extract missing 'name'")
|
||||
if "json_path" not in item:
|
||||
raise ParseError(f"Extract '{item.get('name')}' missing 'json_path'")
|
||||
|
||||
result.append(ExtractModel(
|
||||
name=item["name"],
|
||||
json_path=item["json_path"],
|
||||
source=item.get("source", "body"),
|
||||
))
|
||||
|
||||
return result
|
||||
|
||||
def _parse_assert(self, asserts: list[dict]) -> list[AssertModel]:
|
||||
result = []
|
||||
|
||||
for item in asserts:
|
||||
if "type" not in item:
|
||||
raise ParseError("Assert missing 'type'")
|
||||
|
||||
result.append(AssertModel(
|
||||
type=item["type"],
|
||||
path=item.get("path"),
|
||||
operator=item.get("operator", "equals"),
|
||||
value=item.get("value"),
|
||||
))
|
||||
|
||||
return result
|
||||
Reference in new issue
Block a user