github.com/onsi/ginkgo@v1.16.6-0.20211118180735-4e1925ba4c95/core_dsl.go (about) 1 /* 2 Ginkgo is a testing framework for Go designed to help you write expressive tests. 3 https://github.com/onsi/ginkgo 4 MIT-Licensed 5 6 The godoc documentation outlines Ginkgo's API. Since Ginkgo is a Domain-Specific Language it is important to 7 build a mental model for Ginkgo - the narrative documentation at https://onsi.github.io/ginkgo/ is designed to help you do that. 8 You should start there - even a brief skim will be helpful. At minimum you should skim through the https://onsi.github.io/ginkgo/#getting-started chapter. 9 10 Ginkgo's is best paired with the Gomega matcher library: https://github.com/onsi/gomega 11 12 You can run Ginkgo specs with go test - however we recommend using the ginkgo cli. It enables functionality 13 that go test does not (especially running suites in parallel). You can learn more at https://onsi.github.io/ginkgo/#ginkgo-cli-overview 14 or by running 'ginkgo help'. 15 */ 16 package ginkgo 17 18 import ( 19 "fmt" 20 "io" 21 "os" 22 "path/filepath" 23 "strings" 24 "time" 25 26 "github.com/onsi/ginkgo/formatter" 27 "github.com/onsi/ginkgo/internal" 28 "github.com/onsi/ginkgo/internal/global" 29 "github.com/onsi/ginkgo/internal/interrupt_handler" 30 "github.com/onsi/ginkgo/internal/parallel_support" 31 "github.com/onsi/ginkgo/reporters" 32 "github.com/onsi/ginkgo/types" 33 ) 34 35 const GINKGO_VERSION = types.VERSION 36 37 var flagSet types.GinkgoFlagSet 38 var deprecationTracker = types.NewDeprecationTracker() 39 var suiteConfig = types.NewDefaultSuiteConfig() 40 var reporterConfig = types.NewDefaultReporterConfig() 41 var suiteDidRun = false 42 var outputInterceptor internal.OutputInterceptor 43 var client parallel_support.Client 44 45 func init() { 46 var err error 47 flagSet, err = types.BuildTestSuiteFlagSet(&suiteConfig, &reporterConfig) 48 exitIfErr(err) 49 GinkgoWriter = internal.NewWriter(os.Stdout) 50 } 51 52 func exitIfErr(err error) { 53 if err != nil { 54 if outputInterceptor != nil { 55 outputInterceptor.Shutdown() 56 } 57 if client != nil { 58 client.Close() 59 } 60 fmt.Fprintln(formatter.ColorableStdErr, err.Error()) 61 os.Exit(1) 62 } 63 } 64 65 func exitIfErrors(errors []error) { 66 if len(errors) > 0 { 67 if outputInterceptor != nil { 68 outputInterceptor.Shutdown() 69 } 70 if client != nil { 71 client.Close() 72 } 73 for _, err := range errors { 74 fmt.Fprintln(formatter.ColorableStdErr, err.Error()) 75 } 76 os.Exit(1) 77 } 78 } 79 80 //The interface implemented by GinkgoWriter 81 type GinkgoWriterInterface interface { 82 io.Writer 83 84 Print(a ...interface{}) 85 Printf(format string, a ...interface{}) 86 Println(a ...interface{}) 87 88 TeeTo(writer io.Writer) 89 ClearTeeWriters() 90 } 91 92 /* 93 GinkgoWriter implements a GinkgoWriterInterface and io.Writer 94 95 When running in verbose mode (ginkgo -v) any writes to GinkgoWriter will be immediately printed 96 to stdout. Otherwise, GinkgoWriter will buffer any writes produced during the current test and flush them to screen 97 only if the current test fails. 98 99 GinkgoWriter also provides convenience Print, Printf and Println methods and allows you to tee to a custom writer via GinkgoWriter.TeeTo(writer). 100 Writes to GinkgoWriter are immediately sent to any registered TeeTo() writers. You can unregister all TeeTo() Writers with GinkgoWriter.ClearTeeWriters() 101 102 You can learn more at https://onsi.github.io/ginkgo/#logging-output 103 */ 104 var GinkgoWriter GinkgoWriterInterface 105 106 //The interface by which Ginkgo receives *testing.T 107 type GinkgoTestingT interface { 108 Fail() 109 } 110 111 /* 112 GinkgoConfiguration returns the configuration of the current suite. 113 114 The first return value is the SuiteConfig which controls aspects of how the suite runs, 115 the second return value is the ReporterConfig which controls aspects of how Ginkgo's default 116 reporter emits output. 117 118 Mutating the returned configurations has no effect. To reconfigure Ginkgo programatically you need 119 to pass in your mutated copies into RunSpecs(). 120 121 You can learn more at https://onsi.github.io/ginkgo/#overriding-ginkgos-command-line-configuration-in-the-suite 122 */ 123 func GinkgoConfiguration() (types.SuiteConfig, types.ReporterConfig) { 124 return suiteConfig, reporterConfig 125 } 126 127 /* 128 GinkgoRandomSeed returns the seed used to randomize spec execution order. It is 129 useful for seeding your own pseudorandom number generators to ensure 130 consistent executions from run to run, where your tests contain variability (for 131 example, when selecting random spec data). 132 133 You can learn more at https://onsi.github.io/ginkgo/#spec-randomization 134 */ 135 func GinkgoRandomSeed() int64 { 136 return suiteConfig.RandomSeed 137 } 138 139 /* 140 GinkgoParallelProcess returns the parallel process number for the current ginkgo process 141 The process number is 1-indexed. You can use GinkgoParallelProcess() to shard access to shared 142 resources across your suites. You can learn more about patterns for sharding at https://onsi.github.io/ginkgo/#patterns-for-parallel-integration-specs 143 144 For more on how specs are parallelized in Ginkgo, see http://onsi.github.io/ginkgo/#spec-parallelization 145 */ 146 func GinkgoParallelProcess() int { 147 return suiteConfig.ParallelProcess 148 } 149 150 /* 151 PauseOutputInterception() pauses Ginkgo's output interception. This is only relevant 152 when running in parallel and output to stdout/stderr is being intercepted. You generally 153 don't need to call this function - however there are cases when Ginkgo's output interception 154 mechanisms can interfere with external processes launched by the test process. 155 156 In particular, if an external process is launched that has cmd.Stdout/cmd.Stderr set to os.Stdout/os.Stderr 157 then Ginkgo's output interceptor will hang. To circumvent this, set cmd.Stdout/cmd.Stderr to GinkgoWriter. 158 If, for some reason, you aren't able to do that, you can PauseOutputInterception() before starting the process 159 then ResumeOutputInterception() after starting it. 160 161 Note that PauseOutputInterception() does not cause stdout writes to print to the console - 162 this simply stops intercepting and storing stdout writes to an internal buffer. 163 */ 164 func PauseOutputInterception() { 165 if outputInterceptor == nil { 166 return 167 } 168 outputInterceptor.PauseIntercepting() 169 } 170 171 //ResumeOutputInterception() - see docs for PauseOutputInterception() 172 func ResumeOutputInterception() { 173 if outputInterceptor == nil { 174 return 175 } 176 outputInterceptor.ResumeIntercepting() 177 } 178 179 /* 180 RunSpecs is the entry point for the Ginkgo spec runner. 181 182 You must call this within a Golang testing TestX(t *testing.T) function. 183 If you bootstrapped your suite with "ginkgo bootstrap" this is already 184 done for you. 185 186 Ginkgo is typically configured via command-line flags. This configuration 187 can be overriden, however, and passed into RunSpecs as optional arguments: 188 189 func TestMySuite(t *testing.T) { 190 RegisterFailHandler(gomega.Fail) 191 // fetch the current config 192 suiteConfig, reporterConfig := GinkgoConfiguration() 193 // adjust it 194 suiteConfig.SkipStrings = []string{"NEVER-RUN"} 195 reporterConfig.FullTrace = true 196 // pass it in to RunSpecs 197 RunSpecs(t, "My Suite", suiteConfig, reporterConfig) 198 } 199 200 Note that some configuration changes can lead to undefined behavior. For example, 201 you should not change ParallelProcess or ParallelTotal as the Ginkgo CLI is responsible 202 for setting these and orchestrating parallel specs across the parallel processes. See http://onsi.github.io/ginkgo/#spec-parallelization 203 for more on how specs are parallelized in Ginkgo. 204 205 You can also pass suite-level Label() decorators to RunSpecs. The passed-in labels will apply to all specs in the suite. 206 */ 207 func RunSpecs(t GinkgoTestingT, description string, args ...interface{}) bool { 208 if suiteDidRun { 209 exitIfErr(types.GinkgoErrors.RerunningSuite()) 210 } 211 suiteDidRun = true 212 213 suiteLabels := Labels{} 214 configErrors := []error{} 215 for _, arg := range args { 216 switch arg := arg.(type) { 217 case types.SuiteConfig: 218 suiteConfig = arg 219 case types.ReporterConfig: 220 reporterConfig = arg 221 case Labels: 222 suiteLabels = append(suiteLabels, arg...) 223 default: 224 configErrors = append(configErrors, types.GinkgoErrors.UnkownTypePassedToRunSpecs(arg)) 225 } 226 } 227 exitIfErrors(configErrors) 228 229 configErrors = types.VetConfig(flagSet, suiteConfig, reporterConfig) 230 if len(configErrors) > 0 { 231 fmt.Fprintf(formatter.ColorableStdErr, formatter.F("{{red}}Ginkgo detected configuration issues:{{/}}\n")) 232 for _, err := range configErrors { 233 fmt.Fprintf(formatter.ColorableStdErr, err.Error()) 234 } 235 os.Exit(1) 236 } 237 238 var reporter reporters.Reporter 239 if suiteConfig.ParallelTotal == 1 { 240 reporter = reporters.NewDefaultReporter(reporterConfig, formatter.ColorableStdOut) 241 outputInterceptor = internal.NoopOutputInterceptor{} 242 client = nil 243 } else { 244 reporter = reporters.NoopReporter{} 245 switch strings.ToLower(suiteConfig.OutputInterceptorMode) { 246 case "swap": 247 outputInterceptor = internal.NewOSGlobalReassigningOutputInterceptor() 248 case "none": 249 outputInterceptor = internal.NoopOutputInterceptor{} 250 default: 251 outputInterceptor = internal.NewOutputInterceptor() 252 } 253 client = parallel_support.NewClient(suiteConfig.ParallelHost) 254 if !client.Connect() { 255 client = nil 256 exitIfErr(types.GinkgoErrors.UnreachableParallelHost(suiteConfig.ParallelHost)) 257 } 258 defer client.Close() 259 } 260 261 writer := GinkgoWriter.(*internal.Writer) 262 if reporterConfig.Verbose && suiteConfig.ParallelTotal == 1 { 263 writer.SetMode(internal.WriterModeStreamAndBuffer) 264 } else { 265 writer.SetMode(internal.WriterModeBufferOnly) 266 } 267 268 if reporterConfig.WillGenerateReport() { 269 registerReportAfterSuiteNodeForAutogeneratedReports(reporterConfig) 270 } 271 272 err := global.Suite.BuildTree() 273 exitIfErr(err) 274 275 suitePath, err := os.Getwd() 276 exitIfErr(err) 277 suitePath, err = filepath.Abs(suitePath) 278 exitIfErr(err) 279 280 passed, hasFocusedTests := global.Suite.Run(description, suiteLabels, suitePath, global.Failer, reporter, writer, outputInterceptor, interrupt_handler.NewInterruptHandler(suiteConfig.Timeout, client), client, suiteConfig) 281 outputInterceptor.Shutdown() 282 283 flagSet.ValidateDeprecations(deprecationTracker) 284 if deprecationTracker.DidTrackDeprecations() { 285 fmt.Fprintln(formatter.ColorableStdErr, deprecationTracker.DeprecationsReport()) 286 } 287 288 if !passed { 289 t.Fail() 290 } 291 292 if passed && hasFocusedTests && strings.TrimSpace(os.Getenv("GINKGO_EDITOR_INTEGRATION")) == "" { 293 fmt.Println("PASS | FOCUSED") 294 os.Exit(types.GINKGO_FOCUS_EXIT_CODE) 295 } 296 return passed 297 } 298 299 /* 300 Skip instructs Ginkgo to skip the current spec 301 302 You can call Skip in any Setup or Subject node closure. 303 304 For more on how to filter specs in Ginkgo see https://onsi.github.io/ginkgo/#filtering-specs 305 */ 306 func Skip(message string, callerSkip ...int) { 307 skip := 0 308 if len(callerSkip) > 0 { 309 skip = callerSkip[0] 310 } 311 cl := types.NewCodeLocationWithStackTrace(skip + 1) 312 global.Failer.Skip(message, cl) 313 panic(types.GinkgoErrors.UncaughtGinkgoPanic(cl)) 314 } 315 316 /* 317 Fail notifies Ginkgo that the current spec has failed. (Gomega will call Fail for you automatically when an assertion fails.) 318 319 Under the hood, Fail panics to end execution of the current spec. Ginkgo will catch this panic and proceed with 320 the subsequent spec. If you call Fail, or make an assertion, within a goroutine launched by your spec you must 321 add defer GinkgoRecover() to the goroutine to catch the panic emitted by Fail. 322 323 You can call Fail in any Setup or Subject node closure. 324 325 You can learn more about how Ginkgo manages failures here: https://onsi.github.io/ginkgo/#mental-model-how-ginkgo-handles-failure 326 */ 327 func Fail(message string, callerSkip ...int) { 328 skip := 0 329 if len(callerSkip) > 0 { 330 skip = callerSkip[0] 331 } 332 333 cl := types.NewCodeLocationWithStackTrace(skip + 1) 334 global.Failer.Fail(message, cl) 335 panic(types.GinkgoErrors.UncaughtGinkgoPanic(cl)) 336 } 337 338 /* 339 AbortSuite instructs Ginkgo to fail the current spec and skip all subsequent specs, thereby aborting the suite. 340 341 You can call AbortSuite in any Setup or Subject node closure. 342 343 You can learn more about how Ginkgo handles suite interruptions here: https://onsi.github.io/ginkgo/#interrupting-aborting-and-timing-out-suites 344 */ 345 func AbortSuite(message string, callerSkip ...int) { 346 skip := 0 347 if len(callerSkip) > 0 { 348 skip = callerSkip[0] 349 } 350 351 cl := types.NewCodeLocationWithStackTrace(skip + 1) 352 global.Failer.AbortSuite(message, cl) 353 panic(types.GinkgoErrors.UncaughtGinkgoPanic(cl)) 354 } 355 356 /* 357 GinkgoRecover should be deferred at the top of any spawned goroutine that (may) call `Fail` 358 Since Gomega assertions call fail, you should throw a `defer GinkgoRecover()` at the top of any goroutine that 359 calls out to Gomega 360 361 Here's why: Ginkgo's `Fail` method records the failure and then panics to prevent 362 further assertions from running. This panic must be recovered. Normally, Ginkgo recovers the panic for you, 363 however if a panic originates on a goroutine *launched* from one of your specs there's no 364 way for Ginkgo to rescue the panic. To do this, you must remember to `defer GinkgoRecover()` at the top of such a goroutine. 365 366 You can learn more about how Ginkgo manages failures here: https://onsi.github.io/ginkgo/#mental-model-how-ginkgo-handles-failure 367 */ 368 func GinkgoRecover() { 369 e := recover() 370 if e != nil { 371 global.Failer.Panic(types.NewCodeLocationWithStackTrace(1), e) 372 } 373 } 374 375 // pushNode is used by the various test construction DSL methods to push nodes onto the suite 376 // it handles returned errors, emits a detailed error message to help the user learn what they may have done wrong, then exits 377 func pushNode(node internal.Node, errors []error) bool { 378 exitIfErrors(errors) 379 exitIfErr(global.Suite.PushNode(node)) 380 return true 381 } 382 383 /* 384 Describe nodes are Container nodes that allow you to organize your specs. A Describe node's closure can contain any number of 385 Setup nodes (e.g. BeforeEach, AfterEach, JustBeforeEach), and Subject nodes (i.e. It). 386 387 Context and When nodes are aliases for Describe - use whichever gives your suite a better narrative flow. It is idomatic 388 to Describe the behavior of an object or function and, within that Describe, outline a number of Contexts and Whens. 389 390 You can learn more at https://onsi.github.io/ginkgo/#organizing-specs-with-container-nodes 391 In addition, container nodes can be decorated with a variety of decorators. You can learn more here: https://onsi.github.io/ginkgo/#decorator-reference 392 */ 393 func Describe(text string, args ...interface{}) bool { 394 return pushNode(internal.NewNode(deprecationTracker, types.NodeTypeContainer, text, args...)) 395 } 396 397 /* 398 FDescribe focuses specs within the Describe block. 399 */ 400 func FDescribe(text string, args ...interface{}) bool { 401 args = append(args, internal.Focus) 402 return pushNode(internal.NewNode(deprecationTracker, types.NodeTypeContainer, text, args...)) 403 } 404 405 /* 406 PDescribe marks specs within the Describe block as pending. 407 */ 408 func PDescribe(text string, args ...interface{}) bool { 409 args = append(args, internal.Pending) 410 return pushNode(internal.NewNode(deprecationTracker, types.NodeTypeContainer, text, args...)) 411 } 412 413 /* 414 XDescribe marks specs within the Describe block as pending. 415 416 XDescribe is an alias for PDescribe 417 */ 418 var XDescribe = PDescribe 419 420 /* Context is an alias for Describe - it generates the exact same kind of Container node */ 421 var Context, FContext, PContext, XContext = Describe, FDescribe, PDescribe, XDescribe 422 423 /* When is an alias for Describe - it generates the exact same kind of Container node */ 424 var When, FWhen, PWhen, XWhen = Describe, FDescribe, PDescribe, XDescribe 425 426 /* 427 It nodes are Subject nodes that contain your spec code and assertions. 428 429 Each It node corresponds to an individual Ginkgo spec. You cannot nest any other Ginkgo nodes within an It node's closure. 430 431 You can learn more at https://onsi.github.io/ginkgo/#spec-subjects-it 432 In addition, subject nodes can be decorated with a variety of decorators. You can learn more here: https://onsi.github.io/ginkgo/#decorator-reference 433 */ 434 func It(text string, args ...interface{}) bool { 435 return pushNode(internal.NewNode(deprecationTracker, types.NodeTypeIt, text, args...)) 436 } 437 438 /* 439 FIt allows you to focus an individual It. 440 */ 441 func FIt(text string, args ...interface{}) bool { 442 args = append(args, internal.Focus) 443 return pushNode(internal.NewNode(deprecationTracker, types.NodeTypeIt, text, args...)) 444 } 445 446 /* 447 PIt allows you to mark an individual It as pending. 448 */ 449 func PIt(text string, args ...interface{}) bool { 450 args = append(args, internal.Pending) 451 return pushNode(internal.NewNode(deprecationTracker, types.NodeTypeIt, text, args...)) 452 } 453 454 /* 455 XIt allows you to mark an individual It as pending. 456 457 XIt is an alias for PIt 458 */ 459 var XIt = PIt 460 461 /* 462 Specify is an alias for It - it can allow for more natural wording in some context. 463 */ 464 var Specify, FSpecify, PSpecify, XSpecify = It, FIt, PIt, XIt 465 466 /* 467 By allows you to better document complex Specs. 468 469 Generally you should try to keep your Its short and to the point. This is not always possible, however, 470 especially in the context of integration tests that capture complex or lengthy workflows. 471 472 By allows you to document such flows. By may be called within a Setup or Subject node (It, BeforeEach, etc...) 473 and will simply log the passed in text to the GinkgoWriter. If By is handed a function it will immediately run the function. 474 475 By will also generate and attach a ReportEntry to the spec. This will ensure that By annotations appear in Ginkgo's machine-readable reports. 476 477 Note that By does not generate a new Ginkgo node - rather it is simply synctactic sugar around GinkgoWriter and AddReportEntry 478 You can learn more about By here: https://onsi.github.io/ginkgo/#documenting-complex-specs-by 479 */ 480 func By(text string, callback ...func()) { 481 value := struct { 482 Text string 483 Duration time.Duration 484 }{ 485 Text: text, 486 } 487 t := time.Now() 488 AddReportEntry("By Step", ReportEntryVisibilityNever, Offset(1), &value, t) 489 formatter := formatter.NewWithNoColorBool(reporterConfig.NoColor) 490 GinkgoWriter.Println(formatter.F("{{bold}}STEP:{{/}} %s {{gray}}%s{{/}}", text, t.Format(types.GINKGO_TIME_FORMAT))) 491 if len(callback) == 1 { 492 callback[0]() 493 value.Duration = time.Since(t) 494 } 495 if len(callback) > 1 { 496 panic("just one callback per By, please") 497 } 498 } 499 500 /* 501 BeforeSuite nodes are suite-level Setup nodes that run just once before any specs are run. 502 When running in parallel, each parallel process will call BeforeSuite. 503 504 You may only register *one* BeforeSuite handler per test suite. You typically do so in your bootstrap file at the top level. 505 506 You cannot nest any other Ginkgo nodes within a BeforeSuite node's closure. 507 You can learn more here: https://onsi.github.io/ginkgo/#suite-setup-and-cleanup-beforesuite-and-aftersuite 508 */ 509 func BeforeSuite(body func()) bool { 510 return pushNode(internal.NewNode(deprecationTracker, types.NodeTypeBeforeSuite, "", body)) 511 } 512 513 /* 514 AfterSuite nodes are suite-level Setup nodes run after all specs have finished - regardless of whether specs have passed or failed. 515 AfterSuite node closures always run, even if Ginkgo receives an interrupt signal (^C), in order to ensure cleanup occurs. 516 517 When running in parallel, each parallel process will call AfterSuite. 518 519 You may only register *one* AfterSuite handler per test suite. You typically do so in your bootstrap file at the top level. 520 521 You cannot nest any other Ginkgo nodes within an AfterSuite node's closure. 522 You can learn more here: https://onsi.github.io/ginkgo/#suite-setup-and-cleanup-beforesuite-and-aftersuite 523 */ 524 func AfterSuite(body func()) bool { 525 return pushNode(internal.NewNode(deprecationTracker, types.NodeTypeAfterSuite, "", body)) 526 } 527 528 /* 529 SynchronizedBeforeSuite nodes allow you to perform some of the suite setup just once - on parallel process #1 - and then pass information 530 from that setup to the rest of the suite setup on all processes. This is useful for performing expensive or singleton setup once, then passing 531 information from that setup to all parallel processes. 532 533 SynchronizedBeforeSuite accomplishes this by taking *two* function arguments and passing data between them. 534 The first function is only run on parallel process #1. The second is run on all processes, but *only* after the first function completes successfully. The functions have the following signatures: 535 536 The first function (which only runs on process #1) has the signature: 537 538 func() []byte 539 540 The byte array returned by the first function is then passed to the second function, which has the signature: 541 542 func(data []byte) 543 544 You cannot nest any other Ginkgo nodes within an SynchronizedBeforeSuite node's closure. 545 You can learn more, and see some examples, here: https://onsi.github.io/ginkgo/#parallel-suite-setup-and-cleanup-synchronizedbeforesuite-and-synchronizedaftersuite 546 */ 547 func SynchronizedBeforeSuite(process1Body func() []byte, allProcessBody func([]byte)) bool { 548 return pushNode(internal.NewSynchronizedBeforeSuiteNode(process1Body, allProcessBody, types.NewCodeLocation(1))) 549 } 550 551 /* 552 SynchronizedAfterSuite nodes complement the SynchronizedBeforeSuite nodes in solving the problem of splitting clean up into a piece that runs on all processes 553 and a piece that must only run once - on process #1. 554 555 SynchronizedAfterSuite accomplishes this by taking *two* function arguments. The first runs on all processes. The second runs only on parallel process #1 556 and *only* after all other processes have finished and exited. This ensures that process #1, and any resources it is managing, remain alive until 557 all other processes are finished. 558 559 Note that you can also use DeferCleanup() in SynchronizedBeforeSuite to accomplish similar results. 560 561 You cannot nest any other Ginkgo nodes within an SynchronizedAfterSuite node's closure. 562 You can learn more, and see some examples, here: https://onsi.github.io/ginkgo/#parallel-suite-setup-and-cleanup-synchronizedbeforesuite-and-synchronizedaftersuite 563 */ 564 func SynchronizedAfterSuite(allProcessBody func(), process1Body func()) bool { 565 return pushNode(internal.NewSynchronizedAfterSuiteNode(allProcessBody, process1Body, types.NewCodeLocation(1))) 566 } 567 568 /* 569 BeforeEach nodes are Setup nodes whose closures run before It node closures. When multiple BeforeEach nodes 570 are defined in nested Container nodes the outermost BeforeEach node closures are run first. 571 572 You cannot nest any other Ginkgo nodes within a BeforeEach node's closure. 573 You can learn more here: https://onsi.github.io/ginkgo/#extracting-common-setup-beforeeach 574 */ 575 func BeforeEach(args ...interface{}) bool { 576 return pushNode(internal.NewNode(deprecationTracker, types.NodeTypeBeforeEach, "", args...)) 577 } 578 579 /* 580 JustBeforeEach nodes are similar to BeforeEach nodes, however they are guaranteed to run *after* all BeforeEach node closures - just before the It node closure. 581 This can allow you to separate configuration from creation of resources for a spec. 582 583 You cannot nest any other Ginkgo nodes within a JustBeforeEach node's closure. 584 You can learn more and see some examples here: https://onsi.github.io/ginkgo/#separating-creation-and-configuration-justbeforeeach 585 */ 586 func JustBeforeEach(args ...interface{}) bool { 587 return pushNode(internal.NewNode(deprecationTracker, types.NodeTypeJustBeforeEach, "", args...)) 588 } 589 590 /* 591 AfterEach nodes are Setup nodes whose closures run after It node closures. When multiple AfterEach nodes 592 are defined in nested Container nodes the innermost AfterEach node closures are run first. 593 594 Note that you can also use DeferCleanup() in other Setup or Subject nodes to accomplish similar results. 595 596 You cannot nest any other Ginkgo nodes within an AfterEach node's closure. 597 You can learn more here: https://onsi.github.io/ginkgo/#spec-cleanup-aftereach-and-defercleanup 598 */ 599 func AfterEach(args ...interface{}) bool { 600 return pushNode(internal.NewNode(deprecationTracker, types.NodeTypeAfterEach, "", args...)) 601 } 602 603 /* 604 JustAfterEach nodes are similar to AfterEach nodes, however they are guaranteed to run *before* all AfterEach node closures - just after the It node closure. This can allow you to separate diagnostics collection from teardown for a spec. 605 606 You cannot nest any other Ginkgo nodes within a JustAfterEach node's closure. 607 You can learn more and see some examples here: https://onsi.github.io/ginkgo/#separating-diagnostics-collection-and-teardown-justaftereach 608 */ 609 func JustAfterEach(args ...interface{}) bool { 610 return pushNode(internal.NewNode(deprecationTracker, types.NodeTypeJustAfterEach, "", args...)) 611 } 612 613 /* 614 BeforeAll nodes are Setup nodes that can occur inside Ordered contaienrs. They run just once before any specs in the Ordered container run. 615 616 Multiple BeforeAll nodes can be defined in a given Ordered container however they cannot be nested inside any other container. 617 618 You cannot nest any other Ginkgo nodes within a BeforeAll node's closure. 619 You can learn more about Ordered Containers at: https://onsi.github.io/ginkgo/#ordered-containers 620 And you can learn more about BeforeAll at: https://onsi.github.io/ginkgo/#setup-in-ordered-containers-beforeall-and-afterall 621 */ 622 func BeforeAll(args ...interface{}) bool { 623 return pushNode(internal.NewNode(deprecationTracker, types.NodeTypeBeforeAll, "", args...)) 624 } 625 626 /* 627 AfterAll nodes are Setup nodes that can occur inside Ordered contaienrs. They run just once after all specs in the Ordered container have run. 628 629 Multiple AfterAll nodes can be defined in a given Ordered container however they cannot be nested inside any other container. 630 631 Note that you can also use DeferCleanup() in a BeforeAll node to accomplish similar behavior. 632 633 You cannot nest any other Ginkgo nodes within an AfterAll node's closure. 634 You can learn more about Ordered Containers at: https://onsi.github.io/ginkgo/#ordered-containers 635 And you can learn more about AfterAll at: https://onsi.github.io/ginkgo/#setup-in-ordered-containers-beforeall-and-afterall 636 */ 637 func AfterAll(args ...interface{}) bool { 638 return pushNode(internal.NewNode(deprecationTracker, types.NodeTypeAfterAll, "", args...)) 639 } 640 641 /* 642 DeferCleanup can be called within any Setup or Subject node to register a cleanup callback that Ginkgo will call at the appropriate time to cleanup after the spec. 643 644 DeferCleanup can be passed: 645 1. A function that takes no arguments and returns no values. 646 2. A function that returns an error (in which case it will assert that the returned error was nil, or it will fail the spec). 647 3. A function that takes arguments (and optionally returns an error) followed by a list of arguments to passe to the function. For example: 648 649 BeforeEach(func() { 650 DeferCleanup(os.SetEnv, "FOO", os.GetEnv("FOO")) 651 os.SetEnv("FOO", "BAR") 652 }) 653 654 will register a cleanup handler that will set the environment variable "FOO" to it's current value (obtained by os.GetEnv("FOO")) after the spec runs and then sets the environment variable "FOO" to "BAR" for the current spec. 655 656 When DeferCleanup is called in BeforeEach, JustBeforeEach, It, AfterEach, or JustAfterEach the registered callback will be invoked when the spec completes (i.e. it will behave like an AfterEach node) 657 When DeferCleanup is called in BeforeAll or AfterAll the registered callback will be invoked when the ordered container completes (i.e. it will behave like an AfterAll node) 658 When DeferCleanup is called in BeforeSuite, SynchronizedBeforeSuite, AfterSuite, or SynchronizedAfterSuite the registered callback will be invoked when the suite completes (i.e. it will behave like an AfterSuite node) 659 660 Note that DeferCleanup does not represent a node but rather dynamically generates the appropriate type of cleanup node based on the context in which it is called. As such you must call DeferCleanup within a Setup or Subject node, and not within a Container node. 661 You can learn more about DeferCleanup here: https://onsi.github.io/ginkgo/#cleaning-up-our-cleanup-code-defercleanup 662 */ 663 func DeferCleanup(args ...interface{}) { 664 fail := func(message string, cl types.CodeLocation) { 665 global.Failer.Fail(message, cl) 666 } 667 pushNode(internal.NewCleanupNode(fail, args...)) 668 }