...

Source file src/github.com/onsi/ginkgo/v2/reporters/default_reporter_test.go

Documentation: github.com/onsi/ginkgo/v2/reporters

     1  package reporters_test
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"runtime"
     7  	"strings"
     8  	"time"
     9  
    10  	. "github.com/onsi/ginkgo/v2"
    11  	"github.com/onsi/ginkgo/v2/internal"
    12  	"github.com/onsi/ginkgo/v2/internal/test_helpers"
    13  	"github.com/onsi/ginkgo/v2/reporters"
    14  	"github.com/onsi/ginkgo/v2/types"
    15  	. "github.com/onsi/gomega"
    16  	"github.com/onsi/gomega/format"
    17  	"github.com/onsi/gomega/gbytes"
    18  )
    19  
    20  var MatchLines = test_helpers.MatchLines
    21  
    22  // This is a mini-DSL for quickly and succinctly building Ginkgo SpecReports and all their attendant objects
    23  
    24  const DELIMITER = `{{gray}}------------------------------{{/}}`
    25  const INDENTED_DELIMITER = `  {{gray}}------------------------------{{/}}`
    26  
    27  var cl0 = types.CodeLocation{FileName: "cl0.go", LineNumber: 12, FullStackTrace: "full-trace\ncl-0"}
    28  var cl1 = types.CodeLocation{FileName: "cl1.go", LineNumber: 37, FullStackTrace: "full-trace\ncl-1"}
    29  var cl2 = types.CodeLocation{FileName: "cl2.go", LineNumber: 80, FullStackTrace: "full-trace\ncl-2"}
    30  var cl3 = types.CodeLocation{FileName: "cl3.go", LineNumber: 103, FullStackTrace: "full-trace\ncl-3"}
    31  var cl4 = types.CodeLocation{FileName: "cl4.go", LineNumber: 144, FullStackTrace: "full-trace\ncl-4"}
    32  var now = time.Now()
    33  
    34  func CLS(cls ...types.CodeLocation) []types.CodeLocation { return cls }
    35  func CTS(componentTexts ...string) []string              { return componentTexts }
    36  func CLabels(labels ...Labels) []Labels                  { return labels }
    37  func spr(format string, args ...any) string              { return fmt.Sprintf(format, args...) }
    38  
    39  type FailureNodeLocation types.CodeLocation
    40  type ForwardedPanic string
    41  type StackTrace string
    42  
    43  var PLACEHOLDER_TIME = now
    44  var FORMATTED_TIME = PLACEHOLDER_TIME.Format(types.GINKGO_TIME_FORMAT)
    45  
    46  var tlOrder = 1
    47  
    48  func TL(options ...interface{}) types.TimelineLocation {
    49  	out := types.TimelineLocation{
    50  		Order: tlOrder,
    51  		Time:  now,
    52  	}
    53  	tlOrder += 1
    54  	for _, option := range options {
    55  		switch x := option.(type) {
    56  		case string:
    57  			out.Offset = len(x)
    58  		case int:
    59  			out.Offset = x
    60  		case time.Time:
    61  			out.Time = x
    62  		}
    63  	}
    64  	return out
    65  }
    66  
    67  // convenience helper to quickly make Failures
    68  func F(options ...interface{}) types.Failure {
    69  	failure := types.Failure{TimelineLocation: TL()}
    70  	for _, option := range options {
    71  		switch x := option.(type) {
    72  		case string:
    73  			failure.Message = x
    74  		case types.CodeLocation:
    75  			failure.Location = x
    76  		case ForwardedPanic:
    77  			failure.ForwardedPanic = string(x)
    78  		case types.FailureNodeContext:
    79  			failure.FailureNodeContext = x
    80  		case int:
    81  			failure.FailureNodeContainerIndex = x
    82  		case FailureNodeLocation:
    83  			failure.FailureNodeLocation = types.CodeLocation(x)
    84  		case types.NodeType:
    85  			failure.FailureNodeType = x
    86  		case types.ProgressReport:
    87  			failure.ProgressReport = x
    88  		case types.AdditionalFailure:
    89  			failure.AdditionalFailure = &x
    90  		case types.TimelineLocation:
    91  			failure.TimelineLocation = x
    92  		}
    93  	}
    94  	return failure
    95  }
    96  
    97  func AF(state types.SpecState, options ...interface{}) types.AdditionalFailure {
    98  	return types.AdditionalFailure{
    99  		State:   state,
   100  		Failure: F(options...),
   101  	}
   102  }
   103  
   104  type STD string
   105  type GW string
   106  
   107  // convenience helper to quickly make SpecReports
   108  func S(options ...interface{}) types.SpecReport {
   109  	report := types.SpecReport{
   110  		LeafNodeType:          types.NodeTypeIt,
   111  		State:                 types.SpecStatePassed,
   112  		NumAttempts:           1,
   113  		MaxFlakeAttempts:      1,
   114  		MaxMustPassRepeatedly: 1,
   115  		RunTime:               time.Second,
   116  	}
   117  	for _, option := range options {
   118  		switch x := option.(type) {
   119  		case []string:
   120  			report.ContainerHierarchyTexts = x
   121  		case []types.CodeLocation:
   122  			report.ContainerHierarchyLocations = x
   123  		case []Labels:
   124  			report.ContainerHierarchyLabels = [][]string{}
   125  			for _, labels := range x {
   126  				report.ContainerHierarchyLabels = append(report.ContainerHierarchyLabels, []string(labels))
   127  			}
   128  		case string:
   129  			report.LeafNodeText = x
   130  		case types.NodeType:
   131  			report.LeafNodeType = x
   132  		case types.CodeLocation:
   133  			report.LeafNodeLocation = x
   134  		case Labels:
   135  			report.LeafNodeLabels = x
   136  		case types.SpecState:
   137  			report.State = x
   138  		case time.Duration:
   139  			report.RunTime = x
   140  		case int:
   141  			report.NumAttempts = x
   142  		case FlakeAttempts:
   143  			report.MaxFlakeAttempts = int(x)
   144  		case MustPassRepeatedly:
   145  			report.MaxMustPassRepeatedly = int(x)
   146  		case STD:
   147  			report.CapturedStdOutErr = string(x)
   148  		case GW:
   149  			report.CapturedGinkgoWriterOutput = string(x)
   150  		case types.Failure:
   151  			report.Failure = x
   152  		case types.AdditionalFailure:
   153  			report.AdditionalFailures = append(report.AdditionalFailures, x)
   154  		case types.ReportEntry:
   155  			report.ReportEntries = append(report.ReportEntries, x)
   156  		case types.ProgressReport:
   157  			report.ProgressReports = append(report.ProgressReports, x)
   158  		case types.SpecEvent:
   159  			report.SpecEvents = append(report.SpecEvents, x)
   160  		}
   161  	}
   162  	if len(report.ContainerHierarchyLabels) == 0 {
   163  		for range report.ContainerHierarchyTexts {
   164  			report.ContainerHierarchyLabels = append(report.ContainerHierarchyLabels, []string{})
   165  		}
   166  	}
   167  	return report
   168  }
   169  
   170  type ConfigFlag uint8
   171  
   172  const (
   173  	Succinct ConfigFlag = 1 << iota
   174  	Normal
   175  	Verbose
   176  	VeryVerbose
   177  	FullTrace
   178  	ShowNodeEvents
   179  	GithubOutput
   180  
   181  	Parallel //used in the WillRun => DidRun specs to capture behavior when running in parallel
   182  )
   183  
   184  func (cf ConfigFlag) Has(flag ConfigFlag) bool { return cf&flag != 0 }
   185  func (cf ConfigFlag) String() string {
   186  	out := []string{}
   187  	if cf.Has(Succinct) {
   188  		out = append(out, "succinct")
   189  	}
   190  	if cf.Has(Normal) {
   191  		out = append(out, "normal")
   192  	}
   193  	if cf.Has(Verbose) {
   194  		out = append(out, "verbose")
   195  	}
   196  	if cf.Has(VeryVerbose) {
   197  		out = append(out, "very-verbose")
   198  	}
   199  	if cf.Has(FullTrace) {
   200  		out = append(out, "full-trace")
   201  	}
   202  	if cf.Has(ShowNodeEvents) {
   203  		out = append(out, "show-node-events")
   204  	}
   205  	if cf.Has(Parallel) {
   206  		out = append(out, "parallel")
   207  	}
   208  	if cf.Has(GithubOutput) {
   209  		out = append(out, "github-output")
   210  	}
   211  	return strings.Join(out, "|")
   212  }
   213  
   214  func C(flags ...ConfigFlag) types.ReporterConfig {
   215  	f := ConfigFlag(0)
   216  	if len(flags) > 0 {
   217  		f = flags[0]
   218  	}
   219  	numVerbosity := 0
   220  	for _, verbosityFlag := range []ConfigFlag{Succinct, Normal, Verbose, VeryVerbose} {
   221  		if f.Has(verbosityFlag) {
   222  			numVerbosity += 1
   223  		}
   224  	}
   225  	Ω(numVerbosity).Should(BeNumerically("<=", 1), "Setting more than one of Succinct, Normal, Verbose, or VeryVerbose is a configuration error")
   226  	return types.ReporterConfig{
   227  		NoColor:        true,
   228  		Succinct:       f.Has(Succinct),
   229  		Verbose:        f.Has(Verbose),
   230  		VeryVerbose:    f.Has(VeryVerbose),
   231  		FullTrace:      f.Has(FullTrace),
   232  		ShowNodeEvents: f.Has(ShowNodeEvents),
   233  		GithubOutput:   f.Has(GithubOutput),
   234  	}
   235  }
   236  
   237  type ConfigCase struct {
   238  	ConfigFlags []ConfigFlag
   239  	Expected    []any
   240  }
   241  
   242  func Case(args ...any) ConfigCase {
   243  	out := ConfigCase{}
   244  	for _, arg := range args {
   245  		switch x := arg.(type) {
   246  		case ConfigFlag:
   247  			out.ConfigFlags = append(out.ConfigFlags, x)
   248  		default:
   249  			out.Expected = append(out.Expected, x)
   250  		}
   251  	}
   252  	return out
   253  }
   254  
   255  type CurrentNodeText string
   256  type CurrentStepText string
   257  type LeafNodeText string
   258  type AdditionalReports []string
   259  
   260  func PR(options ...interface{}) types.ProgressReport {
   261  	report := types.ProgressReport{
   262  		ParallelProcess:   1,
   263  		RunningInParallel: false,
   264  
   265  		SpecStartTime:        now.Add(-5 * time.Second),
   266  		CurrentNodeStartTime: now.Add(-3 * time.Second),
   267  		CurrentStepStartTime: now.Add(-1 * time.Second),
   268  
   269  		LeafNodeLocation:    cl0,
   270  		CurrentNodeLocation: cl1,
   271  		CurrentStepLocation: cl2,
   272  		TimelineLocation:    TL(),
   273  	}
   274  	for _, option := range options {
   275  		switch x := option.(type) {
   276  		case []string:
   277  			report.ContainerHierarchyTexts = x
   278  		case GW:
   279  			report.CapturedGinkgoWriterOutput = string(x)
   280  		case LeafNodeText:
   281  			report.LeafNodeText = string(x)
   282  		case types.NodeType:
   283  			report.CurrentNodeType = x
   284  		case CurrentNodeText:
   285  			report.CurrentNodeText = string(x)
   286  		case CurrentStepText:
   287  			report.CurrentStepText = string(x)
   288  		case types.Goroutine:
   289  			report.Goroutines = append(report.Goroutines, x)
   290  		case []types.Goroutine:
   291  			report.Goroutines = append(report.Goroutines, x...)
   292  		case int:
   293  			report.ParallelProcess = x
   294  		case bool:
   295  			report.RunningInParallel = x
   296  		case string:
   297  			report.Message = x
   298  		case AdditionalReports:
   299  			report.AdditionalReports = x
   300  		case types.TimelineLocation:
   301  			report.TimelineLocation = x
   302  		}
   303  	}
   304  	return report
   305  }
   306  
   307  func Fn(f string, filename string, line int, options ...interface{}) types.FunctionCall {
   308  	out := types.FunctionCall{
   309  		Function: f,
   310  		Filename: filename,
   311  		Line:     line,
   312  	}
   313  	for _, option := range options {
   314  		switch option := option.(type) {
   315  		case bool:
   316  			out.Highlight = option
   317  		case string:
   318  			out.Source = append(out.Source, option)
   319  		case int:
   320  			out.SourceHighlight = option
   321  		}
   322  	}
   323  
   324  	return out
   325  }
   326  
   327  func G(options ...interface{}) types.Goroutine {
   328  	goroutine := types.Goroutine{
   329  		ID:              17,
   330  		State:           "running",
   331  		IsSpecGoroutine: false,
   332  	}
   333  
   334  	for _, option := range options {
   335  		switch reflect.TypeOf(option) {
   336  		case reflect.TypeOf(true):
   337  			goroutine.IsSpecGoroutine = option.(bool)
   338  		case reflect.TypeOf(""):
   339  			goroutine.State = option.(string)
   340  		case reflect.TypeOf(types.FunctionCall{}):
   341  			goroutine.Stack = append(goroutine.Stack, option.(types.FunctionCall))
   342  		case reflect.TypeOf([]types.FunctionCall{}):
   343  			goroutine.Stack = append(goroutine.Stack, option.([]types.FunctionCall)...)
   344  		}
   345  	}
   346  
   347  	return goroutine
   348  }
   349  
   350  func RE(name string, cl types.CodeLocation, args ...interface{}) types.ReportEntry {
   351  	var tl = TL()
   352  	finalArgs := []any{}
   353  	for _, arg := range args {
   354  		if theTl, isTl := arg.(types.TimelineLocation); isTl {
   355  			tl = theTl
   356  		} else {
   357  			finalArgs = append(finalArgs, arg)
   358  		}
   359  	}
   360  	entry, _ := internal.NewReportEntry(name, cl, finalArgs...)
   361  	entry.Time = PLACEHOLDER_TIME
   362  	entry.TimelineLocation = tl
   363  	return entry
   364  }
   365  
   366  func SE(options ...interface{}) types.SpecEvent {
   367  	se := types.SpecEvent{TimelineLocation: TL()}
   368  	for _, option := range options {
   369  		switch x := option.(type) {
   370  		case types.SpecEventType:
   371  			se.SpecEventType = x
   372  		case string:
   373  			se.Message = x
   374  		case types.CodeLocation:
   375  			se.CodeLocation = x
   376  		case types.TimelineLocation:
   377  			se.TimelineLocation = x
   378  		case time.Duration:
   379  			se.Duration = x
   380  		case types.NodeType:
   381  			se.NodeType = x
   382  		case int:
   383  			se.Attempt = x
   384  		}
   385  	}
   386  	return se
   387  }
   388  
   389  /*
   390  The strategy:
   391  	use the individual emitters to test the details of each type of output
   392  	only do didRun to test the various header modes and modalities around -v -vv etc.
   393  	spot check a single comprehensive timeline.  no need to super over-do it!
   394  */
   395  
   396  var _ = Describe("DefaultReporter", func() {
   397  	var DENOTER = "•"
   398  	var RETRY_DENOTER = "↺"
   399  	if runtime.GOOS == "windows" {
   400  		DENOTER = "+"
   401  		RETRY_DENOTER = "R"
   402  	}
   403  
   404  	var buf *gbytes.Buffer
   405  
   406  	BeforeEach(func() {
   407  		buf = gbytes.NewBuffer()
   408  		format.CharactersAroundMismatchToInclude = 100
   409  	})
   410  
   411  	DescribeTable("Rendering SuiteWillBegin",
   412  		func(conf types.ReporterConfig, report types.Report, expected ...any) {
   413  			reporter := reporters.NewDefaultReporterUnderTest(conf, buf)
   414  			reporter.SuiteWillBegin(report)
   415  			Expect(string(buf.Contents())).Should(MatchLines(expected...))
   416  		},
   417  		Entry("Default Behavior",
   418  			C(),
   419  			types.Report{
   420  				SuiteDescription: "My Suite", SuitePath: "/path/to/suite", PreRunStats: types.PreRunStats{SpecsThatWillRun: 15, TotalSpecs: 20},
   421  				SuiteConfig: types.SuiteConfig{RandomSeed: 17, ParallelTotal: 1},
   422  			},
   423  			"Running Suite: My Suite - /path/to/suite",
   424  			"========================================",
   425  			"Random Seed: {{bold}}17{{/}}",
   426  			"",
   427  			"Will run {{bold}}15{{/}} of {{bold}}20{{/}} specs",
   428  			"",
   429  		),
   430  		Entry("With Labels",
   431  			C(),
   432  			types.Report{
   433  				SuiteDescription: "My Suite", SuitePath: "/path/to/suite", SuiteLabels: []string{"dog", "fish"}, PreRunStats: types.PreRunStats{SpecsThatWillRun: 15, TotalSpecs: 20},
   434  				SuiteConfig: types.SuiteConfig{RandomSeed: 17, ParallelTotal: 1},
   435  			},
   436  			"Running Suite: My Suite - /path/to/suite",
   437  			"{{coral}}[dog, fish]{{/}} ",
   438  			"========================================",
   439  			"Random Seed: {{bold}}17{{/}}",
   440  			"",
   441  			"Will run {{bold}}15{{/}} of {{bold}}20{{/}} specs",
   442  			"",
   443  		),
   444  		Entry("With long Labels",
   445  			C(),
   446  			types.Report{
   447  				SuiteDescription: "My Suite", SuitePath: "/path/to/suite", SuiteLabels: []string{"dog", "fish", "kalamazoo", "kangaroo", "chicken", "asparagus"}, PreRunStats: types.PreRunStats{SpecsThatWillRun: 15, TotalSpecs: 20},
   448  				SuiteConfig: types.SuiteConfig{RandomSeed: 17, ParallelTotal: 1},
   449  			},
   450  			"Running Suite: My Suite - /path/to/suite",
   451  			"{{coral}}[dog, fish, kalamazoo, kangaroo, chicken, asparagus]{{/}} ",
   452  			"====================================================",
   453  			"Random Seed: {{bold}}17{{/}}",
   454  			"",
   455  			"Will run {{bold}}15{{/}} of {{bold}}20{{/}} specs",
   456  			"",
   457  		),
   458  		Entry("When configured to randomize all specs",
   459  			C(),
   460  			types.Report{
   461  				SuiteDescription: "My Suite", SuitePath: "/path/to/suite", PreRunStats: types.PreRunStats{SpecsThatWillRun: 15, TotalSpecs: 20},
   462  				SuiteConfig: types.SuiteConfig{RandomSeed: 17, ParallelTotal: 1, RandomizeAllSpecs: true},
   463  			},
   464  			"Running Suite: My Suite - /path/to/suite",
   465  			"========================================",
   466  			"Random Seed: {{bold}}17{{/}} - will randomize all specs",
   467  			"",
   468  			"Will run {{bold}}15{{/}} of {{bold}}20{{/}} specs",
   469  			"",
   470  		),
   471  		Entry("when configured to run in parallel",
   472  			C(),
   473  			types.Report{
   474  				SuiteDescription: "My Suite", SuitePath: "/path/to/suite", PreRunStats: types.PreRunStats{SpecsThatWillRun: 15, TotalSpecs: 20},
   475  				SuiteConfig: types.SuiteConfig{RandomSeed: 17, ParallelTotal: 3},
   476  			},
   477  			"Running Suite: My Suite - /path/to/suite",
   478  			"========================================",
   479  			"Random Seed: {{bold}}17{{/}}",
   480  			"",
   481  			"Will run {{bold}}15{{/}} of {{bold}}20{{/}} specs",
   482  			"Running in parallel across {{bold}}3{{/}} processes",
   483  			"",
   484  		),
   485  		Entry("when succinct and in series",
   486  			C(Succinct),
   487  			types.Report{
   488  				SuiteDescription: "My Suite", SuitePath: "/path/to/suite", PreRunStats: types.PreRunStats{SpecsThatWillRun: 15, TotalSpecs: 20},
   489  				SuiteConfig: types.SuiteConfig{RandomSeed: 17, ParallelTotal: 1},
   490  			},
   491  			"[17] {{bold}}My Suite{{/}} - 15/20 specs ",
   492  		),
   493  		Entry("when succinct and in parallel",
   494  			C(Succinct),
   495  			types.Report{
   496  				SuiteDescription: "My Suite", SuitePath: "/path/to/suite", PreRunStats: types.PreRunStats{SpecsThatWillRun: 15, TotalSpecs: 20},
   497  				SuiteConfig: types.SuiteConfig{RandomSeed: 17, ParallelTotal: 3},
   498  			},
   499  			"[17] {{bold}}My Suite{{/}} - 15/20 specs - 3 procs ",
   500  		),
   501  		Entry("when succinct and with labels",
   502  			C(Succinct),
   503  			types.Report{
   504  				SuiteDescription: "My Suite", SuitePath: "/path/to/suite", SuiteLabels: Label("dog, fish"), PreRunStats: types.PreRunStats{SpecsThatWillRun: 15, TotalSpecs: 20},
   505  				SuiteConfig: types.SuiteConfig{RandomSeed: 17, ParallelTotal: 3},
   506  			},
   507  			"[17] {{bold}}My Suite{{/}} {{coral}}[dog, fish]{{/}} - 15/20 specs - 3 procs ",
   508  		),
   509  	)
   510  
   511  	DescribeTable("WillRun",
   512  		func(conf types.ReporterConfig, report types.SpecReport, expected ...any) {
   513  			reporter := reporters.NewDefaultReporterUnderTest(conf, buf)
   514  			reporter.WillRun(report)
   515  			Expect(string(buf.Contents())).Should(MatchLines(expected...))
   516  		},
   517  		Entry("when not verbose, it emits nothing", C(), S(CTS("A"), CLS(cl0))),
   518  		Entry("pending specs are not emitted", C(Verbose), S(types.SpecStatePending)),
   519  		Entry("skipped specs are not emitted", C(Verbose), S(types.SpecStateSkipped)),
   520  		Entry("setup nodes", C(Verbose),
   521  			S(types.NodeTypeBeforeSuite, cl0),
   522  			DELIMITER,
   523  			"{{/}}{{bold}}[BeforeSuite] {{/}}",
   524  			"{{gray}}"+cl0.String()+"{{/}}",
   525  			"",
   526  		),
   527  		Entry("ReportAfterSuite nodes", C(Verbose),
   528  			S("my report", cl0, types.NodeTypeReportAfterSuite),
   529  			DELIMITER,
   530  			"{{/}}{{bold}}[ReportAfterSuite] my report{{/}}",
   531  			"{{gray}}"+cl0.String()+"{{/}}",
   532  			"",
   533  		),
   534  		Entry("top-level it nodes", C(Verbose),
   535  			S("My Test", cl0),
   536  			DELIMITER,
   537  			"{{/}}{{bold}}My Test{{/}}",
   538  			"{{gray}}"+cl0.String()+"{{/}}",
   539  			"",
   540  		),
   541  		Entry("nested it nodes", C(Verbose),
   542  			S(CTS("Container", "Nested Container"), "My Test", CLS(cl0, cl1), cl2),
   543  			DELIMITER,
   544  			"{{/}}Container {{gray}}Nested Container {{/}}{{bold}}My Test{{/}}",
   545  			"{{gray}}"+cl2.String()+"{{/}}",
   546  			"",
   547  		),
   548  		Entry("specs with labels", C(Verbose),
   549  			S(CTS("Container", "Nested Container"), "My Test", CLS(cl0, cl1), cl2, CLabels(Label("dog", "cat"), Label("cat", "fruit")), Label("giraffe", "gorilla", "cat")),
   550  			DELIMITER,
   551  			"{{/}}Container {{gray}}Nested Container {{/}}{{bold}}My Test{{/}} {{coral}}[dog, cat, fruit, giraffe, gorilla]{{/}}",
   552  			"{{gray}}"+cl2.String()+"{{/}}",
   553  			"",
   554  		),
   555  	)
   556  
   557  	DescribeTable("WillRun => DidRun",
   558  		func(report types.SpecReport, cases ...ConfigCase) {
   559  			for _, c := range cases {
   560  				for _, configFlag := range c.ConfigFlags {
   561  					reporter := reporters.NewDefaultReporterUnderTest(C(configFlag), buf)
   562  					report.RunningInParallel = configFlag.Has(Parallel)
   563  					reporter.WillRun(report)
   564  					reporter.DidRun(report)
   565  					Expect(string(buf.Contents())).Should(MatchLines(c.Expected...), "for config: %s", configFlag)
   566  					Ω(buf.Clear()).Should(Succeed())
   567  				}
   568  			}
   569  		},
   570  		// Passing tests
   571  		Entry("a passing test",
   572  			S(CLS(cl0, cl1), CTS("A", "B"), "C", cl2),
   573  			Case(Succinct, Normal, Succinct|Parallel, Normal|Parallel,
   574  				"{{green}}"+DENOTER+"{{/}}"),
   575  			Case(Verbose,
   576  				DELIMITER,
   577  				"{{/}}A {{gray}}B {{/}}{{bold}}C{{/}}",
   578  				"{{gray}}cl2.go:80{{/}}",
   579  				spr("{{green}}%s [1.000 seconds]{{/}}", DENOTER),
   580  				DELIMITER,
   581  				""),
   582  			Case(Verbose|Parallel,
   583  				DELIMITER,
   584  				spr("{{green}}%s [1.000 seconds]{{/}}", DENOTER),
   585  				"{{/}}A {{gray}}B {{green}}{{bold}}C{{/}}",
   586  				"{{gray}}cl2.go:80{{/}}",
   587  				DELIMITER,
   588  				""),
   589  			Case(VeryVerbose,
   590  				DELIMITER,
   591  				"A",
   592  				"{{gray}}cl0.go:12{{/}}",
   593  				"  B",
   594  				"  {{gray}}cl1.go:37{{/}}",
   595  				"    {{/}}{{bold}}C{{/}}",
   596  				"    {{gray}}cl2.go:80{{/}}",
   597  				spr("{{green}}%s [1.000 seconds]{{/}}", DENOTER),
   598  				DELIMITER,
   599  				""),
   600  			Case(VeryVerbose|Parallel,
   601  				DELIMITER,
   602  				spr("{{green}}%s [1.000 seconds]{{/}}", DENOTER),
   603  				"A",
   604  				"{{gray}}cl0.go:12{{/}}",
   605  				"  B",
   606  				"  {{gray}}cl1.go:37{{/}}",
   607  				"    {{green}}{{bold}}C{{/}}",
   608  				"    {{gray}}cl2.go:80{{/}}",
   609  				DELIMITER,
   610  				""),
   611  		),
   612  		Entry("a passing suite-level node",
   613  			S(types.NodeTypeReportAfterSuite, "C", cl0),
   614  			Case(Succinct, Normal, Succinct|Parallel, Normal|Parallel),
   615  			Case(Verbose, VeryVerbose,
   616  				DELIMITER,
   617  				"{{/}}{{bold}}[ReportAfterSuite] C{{/}}",
   618  				"{{gray}}cl0.go:12{{/}}",
   619  				"{{green}}[ReportAfterSuite] PASSED [1.000 seconds]{{/}}",
   620  				DELIMITER,
   621  				""),
   622  			Case(Verbose|Parallel, VeryVerbose|Parallel,
   623  				DELIMITER,
   624  				"{{green}}[ReportAfterSuite] PASSED [1.000 seconds]{{/}}",
   625  				"{{green}}{{bold}}[ReportAfterSuite] C{{/}}",
   626  				"{{gray}}cl0.go:12{{/}}",
   627  				DELIMITER,
   628  				""),
   629  		),
   630  		Entry("a passing test that was flakey",
   631  			S(types.NodeTypeIt, "A", cl0, 3, FlakeAttempts(4),
   632  				AF(types.SpecStateFailed, "failed", types.NodeTypeIt, cl1, types.FailureNodeIsLeafNode, FailureNodeLocation(cl0)),
   633  				SE(types.SpecEventSpecRetry, 1),
   634  				AF(types.SpecStateFailed, "failed again", types.NodeTypeIt, cl1, types.FailureNodeIsLeafNode, FailureNodeLocation(cl0)),
   635  				SE(types.SpecEventSpecRetry, 2),
   636  			),
   637  			Case(Succinct, Normal, Succinct|Parallel, Normal|Parallel,
   638  				DELIMITER,
   639  				spr("{{green}}%s [FLAKEY TEST - TOOK 3 ATTEMPTS TO PASS] [1.000 seconds]{{/}}", RETRY_DENOTER),
   640  				"{{green}}{{bold}}A{{/}}",
   641  				"{{gray}}cl0.go:12{{/}}",
   642  				DELIMITER,
   643  				""),
   644  			Case(Verbose, VeryVerbose,
   645  				DELIMITER,
   646  				"{{/}}{{bold}}A{{/}}",
   647  				"{{gray}}cl0.go:12{{/}}",
   648  				spr("{{green}}%s [FLAKEY TEST - TOOK 3 ATTEMPTS TO PASS] [1.000 seconds]{{/}}", RETRY_DENOTER),
   649  				DELIMITER,
   650  				""),
   651  			Case(Verbose|Parallel,
   652  				DELIMITER,
   653  				spr("{{green}}%s [FLAKEY TEST - TOOK 3 ATTEMPTS TO PASS] [1.000 seconds]{{/}}", RETRY_DENOTER),
   654  				"{{green}}{{bold}}A{{/}}",
   655  				"{{gray}}cl0.go:12{{/}}",
   656  				"",
   657  				"  {{gray}}Timeline >>{{/}}",
   658  				spr("  {{red}}[FAILED]{{/}} in [It] - cl1.go:37 {{gray}}@ %s{{/}}", FORMATTED_TIME),
   659  				"",
   660  				spr("  {{bold}}Attempt #1 {{red}}Failed{{/}}{{bold}}.  Retrying %s{{/}} {{gray}}@ %s{{/}}", RETRY_DENOTER, FORMATTED_TIME),
   661  				"",
   662  				spr("  {{red}}[FAILED]{{/}} in [It] - cl1.go:37 {{gray}}@ %s{{/}}", FORMATTED_TIME),
   663  				"",
   664  				spr("  {{bold}}Attempt #2 {{red}}Failed{{/}}{{bold}}.  Retrying %s{{/}} {{gray}}@ %s{{/}}", RETRY_DENOTER, FORMATTED_TIME),
   665  				"",
   666  				"  {{gray}}<< Timeline{{/}}",
   667  				DELIMITER,
   668  				""),
   669  			Case(VeryVerbose|Parallel,
   670  				DELIMITER,
   671  				spr("{{green}}%s [FLAKEY TEST - TOOK 3 ATTEMPTS TO PASS] [1.000 seconds]{{/}}", RETRY_DENOTER),
   672  				"{{green}}{{bold}}A{{/}}",
   673  				"{{gray}}cl0.go:12{{/}}",
   674  				"",
   675  				"  {{gray}}Timeline >>{{/}}",
   676  				"  {{red}}[FAILED] failed{{/}}",
   677  				spr("  {{red}}In {{bold}}[It]{{/}}{{red}} at: {{bold}}cl1.go:37{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
   678  				"",
   679  				spr("  {{bold}}Attempt #1 {{red}}Failed{{/}}{{bold}}.  Retrying %s{{/}} {{gray}}@ %s{{/}}", RETRY_DENOTER, FORMATTED_TIME),
   680  				"",
   681  				"  {{red}}[FAILED] failed again{{/}}",
   682  				spr("  {{red}}In {{bold}}[It]{{/}}{{red}} at: {{bold}}cl1.go:37{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
   683  				"",
   684  				spr("  {{bold}}Attempt #2 {{red}}Failed{{/}}{{bold}}.  Retrying %s{{/}} {{gray}}@ %s{{/}}", RETRY_DENOTER, FORMATTED_TIME),
   685  				"",
   686  				"  {{gray}}<< Timeline{{/}}",
   687  				DELIMITER,
   688  				""),
   689  		),
   690  		Entry("a passing test that repeated a few times",
   691  			S(types.NodeTypeIt, "A", cl0, 3, MustPassRepeatedly(3),
   692  				SE(types.SpecEventSpecRepeat, 1),
   693  				SE(types.SpecEventSpecRepeat, 2),
   694  			),
   695  			Case(Succinct, Normal, Succinct|Parallel, Normal|Parallel,
   696  				spr("{{green}}%s{{/}}", DENOTER)),
   697  			Case(Verbose, VeryVerbose,
   698  				DELIMITER,
   699  				"{{/}}{{bold}}A{{/}}",
   700  				"{{gray}}cl0.go:12{{/}}",
   701  				spr("{{green}}%s [1.000 seconds]{{/}}", DENOTER),
   702  				DELIMITER,
   703  				""),
   704  			Case(Verbose|Parallel, VeryVerbose|Parallel,
   705  				DELIMITER,
   706  				spr("{{green}}%s [1.000 seconds]{{/}}", DENOTER),
   707  				"{{green}}{{bold}}A{{/}}",
   708  				"{{gray}}cl0.go:12{{/}}",
   709  				"",
   710  				"  {{gray}}Timeline >>{{/}}",
   711  				"",
   712  				spr("  {{bold}}Attempt #1 {{green}}Passed{{/}}{{bold}}.  Repeating ↺{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
   713  				"",
   714  				"",
   715  				spr("  {{bold}}Attempt #2 {{green}}Passed{{/}}{{bold}}.  Repeating ↺{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
   716  				"",
   717  				"  {{gray}}<< Timeline{{/}}",
   718  				DELIMITER,
   719  				""),
   720  		),
   721  		Entry("a passing test with a spec report",
   722  			S(types.NodeTypeIt, "A", cl0,
   723  				RE("my entry", cl1),
   724  			),
   725  			Case(Succinct, Normal, Succinct|Parallel, Normal|Parallel,
   726  				DELIMITER,
   727  				spr("{{green}}%s [1.000 seconds]{{/}}", DENOTER),
   728  				"{{green}}{{bold}}A{{/}}",
   729  				"{{gray}}cl0.go:12{{/}}",
   730  				"",
   731  				"  {{gray}}Report Entries >>{{/}}",
   732  				spr("  {{bold}}my entry{{gray}} - cl1.go:37 @ %s{{/}}", FORMATTED_TIME),
   733  				"  {{gray}}<< Report Entries{{/}}",
   734  				DELIMITER,
   735  				""),
   736  			Case(Verbose, VeryVerbose,
   737  				DELIMITER,
   738  				"{{/}}{{bold}}A{{/}}",
   739  				"{{gray}}cl0.go:12{{/}}",
   740  				spr("{{green}}%s [1.000 seconds]{{/}}", DENOTER),
   741  				DELIMITER,
   742  				""),
   743  			Case(Verbose|Parallel, VeryVerbose|Parallel,
   744  				DELIMITER,
   745  				spr("{{green}}%s [1.000 seconds]{{/}}", DENOTER),
   746  				"{{green}}{{bold}}A{{/}}",
   747  				"{{gray}}cl0.go:12{{/}}",
   748  				"",
   749  				"  {{gray}}Timeline >>{{/}}",
   750  				spr("  {{bold}}my entry{{gray}} - cl1.go:37 @ %s{{/}}", FORMATTED_TIME),
   751  				"  {{gray}}<< Timeline{{/}}",
   752  				DELIMITER,
   753  				""),
   754  		),
   755  		Entry("a passing test with a captured stdout/stderr",
   756  			S(types.NodeTypeIt, "A", cl0, STD("hello there\nthis is my output")),
   757  			Case(Succinct, Normal,
   758  				spr("{{green}}%s{{/}}", DENOTER)),
   759  			Case(Verbose, VeryVerbose,
   760  				DELIMITER,
   761  				"{{/}}{{bold}}A{{/}}",
   762  				"{{gray}}cl0.go:12{{/}}",
   763  				spr("{{green}}%s [1.000 seconds]{{/}}", DENOTER),
   764  				DELIMITER,
   765  				""),
   766  			Case(Succinct|Parallel, Normal|Parallel, Verbose|Parallel, VeryVerbose|Parallel,
   767  				DELIMITER,
   768  				spr("{{green}}%s [1.000 seconds]{{/}}", DENOTER),
   769  				"{{green}}{{bold}}A{{/}}",
   770  				"{{gray}}cl0.go:12{{/}}",
   771  				"",
   772  				"  {{gray}}Captured StdOut/StdErr Output >>{{/}}",
   773  				"  hello there",
   774  				"  this is my output",
   775  				"  {{gray}}<< Captured StdOut/StdErr Output{{/}}",
   776  				DELIMITER,
   777  				""),
   778  			Case(Parallel|GithubOutput,
   779  				DELIMITER,
   780  				spr("{{green}}%s [1.000 seconds]{{/}}", DENOTER),
   781  				"{{green}}{{bold}}A{{/}}",
   782  				"{{gray}}cl0.go:12{{/}}",
   783  				"",
   784  				"  ::group::Captured StdOut/StdErr Output",
   785  				"  hello there",
   786  				"  this is my output",
   787  				"  ::endgroup::",
   788  				DELIMITER,
   789  				""),
   790  		),
   791  		Entry("a passing test with a full timeline that is only visible in verbose/very-verbose mode",
   792  			S(types.NodeTypeIt, "A", cl0, GW("some GinkgoWriter\noutput is interspersed\nhere and there\n"),
   793  				SE(types.SpecEventNodeStart, types.NodeTypeIt, "A", cl0),
   794  				PR("my progress report", LeafNodeText("A"), TL("some GinkgoWriter\n")),
   795  				SE(types.SpecEventByStart, "My Step", cl1, TL("some GinkgoWriter\n")),
   796  				RE("my entry", cl1, types.ReportEntryVisibilityFailureOrVerbose, TL("some GinkgoWriter\noutput is interspersed\n")),
   797  				RE("my hidden entry", cl1, types.ReportEntryVisibilityNever, TL("some GinkgoWriter\noutput is interspersed\n")),
   798  				SE(types.SpecEventByEnd, "My Step", cl1, time.Millisecond*200, TL("some GinkgoWriter\noutput is interspersed\n")),
   799  				SE(types.SpecEventNodeEnd, types.NodeTypeIt, "A", cl0, time.Millisecond*300, TL("some GinkgoWriter\noutput is interspersed\nhere and there\n")),
   800  			),
   801  			Case(Succinct, Normal, Succinct|Parallel, Normal|Parallel, Succinct|ShowNodeEvents, Normal|ShowNodeEvents,
   802  				spr("{{green}}%s{{/}}", DENOTER)),
   803  			Case(Verbose, VeryVerbose, //nothing to see here since things are emitted while streaming, which we don't simulate
   804  				DELIMITER,
   805  				"{{/}}{{bold}}A{{/}}",
   806  				"{{gray}}cl0.go:12{{/}}",
   807  				spr("{{green}}%s [1.000 seconds]{{/}}", DENOTER),
   808  				DELIMITER,
   809  				""),
   810  			Case(Verbose|Parallel|ShowNodeEvents,
   811  				DELIMITER,
   812  				spr("{{green}}%s [1.000 seconds]{{/}}", DENOTER),
   813  				"{{green}}{{bold}}A{{/}}",
   814  				"{{gray}}cl0.go:12{{/}}",
   815  				"",
   816  				"  {{gray}}Timeline >>{{/}}",
   817  				spr("  > Enter {{bold}}[It]{{/}} A {{gray}}@ %s{{/}}", FORMATTED_TIME),
   818  				"  some GinkgoWriter",
   819  				"  my progress report",
   820  				"    {{bold}}{{orange}}A{{/}} (Spec Runtime: 5s)",
   821  				"      {{gray}}cl0.go:12{{/}}",
   822  				spr("  {{bold}}STEP:{{/}} My Step {{gray}}@ %s{{/}}", FORMATTED_TIME),
   823  				"  output is interspersed",
   824  				spr("  {{bold}}my entry{{gray}} - cl1.go:37 @ %s{{/}}", FORMATTED_TIME),
   825  				spr("  {{bold}}END STEP:{{/}} My Step {{gray}}@ %s (200ms){{/}}", FORMATTED_TIME),
   826  				"  here and there",
   827  				spr("  < Exit {{bold}}[It]{{/}} A {{gray}}@ %s (300ms){{/}}", FORMATTED_TIME),
   828  				"  {{gray}}<< Timeline{{/}}",
   829  				DELIMITER,
   830  				""),
   831  			Case(Verbose|Parallel,
   832  				DELIMITER,
   833  				spr("{{green}}%s [1.000 seconds]{{/}}", DENOTER),
   834  				"{{green}}{{bold}}A{{/}}",
   835  				"{{gray}}cl0.go:12{{/}}",
   836  				"",
   837  				"  {{gray}}Timeline >>{{/}}",
   838  				"  some GinkgoWriter",
   839  				"  my progress report",
   840  				"    {{bold}}{{orange}}A{{/}} (Spec Runtime: 5s)",
   841  				"      {{gray}}cl0.go:12{{/}}",
   842  				spr("  {{bold}}STEP:{{/}} My Step {{gray}}@ %s{{/}}", FORMATTED_TIME),
   843  				"  output is interspersed",
   844  				spr("  {{bold}}my entry{{gray}} - cl1.go:37 @ %s{{/}}", FORMATTED_TIME),
   845  				"  here and there",
   846  				"  {{gray}}<< Timeline{{/}}",
   847  				DELIMITER,
   848  				""),
   849  			Case(VeryVerbose|Parallel,
   850  				DELIMITER,
   851  				spr("{{green}}%s [1.000 seconds]{{/}}", DENOTER),
   852  				"{{green}}{{bold}}A{{/}}",
   853  				"{{gray}}cl0.go:12{{/}}",
   854  				"",
   855  				"  {{gray}}Timeline >>{{/}}",
   856  				spr("  > Enter {{bold}}[It]{{/}} A {{gray}}- cl0.go:12 @ %s{{/}}", FORMATTED_TIME),
   857  				"  some GinkgoWriter",
   858  				"  my progress report",
   859  				"    {{bold}}{{orange}}A{{/}} (Spec Runtime: 5s)",
   860  				"      {{gray}}cl0.go:12{{/}}",
   861  				spr("  {{bold}}STEP:{{/}} My Step {{gray}}- cl1.go:37 @ %s{{/}}", FORMATTED_TIME),
   862  				"  output is interspersed",
   863  				spr("  {{bold}}my entry{{gray}} - cl1.go:37 @ %s{{/}}", FORMATTED_TIME),
   864  				spr("  {{bold}}END STEP:{{/}} My Step {{gray}}- cl1.go:37 @ %s (200ms){{/}}", FORMATTED_TIME),
   865  				"  here and there",
   866  				spr("  < Exit {{bold}}[It]{{/}} A {{gray}}- cl0.go:12 @ %s (300ms){{/}}", FORMATTED_TIME),
   867  				"  {{gray}}<< Timeline{{/}}",
   868  				DELIMITER,
   869  				""),
   870  		),
   871  		// Skipped tests
   872  		Entry("a skipped test",
   873  			S(types.NodeTypeIt, "A", types.SpecStateSkipped, cl0),
   874  			Case(Succinct, Normal, Succinct|Parallel, Normal|Parallel, Verbose, Verbose|Parallel,
   875  				"{{cyan}}S{{/}}"),
   876  			Case(VeryVerbose,
   877  				"{{cyan}}S [SKIPPED]{{/}}",
   878  				"{{cyan}}{{bold}}A{{/}}",
   879  				"{{gray}}cl0.go:12{{/}}",
   880  				DELIMITER,
   881  				""),
   882  			Case(VeryVerbose|Parallel,
   883  				DELIMITER,
   884  				"{{cyan}}S [SKIPPED]{{/}}",
   885  				"{{cyan}}{{bold}}A{{/}}",
   886  				"{{gray}}cl0.go:12{{/}}",
   887  				DELIMITER,
   888  				""),
   889  		),
   890  		Entry("a user-skipped test",
   891  			S(types.NodeTypeIt, "A", types.SpecStateSkipped, cl0,
   892  				F("let's skip it", cl1, types.NodeTypeIt, types.FailureNodeIsLeafNode, FailureNodeLocation(cl0)),
   893  			),
   894  			Case(Succinct, Normal, Succinct|Parallel, Normal|Parallel,
   895  				"{{cyan}}S{{/}}"),
   896  			Case(Verbose,
   897  				"{{cyan}}S [SKIPPED] [1.000 seconds]{{/}}",
   898  				"{{cyan}}{{bold}}[It] A{{/}}",
   899  				"{{gray}}cl0.go:12{{/}}",
   900  				"",
   901  				"  {{cyan}}[SKIPPED] let's skip it{{/}}",
   902  				spr("  {{cyan}}In {{bold}}[It]{{/}}{{cyan}} at: {{bold}}cl1.go:37{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
   903  				DELIMITER,
   904  				""),
   905  			Case(VeryVerbose,
   906  				"{{cyan}}S [SKIPPED] [1.000 seconds]{{/}}",
   907  				"{{cyan}}{{bold}}[It] A{{/}}",
   908  				"{{gray}}cl0.go:12{{/}}",
   909  				DELIMITER,
   910  				"",
   911  			),
   912  			Case(Verbose|Parallel,
   913  				DELIMITER,
   914  				"{{cyan}}S [SKIPPED] [1.000 seconds]{{/}}",
   915  				"{{cyan}}{{bold}}[It] A{{/}}",
   916  				"{{gray}}cl0.go:12{{/}}",
   917  				"",
   918  				"  {{cyan}}[SKIPPED] let's skip it{{/}}",
   919  				spr("  {{cyan}}In {{bold}}[It]{{/}}{{cyan}} at: {{bold}}cl1.go:37{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
   920  				DELIMITER,
   921  				""),
   922  			Case(VeryVerbose|Parallel,
   923  				DELIMITER,
   924  				"{{cyan}}S [SKIPPED] [1.000 seconds]{{/}}",
   925  				"{{cyan}}{{bold}}[It] A{{/}}",
   926  				"{{gray}}cl0.go:12{{/}}",
   927  				"",
   928  				"  {{gray}}Timeline >>{{/}}",
   929  				"  {{cyan}}[SKIPPED] let's skip it{{/}}",
   930  				spr("  {{cyan}}In {{bold}}[It]{{/}}{{cyan}} at: {{bold}}cl1.go:37{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
   931  				"  {{gray}}<< Timeline{{/}}",
   932  				DELIMITER,
   933  				""),
   934  		),
   935  		Entry("a user-skipped test with timeline content",
   936  			S(types.NodeTypeIt, "A", types.SpecStateSkipped, cl0,
   937  				GW("should we skip it?"),
   938  				F("let's skip it", TL("should we skip it?"), cl1, types.NodeTypeIt, types.FailureNodeIsLeafNode, FailureNodeLocation(cl0)),
   939  			),
   940  			Case(Succinct, Normal, Succinct|Parallel, Normal|Parallel,
   941  				"{{cyan}}S{{/}}"),
   942  			Case(Verbose|Parallel,
   943  				DELIMITER,
   944  				"{{cyan}}S [SKIPPED] [1.000 seconds]{{/}}",
   945  				"{{cyan}}{{bold}}[It] A{{/}}",
   946  				"{{gray}}cl0.go:12{{/}}",
   947  				"",
   948  				"  {{gray}}Timeline >>{{/}}",
   949  				"  should we skip it?",
   950  				spr("  {{cyan}}[SKIPPED]{{/}} in [It] - cl1.go:37 {{gray}}@ %s{{/}}", FORMATTED_TIME),
   951  				"  {{gray}}<< Timeline{{/}}",
   952  				"",
   953  				"  {{cyan}}[SKIPPED] let's skip it{{/}}",
   954  				spr("  {{cyan}}In {{bold}}[It]{{/}}{{cyan}} at: {{bold}}cl1.go:37{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
   955  				DELIMITER,
   956  				""),
   957  			Case(VeryVerbose|Parallel,
   958  				DELIMITER,
   959  				"{{cyan}}S [SKIPPED] [1.000 seconds]{{/}}",
   960  				"{{cyan}}{{bold}}[It] A{{/}}",
   961  				"{{gray}}cl0.go:12{{/}}",
   962  				"",
   963  				"  {{gray}}Timeline >>{{/}}",
   964  				"  should we skip it?",
   965  				"  {{cyan}}[SKIPPED] let's skip it{{/}}",
   966  				spr("  {{cyan}}In {{bold}}[It]{{/}}{{cyan}} at: {{bold}}cl1.go:37{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
   967  				"  {{gray}}<< Timeline{{/}}",
   968  				DELIMITER,
   969  				""),
   970  			Case(Verbose,
   971  				"{{cyan}}S [SKIPPED] [1.000 seconds]{{/}}",
   972  				"{{cyan}}{{bold}}[It] A{{/}}",
   973  				"{{gray}}cl0.go:12{{/}}",
   974  				"",
   975  				"  {{cyan}}[SKIPPED] let's skip it{{/}}",
   976  				spr("  {{cyan}}In {{bold}}[It]{{/}}{{cyan}} at: {{bold}}cl1.go:37{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
   977  				DELIMITER,
   978  				""),
   979  			Case(VeryVerbose,
   980  				"{{cyan}}S [SKIPPED] [1.000 seconds]{{/}}",
   981  				"{{cyan}}{{bold}}[It] A{{/}}",
   982  				"{{gray}}cl0.go:12{{/}}",
   983  				DELIMITER,
   984  				"",
   985  			),
   986  		),
   987  		Entry("a pending test",
   988  			S(types.NodeTypeIt, "C", types.SpecStatePending, cl2, CTS("A", "B"), CLS(cl0, cl1)),
   989  			Case(Succinct, Succinct|Parallel,
   990  				"{{yellow}}P{{/}}"),
   991  			Case(Normal, Normal|Parallel, Verbose|Parallel,
   992  				DELIMITER,
   993  				"{{yellow}}P [PENDING]{{/}}",
   994  				"{{/}}A {{gray}}B {{yellow}}{{bold}}C{{/}}",
   995  				"{{gray}}cl2.go:80{{/}}",
   996  				DELIMITER,
   997  				"",
   998  			),
   999  			Case(VeryVerbose|Parallel,
  1000  				DELIMITER,
  1001  				"{{yellow}}P [PENDING]{{/}}",
  1002  				"A",
  1003  				"{{gray}}cl0.go:12{{/}}",
  1004  				"  B",
  1005  				"  {{gray}}cl1.go:37{{/}}",
  1006  				"    {{yellow}}{{bold}}C{{/}}",
  1007  				"    {{gray}}cl2.go:80{{/}}",
  1008  				DELIMITER,
  1009  				""),
  1010  			Case(Verbose,
  1011  				"{{yellow}}P [PENDING]{{/}}",
  1012  				"{{/}}A {{gray}}B {{yellow}}{{bold}}C{{/}}",
  1013  				"{{gray}}cl2.go:80{{/}}",
  1014  				DELIMITER,
  1015  				"",
  1016  			),
  1017  			Case(VeryVerbose,
  1018  				"{{yellow}}P [PENDING]{{/}}",
  1019  				"A",
  1020  				"{{gray}}cl0.go:12{{/}}",
  1021  				"  B",
  1022  				"  {{gray}}cl1.go:37{{/}}",
  1023  				"    {{yellow}}{{bold}}C{{/}}",
  1024  				"    {{gray}}cl2.go:80{{/}}",
  1025  				DELIMITER,
  1026  				""),
  1027  		),
  1028  		Entry("a failed test with a failure in the It",
  1029  			S(types.NodeTypeIt, CTS("A", "B"), CLS(cl0, cl1), "C", cl2, types.SpecStateFailed,
  1030  				F("failure\nmessage", cl3, types.FailureNodeIsLeafNode, FailureNodeLocation(cl2), types.NodeTypeIt),
  1031  			),
  1032  			Case(Succinct, Succinct|Parallel, Normal, Normal|Parallel, Verbose|Parallel,
  1033  				DELIMITER, //note: no timeline because there is only a single failure in here
  1034  				spr("{{red}}%s [FAILED] [1.000 seconds]{{/}}", DENOTER),
  1035  				"{{/}}A {{gray}}B {{red}}{{bold}}[It] C{{/}}",
  1036  				"{{gray}}cl2.go:80{{/}}",
  1037  				"",
  1038  				"  {{red}}[FAILED] failure",
  1039  				"  message{{/}}",
  1040  				spr("  {{red}}In {{bold}}[It]{{/}}{{red}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1041  				DELIMITER,
  1042  				""),
  1043  			Case(VeryVerbose|Parallel,
  1044  				DELIMITER,
  1045  				spr("{{red}}%s [FAILED] [1.000 seconds]{{/}}", DENOTER),
  1046  				"A",
  1047  				"{{gray}}cl0.go:12{{/}}",
  1048  				"  B",
  1049  				"  {{gray}}cl1.go:37{{/}}",
  1050  				"    {{red}}{{bold}}[It] C{{/}}",
  1051  				"    {{gray}}cl2.go:80{{/}}",
  1052  				"",
  1053  				"  {{gray}}Timeline >>{{/}}",
  1054  				"  {{red}}[FAILED] failure",
  1055  				"  message{{/}}",
  1056  				spr("  {{red}}In {{bold}}[It]{{/}}{{red}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1057  				"  {{gray}}<< Timeline{{/}}",
  1058  				DELIMITER,
  1059  				""),
  1060  			Case(Verbose,
  1061  				DELIMITER,
  1062  				"{{/}}A {{gray}}B {{/}}{{bold}}[It] C{{/}}",
  1063  				"{{gray}}cl2.go:80{{/}}",
  1064  				spr("{{red}}%s [FAILED] [1.000 seconds]{{/}}", DENOTER),
  1065  				"{{/}}A {{gray}}B {{red}}{{bold}}[It] C{{/}}",
  1066  				"{{gray}}cl2.go:80{{/}}",
  1067  				"",
  1068  				"  {{red}}[FAILED] failure",
  1069  				"  message{{/}}",
  1070  				spr("  {{red}}In {{bold}}[It]{{/}}{{red}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1071  				DELIMITER,
  1072  				""),
  1073  			Case(VeryVerbose, //note: no failure summary as it will appear in the timeline (which isn't shown here since we don't replay the timeline in the spec)
  1074  				DELIMITER,
  1075  				"A",
  1076  				"{{gray}}cl0.go:12{{/}}",
  1077  				"  B",
  1078  				"  {{gray}}cl1.go:37{{/}}",
  1079  				"    {{/}}{{bold}}[It] C{{/}}",
  1080  				"    {{gray}}cl2.go:80{{/}}",
  1081  				spr("{{red}}%s [FAILED] [1.000 seconds]{{/}}", DENOTER),
  1082  				"A",
  1083  				"{{gray}}cl0.go:12{{/}}",
  1084  				"  B",
  1085  				"  {{gray}}cl1.go:37{{/}}",
  1086  				"    {{red}}{{bold}}[It] C{{/}}",
  1087  				"    {{gray}}cl2.go:80{{/}}",
  1088  				DELIMITER,
  1089  				""),
  1090  		),
  1091  		Entry("a failed test with a failure in an intermediate BeforeEach",
  1092  			S(types.NodeTypeIt, CTS("A", "B"), CLS(cl0, cl1), "C", cl2, types.SpecStateFailed,
  1093  				F("failure\nmessage", cl3, types.FailureNodeInContainer, FailureNodeLocation(cl4), types.NodeTypeBeforeEach, 1),
  1094  			),
  1095  			Case(Succinct, Succinct|Parallel, Normal, Normal|Parallel, Verbose|Parallel,
  1096  				DELIMITER, //note: no timeline because there is only a single failure in here
  1097  				spr("{{red}}%s [FAILED] [1.000 seconds]{{/}}", DENOTER),
  1098  				"{{/}}A {{red}}{{bold}}B [BeforeEach] {{/}}C{{/}}",
  1099  				"  {{red}}[BeforeEach]{{/}} {{gray}}cl4.go:144{{/}}",
  1100  				"  {{gray}}[It] cl2.go:80{{/}}",
  1101  				"",
  1102  				"  {{red}}[FAILED] failure",
  1103  				"  message{{/}}",
  1104  				spr("  {{red}}In {{bold}}[BeforeEach]{{/}}{{red}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1105  				DELIMITER,
  1106  				""),
  1107  			Case(VeryVerbose|Parallel,
  1108  				DELIMITER,
  1109  				spr("{{red}}%s [FAILED] [1.000 seconds]{{/}}", DENOTER),
  1110  				"A",
  1111  				"{{gray}}cl0.go:12{{/}}",
  1112  				"  {{red}}{{bold}}B [BeforeEach]{{/}}",
  1113  				"  {{gray}}cl4.go:144{{/}}",
  1114  				"    C",
  1115  				"    {{gray}}cl2.go:80{{/}}",
  1116  				"",
  1117  				"  {{gray}}Timeline >>{{/}}",
  1118  				"  {{red}}[FAILED] failure",
  1119  				"  message{{/}}",
  1120  				spr("  {{red}}In {{bold}}[BeforeEach]{{/}}{{red}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1121  				"  {{gray}}<< Timeline{{/}}",
  1122  				DELIMITER,
  1123  				""),
  1124  			Case(Verbose,
  1125  				DELIMITER,
  1126  				"{{/}}A {{/}}{{bold}}B [BeforeEach] {{/}}C{{/}}",
  1127  				"  {{/}}[BeforeEach]{{/}} {{gray}}cl4.go:144{{/}}",
  1128  				"  {{gray}}[It] cl2.go:80{{/}}",
  1129  				spr("{{red}}%s [FAILED] [1.000 seconds]{{/}}", DENOTER),
  1130  				"{{/}}A {{red}}{{bold}}B [BeforeEach] {{/}}C{{/}}",
  1131  				"  {{red}}[BeforeEach]{{/}} {{gray}}cl4.go:144{{/}}",
  1132  				"  {{gray}}[It] cl2.go:80{{/}}",
  1133  				"",
  1134  				"  {{red}}[FAILED] failure",
  1135  				"  message{{/}}",
  1136  				spr("  {{red}}In {{bold}}[BeforeEach]{{/}}{{red}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1137  				DELIMITER,
  1138  				""),
  1139  			Case(VeryVerbose, //note: no failure summary as it will appear in the timeline (which isn't shown here since we don't replay the timeline in the spec)
  1140  				DELIMITER,
  1141  				"A",
  1142  				"{{gray}}cl0.go:12{{/}}",
  1143  				"  {{/}}{{bold}}B [BeforeEach]{{/}}",
  1144  				"  {{gray}}cl4.go:144{{/}}",
  1145  				"    C",
  1146  				"    {{gray}}cl2.go:80{{/}}",
  1147  				spr("{{red}}%s [FAILED] [1.000 seconds]{{/}}", DENOTER),
  1148  				"A",
  1149  				"{{gray}}cl0.go:12{{/}}",
  1150  				"  {{red}}{{bold}}B [BeforeEach]{{/}}",
  1151  				"  {{gray}}cl4.go:144{{/}}",
  1152  				"    C",
  1153  				"    {{gray}}cl2.go:80{{/}}",
  1154  				DELIMITER,
  1155  				""),
  1156  		),
  1157  		Entry("a failed test with a failure at the top-level",
  1158  			S(types.NodeTypeIt, CTS("A", "B"), CLS(cl0, cl1), "C", cl2, types.SpecStateFailed,
  1159  				F("failure\nmessage", cl3, types.FailureNodeAtTopLevel, FailureNodeLocation(cl4), types.NodeTypeAfterEach),
  1160  			),
  1161  			Case(Succinct, Succinct|Parallel, Normal, Normal|Parallel, Verbose|Parallel,
  1162  				DELIMITER, //note: no timeline because there is only a single failure in here
  1163  				spr("{{red}}%s [FAILED] [1.000 seconds]{{/}}", DENOTER),
  1164  				"{{red}}{{bold}}TOP-LEVEL [AfterEach] {{gray}}A {{/}}B {{gray}}C{{/}}",
  1165  				"  {{red}}[AfterEach]{{/}} {{gray}}cl4.go:144{{/}}",
  1166  				"  {{gray}}[It] cl2.go:80{{/}}",
  1167  				"",
  1168  				"  {{red}}[FAILED] failure",
  1169  				"  message{{/}}",
  1170  				spr("  {{red}}In {{bold}}[AfterEach]{{/}}{{red}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1171  				DELIMITER,
  1172  				""),
  1173  			Case(VeryVerbose|Parallel,
  1174  				DELIMITER,
  1175  				spr("{{red}}%s [FAILED] [1.000 seconds]{{/}}", DENOTER),
  1176  				"{{red}}{{bold}}TOP-LEVEL [AfterEach]{{/}}",
  1177  				"{{gray}}cl4.go:144{{/}}",
  1178  				"  A",
  1179  				"  {{gray}}cl0.go:12{{/}}",
  1180  				"    B",
  1181  				"    {{gray}}cl1.go:37{{/}}",
  1182  				"      C",
  1183  				"      {{gray}}cl2.go:80{{/}}",
  1184  				"",
  1185  				"  {{gray}}Timeline >>{{/}}",
  1186  				"  {{red}}[FAILED] failure",
  1187  				"  message{{/}}",
  1188  				spr("  {{red}}In {{bold}}[AfterEach]{{/}}{{red}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1189  				"  {{gray}}<< Timeline{{/}}",
  1190  				DELIMITER,
  1191  				""),
  1192  			Case(Verbose,
  1193  				DELIMITER,
  1194  				"{{/}}{{bold}}TOP-LEVEL [AfterEach] {{gray}}A {{/}}B {{gray}}C{{/}}",
  1195  				"  {{/}}[AfterEach]{{/}} {{gray}}cl4.go:144{{/}}",
  1196  				"  {{gray}}[It] cl2.go:80{{/}}",
  1197  				spr("{{red}}%s [FAILED] [1.000 seconds]{{/}}", DENOTER),
  1198  				"{{red}}{{bold}}TOP-LEVEL [AfterEach] {{gray}}A {{/}}B {{gray}}C{{/}}",
  1199  				"  {{red}}[AfterEach]{{/}} {{gray}}cl4.go:144{{/}}",
  1200  				"  {{gray}}[It] cl2.go:80{{/}}",
  1201  				"",
  1202  				"  {{red}}[FAILED] failure",
  1203  				"  message{{/}}",
  1204  				spr("  {{red}}In {{bold}}[AfterEach]{{/}}{{red}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1205  				DELIMITER,
  1206  				""),
  1207  			Case(VeryVerbose, //note: no failure summary as it will appear in the timeline (which isn't shown here since we don't replay the timeline in the spec)
  1208  				DELIMITER,
  1209  				"{{/}}{{bold}}TOP-LEVEL [AfterEach]{{/}}",
  1210  				"{{gray}}cl4.go:144{{/}}",
  1211  				"  A",
  1212  				"  {{gray}}cl0.go:12{{/}}",
  1213  				"    B",
  1214  				"    {{gray}}cl1.go:37{{/}}",
  1215  				"      C",
  1216  				"      {{gray}}cl2.go:80{{/}}",
  1217  				spr("{{red}}%s [FAILED] [1.000 seconds]{{/}}", DENOTER),
  1218  				"{{red}}{{bold}}TOP-LEVEL [AfterEach]{{/}}",
  1219  				"{{gray}}cl4.go:144{{/}}",
  1220  				"  A",
  1221  				"  {{gray}}cl0.go:12{{/}}",
  1222  				"    B",
  1223  				"    {{gray}}cl1.go:37{{/}}",
  1224  				"      C",
  1225  				"      {{gray}}cl2.go:80{{/}}",
  1226  				DELIMITER,
  1227  				""),
  1228  		),
  1229  		Entry("a failed test with a failure in a suite-node",
  1230  			S(types.NodeTypeBeforeSuite, cl0, types.SpecStateAborted,
  1231  				F("failure\nmessage", cl1, types.FailureNodeAtTopLevel, FailureNodeLocation(cl0), types.NodeTypeBeforeSuite),
  1232  			),
  1233  			Case(Succinct, Succinct|Parallel, Normal, Normal|Parallel, Verbose|Parallel,
  1234  				DELIMITER, //note: no timeline because there is only a single failure in here
  1235  				"{{coral}}[BeforeSuite] [ABORTED] [1.000 seconds]{{/}}",
  1236  				"{{coral}}{{bold}}TOP-LEVEL [BeforeSuite] {{gray}}[BeforeSuite] {{/}}",
  1237  				"{{gray}}cl0.go:12{{/}}",
  1238  				"",
  1239  				"  {{coral}}[ABORTED] failure",
  1240  				"  message{{/}}",
  1241  				spr("  {{coral}}In {{bold}}[BeforeSuite]{{/}}{{coral}} at: {{bold}}cl1.go:37{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1242  				DELIMITER,
  1243  				""),
  1244  			Case(VeryVerbose|Parallel,
  1245  				DELIMITER,
  1246  				"{{coral}}[BeforeSuite] [ABORTED] [1.000 seconds]{{/}}",
  1247  				"{{coral}}{{bold}}TOP-LEVEL [BeforeSuite]{{/}}",
  1248  				"{{gray}}cl0.go:12{{/}}",
  1249  				"  [BeforeSuite] ",
  1250  				"  {{gray}}cl0.go:12{{/}}",
  1251  				"",
  1252  				"  {{gray}}Timeline >>{{/}}",
  1253  				"  {{coral}}[ABORTED] failure",
  1254  				"  message{{/}}",
  1255  				spr("  {{coral}}In {{bold}}[BeforeSuite]{{/}}{{coral}} at: {{bold}}cl1.go:37{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1256  				"  {{gray}}<< Timeline{{/}}",
  1257  				DELIMITER,
  1258  				""),
  1259  			Case(Verbose,
  1260  				DELIMITER,
  1261  				"{{/}}{{bold}}TOP-LEVEL [BeforeSuite] {{gray}}[BeforeSuite] {{/}}",
  1262  				"{{gray}}cl0.go:12{{/}}",
  1263  				"{{coral}}[BeforeSuite] [ABORTED] [1.000 seconds]{{/}}",
  1264  				"{{coral}}{{bold}}TOP-LEVEL [BeforeSuite] {{gray}}[BeforeSuite] {{/}}",
  1265  				"{{gray}}cl0.go:12{{/}}",
  1266  				"",
  1267  				"  {{coral}}[ABORTED] failure",
  1268  				"  message{{/}}",
  1269  				spr("  {{coral}}In {{bold}}[BeforeSuite]{{/}}{{coral}} at: {{bold}}cl1.go:37{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1270  				DELIMITER,
  1271  				""),
  1272  			Case(VeryVerbose, //note: no failure summary as it will appear in the timeline (which isn't shown here since we don't replay the timeline in the spec)
  1273  				DELIMITER,
  1274  				"{{/}}{{bold}}TOP-LEVEL [BeforeSuite]{{/}}",
  1275  				"{{gray}}cl0.go:12{{/}}",
  1276  				"  [BeforeSuite] ",
  1277  				"  {{gray}}cl0.go:12{{/}}",
  1278  				"{{coral}}[BeforeSuite] [ABORTED] [1.000 seconds]{{/}}",
  1279  				"{{coral}}{{bold}}TOP-LEVEL [BeforeSuite]{{/}}",
  1280  				"{{gray}}cl0.go:12{{/}}",
  1281  				"  [BeforeSuite] ",
  1282  				"  {{gray}}cl0.go:12{{/}}",
  1283  				DELIMITER,
  1284  				""),
  1285  		),
  1286  		Entry("a failed test that failed during a repetition",
  1287  			S(types.NodeTypeIt, CTS("A", "B"), CLS(cl0, cl1), 2, "C", cl2, types.SpecStateFailed, MustPassRepeatedly(3),
  1288  				F("failure\nmessage", cl3, types.FailureNodeIsLeafNode, FailureNodeLocation(cl2), types.NodeTypeIt),
  1289  			),
  1290  			Case(Succinct, Succinct|Parallel, Normal, Normal|Parallel, Verbose|Parallel,
  1291  				DELIMITER, //note: no timeline because there is only a single failure in here
  1292  				spr("{{red}}%s [FAILED] DURING REPETITION #2 [1.000 seconds]{{/}}", DENOTER),
  1293  				"{{/}}A {{gray}}B {{red}}{{bold}}[It] C{{/}}",
  1294  				"{{gray}}cl2.go:80{{/}}",
  1295  				"",
  1296  				"  {{red}}[FAILED] failure",
  1297  				"  message{{/}}",
  1298  				spr("  {{red}}In {{bold}}[It]{{/}}{{red}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1299  				DELIMITER,
  1300  				""),
  1301  			Case(VeryVerbose|Parallel,
  1302  				DELIMITER,
  1303  				spr("{{red}}%s [FAILED] DURING REPETITION #2 [1.000 seconds]{{/}}", DENOTER),
  1304  				"A",
  1305  				"{{gray}}cl0.go:12{{/}}",
  1306  				"  B",
  1307  				"  {{gray}}cl1.go:37{{/}}",
  1308  				"    {{red}}{{bold}}[It] C{{/}}",
  1309  				"    {{gray}}cl2.go:80{{/}}",
  1310  				"",
  1311  				"  {{gray}}Timeline >>{{/}}",
  1312  				"  {{red}}[FAILED] failure",
  1313  				"  message{{/}}",
  1314  				spr("  {{red}}In {{bold}}[It]{{/}}{{red}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1315  				"  {{gray}}<< Timeline{{/}}",
  1316  				DELIMITER,
  1317  				""),
  1318  			Case(Verbose,
  1319  				DELIMITER,
  1320  				"{{/}}A {{gray}}B {{/}}{{bold}}[It] C{{/}}",
  1321  				"{{gray}}cl2.go:80{{/}}",
  1322  				spr("{{red}}%s [FAILED] DURING REPETITION #2 [1.000 seconds]{{/}}", DENOTER),
  1323  				"{{/}}A {{gray}}B {{red}}{{bold}}[It] C{{/}}",
  1324  				"{{gray}}cl2.go:80{{/}}",
  1325  				"",
  1326  				"  {{red}}[FAILED] failure",
  1327  				"  message{{/}}",
  1328  				spr("  {{red}}In {{bold}}[It]{{/}}{{red}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1329  				DELIMITER,
  1330  				""),
  1331  		),
  1332  		Entry("a failed test with nothing but a failure + the associated additional-failure in the timeline",
  1333  			S(types.NodeTypeIt, CTS("A", "B"), CLS(cl0, cl1), "C", cl2, types.SpecStateTimedout,
  1334  				F("failure\nmessage", cl3, types.FailureNodeIsLeafNode, FailureNodeLocation(cl2), types.NodeTypeIt, TL(0), AF(types.SpecStatePanicked, cl4, types.FailureNodeIsLeafNode, FailureNodeLocation(cl2), types.NodeTypeIt, TL(0))),
  1335  			),
  1336  			Case(Succinct, Succinct|Parallel, Normal, Normal|Parallel, Verbose|Parallel,
  1337  				DELIMITER, //note: no timeline because there is only a single failure + its additional-failure in here
  1338  				spr("{{orange}}%s [TIMEDOUT] [1.000 seconds]{{/}}", DENOTER),
  1339  				"{{/}}A {{gray}}B {{orange}}{{bold}}[It] C{{/}}",
  1340  				"{{gray}}cl2.go:80{{/}}",
  1341  				"",
  1342  				"  {{orange}}[TIMEDOUT] failure",
  1343  				"  message{{/}}",
  1344  				spr("  {{orange}}In {{bold}}[It]{{/}}{{orange}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1345  				"",
  1346  				"  {{magenta}}[PANICKED] {{/}}",
  1347  				spr("  {{magenta}}In {{bold}}[It]{{/}}{{magenta}} at: {{bold}}cl4.go:144{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1348  				DELIMITER,
  1349  				""),
  1350  			Case(VeryVerbose|Parallel,
  1351  				DELIMITER,
  1352  				spr("{{orange}}%s [TIMEDOUT] [1.000 seconds]{{/}}", DENOTER),
  1353  				"A",
  1354  				"{{gray}}cl0.go:12{{/}}",
  1355  				"  B",
  1356  				"  {{gray}}cl1.go:37{{/}}",
  1357  				"    {{orange}}{{bold}}[It] C{{/}}",
  1358  				"    {{gray}}cl2.go:80{{/}}",
  1359  				"",
  1360  				"  {{gray}}Timeline >>{{/}}",
  1361  				"  {{orange}}[TIMEDOUT] failure",
  1362  				"  message{{/}}",
  1363  				spr("  {{orange}}In {{bold}}[It]{{/}}{{orange}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1364  				"  {{magenta}}[PANICKED] {{/}}",
  1365  				spr("  {{magenta}}In {{bold}}[It]{{/}}{{magenta}} at: {{bold}}cl4.go:144{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1366  				"  {{gray}}<< Timeline{{/}}",
  1367  				DELIMITER,
  1368  				""),
  1369  			Case(Verbose,
  1370  				DELIMITER,
  1371  				"{{/}}A {{gray}}B {{/}}{{bold}}[It] C{{/}}",
  1372  				"{{gray}}cl2.go:80{{/}}",
  1373  				spr("{{orange}}%s [TIMEDOUT] [1.000 seconds]{{/}}", DENOTER),
  1374  				"{{/}}A {{gray}}B {{orange}}{{bold}}[It] C{{/}}",
  1375  				"{{gray}}cl2.go:80{{/}}",
  1376  				"",
  1377  				"  {{orange}}[TIMEDOUT] failure",
  1378  				"  message{{/}}",
  1379  				spr("  {{orange}}In {{bold}}[It]{{/}}{{orange}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1380  				"",
  1381  				"  {{magenta}}[PANICKED] {{/}}",
  1382  				spr("  {{magenta}}In {{bold}}[It]{{/}}{{magenta}} at: {{bold}}cl4.go:144{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1383  				DELIMITER,
  1384  				""),
  1385  			Case(VeryVerbose, //note: no failure summary as it will appear in the timeline (which isn't shown here since we don't replay the timeline in the spec)
  1386  				DELIMITER,
  1387  				"A",
  1388  				"{{gray}}cl0.go:12{{/}}",
  1389  				"  B",
  1390  				"  {{gray}}cl1.go:37{{/}}",
  1391  				"    {{/}}{{bold}}[It] C{{/}}",
  1392  				"    {{gray}}cl2.go:80{{/}}",
  1393  				spr("{{orange}}%s [TIMEDOUT] [1.000 seconds]{{/}}", DENOTER),
  1394  				"A",
  1395  				"{{gray}}cl0.go:12{{/}}",
  1396  				"  B",
  1397  				"  {{gray}}cl1.go:37{{/}}",
  1398  				"    {{orange}}{{bold}}[It] C{{/}}",
  1399  				"    {{gray}}cl2.go:80{{/}}",
  1400  				DELIMITER,
  1401  				""),
  1402  		),
  1403  		Entry("a failed test with GinkgoWriter output",
  1404  			S(types.NodeTypeIt, CTS("A", "B"), CLS(cl0, cl1), "C", cl2, types.SpecStateTimedout, GW("some ginkgowriter\noutput\n"),
  1405  				F("failure\nmessage", cl3, types.FailureNodeIsLeafNode, FailureNodeLocation(cl2), types.NodeTypeIt, TL("some ginkgowriter\n"), AF(types.SpecStatePanicked, cl4, types.FailureNodeIsLeafNode, FailureNodeLocation(cl2), types.NodeTypeIt, TL("some ginkgowriter\noutput\n"))),
  1406  			),
  1407  			Case(Succinct, Succinct|Parallel, Normal, Normal|Parallel, Verbose|Parallel,
  1408  				DELIMITER,
  1409  				spr("{{orange}}%s [TIMEDOUT] [1.000 seconds]{{/}}", DENOTER),
  1410  				"{{/}}A {{gray}}B {{orange}}{{bold}}[It] C{{/}}",
  1411  				"{{gray}}cl2.go:80{{/}}",
  1412  				"",
  1413  				"  {{gray}}Timeline >>{{/}}",
  1414  				"  some ginkgowriter",
  1415  				spr("  {{orange}}[TIMEDOUT]{{/}} in [It] - cl3.go:103 {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1416  				"  output",
  1417  				spr("  {{magenta}}[PANICKED]{{/}} in [It] - cl4.go:144 {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1418  				"  {{gray}}<< Timeline{{/}}",
  1419  				"",
  1420  				"  {{orange}}[TIMEDOUT] failure",
  1421  				"  message{{/}}",
  1422  				spr("  {{orange}}In {{bold}}[It]{{/}}{{orange}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1423  				"",
  1424  				"  {{magenta}}[PANICKED] {{/}}",
  1425  				spr("  {{magenta}}In {{bold}}[It]{{/}}{{magenta}} at: {{bold}}cl4.go:144{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1426  				DELIMITER,
  1427  				""),
  1428  			Case(VeryVerbose|Parallel,
  1429  				DELIMITER,
  1430  				spr("{{orange}}%s [TIMEDOUT] [1.000 seconds]{{/}}", DENOTER),
  1431  				"A",
  1432  				"{{gray}}cl0.go:12{{/}}",
  1433  				"  B",
  1434  				"  {{gray}}cl1.go:37{{/}}",
  1435  				"    {{orange}}{{bold}}[It] C{{/}}",
  1436  				"    {{gray}}cl2.go:80{{/}}",
  1437  				"",
  1438  				"  {{gray}}Timeline >>{{/}}",
  1439  				"  some ginkgowriter",
  1440  				"  {{orange}}[TIMEDOUT] failure",
  1441  				"  message{{/}}",
  1442  				spr("  {{orange}}In {{bold}}[It]{{/}}{{orange}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1443  				"  output",
  1444  				"  {{magenta}}[PANICKED] {{/}}",
  1445  				spr("  {{magenta}}In {{bold}}[It]{{/}}{{magenta}} at: {{bold}}cl4.go:144{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1446  				"  {{gray}}<< Timeline{{/}}",
  1447  				DELIMITER,
  1448  				""),
  1449  			Case(Verbose,
  1450  				DELIMITER,
  1451  				"{{/}}A {{gray}}B {{/}}{{bold}}[It] C{{/}}",
  1452  				"{{gray}}cl2.go:80{{/}}",
  1453  				spr("{{orange}}%s [TIMEDOUT] [1.000 seconds]{{/}}", DENOTER),
  1454  				"{{/}}A {{gray}}B {{orange}}{{bold}}[It] C{{/}}",
  1455  				"{{gray}}cl2.go:80{{/}}",
  1456  				"",
  1457  				"  {{orange}}[TIMEDOUT] failure",
  1458  				"  message{{/}}",
  1459  				spr("  {{orange}}In {{bold}}[It]{{/}}{{orange}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1460  				"",
  1461  				"  {{magenta}}[PANICKED] {{/}}",
  1462  				spr("  {{magenta}}In {{bold}}[It]{{/}}{{magenta}} at: {{bold}}cl4.go:144{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1463  				DELIMITER,
  1464  				""),
  1465  			Case(VeryVerbose, //note: no failure summary as it will appear in the timeline (which isn't shown here since we don't replay the timeline in the spec)
  1466  				DELIMITER,
  1467  				"A",
  1468  				"{{gray}}cl0.go:12{{/}}",
  1469  				"  B",
  1470  				"  {{gray}}cl1.go:37{{/}}",
  1471  				"    {{/}}{{bold}}[It] C{{/}}",
  1472  				"    {{gray}}cl2.go:80{{/}}",
  1473  				spr("{{orange}}%s [TIMEDOUT] [1.000 seconds]{{/}}", DENOTER),
  1474  				"A",
  1475  				"{{gray}}cl0.go:12{{/}}",
  1476  				"  B",
  1477  				"  {{gray}}cl1.go:37{{/}}",
  1478  				"    {{orange}}{{bold}}[It] C{{/}}",
  1479  				"    {{gray}}cl2.go:80{{/}}",
  1480  				DELIMITER,
  1481  				""),
  1482  		),
  1483  		Entry("a failed test with timeline entries",
  1484  			S(types.NodeTypeIt, CTS("A", "B"), CLS(cl0, cl1), "C", cl2, types.SpecStateInterrupted, SE(types.SpecEventByStart, "a by step", cl0),
  1485  				F("failure\nmessage", cl3, types.FailureNodeIsLeafNode, FailureNodeLocation(cl2), types.NodeTypeIt, TL(0),
  1486  					PR("Interrupt Progress Report", types.NodeTypeIt, CurrentNodeText("C"), LeafNodeText("C"), []string{"A", "B"}),
  1487  					AF(types.SpecStatePanicked, cl4, types.FailureNodeIsLeafNode, FailureNodeLocation(cl2), types.NodeTypeIt, TL(0))),
  1488  				RE("a report entry", cl1),
  1489  			),
  1490  			Case(Succinct, Succinct|Parallel, Normal, Normal|Parallel, Verbose|Parallel,
  1491  				DELIMITER,
  1492  				spr("{{orange}}%s [INTERRUPTED] [1.000 seconds]{{/}}", DENOTER),
  1493  				"{{/}}A {{gray}}B {{orange}}{{bold}}[It] C{{/}}",
  1494  				"{{gray}}cl2.go:80{{/}}",
  1495  				"",
  1496  				"  {{gray}}Timeline >>{{/}}",
  1497  				spr("  {{bold}}STEP:{{/}} a by step {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1498  				spr("  {{orange}}[INTERRUPTED]{{/}} in [It] - cl3.go:103 {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1499  				spr("  {{magenta}}[PANICKED]{{/}} in [It] - cl4.go:144 {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1500  				spr("  {{bold}}a report entry{{gray}} - cl1.go:37 @ %s{{/}}", FORMATTED_TIME),
  1501  				"  {{gray}}<< Timeline{{/}}",
  1502  				"",
  1503  				"  {{orange}}[INTERRUPTED] failure",
  1504  				"  message{{/}}",
  1505  				spr("  {{orange}}In {{bold}}[It]{{/}}{{orange}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1506  				"",
  1507  				"  Interrupt Progress Report",
  1508  				"    {{/}}A {{gray}}B{{/}} {{bold}}{{orange}}C{{/}} (Spec Runtime: 5s)",
  1509  				"      {{gray}}cl0.go:12{{/}}",
  1510  				"      In {{bold}}{{orange}}[It]{{/}} (Node Runtime: 3s)",
  1511  				"        {{gray}}cl1.go:37{{/}}",
  1512  				"",
  1513  				"  {{magenta}}[PANICKED] {{/}}",
  1514  				spr("  {{magenta}}In {{bold}}[It]{{/}}{{magenta}} at: {{bold}}cl4.go:144{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1515  				DELIMITER,
  1516  				""),
  1517  			Case(VeryVerbose|Parallel,
  1518  				DELIMITER,
  1519  				spr("{{orange}}%s [INTERRUPTED] [1.000 seconds]{{/}}", DENOTER),
  1520  				"A",
  1521  				"{{gray}}cl0.go:12{{/}}",
  1522  				"  B",
  1523  				"  {{gray}}cl1.go:37{{/}}",
  1524  				"    {{orange}}{{bold}}[It] C{{/}}",
  1525  				"    {{gray}}cl2.go:80{{/}}",
  1526  				"",
  1527  				"  {{gray}}Timeline >>{{/}}",
  1528  				spr("  {{bold}}STEP:{{/}} a by step {{gray}}- cl0.go:12 @ %s{{/}}", FORMATTED_TIME),
  1529  				"  {{orange}}[INTERRUPTED] failure",
  1530  				"  message{{/}}",
  1531  				spr("  {{orange}}In {{bold}}[It]{{/}}{{orange}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1532  				"",
  1533  				"  Interrupt Progress Report",
  1534  				"    {{/}}A {{gray}}B{{/}} {{bold}}{{orange}}C{{/}} (Spec Runtime: 5s)",
  1535  				"      {{gray}}cl0.go:12{{/}}",
  1536  				"      In {{bold}}{{orange}}[It]{{/}} (Node Runtime: 3s)",
  1537  				"        {{gray}}cl1.go:37{{/}}",
  1538  				"  {{magenta}}[PANICKED] {{/}}",
  1539  				spr("  {{magenta}}In {{bold}}[It]{{/}}{{magenta}} at: {{bold}}cl4.go:144{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1540  				spr("  {{bold}}a report entry{{gray}} - cl1.go:37 @ %s{{/}}", FORMATTED_TIME),
  1541  				"  {{gray}}<< Timeline{{/}}",
  1542  				DELIMITER,
  1543  				""),
  1544  			Case(Verbose, // don't see the other timeline entries because they are emitted in realthime (which isn't shown here since we don't replay the timeline in the spec)
  1545  				DELIMITER,
  1546  				"{{/}}A {{gray}}B {{/}}{{bold}}[It] C{{/}}",
  1547  				"{{gray}}cl2.go:80{{/}}",
  1548  				spr("{{orange}}%s [INTERRUPTED] [1.000 seconds]{{/}}", DENOTER),
  1549  				"{{/}}A {{gray}}B {{orange}}{{bold}}[It] C{{/}}",
  1550  				"{{gray}}cl2.go:80{{/}}",
  1551  				"",
  1552  				"  {{orange}}[INTERRUPTED] failure",
  1553  				"  message{{/}}",
  1554  				spr("  {{orange}}In {{bold}}[It]{{/}}{{orange}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1555  				"",
  1556  				"  Interrupt Progress Report",
  1557  				"    {{/}}A {{gray}}B{{/}} {{bold}}{{orange}}C{{/}} (Spec Runtime: 5s)",
  1558  				"      {{gray}}cl0.go:12{{/}}",
  1559  				"      In {{bold}}{{orange}}[It]{{/}} (Node Runtime: 3s)",
  1560  				"        {{gray}}cl1.go:37{{/}}",
  1561  				"",
  1562  				"  {{magenta}}[PANICKED] {{/}}",
  1563  				spr("  {{magenta}}In {{bold}}[It]{{/}}{{magenta}} at: {{bold}}cl4.go:144{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1564  				DELIMITER,
  1565  				""),
  1566  			Case(VeryVerbose, //note: no failure summary as it will appear in the timeline (which isn't shown here since we don't replay the timeline in the spec)
  1567  				DELIMITER,
  1568  				"A",
  1569  				"{{gray}}cl0.go:12{{/}}",
  1570  				"  B",
  1571  				"  {{gray}}cl1.go:37{{/}}",
  1572  				"    {{/}}{{bold}}[It] C{{/}}",
  1573  				"    {{gray}}cl2.go:80{{/}}",
  1574  				spr("{{orange}}%s [INTERRUPTED] [1.000 seconds]{{/}}", DENOTER),
  1575  				"A",
  1576  				"{{gray}}cl0.go:12{{/}}",
  1577  				"  B",
  1578  				"  {{gray}}cl1.go:37{{/}}",
  1579  				"    {{orange}}{{bold}}[It] C{{/}}",
  1580  				"    {{gray}}cl2.go:80{{/}}",
  1581  				DELIMITER,
  1582  				""),
  1583  		),
  1584  		Entry("a failed test with both GinkgoWriter output and timeline entries (including multiple additional failures)",
  1585  			S(types.NodeTypeIt, Label("cat", "dog"), CLabels(Label("dolphin"), Label("gorilla", "cow")), CTS("A", "B"), CLS(cl0, cl1), "C", cl2, types.SpecStateTimedout, STD("some captured stdout\n"), GW("ginkgowriter\noutput\ncleanup!"), SE(types.SpecEventByStart, "a by step", cl0),
  1586  				SE(types.SpecEventNodeStart, types.NodeTypeIt, "C", cl2, TL(0)),
  1587  				F("failure\nmessage", cl3, types.FailureNodeIsLeafNode, FailureNodeLocation(cl2), types.NodeTypeIt, TL("ginkgowriter\n"), AF(types.SpecStatePanicked, cl4, types.FailureNodeIsLeafNode, FailureNodeLocation(cl2), types.NodeTypeIt, TL("ginkgowriter\noutput\n"), ForwardedPanic("the panic!"))),
  1588  				SE(types.SpecEventNodeEnd, types.NodeTypeIt, "C", cl2, TL("ginkgowriter\noutput\n"), time.Microsecond*87230),
  1589  				RE("a report entry", cl1, TL("ginkgowriter\noutput\n")),
  1590  				RE("a hidden report entry", cl1, TL("ginkgowriter\noutput\n"), types.ReportEntryVisibilityNever),
  1591  				AF(types.SpecStateFailed, "a subsequent failure", types.FailureNodeInContainer, FailureNodeLocation(cl3), types.NodeTypeAfterEach, 0, TL("ginkgowriter\noutput\ncleanup!")),
  1592  			),
  1593  			Case(Succinct, Normal,
  1594  				DELIMITER,
  1595  				spr("{{orange}}%s [TIMEDOUT] [1.000 seconds]{{/}}", DENOTER),
  1596  				"{{/}}A {{gray}}B {{orange}}{{bold}}[It] C{{/}} {{coral}}[dolphin, gorilla, cow, cat, dog]{{/}}",
  1597  				"{{gray}}cl2.go:80{{/}}",
  1598  				"",
  1599  				"  {{gray}}Timeline >>{{/}}",
  1600  				spr("  {{bold}}STEP:{{/}} a by step {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1601  				"  ginkgowriter",
  1602  				spr("  {{orange}}[TIMEDOUT]{{/}} in [It] - cl3.go:103 {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1603  				"  output",
  1604  				spr("  {{magenta}}[PANICKED]{{/}} in [It] - cl4.go:144 {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1605  				spr("  {{bold}}a report entry{{gray}} - cl1.go:37 @ %s{{/}}", FORMATTED_TIME),
  1606  				"  cleanup!",
  1607  				spr("  {{red}}[FAILED]{{/}} in [AfterEach] - :0 {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1608  				"  {{gray}}<< Timeline{{/}}",
  1609  				"",
  1610  				"  {{orange}}[TIMEDOUT] failure",
  1611  				"  message{{/}}",
  1612  				spr("  {{orange}}In {{bold}}[It]{{/}}{{orange}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1613  				"",
  1614  				"  {{magenta}}[PANICKED] {{/}}",
  1615  				spr("  {{magenta}}In {{bold}}[It]{{/}}{{magenta}} at: {{bold}}cl4.go:144{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1616  				"",
  1617  				"  {{magenta}}the panic!{{/}}",
  1618  				"",
  1619  				"  {{magenta}}Full Stack Trace{{/}}",
  1620  				"    full-trace",
  1621  				"    cl-4",
  1622  				"",
  1623  				"  There were {{bold}}{{red}}additional failures{{/}} detected.  To view them in detail run {{bold}}ginkgo -vv{{/}}",
  1624  				DELIMITER,
  1625  				""),
  1626  
  1627  			Case(Succinct|ShowNodeEvents, Normal|ShowNodeEvents,
  1628  				DELIMITER,
  1629  				spr("{{orange}}%s [TIMEDOUT] [1.000 seconds]{{/}}", DENOTER),
  1630  				"{{/}}A {{gray}}B {{orange}}{{bold}}[It] C{{/}} {{coral}}[dolphin, gorilla, cow, cat, dog]{{/}}",
  1631  				"{{gray}}cl2.go:80{{/}}",
  1632  				"",
  1633  				"  {{gray}}Timeline >>{{/}}",
  1634  				spr("  {{bold}}STEP:{{/}} a by step {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1635  				spr("  > Enter {{bold}}[It]{{/}} C {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1636  				"  ginkgowriter",
  1637  				spr("  {{orange}}[TIMEDOUT]{{/}} in [It] - cl3.go:103 {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1638  				"  output",
  1639  				spr("  {{magenta}}[PANICKED]{{/}} in [It] - cl4.go:144 {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1640  				spr("  < Exit {{bold}}[It]{{/}} C {{gray}}@ %s (87ms){{/}}", FORMATTED_TIME),
  1641  				spr("  {{bold}}a report entry{{gray}} - cl1.go:37 @ %s{{/}}", FORMATTED_TIME),
  1642  				"  cleanup!",
  1643  				spr("  {{red}}[FAILED]{{/}} in [AfterEach] - :0 {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1644  				"  {{gray}}<< Timeline{{/}}",
  1645  				"",
  1646  				"  {{orange}}[TIMEDOUT] failure",
  1647  				"  message{{/}}",
  1648  				spr("  {{orange}}In {{bold}}[It]{{/}}{{orange}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1649  				"",
  1650  				"  {{magenta}}[PANICKED] {{/}}",
  1651  				spr("  {{magenta}}In {{bold}}[It]{{/}}{{magenta}} at: {{bold}}cl4.go:144{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1652  				"",
  1653  				"  {{magenta}}the panic!{{/}}",
  1654  				"",
  1655  				"  {{magenta}}Full Stack Trace{{/}}",
  1656  				"    full-trace",
  1657  				"    cl-4",
  1658  				"",
  1659  				"  There were {{bold}}{{red}}additional failures{{/}} detected.  To view them in detail run {{bold}}ginkgo -vv{{/}}",
  1660  				DELIMITER,
  1661  				""),
  1662  			Case(Succinct|Parallel, Normal|Parallel, Verbose|Parallel,
  1663  				DELIMITER,
  1664  				spr("{{orange}}%s [TIMEDOUT] [1.000 seconds]{{/}}", DENOTER),
  1665  				"{{/}}A {{gray}}B {{orange}}{{bold}}[It] C{{/}} {{coral}}[dolphin, gorilla, cow, cat, dog]{{/}}",
  1666  				"{{gray}}cl2.go:80{{/}}",
  1667  				"",
  1668  				"  {{gray}}Captured StdOut/StdErr Output >>{{/}}",
  1669  				"  some captured stdout",
  1670  				"  {{gray}}<< Captured StdOut/StdErr Output{{/}}",
  1671  				"",
  1672  				"  {{gray}}Timeline >>{{/}}",
  1673  				spr("  {{bold}}STEP:{{/}} a by step {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1674  				"  ginkgowriter",
  1675  				spr("  {{orange}}[TIMEDOUT]{{/}} in [It] - cl3.go:103 {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1676  				"  output",
  1677  				spr("  {{magenta}}[PANICKED]{{/}} in [It] - cl4.go:144 {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1678  				spr("  {{bold}}a report entry{{gray}} - cl1.go:37 @ %s{{/}}", FORMATTED_TIME),
  1679  				"  cleanup!",
  1680  				spr("  {{red}}[FAILED]{{/}} in [AfterEach] - :0 {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1681  				"  {{gray}}<< Timeline{{/}}",
  1682  				"",
  1683  				"  {{orange}}[TIMEDOUT] failure",
  1684  				"  message{{/}}",
  1685  				spr("  {{orange}}In {{bold}}[It]{{/}}{{orange}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1686  				"",
  1687  				"  {{magenta}}[PANICKED] {{/}}",
  1688  				spr("  {{magenta}}In {{bold}}[It]{{/}}{{magenta}} at: {{bold}}cl4.go:144{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1689  				"",
  1690  				"  {{magenta}}the panic!{{/}}",
  1691  				"",
  1692  				"  {{magenta}}Full Stack Trace{{/}}",
  1693  				"    full-trace",
  1694  				"    cl-4",
  1695  				"",
  1696  				"  There were {{bold}}{{red}}additional failures{{/}} detected.  To view them in detail run {{bold}}ginkgo -vv{{/}}",
  1697  				DELIMITER,
  1698  				""),
  1699  			Case(Succinct|Parallel|FullTrace, Normal|Parallel|FullTrace, Verbose|Parallel|FullTrace,
  1700  				DELIMITER,
  1701  				spr("{{orange}}%s [TIMEDOUT] [1.000 seconds]{{/}}", DENOTER),
  1702  				"{{/}}A {{gray}}B {{orange}}{{bold}}[It] C{{/}} {{coral}}[dolphin, gorilla, cow, cat, dog]{{/}}",
  1703  				"{{gray}}cl2.go:80{{/}}",
  1704  				"",
  1705  				"  {{gray}}Captured StdOut/StdErr Output >>{{/}}",
  1706  				"  some captured stdout",
  1707  				"  {{gray}}<< Captured StdOut/StdErr Output{{/}}",
  1708  				"",
  1709  				"  {{gray}}Timeline >>{{/}}",
  1710  				spr("  {{bold}}STEP:{{/}} a by step {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1711  				"  ginkgowriter",
  1712  				spr("  {{orange}}[TIMEDOUT]{{/}} in [It] - cl3.go:103 {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1713  				"  output",
  1714  				spr("  {{magenta}}[PANICKED]{{/}} in [It] - cl4.go:144 {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1715  				spr("  {{bold}}a report entry{{gray}} - cl1.go:37 @ %s{{/}}", FORMATTED_TIME),
  1716  				"  cleanup!",
  1717  				spr("  {{red}}[FAILED]{{/}} in [AfterEach] - :0 {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1718  				"  {{gray}}<< Timeline{{/}}",
  1719  				"",
  1720  				"  {{orange}}[TIMEDOUT] failure",
  1721  				"  message{{/}}",
  1722  				spr("  {{orange}}In {{bold}}[It]{{/}}{{orange}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1723  				"",
  1724  				"  {{orange}}Full Stack Trace{{/}}",
  1725  				"    full-trace",
  1726  				"    cl-3",
  1727  				"",
  1728  				"  {{magenta}}[PANICKED] {{/}}",
  1729  				spr("  {{magenta}}In {{bold}}[It]{{/}}{{magenta}} at: {{bold}}cl4.go:144{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1730  				"",
  1731  				"  {{magenta}}the panic!{{/}}",
  1732  				"",
  1733  				"  {{magenta}}Full Stack Trace{{/}}",
  1734  				"    full-trace",
  1735  				"    cl-4",
  1736  				"",
  1737  				"  There were {{bold}}{{red}}additional failures{{/}} detected.  To view them in detail run {{bold}}ginkgo -vv{{/}}",
  1738  				DELIMITER,
  1739  				""),
  1740  			Case(VeryVerbose|Parallel,
  1741  				DELIMITER,
  1742  				spr("{{orange}}%s [TIMEDOUT] [1.000 seconds]{{/}}", DENOTER),
  1743  				"A {{coral}}[dolphin]{{/}}",
  1744  				"{{gray}}cl0.go:12{{/}}",
  1745  				"  B {{coral}}[gorilla, cow]{{/}}",
  1746  				"  {{gray}}cl1.go:37{{/}}",
  1747  				"    {{orange}}{{bold}}[It] C{{/}} {{coral}}[cat, dog]{{/}}",
  1748  				"    {{gray}}cl2.go:80{{/}}",
  1749  				"",
  1750  				"  {{gray}}Captured StdOut/StdErr Output >>{{/}}",
  1751  				"  some captured stdout",
  1752  				"  {{gray}}<< Captured StdOut/StdErr Output{{/}}",
  1753  				"",
  1754  				"  {{gray}}Timeline >>{{/}}",
  1755  				spr("  {{bold}}STEP:{{/}} a by step {{gray}}- cl0.go:12 @ %s{{/}}", FORMATTED_TIME),
  1756  				spr("  > Enter {{bold}}[It]{{/}} C {{gray}}- cl2.go:80 @ %s{{/}}", FORMATTED_TIME),
  1757  				"  ginkgowriter",
  1758  				"  {{orange}}[TIMEDOUT] failure",
  1759  				"  message{{/}}",
  1760  				spr("  {{orange}}In {{bold}}[It]{{/}}{{orange}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1761  				"  output",
  1762  				"  {{magenta}}[PANICKED] {{/}}",
  1763  				spr("  {{magenta}}In {{bold}}[It]{{/}}{{magenta}} at: {{bold}}cl4.go:144{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1764  				"",
  1765  				"  {{magenta}}the panic!{{/}}",
  1766  				"",
  1767  				"  {{magenta}}Full Stack Trace{{/}}",
  1768  				"    full-trace",
  1769  				"    cl-4",
  1770  				spr("  < Exit {{bold}}[It]{{/}} C {{gray}}- cl2.go:80 @ %s (87ms){{/}}", FORMATTED_TIME),
  1771  				spr("  {{bold}}a report entry{{gray}} - cl1.go:37 @ %s{{/}}", FORMATTED_TIME),
  1772  				"  cleanup!",
  1773  				"  {{red}}[FAILED] a subsequent failure{{/}}",
  1774  				spr("  {{red}}In {{bold}}[AfterEach]{{/}}{{red}} at: {{bold}}:0{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1775  				"  {{gray}}<< Timeline{{/}}",
  1776  				DELIMITER,
  1777  				""),
  1778  			Case(Verbose, // don't see the other timeline entries because they are emitted in realthime (which isn't shown here since we don't replay the timeline in the spec)
  1779  				DELIMITER,
  1780  				"{{/}}A {{gray}}B {{/}}{{bold}}[It] C{{/}} {{coral}}[dolphin, gorilla, cow, cat, dog]{{/}}",
  1781  				"{{gray}}cl2.go:80{{/}}",
  1782  				spr("{{orange}}%s [TIMEDOUT] [1.000 seconds]{{/}}", DENOTER),
  1783  				"{{/}}A {{gray}}B {{orange}}{{bold}}[It] C{{/}} {{coral}}[dolphin, gorilla, cow, cat, dog]{{/}}",
  1784  				"{{gray}}cl2.go:80{{/}}",
  1785  				"",
  1786  				"  {{orange}}[TIMEDOUT] failure",
  1787  				"  message{{/}}",
  1788  				spr("  {{orange}}In {{bold}}[It]{{/}}{{orange}} at: {{bold}}cl3.go:103{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1789  				"",
  1790  				"  {{magenta}}[PANICKED] {{/}}",
  1791  				spr("  {{magenta}}In {{bold}}[It]{{/}}{{magenta}} at: {{bold}}cl4.go:144{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  1792  				"",
  1793  				"  {{magenta}}the panic!{{/}}",
  1794  				"",
  1795  				"  {{magenta}}Full Stack Trace{{/}}",
  1796  				"    full-trace",
  1797  				"    cl-4",
  1798  				"",
  1799  				"  There were {{bold}}{{red}}additional failures{{/}} detected.  To view them in detail run {{bold}}ginkgo -vv{{/}}",
  1800  				DELIMITER,
  1801  				""),
  1802  			Case(VeryVerbose, //note: no failure summary as it will appear in the timeline (which isn't shown here since we don't replay the timeline in the spec)
  1803  				DELIMITER,
  1804  				"A {{coral}}[dolphin]{{/}}",
  1805  				"{{gray}}cl0.go:12{{/}}",
  1806  				"  B {{coral}}[gorilla, cow]{{/}}",
  1807  				"  {{gray}}cl1.go:37{{/}}",
  1808  				"    {{/}}{{bold}}[It] C{{/}} {{coral}}[cat, dog]{{/}}",
  1809  				"    {{gray}}cl2.go:80{{/}}",
  1810  				spr("{{orange}}%s [TIMEDOUT] [1.000 seconds]{{/}}", DENOTER),
  1811  				"A {{coral}}[dolphin]{{/}}",
  1812  				"{{gray}}cl0.go:12{{/}}",
  1813  				"  B {{coral}}[gorilla, cow]{{/}}",
  1814  				"  {{gray}}cl1.go:37{{/}}",
  1815  				"    {{orange}}{{bold}}[It] C{{/}} {{coral}}[cat, dog]{{/}}",
  1816  				"    {{gray}}cl2.go:80{{/}}",
  1817  				DELIMITER,
  1818  				""),
  1819  		),
  1820  	)
  1821  
  1822  	DescribeTable("Rendering SuiteDidEnd",
  1823  		func(conf types.ReporterConfig, report types.Report, expected ...any) {
  1824  			reporter := reporters.NewDefaultReporterUnderTest(conf, buf)
  1825  			reporter.SuiteDidEnd(report)
  1826  			Expect(string(buf.Contents())).Should(MatchLines(expected...))
  1827  		},
  1828  
  1829  		Entry("when configured to be succinct",
  1830  			C(Succinct),
  1831  			types.Report{
  1832  				SuiteSucceeded: true,
  1833  				RunTime:        time.Minute,
  1834  				SpecReports:    types.SpecReports{S()},
  1835  			},
  1836  			" {{green}}SUCCESS!{{/}} 1m0s ",
  1837  		),
  1838  		Entry("the suite passes",
  1839  			C(),
  1840  			types.Report{
  1841  				SuiteSucceeded: true,
  1842  				PreRunStats:    types.PreRunStats{TotalSpecs: 8, SpecsThatWillRun: 8},
  1843  				RunTime:        time.Minute,
  1844  				SpecReports: types.SpecReports{
  1845  					S(types.NodeTypeBeforeSuite),
  1846  					S(types.SpecStatePassed), S(types.SpecStatePassed), S(types.SpecStatePassed),
  1847  					S(types.SpecStatePending), S(types.SpecStatePending),
  1848  					S(types.SpecStateSkipped), S(types.SpecStateSkipped), S(types.SpecStateSkipped),
  1849  					S(types.NodeTypeAfterSuite),
  1850  				},
  1851  			},
  1852  			"",
  1853  			"{{green}}{{bold}}Ran 3 of 8 Specs in 60.000 seconds{{/}}",
  1854  			"{{green}}{{bold}}SUCCESS!{{/}} -- {{green}}{{bold}}3 Passed{{/}} | {{red}}{{bold}}0 Failed{{/}} | {{yellow}}{{bold}}2 Pending{{/}} | {{cyan}}{{bold}}3 Skipped{{/}}",
  1855  			"",
  1856  		),
  1857  		Entry("the suite passes and has flaky specs",
  1858  			C(),
  1859  			types.Report{
  1860  				SuiteSucceeded: true,
  1861  				PreRunStats:    types.PreRunStats{TotalSpecs: 10, SpecsThatWillRun: 8},
  1862  				RunTime:        time.Minute,
  1863  				SpecReports: types.SpecReports{
  1864  					S(types.NodeTypeBeforeSuite),
  1865  					S(types.SpecStatePassed), S(types.SpecStatePassed), S(types.SpecStatePassed),
  1866  					S(types.SpecStatePassed, 3, FlakeAttempts(5)), S(types.SpecStatePassed, 4, FlakeAttempts(5)), //flakey
  1867  					S(types.SpecStatePassed, 3, MustPassRepeatedly(5)), S(types.SpecStatePassed, 4, MustPassRepeatedly(5)), //repeated
  1868  					S(types.SpecStatePending), S(types.SpecStatePending),
  1869  					S(types.SpecStateSkipped), S(types.SpecStateSkipped), S(types.SpecStateSkipped),
  1870  					S(types.NodeTypeAfterSuite),
  1871  				},
  1872  			},
  1873  			"",
  1874  			"{{green}}{{bold}}Ran 7 of 10 Specs in 60.000 seconds{{/}}",
  1875  			"{{green}}{{bold}}SUCCESS!{{/}} -- {{green}}{{bold}}7 Passed{{/}} | {{red}}{{bold}}0 Failed{{/}} | {{light-yellow}}{{bold}}2 Flaked{{/}} | {{yellow}}{{bold}}2 Pending{{/}} | {{cyan}}{{bold}}3 Skipped{{/}}",
  1876  			"",
  1877  		),
  1878  		Entry("the suite fails with one failed test",
  1879  			C(),
  1880  			types.Report{
  1881  				SuiteSucceeded: false,
  1882  				PreRunStats:    types.PreRunStats{TotalSpecs: 18, SpecsThatWillRun: 8},
  1883  				RunTime:        time.Minute,
  1884  				SpecReports: types.SpecReports{
  1885  					S(types.NodeTypeBeforeSuite),
  1886  					S(types.SpecStatePassed), S(types.SpecStatePassed), S(types.SpecStatePassed),
  1887  					S(types.SpecStatePassed, 3, FlakeAttempts(5)), S(types.SpecStatePassed, 4, FlakeAttempts(5)), //flakey
  1888  					S(types.SpecStatePassed, 3, MustPassRepeatedly(5)), S(types.SpecStatePassed, 4, MustPassRepeatedly(5)), //repeated
  1889  					S(types.SpecStatePending), S(types.SpecStatePending),
  1890  					S(types.SpecStateSkipped), S(types.SpecStateSkipped), S(types.SpecStateSkipped),
  1891  					S(CTS("Describe A", "Context B"), "The Test", CLS(cl0, cl1), cl2,
  1892  						types.SpecStateFailed, 2,
  1893  						F("FAILURE MESSAGE\nWITH DETAILS", types.FailureNodeInContainer, FailureNodeLocation(cl3), types.NodeTypeJustBeforeEach, 1, cl4),
  1894  					),
  1895  					S(types.NodeTypeAfterSuite),
  1896  				},
  1897  			},
  1898  			"",
  1899  			"{{red}}{{bold}}Summarizing 1 Failure:{{/}}",
  1900  			"  {{red}}[FAIL]{{/}} {{/}}Describe A {{red}}{{bold}}Context B [JustBeforeEach] {{/}}The Test{{/}}",
  1901  			"  {{gray}}cl4.go:144{{/}}",
  1902  			"",
  1903  			"{{red}}{{bold}}Ran 8 of 18 Specs in 60.000 seconds{{/}}",
  1904  			"{{red}}{{bold}}FAIL!{{/}} -- {{green}}{{bold}}7 Passed{{/}} | {{red}}{{bold}}1 Failed{{/}} | {{light-yellow}}{{bold}}2 Flaked{{/}} | {{yellow}}{{bold}}2 Pending{{/}} | {{cyan}}{{bold}}3 Skipped{{/}}",
  1905  			"",
  1906  		),
  1907  		Entry("the suite fails with multiple failed tests",
  1908  			C(),
  1909  			types.Report{
  1910  				SuiteSucceeded: false,
  1911  				PreRunStats:    types.PreRunStats{TotalSpecs: 14, SpecsThatWillRun: 10},
  1912  				RunTime:        time.Minute,
  1913  				SpecReports: types.SpecReports{
  1914  					S(types.NodeTypeBeforeSuite),
  1915  					S(types.SpecStatePassed), S(types.SpecStatePassed), S(types.SpecStatePassed),
  1916  					S(types.SpecStatePassed, 3, FlakeAttempts(5)), S(types.SpecStatePassed, 4, FlakeAttempts(5)), //flakey
  1917  					S(types.SpecStatePassed, 3, MustPassRepeatedly(5)), //repeated, and passed
  1918  					S(types.SpecStateFailed, 3, MustPassRepeatedly(5), "repeater", F("failure", types.FailureNodeIsLeafNode, FailureNodeLocation(cl2), types.NodeTypeIt, cl3)),               //repeated, but failed
  1919  					S(types.SpecStateFailed, 4, MustPassRepeatedly(5), "another-repeater", F("failure-again", types.FailureNodeIsLeafNode, FailureNodeLocation(cl2), types.NodeTypeIt, cl3)), //repeated, but failed
  1920  					S(types.SpecStatePending), S(types.SpecStatePending),
  1921  					S(types.SpecStateSkipped), S(types.SpecStateSkipped), S(types.SpecStateSkipped),
  1922  					S(CTS("Describe A", "Context B"), "The Test", CLS(cl0, cl1), cl2, CLabels(Label("cat", "dog"), Label("dog", "fish")), Label("fish", "giraffe"),
  1923  						types.SpecStateFailed, 2,
  1924  						F("FAILURE MESSAGE\nWITH DETAILS", types.FailureNodeInContainer, FailureNodeLocation(cl3), types.NodeTypeJustBeforeEach, 1, cl4),
  1925  					),
  1926  					S(CTS("Describe A"), "The Test", CLS(cl0), cl1,
  1927  						types.SpecStatePanicked, 2,
  1928  						F("FAILURE MESSAGE\nWITH DETAILS", types.FailureNodeIsLeafNode, FailureNodeLocation(cl1), types.NodeTypeIt, cl2),
  1929  					),
  1930  					S("The Test", cl0,
  1931  						types.SpecStateInterrupted, 2,
  1932  						F("FAILURE MESSAGE\nWITH DETAILS", types.FailureNodeIsLeafNode, FailureNodeLocation(cl0), types.NodeTypeIt, cl1),
  1933  					),
  1934  					S("The Test", cl0,
  1935  						types.SpecStateAborted, 2,
  1936  						F("FAILURE MESSAGE\nWITH DETAILS", types.FailureNodeIsLeafNode, FailureNodeLocation(cl0), types.NodeTypeIt, cl1),
  1937  					),
  1938  					S("The Test", cl0,
  1939  						types.SpecStateTimedout, 2,
  1940  						F("FAILURE MESSAGE\nWITH DETAILS", types.FailureNodeIsLeafNode, FailureNodeLocation(cl0), types.NodeTypeIt, cl1),
  1941  					),
  1942  					S(types.NodeTypeAfterSuite),
  1943  				},
  1944  			},
  1945  			"",
  1946  			"{{red}}{{bold}}Summarizing 7 Failures:{{/}}",
  1947  			"  {{red}}[FAIL]{{/}} {{red}}{{bold}}[It] repeater{{/}}",
  1948  			"  {{gray}}cl3.go:103{{/}}",
  1949  			"  {{red}}[FAIL]{{/}} {{red}}{{bold}}[It] another-repeater{{/}}",
  1950  			"  {{gray}}cl3.go:103{{/}}",
  1951  			"  {{red}}[FAIL]{{/}} {{/}}Describe A {{red}}{{bold}}Context B [JustBeforeEach] {{/}}The Test{{/}} {{coral}}[cat, dog, fish, giraffe]{{/}}",
  1952  			"  {{gray}}cl4.go:144{{/}}",
  1953  			"  {{magenta}}[PANICKED!]{{/}} {{/}}Describe A {{magenta}}{{bold}}[It] The Test{{/}}",
  1954  			"  {{gray}}cl2.go:80{{/}}",
  1955  			"  {{orange}}[INTERRUPTED]{{/}} {{orange}}{{bold}}[It] The Test{{/}}",
  1956  			"  {{gray}}cl1.go:37{{/}}",
  1957  			"  {{coral}}[ABORTED]{{/}} {{coral}}{{bold}}[It] The Test{{/}}",
  1958  			"  {{gray}}cl1.go:37{{/}}",
  1959  			"  {{orange}}[TIMEDOUT]{{/}} {{orange}}{{bold}}[It] The Test{{/}}",
  1960  			"  {{gray}}cl1.go:37{{/}}",
  1961  			"",
  1962  			"{{red}}{{bold}}Ran 13 of 14 Specs in 60.000 seconds{{/}}",
  1963  			"{{red}}{{bold}}FAIL!{{/}} -- {{green}}{{bold}}6 Passed{{/}} | {{red}}{{bold}}7 Failed{{/}} | {{light-yellow}}{{bold}}2 Flaked{{/}} | {{light-yellow}}{{bold}}2 Repeated{{/}} | {{yellow}}{{bold}}2 Pending{{/}} | {{cyan}}{{bold}}3 Skipped{{/}}",
  1964  			"",
  1965  		),
  1966  		Entry("the suite fails with failed suite setups",
  1967  			C(),
  1968  			types.Report{
  1969  				SuiteSucceeded: false,
  1970  				PreRunStats:    types.PreRunStats{TotalSpecs: 10, SpecsThatWillRun: 5},
  1971  				RunTime:        time.Minute,
  1972  				SpecReports: types.SpecReports{
  1973  					S(types.NodeTypeBeforeSuite, cl0, types.SpecStateFailed, 2,
  1974  						F("FAILURE MESSAGE\nWITH DETAILS", types.FailureNodeIsLeafNode, FailureNodeLocation(cl0), types.NodeTypeBeforeSuite, 1, cl1),
  1975  					),
  1976  					S(types.NodeTypeAfterSuite, cl2, types.SpecStateFailed, 2,
  1977  						F("FAILURE MESSAGE\nWITH DETAILS", types.FailureNodeIsLeafNode, FailureNodeLocation(cl2), types.NodeTypeAfterSuite, 1, cl3),
  1978  					),
  1979  					S(types.NodeTypeReportAfterSuite, "my report", cl1, types.SpecStateFailed, 2,
  1980  						F("FAILURE MESSAGE\nWITH DETAILS", types.FailureNodeIsLeafNode, FailureNodeLocation(cl3), types.NodeTypeReportAfterSuite, 1, cl4),
  1981  					),
  1982  				},
  1983  			},
  1984  			"",
  1985  			"{{red}}{{bold}}Summarizing 3 Failures:{{/}}",
  1986  			"  {{red}}[FAIL]{{/}} {{red}}{{bold}}[BeforeSuite] {{/}}",
  1987  			"  {{gray}}"+cl1.String()+"{{/}}",
  1988  			"  {{red}}[FAIL]{{/}} {{red}}{{bold}}[AfterSuite] {{/}}",
  1989  			"  {{gray}}"+cl3.String()+"{{/}}",
  1990  			"  {{red}}[FAIL]{{/}} {{red}}{{bold}}[ReportAfterSuite] my report{{/}}",
  1991  			"  {{gray}}"+cl4.String()+"{{/}}",
  1992  			"",
  1993  			"{{red}}{{bold}}Ran 0 of 10 Specs in 60.000 seconds{{/}}",
  1994  			"{{red}}{{bold}}FAIL!{{/}} -- {{cyan}}{{bold}}A BeforeSuite node failed so all tests were skipped.{{/}}",
  1995  			"",
  1996  		),
  1997  		Entry("when the suite includes a special failure reason",
  1998  			C(),
  1999  			types.Report{
  2000  				SuiteSucceeded:             false,
  2001  				SpecialSuiteFailureReasons: []string{"Detected pending specs and --fail-on-pending is set"},
  2002  				SuiteConfig:                types.SuiteConfig{FailOnPending: true},
  2003  				PreRunStats:                types.PreRunStats{TotalSpecs: 5, SpecsThatWillRun: 3},
  2004  				RunTime:                    time.Minute,
  2005  				SpecReports: types.SpecReports{
  2006  					S(types.SpecStatePassed), S(types.SpecStatePassed), S(types.SpecStatePassed),
  2007  					S(types.SpecStatePending), S(types.SpecStatePending),
  2008  				},
  2009  			},
  2010  			"",
  2011  			"{{red}}{{bold}}Ran 3 of 5 Specs in 60.000 seconds{{/}}",
  2012  			"{{red}}{{bold}}FAIL! - Detected pending specs and --fail-on-pending is set{{/}} -- {{green}}{{bold}}3 Passed{{/}} | {{red}}{{bold}}0 Failed{{/}} | {{yellow}}{{bold}}2 Pending{{/}} | {{cyan}}{{bold}}0 Skipped{{/}}",
  2013  			"",
  2014  		),
  2015  		Entry("when the suite includes multiple special failure reasons",
  2016  			C(),
  2017  			types.Report{
  2018  				SuiteSucceeded:             false,
  2019  				SpecialSuiteFailureReasons: []string{"Detected pending specs and --fail-on-pending is set", "Interrupted by Timeout"},
  2020  				SuiteConfig:                types.SuiteConfig{FailOnPending: true},
  2021  				PreRunStats:                types.PreRunStats{TotalSpecs: 5, SpecsThatWillRun: 3},
  2022  				RunTime:                    time.Minute,
  2023  				SpecReports: types.SpecReports{
  2024  					S(types.SpecStatePassed), S(types.SpecStatePassed), S(types.SpecStatePassed),
  2025  					S(types.SpecStatePending), S(types.SpecStatePending),
  2026  				},
  2027  			},
  2028  			"",
  2029  			"{{red}}{{bold}}Ran 3 of 5 Specs in 60.000 seconds{{/}}",
  2030  			"{{red}}{{bold}}FAIL! - Detected pending specs and --fail-on-pending is set, Interrupted by Timeout{{/}}",
  2031  			"{{green}}{{bold}}3 Passed{{/}} | {{red}}{{bold}}0 Failed{{/}} | {{yellow}}{{bold}}2 Pending{{/}} | {{cyan}}{{bold}}0 Skipped{{/}}",
  2032  			"",
  2033  		),
  2034  	)
  2035  
  2036  	DescribeTable("EmitProgressReport",
  2037  		func(conf types.ReporterConfig, report types.ProgressReport, expected ...any) {
  2038  			reporter := reporters.NewDefaultReporterUnderTest(conf, buf)
  2039  			reporter.EmitProgressReport(report)
  2040  			Expect(string(buf.Contents())).Should(MatchLines(expected...))
  2041  		},
  2042  		//just headers to start
  2043  		Entry("With a suite node",
  2044  			C(),
  2045  			PR("A Message", types.NodeTypeBeforeSuite),
  2046  			INDENTED_DELIMITER,
  2047  			"  A Message",
  2048  			"    In {{bold}}{{orange}}[BeforeSuite]{{/}} (Node Runtime: 3s)",
  2049  			"      {{gray}}"+cl1.String()+"{{/}}",
  2050  			INDENTED_DELIMITER,
  2051  			""),
  2052  		Entry("With a top-level spec",
  2053  			C(),
  2054  			PR("A Message", types.NodeTypeIt, CurrentNodeText("A Top-Level It"), LeafNodeText("A Top-Level It")),
  2055  			INDENTED_DELIMITER,
  2056  			"  A Message",
  2057  			"    {{bold}}{{orange}}A Top-Level It{{/}} (Spec Runtime: 5s)",
  2058  			"      {{gray}}"+cl0.String()+"{{/}}",
  2059  			"      In {{bold}}{{orange}}[It]{{/}} (Node Runtime: 3s)",
  2060  			"        {{gray}}"+cl1.String()+"{{/}}",
  2061  			INDENTED_DELIMITER,
  2062  			""),
  2063  		Entry("With a spec in containers",
  2064  			C(),
  2065  			PR(types.NodeTypeIt, CurrentNodeText("My Spec"), LeafNodeText("My Spec"), []string{"Container A", "Container B", "Container C"}),
  2066  			INDENTED_DELIMITER,
  2067  			"  {{/}}Container A {{gray}}Container B {{/}}Container C{{/}} {{bold}}{{orange}}My Spec{{/}} (Spec Runtime: 5s)",
  2068  			"    {{gray}}"+cl0.String()+"{{/}}",
  2069  			"    In {{bold}}{{orange}}[It]{{/}} (Node Runtime: 3s)",
  2070  			"      {{gray}}"+cl1.String()+"{{/}}",
  2071  			INDENTED_DELIMITER,
  2072  			""),
  2073  		Entry("With no current node",
  2074  			C(),
  2075  			PR(LeafNodeText("My Spec"), []string{"Container A", "Container B", "Container C"}),
  2076  			INDENTED_DELIMITER,
  2077  			"  {{/}}Container A {{gray}}Container B {{/}}Container C{{/}} {{bold}}{{orange}}My Spec{{/}} (Spec Runtime: 5s)",
  2078  			"    {{gray}}"+cl0.String()+"{{/}}",
  2079  			INDENTED_DELIMITER,
  2080  			""),
  2081  		Entry("With a current node that is not an It",
  2082  			C(),
  2083  			PR(LeafNodeText("My Spec"), []string{"Container A", "Container B", "Container C"}, types.NodeTypeBeforeEach),
  2084  			INDENTED_DELIMITER,
  2085  			"  {{/}}Container A {{gray}}Container B {{/}}Container C{{/}} {{bold}}{{orange}}My Spec{{/}} (Spec Runtime: 5s)",
  2086  			"    {{gray}}"+cl0.String()+"{{/}}",
  2087  			"    In {{bold}}{{orange}}[BeforeEach]{{/}} (Node Runtime: 3s)",
  2088  			"      {{gray}}"+cl1.String()+"{{/}}",
  2089  			INDENTED_DELIMITER,
  2090  			""),
  2091  		Entry("With a current node that is not an It, but has text",
  2092  			C(),
  2093  			PR(types.NodeTypeReportAfterSuite, CurrentNodeText("My Report")),
  2094  			INDENTED_DELIMITER,
  2095  			"  In {{bold}}{{orange}}[ReportAfterSuite]{{/}} {{bold}}{{orange}}My Report{{/}} (Node Runtime: 3s)",
  2096  			"    {{gray}}"+cl1.String()+"{{/}}",
  2097  			INDENTED_DELIMITER,
  2098  			""),
  2099  		Entry("With a current step",
  2100  			C(),
  2101  			PR(types.NodeTypeIt, CurrentNodeText("My Spec"), LeafNodeText("My Spec"), []string{"Container A", "Container B", "Container C"}, CurrentStepText("Reticulating Splines")),
  2102  			INDENTED_DELIMITER,
  2103  			"  {{/}}Container A {{gray}}Container B {{/}}Container C{{/}} {{bold}}{{orange}}My Spec{{/}} (Spec Runtime: 5s)",
  2104  			"    {{gray}}"+cl0.String()+"{{/}}",
  2105  			"    In {{bold}}{{orange}}[It]{{/}} (Node Runtime: 3s)",
  2106  			"      {{gray}}"+cl1.String()+"{{/}}",
  2107  			"      At {{bold}}{{orange}}[By Step] Reticulating Splines{{/}} (Step Runtime: 1s)",
  2108  			"        {{gray}}"+cl2.String()+"{{/}}",
  2109  			INDENTED_DELIMITER,
  2110  			""),
  2111  		//including GinkgoWriter output
  2112  		Entry("when there is GinkgoWriter output and the spec is not running verbosely",
  2113  			C(),
  2114  			PR(
  2115  				types.NodeTypeIt, CurrentNodeText("My Spec"), LeafNodeText("My Spec"),
  2116  				GW("gw-1\ngw-2\ngw-3\ngw-4\ngw-5\ngw-6\ngw-7\ngw-8\ngw-9\ngw-10\ngw-11\ngw-12\n"),
  2117  			),
  2118  			INDENTED_DELIMITER,
  2119  			"  {{bold}}{{orange}}My Spec{{/}} (Spec Runtime: 5s)",
  2120  			"    {{gray}}"+cl0.String()+"{{/}}",
  2121  			"    In {{bold}}{{orange}}[It]{{/}} (Node Runtime: 3s)",
  2122  			"      {{gray}}"+cl1.String()+"{{/}}",
  2123  			"",
  2124  			"    {{gray}}Begin Captured GinkgoWriter Output >>{{/}}",
  2125  			"      {{gray}}...{{/}}",
  2126  			"      gw-3",
  2127  			"      gw-4",
  2128  			"      gw-5",
  2129  			"      gw-6",
  2130  			"      gw-7",
  2131  			"      gw-8",
  2132  			"      gw-9",
  2133  			"      gw-10",
  2134  			"      gw-11",
  2135  			"      gw-12",
  2136  			"    {{gray}}<< End Captured GinkgoWriter Output{{/}}",
  2137  			INDENTED_DELIMITER,
  2138  			""),
  2139  		Entry("when there is fewer than 10 lines of GinkgoWriter output",
  2140  			C(),
  2141  			PR(
  2142  				types.NodeTypeIt, CurrentNodeText("My Spec"), LeafNodeText("My Spec"),
  2143  				GW("gw-1\ngw-2\ngw-3\ngw-4\ngw-5\ngw-6\ngw-7\ngw-8\ngw-9\n"),
  2144  			),
  2145  			INDENTED_DELIMITER,
  2146  			"  {{bold}}{{orange}}My Spec{{/}} (Spec Runtime: 5s)",
  2147  			"    {{gray}}"+cl0.String()+"{{/}}",
  2148  			"    In {{bold}}{{orange}}[It]{{/}} (Node Runtime: 3s)",
  2149  			"      {{gray}}"+cl1.String()+"{{/}}",
  2150  			"",
  2151  			"    {{gray}}Begin Captured GinkgoWriter Output >>{{/}}",
  2152  			"      gw-1",
  2153  			"      gw-2",
  2154  			"      gw-3",
  2155  			"      gw-4",
  2156  			"      gw-5",
  2157  			"      gw-6",
  2158  			"      gw-7",
  2159  			"      gw-8",
  2160  			"      gw-9",
  2161  			"    {{gray}}<< End Captured GinkgoWriter Output{{/}}",
  2162  			INDENTED_DELIMITER,
  2163  			""),
  2164  		Entry("when running in verbose mode and not in parallel",
  2165  			C(Verbose),
  2166  			PR(
  2167  				types.NodeTypeIt, CurrentNodeText("My Spec"), LeafNodeText("My Spec"),
  2168  				GW("gw-1\n"),
  2169  			),
  2170  			INDENTED_DELIMITER,
  2171  			"  {{bold}}{{orange}}My Spec{{/}} (Spec Runtime: 5s)",
  2172  			"    {{gray}}"+cl0.String()+"{{/}}",
  2173  			"    In {{bold}}{{orange}}[It]{{/}} (Node Runtime: 3s)",
  2174  			"      {{gray}}"+cl1.String()+"{{/}}",
  2175  			INDENTED_DELIMITER,
  2176  			""),
  2177  		Entry("when running in verbose mode and in parallel",
  2178  			C(),
  2179  			PR(
  2180  				true, types.NodeTypeIt, CurrentNodeText("My Spec"), LeafNodeText("My Spec"),
  2181  				GW("gw-1\n"),
  2182  			),
  2183  			INDENTED_DELIMITER,
  2184  			"  {{coral}}Progress Report for Ginkgo Process #{{bold}}1{{/}}",
  2185  			"  {{bold}}{{orange}}My Spec{{/}} (Spec Runtime: 5s)",
  2186  			"    {{gray}}"+cl0.String()+"{{/}}",
  2187  			"    In {{bold}}{{orange}}[It]{{/}} (Node Runtime: 3s)",
  2188  			"      {{gray}}"+cl1.String()+"{{/}}",
  2189  			"",
  2190  			"    {{gray}}Begin Captured GinkgoWriter Output >>{{/}}",
  2191  			"      gw-1",
  2192  			"    {{gray}}<< End Captured GinkgoWriter Output{{/}}",
  2193  			INDENTED_DELIMITER,
  2194  			""),
  2195  		//various goroutines
  2196  		Entry("with a spec goroutine",
  2197  			C(),
  2198  			PR(
  2199  				types.NodeTypeIt, CurrentNodeText("My Spec"), LeafNodeText("My Spec"),
  2200  				G(true, "sleeping",
  2201  					Fn("F1()", "fileA", 15),
  2202  					Fn("F2()", "fileB", 11, true),
  2203  					Fn("F3()", "fileC", 9),
  2204  				),
  2205  			),
  2206  			INDENTED_DELIMITER,
  2207  			"  {{bold}}{{orange}}My Spec{{/}} (Spec Runtime: 5s)",
  2208  			"    {{gray}}"+cl0.String()+"{{/}}",
  2209  			"    In {{bold}}{{orange}}[It]{{/}} (Node Runtime: 3s)",
  2210  			"      {{gray}}"+cl1.String()+"{{/}}",
  2211  			"",
  2212  			"    {{bold}}{{underline}}Spec Goroutine{{/}}",
  2213  			"    {{orange}}goroutine 17 [sleeping]{{/}}",
  2214  			"      {{gray}}F1(){{/}}",
  2215  			"        {{gray}}fileA:15{{/}}",
  2216  			"    {{orange}}{{bold}}> F2(){{/}}",
  2217  			"        {{orange}}{{bold}}fileB:11{{/}}",
  2218  			"      {{gray}}F3(){{/}}",
  2219  			"        {{gray}}fileC:9{{/}}",
  2220  			INDENTED_DELIMITER,
  2221  			""),
  2222  		Entry("with highlighted goroutines",
  2223  			C(),
  2224  			PR(
  2225  				types.NodeTypeIt, CurrentNodeText("My Spec"), LeafNodeText("My Spec"),
  2226  				G(false, "sleeping",
  2227  					Fn("F1()", "fileA", 15),
  2228  					Fn("F2()", "fileB", 11, true),
  2229  					Fn("F3()", "fileC", 9),
  2230  				),
  2231  				G(false, "sleeping as well",
  2232  					Fn("F4()", "fileB", 12, true),
  2233  					Fn("F5()", "fileC", 30),
  2234  					Fn("F6()", "fileD", 2),
  2235  				),
  2236  			),
  2237  			INDENTED_DELIMITER,
  2238  			"  {{bold}}{{orange}}My Spec{{/}} (Spec Runtime: 5s)",
  2239  			"    {{gray}}cl0.go:12{{/}}",
  2240  			"    In {{bold}}{{orange}}[It]{{/}} (Node Runtime: 3s)",
  2241  			"      {{gray}}cl1.go:37{{/}}",
  2242  			"",
  2243  			"    {{bold}}{{underline}}Goroutines of Interest{{/}}",
  2244  			"    {{orange}}goroutine 17 [sleeping]{{/}}",
  2245  			"      {{gray}}F1(){{/}}",
  2246  			"        {{gray}}fileA:15{{/}}",
  2247  			"    {{orange}}{{bold}}> F2(){{/}}",
  2248  			"        {{orange}}{{bold}}fileB:11{{/}}",
  2249  			"      {{gray}}F3(){{/}}",
  2250  			"        {{gray}}fileC:9{{/}}",
  2251  			"",
  2252  			"    {{orange}}goroutine 17 [sleeping as well]{{/}}",
  2253  			"    {{orange}}{{bold}}> F4(){{/}}",
  2254  			"        {{orange}}{{bold}}fileB:12{{/}}",
  2255  			"      {{gray}}F5(){{/}}",
  2256  			"        {{gray}}fileC:30{{/}}",
  2257  			"      {{gray}}F6(){{/}}",
  2258  			"        {{gray}}fileD:2{{/}}",
  2259  			INDENTED_DELIMITER,
  2260  			""),
  2261  		Entry("with other goroutines",
  2262  			C(),
  2263  			PR(
  2264  				types.NodeTypeIt, CurrentNodeText("My Spec"), LeafNodeText("My Spec"),
  2265  				G(false, "sleeping",
  2266  					Fn("F1()", "fileA", 15),
  2267  					Fn("F2()", "fileB", 11),
  2268  					Fn("F3()", "fileC", 9),
  2269  				),
  2270  			),
  2271  			INDENTED_DELIMITER,
  2272  			"  {{bold}}{{orange}}My Spec{{/}} (Spec Runtime: 5s)",
  2273  			"    {{gray}}"+cl0.String()+"{{/}}",
  2274  			"    In {{bold}}{{orange}}[It]{{/}} (Node Runtime: 3s)",
  2275  			"      {{gray}}"+cl1.String()+"{{/}}",
  2276  			"",
  2277  			"    {{gray}}{{bold}}{{underline}}Other Goroutines{{/}}",
  2278  			"    {{gray}}goroutine 17 [sleeping]{{/}}",
  2279  			"      {{gray}}F1(){{/}}",
  2280  			"        {{gray}}fileA:15{{/}}",
  2281  			"      {{gray}}F2(){{/}}",
  2282  			"        {{gray}}fileB:11{{/}}",
  2283  			"      {{gray}}F3(){{/}}",
  2284  			"        {{gray}}fileC:9{{/}}",
  2285  			INDENTED_DELIMITER,
  2286  			""),
  2287  		//fetching source code
  2288  		Entry("when source code is found",
  2289  			C(),
  2290  			PR(
  2291  				types.NodeTypeIt, CurrentNodeText("My Spec"), LeafNodeText("My Spec"),
  2292  				G(true, "sleeping",
  2293  					Fn("F1()", "fileA", 15),
  2294  					Fn(
  2295  						"F2()", "fileB", 21, true, 2,
  2296  						"source line 1",
  2297  						"source line 2",
  2298  						"source line 3 (highlight!)",
  2299  						"source line 4",
  2300  						"source line 5",
  2301  					),
  2302  					Fn("F3()", "fileC", 9),
  2303  				),
  2304  			),
  2305  			INDENTED_DELIMITER,
  2306  			"  {{bold}}{{orange}}My Spec{{/}} (Spec Runtime: 5s)",
  2307  			"    {{gray}}"+cl0.String()+"{{/}}",
  2308  			"    In {{bold}}{{orange}}[It]{{/}} (Node Runtime: 3s)",
  2309  			"      {{gray}}"+cl1.String()+"{{/}}",
  2310  			"",
  2311  			"    {{bold}}{{underline}}Spec Goroutine{{/}}",
  2312  			"    {{orange}}goroutine 17 [sleeping]{{/}}",
  2313  			"      {{gray}}F1(){{/}}",
  2314  			"        {{gray}}fileA:15{{/}}",
  2315  			"    {{orange}}{{bold}}> F2(){{/}}",
  2316  			"        {{orange}}{{bold}}fileB:21{{/}}",
  2317  			"          | source line 1",
  2318  			"          | source line 2",
  2319  			"          {{bold}}{{orange}}> source line 3 (highlight!){{/}}",
  2320  			"          | source line 4",
  2321  			"          | source line 5",
  2322  			"      {{gray}}F3(){{/}}",
  2323  			"        {{gray}}fileC:9{{/}}",
  2324  			INDENTED_DELIMITER,
  2325  			""),
  2326  		Entry("correcting source code indentation",
  2327  			C(),
  2328  			PR(
  2329  				types.NodeTypeIt, CurrentNodeText("My Spec"), LeafNodeText("My Spec"),
  2330  				G(true, "sleeping",
  2331  					Fn("F1()", "fileA", 15),
  2332  					Fn(
  2333  						"F2()", "fileB", 26, true, 1,
  2334  						"\t\t\thello",
  2335  						"\t\t\t\tthere",
  2336  						"",
  2337  						"\t\t\tit",
  2338  						"\t\tworks",
  2339  					),
  2340  					Fn("F3()", "fileC", 9),
  2341  				),
  2342  			),
  2343  			INDENTED_DELIMITER,
  2344  			"  {{bold}}{{orange}}My Spec{{/}} (Spec Runtime: 5s)",
  2345  			"    {{gray}}"+cl0.String()+"{{/}}",
  2346  			"    In {{bold}}{{orange}}[It]{{/}} (Node Runtime: 3s)",
  2347  			"      {{gray}}"+cl1.String()+"{{/}}",
  2348  			"",
  2349  			"    {{bold}}{{underline}}Spec Goroutine{{/}}",
  2350  			"    {{orange}}goroutine 17 [sleeping]{{/}}",
  2351  			"      {{gray}}F1(){{/}}",
  2352  			"        {{gray}}fileA:15{{/}}",
  2353  			"    {{orange}}{{bold}}> F2(){{/}}",
  2354  			"        {{orange}}{{bold}}fileB:26{{/}}",
  2355  			"          | \thello",
  2356  			"          {{bold}}{{orange}}> \t\tthere{{/}}",
  2357  			"          | ",
  2358  			"          | \tit",
  2359  			"          | works",
  2360  			"      {{gray}}F3(){{/}}",
  2361  			"        {{gray}}fileC:9{{/}}",
  2362  			INDENTED_DELIMITER,
  2363  			""),
  2364  		Entry("random edge case where source code is empty (it doesn't explode)",
  2365  			C(),
  2366  			PR(
  2367  				types.NodeTypeIt, CurrentNodeText("My Spec"), LeafNodeText("My Spec"),
  2368  				G(true, "sleeping",
  2369  					Fn("F1()", "fileA", 15),
  2370  					Fn(
  2371  						"F2()", "fileB", 26, true, 1,
  2372  						"",
  2373  						"",
  2374  						"",
  2375  						"",
  2376  						"",
  2377  					),
  2378  					Fn("F3()", "fileC", 9),
  2379  				),
  2380  			),
  2381  			INDENTED_DELIMITER,
  2382  			"  {{bold}}{{orange}}My Spec{{/}} (Spec Runtime: 5s)",
  2383  			"    {{gray}}"+cl0.String()+"{{/}}",
  2384  			"    In {{bold}}{{orange}}[It]{{/}} (Node Runtime: 3s)",
  2385  			"      {{gray}}"+cl1.String()+"{{/}}",
  2386  			"",
  2387  			"    {{bold}}{{underline}}Spec Goroutine{{/}}",
  2388  			"    {{orange}}goroutine 17 [sleeping]{{/}}",
  2389  			"      {{gray}}F1(){{/}}",
  2390  			"        {{gray}}fileA:15{{/}}",
  2391  			"    {{orange}}{{bold}}> F2(){{/}}",
  2392  			"        {{orange}}{{bold}}fileB:26{{/}}",
  2393  			"          | ",
  2394  			"          {{bold}}{{orange}}> {{/}}",
  2395  			"          | ",
  2396  			"          | ",
  2397  			"          | ",
  2398  			"      {{gray}}F3(){{/}}",
  2399  			"        {{gray}}fileC:9{{/}}",
  2400  			INDENTED_DELIMITER,
  2401  			""),
  2402  		// including additional reports
  2403  
  2404  		Entry("with one additional report",
  2405  			C(),
  2406  			PR(
  2407  				types.NodeTypeIt, CurrentNodeText("My Spec"), LeafNodeText("My Spec"),
  2408  				G(true, "sleeping",
  2409  					Fn("F1()", "fileA", 15),
  2410  					Fn("F2()", "fileB", 11, true),
  2411  					Fn("F3()", "fileC", 9),
  2412  				),
  2413  				G(false, "sleeping",
  2414  					Fn("F1()", "fileA", 15),
  2415  					Fn("F2()", "fileB", 11, true),
  2416  					Fn("F3()", "fileC", 9),
  2417  				),
  2418  				AdditionalReports{"{{blue}}Report 1{{/}}"},
  2419  			),
  2420  			INDENTED_DELIMITER,
  2421  			"  {{bold}}{{orange}}My Spec{{/}} (Spec Runtime: 5s)",
  2422  			"    {{gray}}"+cl0.String()+"{{/}}",
  2423  			"    In {{bold}}{{orange}}[It]{{/}} (Node Runtime: 3s)",
  2424  			"      {{gray}}"+cl1.String()+"{{/}}",
  2425  			"",
  2426  			"    {{bold}}{{underline}}Spec Goroutine{{/}}",
  2427  			"    {{orange}}goroutine 17 [sleeping]{{/}}",
  2428  			"      {{gray}}F1(){{/}}",
  2429  			"        {{gray}}fileA:15{{/}}",
  2430  			"    {{orange}}{{bold}}> F2(){{/}}",
  2431  			"        {{orange}}{{bold}}fileB:11{{/}}",
  2432  			"      {{gray}}F3(){{/}}",
  2433  			"        {{gray}}fileC:9{{/}}",
  2434  			"",
  2435  			"    {{gray}}Begin Additional Progress Reports >>{{/}}",
  2436  			"      {{blue}}Report 1{{/}}",
  2437  			"    {{gray}}<< End Additional Progress Reports{{/}}",
  2438  			"",
  2439  			"    {{bold}}{{underline}}Goroutines of Interest{{/}}",
  2440  			"    {{orange}}goroutine 17 [sleeping]{{/}}",
  2441  			"      {{gray}}F1(){{/}}",
  2442  			"        {{gray}}fileA:15{{/}}",
  2443  			"    {{orange}}{{bold}}> F2(){{/}}",
  2444  			"        {{orange}}{{bold}}fileB:11{{/}}",
  2445  			"      {{gray}}F3(){{/}}",
  2446  			"        {{gray}}fileC:9{{/}}",
  2447  			INDENTED_DELIMITER,
  2448  			""),
  2449  		Entry("with multiple additional reports",
  2450  			C(),
  2451  			PR(
  2452  				types.NodeTypeIt, CurrentNodeText("My Spec"), LeafNodeText("My Spec"),
  2453  				G(true, "sleeping",
  2454  					Fn("F1()", "fileA", 15),
  2455  					Fn("F2()", "fileB", 11, true),
  2456  					Fn("F3()", "fileC", 9),
  2457  				),
  2458  				G(false, "sleeping",
  2459  					Fn("F1()", "fileA", 15),
  2460  					Fn("F2()", "fileB", 11, true),
  2461  					Fn("F3()", "fileC", 9),
  2462  				),
  2463  				AdditionalReports{"{{blue}}Report 1{{/}}", "{{green}}Report 2{{/}}"},
  2464  			),
  2465  			INDENTED_DELIMITER,
  2466  			"  {{bold}}{{orange}}My Spec{{/}} (Spec Runtime: 5s)",
  2467  			"    {{gray}}"+cl0.String()+"{{/}}",
  2468  			"    In {{bold}}{{orange}}[It]{{/}} (Node Runtime: 3s)",
  2469  			"      {{gray}}"+cl1.String()+"{{/}}",
  2470  			"",
  2471  			"    {{bold}}{{underline}}Spec Goroutine{{/}}",
  2472  			"    {{orange}}goroutine 17 [sleeping]{{/}}",
  2473  			"      {{gray}}F1(){{/}}",
  2474  			"        {{gray}}fileA:15{{/}}",
  2475  			"    {{orange}}{{bold}}> F2(){{/}}",
  2476  			"        {{orange}}{{bold}}fileB:11{{/}}",
  2477  			"      {{gray}}F3(){{/}}",
  2478  			"        {{gray}}fileC:9{{/}}",
  2479  			"",
  2480  			"    {{gray}}Begin Additional Progress Reports >>{{/}}",
  2481  			"      {{blue}}Report 1{{/}}",
  2482  			"      {{gray}}----------{{/}}",
  2483  			"      {{green}}Report 2{{/}}",
  2484  			"    {{gray}}<< End Additional Progress Reports{{/}}",
  2485  			"",
  2486  			"    {{bold}}{{underline}}Goroutines of Interest{{/}}",
  2487  			"    {{orange}}goroutine 17 [sleeping]{{/}}",
  2488  			"      {{gray}}F1(){{/}}",
  2489  			"        {{gray}}fileA:15{{/}}",
  2490  			"    {{orange}}{{bold}}> F2(){{/}}",
  2491  			"        {{orange}}{{bold}}fileB:11{{/}}",
  2492  			"      {{gray}}F3(){{/}}",
  2493  			"        {{gray}}fileC:9{{/}}",
  2494  			INDENTED_DELIMITER,
  2495  			""),
  2496  		// when running in parallel
  2497  
  2498  		Entry("when running in parallel",
  2499  			C(),
  2500  			PR(
  2501  				"A Message",
  2502  				true, 3,
  2503  				types.NodeTypeIt, CurrentNodeText("My Spec"), LeafNodeText("My Spec"),
  2504  			),
  2505  			INDENTED_DELIMITER,
  2506  			"  {{coral}}Progress Report for Ginkgo Process #{{bold}}3{{/}}",
  2507  			"  A Message",
  2508  			"    {{bold}}{{orange}}My Spec{{/}} (Spec Runtime: 5s)",
  2509  			"      {{gray}}cl0.go:12{{/}}",
  2510  			"      In {{bold}}{{orange}}[It]{{/}} (Node Runtime: 3s)",
  2511  			"        {{gray}}cl1.go:37{{/}}",
  2512  			INDENTED_DELIMITER,
  2513  			""),
  2514  	)
  2515  
  2516  	DescribeTable("EmitFailure",
  2517  		func(conf types.ReporterConfig, af types.AdditionalFailure, expected ...any) {
  2518  			reporter := reporters.NewDefaultReporterUnderTest(conf, buf)
  2519  			reporter.EmitFailure(af.State, af.Failure)
  2520  			Expect(string(buf.Contents())).Should(MatchLines(expected...))
  2521  		},
  2522  
  2523  		// silent when running succinctly or normal
  2524  		Entry("emits nothing when running with succinct verbosity",
  2525  			C(Succinct),
  2526  			AF(types.SpecStateFailed, "message"),
  2527  		),
  2528  		Entry("emits nothing when running in normal verbosity",
  2529  			C(),
  2530  			AF(types.SpecStateFailed, "message"),
  2531  		),
  2532  		// one-line summary when running verbosely
  2533  		Entry("emits a one line summary when running in verbose mode",
  2534  			C(Verbose),
  2535  			AF(types.SpecStateFailed, "message", types.NodeTypeIt, cl0),
  2536  			spr("  {{red}}[FAILED]{{/}} in [It] - cl0.go:12 {{gray}}@ %s{{/}}", FORMATTED_TIME),
  2537  			"",
  2538  		),
  2539  		Entry("is cyan when skipped",
  2540  			C(Verbose),
  2541  			AF(types.SpecStateSkipped, "message", types.NodeTypeIt, cl0),
  2542  			spr("  {{cyan}}[SKIPPED]{{/}} in [It] - cl0.go:12 {{gray}}@ %s{{/}}", FORMATTED_TIME),
  2543  			"",
  2544  		),
  2545  		Entry("is orange when timedout",
  2546  			C(Verbose),
  2547  			AF(types.SpecStateTimedout, "message", types.NodeTypeIt, cl0),
  2548  			spr("  {{orange}}[TIMEDOUT]{{/}} in [It] - cl0.go:12 {{gray}}@ %s{{/}}", FORMATTED_TIME),
  2549  			"",
  2550  		),
  2551  		Entry("is orange when interrupted",
  2552  			C(Verbose),
  2553  			AF(types.SpecStateInterrupted, "message", types.NodeTypeIt, cl0),
  2554  			spr("  {{orange}}[INTERRUPTED]{{/}} in [It] - cl0.go:12 {{gray}}@ %s{{/}}", FORMATTED_TIME),
  2555  			"",
  2556  		),
  2557  		Entry("is coral when aborted",
  2558  			C(Verbose),
  2559  			AF(types.SpecStateAborted, "message", types.NodeTypeIt, cl0),
  2560  			spr("  {{coral}}[ABORTED]{{/}} in [It] - cl0.go:12 {{gray}}@ %s{{/}}", FORMATTED_TIME),
  2561  			"",
  2562  		),
  2563  		// now, when running in VeryVerbose mode - all the things emerge... (and this is what also appears in summaries at the end of tests)
  2564  		Entry("emits a full summary when running in -vv",
  2565  			C(VeryVerbose),
  2566  			AF(types.SpecStateFailed, "MY FAILURE:\nFailure Details", types.NodeTypeIt, cl0),
  2567  			"  {{red}}[FAILED] MY FAILURE:",
  2568  			"  Failure Details{{/}}",
  2569  			spr("  {{red}}In {{bold}}[It]{{/}}{{red}} at: {{bold}}cl0.go:12{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  2570  			"",
  2571  		),
  2572  		Entry("includes the trace when FullTrace is enabled",
  2573  			C(VeryVerbose|FullTrace),
  2574  			AF(types.SpecStateFailed, "MY FAILURE:\nFailure Details", types.NodeTypeIt, cl0),
  2575  			"  {{red}}[FAILED] MY FAILURE:",
  2576  			"  Failure Details{{/}}",
  2577  			spr("  {{red}}In {{bold}}[It]{{/}}{{red}} at: {{bold}}cl0.go:12{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  2578  			"",
  2579  			"  {{red}}Full Stack Trace{{/}}",
  2580  			"    full-trace",
  2581  			"    cl-0",
  2582  			"",
  2583  		),
  2584  		Entry("includes the forwarded panic and full-trace when a forwarded panic is provided",
  2585  			C(VeryVerbose),
  2586  			AF(types.SpecStatePanicked, "MY FAILURE:\nFailure Details", types.NodeTypeIt, cl0, ForwardedPanic("the panic!")),
  2587  			"  {{magenta}}[PANICKED] MY FAILURE:",
  2588  			"  Failure Details{{/}}",
  2589  			spr("  {{magenta}}In {{bold}}[It]{{/}}{{magenta}} at: {{bold}}cl0.go:12{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  2590  			"",
  2591  			"  {{magenta}}the panic!{{/}}",
  2592  			"",
  2593  			"  {{magenta}}Full Stack Trace{{/}}",
  2594  			"    full-trace",
  2595  			"    cl-0",
  2596  			"",
  2597  		),
  2598  		Entry("includes a progress report and an additional failure if any are attached",
  2599  			C(VeryVerbose),
  2600  			AF(types.SpecStateTimedout, "A node timeout occurred:\nTimeout details", types.NodeTypeIt, cl0,
  2601  				PR("A Progress Report Message", types.NodeTypeIt, CurrentNodeText("A Top-Level It"), LeafNodeText("A Top-Level It")),
  2602  				AF(types.SpecStateFailed, "An additional failure", types.NodeTypeIt, cl1)),
  2603  			"  {{orange}}[TIMEDOUT] A node timeout occurred:",
  2604  			"  Timeout details{{/}}",
  2605  			spr("  {{orange}}In {{bold}}[It]{{/}}{{orange}} at: {{bold}}cl0.go:12{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  2606  			"",
  2607  			"  A Progress Report Message",
  2608  			"    {{bold}}{{orange}}A Top-Level It{{/}} (Spec Runtime: 5s)",
  2609  			"      {{gray}}cl0.go:12{{/}}",
  2610  			"      In {{bold}}{{orange}}[It]{{/}} (Node Runtime: 3s)",
  2611  			"        {{gray}}cl1.go:37{{/}}",
  2612  			"",
  2613  			"  {{red}}[FAILED] An additional failure{{/}}",
  2614  			spr("  {{red}}In {{bold}}[It]{{/}}{{red}} at: {{bold}}cl1.go:37{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  2615  			"",
  2616  		),
  2617  	)
  2618  
  2619  	DescribeTable("EmitReportentry",
  2620  		func(conf types.ReporterConfig, reportEntry types.ReportEntry, expected ...any) {
  2621  			reporter := reporters.NewDefaultReporterUnderTest(conf, buf)
  2622  			reporter.EmitReportEntry(reportEntry)
  2623  			Expect(string(buf.Contents())).Should(MatchLines(expected...))
  2624  		},
  2625  
  2626  		// silent when running succinctly or normal
  2627  		Entry("emits nothing when running with succinct verbosity",
  2628  			C(Succinct),
  2629  			RE("my report", cl0),
  2630  		),
  2631  		Entry("emits nothing when running with normal verbosity",
  2632  			C(),
  2633  			RE("my report", cl0),
  2634  		),
  2635  		Entry("emits nothing if hte report has VisiblityNever, regardless of verbosity level",
  2636  			C(Verbose),
  2637  			RE("my report", cl0, types.ReportEntryVisibilityNever),
  2638  		),
  2639  		//emitting reports with no StringRepresentation()
  2640  		Entry("emits the report",
  2641  			C(Verbose),
  2642  			RE("my report", cl0),
  2643  			spr("  {{bold}}my report{{gray}} - cl0.go:12 @ %s{{/}}", FORMATTED_TIME),
  2644  			"",
  2645  		),
  2646  		//emitting reports with a StringRepresentation()
  2647  		Entry("emits the report along with it's string representation",
  2648  			C(Verbose),
  2649  			RE("my report", cl0, 3),
  2650  			spr("  {{bold}}my report{{gray}} - cl0.go:12 @ %s{{/}}", FORMATTED_TIME),
  2651  			"    3",
  2652  			"",
  2653  		),
  2654  		Entry("emits the report along with it's string representation (and indents it correctly)",
  2655  			C(Verbose),
  2656  			RE("my report", cl0, "{{yellow}}My awesome report{{/}}\n{{coral}}Is beautiful{{/}}"),
  2657  			spr("  {{bold}}my report{{gray}} - cl0.go:12 @ %s{{/}}", FORMATTED_TIME),
  2658  			"    {{yellow}}My awesome report{{/}}",
  2659  			"    {{coral}}Is beautiful{{/}}",
  2660  			"",
  2661  		),
  2662  		//correctly handling reports that have format string components
  2663  		Entry("emits the report without running it through sprintf",
  2664  			C(Verbose),
  2665  			RE("my %f report", cl0, "{{green}}my report http://example.com/?q=%d%3%%{{/}}", cl0),
  2666  			spr("  {{bold}}my %%f report{{gray}} - cl0.go:12 @ %s{{/}}", FORMATTED_TIME),
  2667  			"    {{green}}my report http://example.com/?q=%d%3%%{{/}}",
  2668  			"",
  2669  		),
  2670  	)
  2671  
  2672  	DescribeTable("EmitSpecEvent",
  2673  		func(conf types.ReporterConfig, specEvent types.SpecEvent, expected ...any) {
  2674  			reporter := reporters.NewDefaultReporterUnderTest(conf, buf)
  2675  			reporter.EmitSpecEvent(specEvent)
  2676  			Expect(string(buf.Contents())).Should(MatchLines(expected...))
  2677  		},
  2678  
  2679  		// silent when running succinctly or normal
  2680  		Entry("emits nothing when running with succinct verbosity",
  2681  			C(Succinct),
  2682  			SE(types.SpecEventByStart),
  2683  		),
  2684  		Entry("emits nothing when running with normal verbosity",
  2685  			C(),
  2686  			SE(types.SpecEventByStart),
  2687  		),
  2688  		Entry("emits nothing when running with normal verbosity and ShowNodeEvents",
  2689  			C(ShowNodeEvents),
  2690  			SE(types.SpecEventByStart),
  2691  		),
  2692  		Entry("emits nothing when running with normal verbosity and ShowNodeEvents",
  2693  			C(ShowNodeEvents),
  2694  			SE(types.SpecEventByEnd),
  2695  		),
  2696  		Entry("emits nothing when running with -v and the event is not visible at that verbosity level",
  2697  			C(Verbose),
  2698  			SE(types.SpecEventByEnd),
  2699  		),
  2700  		Entry("emits the event when running with -v and ShowNodeEvents",
  2701  			C(Verbose|ShowNodeEvents),
  2702  			SE(types.SpecEventByEnd, "hello world", 90*time.Millisecond),
  2703  			spr("  {{bold}}END STEP:{{/}} hello world {{gray}}@ %s (90ms){{/}}", FORMATTED_TIME),
  2704  			"",
  2705  		),
  2706  
  2707  		// when running in verbose mode
  2708  		Entry("emits By start events",
  2709  			C(Verbose),
  2710  			SE(types.SpecEventByStart, "hello world", cl0),
  2711  			spr("  {{bold}}STEP:{{/}} hello world {{gray}}@ %s{{/}}", FORMATTED_TIME),
  2712  			"",
  2713  		),
  2714  		Entry("does not emit By end events",
  2715  			C(Verbose),
  2716  			SE(types.SpecEventByEnd, "hello world", cl0, 89734*time.Microsecond),
  2717  		),
  2718  		Entry("does not emit node start events",
  2719  			C(Verbose),
  2720  			SE(types.SpecEventNodeStart, "my node", types.NodeTypeIt, cl0),
  2721  		),
  2722  		Entry("does not emit node end events",
  2723  			C(Verbose),
  2724  			SE(types.SpecEventNodeEnd, "my node", types.NodeTypeIt, cl0, 89734*time.Microsecond),
  2725  		),
  2726  		Entry("emits spec repeats",
  2727  			C(Verbose),
  2728  			SE(types.SpecEventSpecRepeat, 3),
  2729  			"",
  2730  			spr("  {{bold}}Attempt #3 {{green}}Passed{{/}}{{bold}}.  Repeating ↺{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  2731  			"",
  2732  			"",
  2733  		),
  2734  		Entry("emits spec retries",
  2735  			C(Verbose),
  2736  			SE(types.SpecEventSpecRetry, 7),
  2737  			"",
  2738  			spr("  {{bold}}Attempt #7 {{red}}Failed{{/}}{{bold}}.  Retrying ↺{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  2739  			"",
  2740  			"",
  2741  		),
  2742  		// when running in very-verbose mode
  2743  		Entry("emits By start events",
  2744  			C(VeryVerbose),
  2745  			SE(types.SpecEventByStart, "hello world", cl0),
  2746  			spr("  {{bold}}STEP:{{/}} hello world {{gray}}- cl0.go:12 @ %s{{/}}", FORMATTED_TIME),
  2747  			"",
  2748  		),
  2749  		Entry("emits By end events",
  2750  			C(VeryVerbose),
  2751  			SE(types.SpecEventByEnd, "hello world", cl0, 89734*time.Microsecond),
  2752  			spr("  {{bold}}END STEP:{{/}} hello world {{gray}}- cl0.go:12 @ %s (90ms){{/}}", FORMATTED_TIME),
  2753  			"",
  2754  		),
  2755  		Entry("emits node start events",
  2756  			C(VeryVerbose),
  2757  			SE(types.SpecEventNodeStart, "my node", types.NodeTypeIt, cl0),
  2758  			spr("  > Enter {{bold}}[It]{{/}} my node {{gray}}- cl0.go:12 @ %s{{/}}", FORMATTED_TIME),
  2759  			"",
  2760  		),
  2761  		Entry("emits node end events",
  2762  			C(VeryVerbose),
  2763  			SE(types.SpecEventNodeEnd, "my node", types.NodeTypeIt, cl0, 89734*time.Microsecond),
  2764  			spr("  < Exit {{bold}}[It]{{/}} my node {{gray}}- cl0.go:12 @ %s (90ms){{/}}", FORMATTED_TIME),
  2765  			"",
  2766  		),
  2767  		Entry("emits spec repeats",
  2768  			C(VeryVerbose),
  2769  			SE(types.SpecEventSpecRepeat, 3),
  2770  			"",
  2771  			spr("  {{bold}}Attempt #3 {{green}}Passed{{/}}{{bold}}.  Repeating ↺{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  2772  			"",
  2773  			"",
  2774  		),
  2775  		Entry("emits spec retries",
  2776  			C(VeryVerbose),
  2777  			SE(types.SpecEventSpecRetry, 7),
  2778  			"",
  2779  			spr("  {{bold}}Attempt #7 {{red}}Failed{{/}}{{bold}}.  Retrying ↺{{/}} {{gray}}@ %s{{/}}", FORMATTED_TIME),
  2780  			"",
  2781  			"",
  2782  		),
  2783  	)
  2784  })
  2785  

View as plain text