1 /++ 2 A module containing the SpecStepsReporter 3 4 This is an example of how this reporter looks 5 <script type="text/javascript" src="https://asciinema.org/a/bsk6do8t4zay9k9vznvh8yn71.js" id="asciicast-bsk6do8t4zay9k9vznvh8yn71" async></script> 6 7 Copyright: © 2017 Szabo Bogdan 8 License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. 9 Authors: Szabo Bogdan 10 +/ 11 module trial.reporters.specsteps; 12 13 import trial.interfaces; 14 import trial.reporters.spec; 15 import trial.reporters.writer; 16 import trial.settings; 17 18 import std.datetime; 19 import std.conv; 20 21 /// A structure containing the glyphs used for the spec steps reporter 22 struct SpecStepsGlyphs { 23 version(Windows) { 24 /// 25 string testBegin = "/"; 26 27 /// 28 string testEnd = "\\"; 29 30 /// 31 string step = "|"; 32 } else { 33 /// 34 string testBegin = "┌"; 35 36 /// 37 string testEnd = "└"; 38 39 /// 40 string step = "│"; 41 } 42 } 43 44 /// 45 string specStepsGlyphsToCode(SpecStepsGlyphs glyphs) { 46 return "SpecStepsGlyphs(`" ~ glyphs.testBegin ~ "`, `" ~ glyphs.testEnd ~ "`, `" ~ glyphs.step ~ "`)"; 47 } 48 49 /// A flavour of the "spec" reporter that show the tests and the steps of your tests. 50 class SpecStepsReporter : SpecReporter, ISuiteLifecycleListener, IStepLifecycleListener 51 { 52 private { 53 size_t indents; 54 size_t stepIndents; 55 56 Settings settings; 57 } 58 59 60 this(Settings settings) 61 { 62 super(settings); 63 this.settings = settings; 64 } 65 66 this(ReportWriter writer) 67 { 68 super(writer); 69 } 70 71 void begin(ref SuiteResult suite) 72 { 73 indents = printSuite(suite.name); 74 } 75 76 void end(ref SuiteResult) { } 77 78 override 79 { 80 void begin(string suite, ref TestResult test) 81 { 82 stepIndents = 0; 83 write!(Type.none)(settings.glyphs.specSteps.testBegin ~ " " ~ test.name ~ "\n", indents); 84 } 85 86 void end(string suite, ref TestResult test) 87 { 88 write!(Type.none)(settings.glyphs.specSteps.testEnd ~ " ", indents); 89 90 if(test.status == TestResult.Status.success) { 91 write!(Type.success)("Success", 0); 92 } else if(test.status == TestResult.Status.failure) { 93 write!(Type.failure)("Failure", 0); 94 failedTests++; 95 } else if(test.status == TestResult.Status.pending) { 96 write!(Type.pending)("Pending", 0); 97 } else { 98 write!(Type.none)("Unknown", 0); 99 } 100 101 auto timeDiff = (test.end - test.begin).total!"msecs"; 102 103 if(timeDiff >= settings.warningTestDuration && timeDiff < settings.dangerTestDuration) { 104 write!(Type.warning)(" (" ~ timeDiff.to!string ~ "ms)", 0); 105 } 106 107 if(timeDiff >= settings.dangerTestDuration) { 108 write!(Type.danger)(" (" ~ timeDiff.to!string ~ "ms)", 0); 109 } 110 111 write!(Type.none)("\n", 0); 112 } 113 } 114 115 void begin(string suite, string test, ref StepResult s) 116 { 117 stepIndents++; 118 write!(Type.none)(settings.glyphs.specSteps.step, indents); 119 write!(Type.none)(" " ~ s.name ~ "\n", stepIndents); 120 } 121 122 void end(string suite, string test, ref StepResult) 123 { 124 stepIndents--; 125 } 126 } 127 128 version (unittest) 129 { 130 version(Have_fluent_asserts) { 131 import fluent.asserts; 132 } 133 } 134 135 @("it should format the steps for a success test") 136 unittest 137 { 138 auto writer = new BufferedWriter; 139 auto reporter = new SpecStepsReporter(writer); 140 141 auto suite = SuiteResult("some suite"); 142 auto test = new TestResult("some test"); 143 test.status = TestResult.Status.success; 144 145 auto step = new StepResult(); 146 step.name = "some step"; 147 148 reporter.begin(suite); 149 reporter.begin("some suite", test); 150 151 reporter.begin("some suite", "some test", step); 152 reporter.begin("some suite", "some test", step); 153 reporter.end("some suite", "some test", step); 154 reporter.end("some suite", "some test", step); 155 reporter.begin("some suite", "some test", step); 156 reporter.end("some suite", "some test", step); 157 158 reporter.end("some suite", test); 159 160 reporter.begin("some suite", test); 161 reporter.end("some suite", test); 162 163 reporter.end(suite); 164 165 writer.buffer.should.equal("\n" ~ 166 " some suite\n" ~ 167 " ┌ some test\n" ~ 168 " │ some step\n" ~ 169 " │ some step\n" ~ 170 " │ some step\n" ~ 171 " └ ✓ Success\n" ~ 172 " ┌ some test\n" ~ 173 " └ ✓ Success\n"); 174 } 175 176 @("it should format a pending test") 177 unittest 178 { 179 auto writer = new BufferedWriter; 180 auto reporter = new SpecStepsReporter(writer); 181 182 auto suite = SuiteResult("some suite"); 183 auto test = new TestResult("some test"); 184 test.status = TestResult.Status.pending; 185 186 reporter.begin(suite); 187 reporter.begin("some suite", test); 188 reporter.end("some suite", test); 189 190 reporter.end(suite); 191 192 writer.buffer.should.equal("\n" ~ 193 " some suite\n" ~ 194 " ┌ some test\n" ~ 195 " └ - Pending\n"); 196 } 197 198 199 @("it should print the duration of a long test") 200 unittest 201 { 202 auto writer = new BufferedWriter; 203 auto reporter = new SpecStepsReporter(writer); 204 205 auto suite = SuiteResult("some suite"); 206 auto test = new TestResult("some test"); 207 test.status = TestResult.Status.success; 208 test.end = Clock.currTime; 209 test.begin = test.end - 200.msecs; 210 211 reporter.begin(suite); 212 reporter.begin("some suite", test); 213 reporter.end("some suite", test); 214 215 reporter.end(suite); 216 217 writer.buffer.should.equal("\n" ~ 218 " some suite\n" ~ 219 " ┌ some test\n" ~ 220 " └ ✓ Success (200ms)\n"); 221 } 222 223 224 @("it should format the steps for a failing test") 225 unittest 226 { 227 auto writer = new BufferedWriter; 228 auto reporter = new SpecStepsReporter(writer); 229 230 auto suite = SuiteResult("some suite"); 231 auto test = new TestResult("some test"); 232 test.status = TestResult.Status.failure; 233 234 auto step = new StepResult(); 235 step.name = "some step"; 236 237 reporter.begin(suite); 238 reporter.begin("some suite", test); 239 240 reporter.begin("some suite", "some test", step); 241 reporter.begin("some suite", "some test", step); 242 reporter.end("some suite", "some test", step); 243 reporter.end("some suite", "some test", step); 244 reporter.begin("some suite", "some test", step); 245 reporter.end("some suite", "some test", step); 246 247 reporter.end("some suite", test); 248 249 reporter.begin("some suite", test); 250 reporter.end("some suite", test); 251 252 reporter.end(suite); 253 254 writer.buffer.should.equal("\n" ~ 255 " some suite\n" ~ 256 " ┌ some test\n" ~ 257 " │ some step\n" ~ 258 " │ some step\n" ~ 259 " │ some step\n" ~ 260 " └ 0) Failure\n" ~ 261 " ┌ some test\n" ~ 262 " └ 1) Failure\n"); 263 }