Skip to content
Open
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
1 change: 1 addition & 0 deletions pkg/flow/flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ type Config struct {
Name string `yaml:"name"`
Tags []string `yaml:"tags"`
Env map[string]string `yaml:"env"`
Properties map[string]string `yaml:"properties"`
Timeout int `yaml:"timeout"` // Flow timeout in ms
CommandTimeout int `yaml:"commandTimeout"` // Default timeout for all commands in ms (overrides driver default)
WaitForIdleTimeout *int `yaml:"waitForIdleTimeout"` // Wait for device idle in ms (nil = use global, 0 = disabled)
Expand Down
2 changes: 2 additions & 0 deletions pkg/report/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ func BuildSkeleton(flows []flow.Flow, cfg BuilderConfig) (*Index, []FlowDetail,
Name: flowName,
SourceFile: f.SourcePath,
Tags: f.Config.Tags,
Properties: f.Config.Properties,
Device: &cfg.Device,
DataFile: filepath.Join("flows", flowID+".json"),
AssetsDir: filepath.Join("assets", flowID),
Expand All @@ -80,6 +81,7 @@ func BuildSkeleton(flows []flow.Flow, cfg BuilderConfig) (*Index, []FlowDetail,
Name: flowName,
SourceFile: f.SourcePath,
Tags: f.Config.Tags,
Properties: f.Config.Properties,
Device: &cfg.Device, // Device that runs this flow (for multi-device support)
Commands: commands,
Artifacts: FlowArtifacts{},
Expand Down
9 changes: 9 additions & 0 deletions pkg/report/junit.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,15 @@ func buildTestCase(entry *FlowEntry, detail *FlowDetail, index *Index) string {
))
}
}
if len(entry.Properties) > 0 {
for key, value := range entry.Properties {
b.WriteString(fmt.Sprintf(
` <property name="%s" value="%s"/>`+"\n",
xmlEscape(key),
xmlEscape(value),
))
}
}
b.WriteString(" </properties>\n")

// Status-specific elements
Expand Down
28 changes: 28 additions & 0 deletions pkg/report/junit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -634,3 +634,31 @@ func TestBuildJUnitXMLNoEndTime(t *testing.T) {
t.Errorf("expected time=0.000 when no end time\nGot:\n%s", xml)
}
}

func TestBuildJUnitXMLCustomProperties(t *testing.T) {
now := time.Now()
index := &Index{
Version: "1.0.0",
Status: StatusPassed,
StartTime: now,
Device: Device{ID: "test", Name: "Test", Platform: "android"},
Summary: Summary{Total: 1, Passed: 1},
Flows: []FlowEntry{
{
Index: 0, ID: "flow-000", Name: "Test",
SourceFile: "test.yaml", DataFile: "flows/flow-000.json",
Status: StatusPassed, Properties: map[string]string{"testID": "Test-1234"},
},
},
}

flows := []FlowDetail{
{ID: "flow-000", Name: "Test", Commands: []Command{}},
}

xml := buildJUnitXML(index, flows)

if !strings.Contains(xml, `property name="testID" value="Test-1234"`) {
t.Errorf("expected custom property\nGot:\n%s", xml)
}
}
60 changes: 31 additions & 29 deletions pkg/report/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,24 +98,25 @@ type Summary struct {

// FlowEntry is the index entry for a flow (minimal info).
type FlowEntry struct {
Index int `json:"index"` // Original position
ID string `json:"id"` // Unique flow ID
Name string `json:"name"` // Display name
SourceFile string `json:"sourceFile"` // Path to YAML file
Tags []string `json:"tags,omitempty"` // Tags for filtering
Device *Device `json:"device,omitempty"` // Device that ran this flow (for multi-device runs)
DataFile string `json:"dataFile"` // Path to flow detail JSON
AssetsDir string `json:"assetsDir"` // Path to assets directory
Status Status `json:"status"`
UpdateSeq uint64 `json:"updateSeq"`
StartTime *time.Time `json:"startTime,omitempty"`
EndTime *time.Time `json:"endTime,omitempty"`
Duration *int64 `json:"duration,omitempty"` // milliseconds
LastUpdated *time.Time `json:"lastUpdated,omitempty"`
Commands CommandSummary `json:"commands"`
Attempts int `json:"attempts"`
AttemptHistory []AttemptEntry `json:"attemptHistory,omitempty"`
Error *string `json:"error,omitempty"`
Index int `json:"index"` // Original position
ID string `json:"id"` // Unique flow ID
Name string `json:"name"` // Display name
SourceFile string `json:"sourceFile"` // Path to YAML file
Tags []string `json:"tags,omitempty"` // Tags for filtering
Properties map[string]string `json:"properties,omitempty"` // Custom metadata for junit XML
Device *Device `json:"device,omitempty"` // Device that ran this flow (for multi-device runs)
DataFile string `json:"dataFile"` // Path to flow detail JSON
AssetsDir string `json:"assetsDir"` // Path to assets directory
Status Status `json:"status"`
UpdateSeq uint64 `json:"updateSeq"`
StartTime *time.Time `json:"startTime,omitempty"`
EndTime *time.Time `json:"endTime,omitempty"`
Duration *int64 `json:"duration,omitempty"` // milliseconds
LastUpdated *time.Time `json:"lastUpdated,omitempty"`
Commands CommandSummary `json:"commands"`
Attempts int `json:"attempts"`
AttemptHistory []AttemptEntry `json:"attemptHistory,omitempty"`
Error *string `json:"error,omitempty"`
}

// CommandSummary contains command counts for a flow.
Expand Down Expand Up @@ -144,17 +145,18 @@ type AttemptEntry struct {

// FlowDetail contains full flow execution details.
type FlowDetail struct {
ID string `json:"id"`
Name string `json:"name"`
SourceFile string `json:"sourceFile"`
Tags []string `json:"tags,omitempty"`
Device *Device `json:"device,omitempty"` // Device that ran this flow (for multi-device runs)
StartTime time.Time `json:"startTime"`
EndTime *time.Time `json:"endTime,omitempty"`
Duration *int64 `json:"duration,omitempty"` // milliseconds
Commands []Command `json:"commands"`
Artifacts FlowArtifacts `json:"artifacts"`
ConsoleLogs []ConsoleLog `json:"consoleLogs,omitempty"` // Browser console / page errors captured during the flow (web only)
ID string `json:"id"`
Name string `json:"name"`
SourceFile string `json:"sourceFile"`
Tags []string `json:"tags,omitempty"`
Properties map[string]string `json:"properties,omitempty"` // Custom metadata for junit XML
Device *Device `json:"device,omitempty"` // Device that ran this flow (for multi-device runs)
StartTime time.Time `json:"startTime"`
EndTime *time.Time `json:"endTime,omitempty"`
Duration *int64 `json:"duration,omitempty"` // milliseconds
Commands []Command `json:"commands"`
Artifacts FlowArtifacts `json:"artifacts"`
ConsoleLogs []ConsoleLog `json:"consoleLogs,omitempty"` // Browser console / page errors captured during the flow (web only)
}

// ConsoleLog represents a single browser console message or uncaught JS
Expand Down