navigation_validation.jl
1 #!/usr/bin/env julia 2 3 """ 4 Navigation and User Journey Validation Script 5 6 This script validates the complete user journey from landing page through 7 getting started, ensuring all navigation paths work correctly. 8 """ 9 10 function validate_user_journey() 11 println("š¤ļø Validating User Journey Navigation") 12 println("=" ^ 40) 13 14 # Define the expected user journey 15 journey_steps = [ 16 ("docs/src/index.md", "Landing Page"), 17 ("docs/src/getting-started/index.md", "Getting Started Overview"), 18 ("docs/src/getting-started/installation.md", "Installation Guide"), 19 ("docs/src/getting-started/quick-start.md", "Quick Start Guide"), 20 ("docs/src/getting-started/first-strategy.md", "First Strategy Tutorial") 21 ] 22 23 validation_results = Dict{String, Bool}() 24 25 for (filepath, description) in journey_steps 26 println("\nš Validating: $description") 27 28 if !isfile(filepath) 29 println(" ā File missing: $filepath") 30 validation_results[description] = false 31 continue 32 end 33 34 content = read(filepath, String) 35 36 # Check for required elements 37 checks = Dict{String, Bool}() 38 39 # 1. Has frontmatter 40 checks["Has frontmatter"] = startswith(content, "---") 41 42 # 2. Has title/heading 43 checks["Has main heading"] = occursin(r"^#\s+\w+"m, content) || occursin("\n# ", content) 44 45 # 3. Has navigation elements 46 if filepath == "docs/src/index.md" 47 checks["Has user paths"] = occursin("First Time Here", content) || occursin("Getting Started", content) 48 checks["Has quick access"] = occursin("Quick access", content) || occursin("API Docs", content) 49 else 50 checks["Has next steps"] = occursin("Next Steps", content) || occursin("What's Next", content) 51 checks["Has see also"] = occursin("See Also", content) || occursin("Related", content) 52 end 53 54 # 4. Links to next step in journey 55 if filepath != last(journey_steps)[1] # Not the last step 56 next_step_index = findfirst(x -> x[1] == filepath, journey_steps) 57 if next_step_index !== nothing && next_step_index < length(journey_steps) 58 next_file = journey_steps[next_step_index + 1][1] 59 next_filename = basename(next_file) 60 checks["Links to next step"] = occursin(next_filename, content) 61 end 62 end 63 64 # 5. Has estimated time (for getting-started pages) 65 if contains(filepath, "getting-started") && filepath != "docs/src/getting-started/index.md" 66 checks["Has time estimate"] = occursin("estimated_time", content) || occursin("minutes", content) 67 end 68 69 # Report results for this page 70 all_passed = all(values(checks)) 71 validation_results[description] = all_passed 72 73 for (check_name, passed) in checks 74 status = passed ? "ā " : "ā" 75 println(" $status $check_name") 76 end 77 78 if all_passed 79 println(" š All checks passed for $description") 80 else 81 failed_checks = [name for (name, passed) in checks if !passed] 82 println(" ā ļø Failed checks: $(join(failed_checks, ", "))") 83 end 84 end 85 86 return validation_results 87 end 88 89 function validate_cross_references() 90 println("\nš Validating Cross-References") 91 println("=" ^ 30) 92 93 # Key files that should cross-reference each other 94 cross_ref_pairs = [ 95 ("docs/src/index.md", "docs/src/getting-started/installation.md"), 96 ("docs/src/getting-started/installation.md", "docs/src/getting-started/quick-start.md"), 97 ("docs/src/getting-started/quick-start.md", "docs/src/getting-started/first-strategy.md"), 98 ("docs/src/getting-started/first-strategy.md", "docs/src/guides/strategy-development.md") 99 ] 100 101 cross_ref_results = Dict{String, Bool}() 102 103 for (source_file, target_file) in cross_ref_pairs 104 if !isfile(source_file) || !isfile(target_file) 105 cross_ref_results["$(basename(source_file)) ā $(basename(target_file))"] = false 106 continue 107 end 108 109 source_content = read(source_file, String) 110 target_filename = basename(target_file) 111 112 # Check if source links to target 113 has_link = occursin(target_filename, source_content) 114 cross_ref_results["$(basename(source_file)) ā $(basename(target_file))"] = has_link 115 116 status = has_link ? "ā " : "ā" 117 println("$status $(basename(source_file)) ā $(basename(target_file))") 118 end 119 120 return cross_ref_results 121 end 122 123 function validate_content_completeness() 124 println("\nš Validating Content Completeness") 125 println("=" ^ 35) 126 127 # Required content sections for each page type 128 content_requirements = Dict( 129 "docs/src/index.md" => [ 130 "What's Next", "First Time Here", "Ready to Build", "Going Live" 131 ], 132 "docs/src/getting-started/installation.md" => [ 133 "Prerequisites", "Docker", "Verification", "Troubleshooting", "Next Steps" 134 ], 135 "docs/src/getting-started/quick-start.md" => [ 136 "What You'll Accomplish", "Step 1", "Step 2", "Expected output" 137 ], 138 "docs/src/getting-started/first-strategy.md" => [ 139 "What You'll Learn", "Prerequisites", "Strategy Structure", "Step" 140 ] 141 ) 142 143 completeness_results = Dict{String, Float64}() 144 145 for (filepath, required_sections) in content_requirements 146 if !isfile(filepath) 147 completeness_results[basename(filepath)] = 0.0 148 continue 149 end 150 151 content = read(filepath, String) 152 found_sections = 0 153 154 println("\nš $(basename(filepath)):") 155 for section in required_sections 156 has_section = occursin(section, content) 157 status = has_section ? "ā " : "ā" 158 println(" $status $section") 159 if has_section 160 found_sections += 1 161 end 162 end 163 164 completeness_score = found_sections / length(required_sections) 165 completeness_results[basename(filepath)] = completeness_score 166 167 println(" š Completeness: $(round(completeness_score * 100, digits=1))%") 168 end 169 170 return completeness_results 171 end 172 173 function validate_time_requirements() 174 println("\nā±ļø Validating Time Requirements") 175 println("=" ^ 30) 176 177 # Extract time estimates from frontmatter 178 time_files = [ 179 "docs/src/getting-started/installation.md", 180 "docs/src/getting-started/quick-start.md", 181 "docs/src/getting-started/first-strategy.md" 182 ] 183 184 total_time = 0 185 time_results = Dict{String, Int}() 186 187 for filepath in time_files 188 if !isfile(filepath) 189 continue 190 end 191 192 content = read(filepath, String) 193 194 # Look for estimated_time in frontmatter 195 time_match = match(r"estimated_time:\s*[\"']?(\d+)", content) 196 if time_match !== nothing 197 estimated_time = parse(Int, time_match.captures[1]) 198 time_results[basename(filepath)] = estimated_time 199 total_time += estimated_time 200 201 println("š $(basename(filepath)): $estimated_time minutes") 202 else 203 println("ā $(basename(filepath)): No time estimate found") 204 time_results[basename(filepath)] = 0 205 end 206 end 207 208 println("\nš Total estimated time: $total_time minutes") 209 210 # Check against requirement (should be ⤠30 minutes) 211 meets_requirement = total_time <= 30 212 status = meets_requirement ? "ā " : "ā" 213 println("$status Meets 30-minute requirement: $meets_requirement") 214 215 return time_results, total_time, meets_requirement 216 end 217 218 # Main execution 219 println("š Starting Navigation and User Journey Validation") 220 println("=" ^ 55) 221 222 # Run all validations 223 journey_results = validate_user_journey() 224 cross_ref_results = validate_cross_references() 225 completeness_results = validate_content_completeness() 226 time_results, total_time, time_ok = validate_time_requirements() 227 228 # Generate summary report 229 println("\nš VALIDATION SUMMARY") 230 println("=" ^ 25) 231 232 # Journey validation 233 journey_passed = count(values(journey_results)) 234 journey_total = length(journey_results) 235 println("User Journey: $journey_passed/$journey_total pages validated ($(round(journey_passed/journey_total*100, digits=1))%)") 236 237 # Cross-reference validation 238 cross_ref_passed = count(values(cross_ref_results)) 239 cross_ref_total = length(cross_ref_results) 240 println("Cross-References: $cross_ref_passed/$cross_ref_total links working ($(round(cross_ref_passed/cross_ref_total*100, digits=1))%)") 241 242 # Content completeness 243 avg_completeness = sum(values(completeness_results)) / length(completeness_results) * 100 244 println("Content Completeness: $(round(avg_completeness, digits=1))% average") 245 246 # Time requirements 247 println("Time Requirements: $(time_ok ? "ā PASS" : "ā FAIL") ($total_time/30 minutes)") 248 249 # Overall assessment 250 overall_score = (journey_passed/journey_total + cross_ref_passed/cross_ref_total + avg_completeness/100) / 3 251 println("\nšÆ Overall Score: $(round(overall_score * 100, digits=1))%") 252 253 if overall_score >= 0.8 254 println("š User journey validation PASSED!") 255 exit(0) 256 else 257 println("ā ļø User journey validation needs improvement") 258 exit(1) 259 end