Control spec ordering and manage flaky specs — Serial, Ordered containers with BeforeAll/AfterAll/ContinueOnFailure, OncePerOrdered, SpecPriority, plus FlakeAttempts/--flake-attempts, MustPassRepeatedly, --repeat, and --until-it-fails. Use when specs must run in a fixed order, you need once-per-group setup, you're combining Serial+Ordered, a spec is flaky, or you want to hunt order-dependence with --until-it-fails -p --randomize-all.
77
96%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Two topics that share a root cause: specs that aren't truly independent (ginkgo:overview). Ordering decorators let you declare a dependency on purpose; flake controls let you manage or expose one. Docs: https://onsi.github.io/ginkgo/#serial-specs, https://onsi.github.io/ginkgo/#ordered-containers, https://onsi.github.io/ginkgo/#repeating-spec-runs-and-managing-flaky-specs.
Serial (container or subject) guarantees a spec never runs in parallel with anything else. Under the hood Ginkgo runs serial specs last, on process #1, after all other processes have exited. Reach for it sparingly. OK for benchmarks, resource hogs, or specs that put an external resource into a known-bad state - but not OK as a band-aid for order-dependence or poorly isolated code/specs.
Describe("Something expensive", Serial, func() {
It("is a resource hog that can't share the box", func() { ... })
})→ ginkgo:decorators, ginkgo:parallelism.
Ordered (container only) guarantees its child specs run sequentially, in written order, on one process — so they may legitimately mutate shared closure state. They can still parallelize against specs in other containers; only the inner order is pinned.
Describe("checking out a book", Ordered, func() {
var libraryClient *library.Client
var book *books.Book
BeforeAll(func() { // once, before the first spec
libraryClient = library.NewClient()
Expect(libraryClient.Connect()).To(Succeed())
DeferCleanup(libraryClient.Disconnect) // context-aware: behaves like AfterAll
})
It("can fetch a book", func() { book, _ = libraryClient.FetchByTitle("Les Miserables") })
It("can check it out", func() { Expect(library.CheckOut(book)).To(Succeed()) })
It("is then out of stock", func() { ... })
AfterAll(func() { ... }) // once, after the last spec
})BeforeAll/AfterAll are legal only inside an Ordered container (or a container nested within one). That's the whole point of Ordered — once-per-group expensive setup.AfterAll still runs). Spec independence is gone, so Ginkgo won't pretend the later specs are meaningful.ContinueOnFailure (outermost Ordered only — error on a nested container) overrides that: keep running later specs after a failure. Use it when Ordered is just shared setup, not a dependent flow. A failed BeforeAll still skips everything — the setup is presumed broken.Ordered container are automatically Ordered; there's no way to un-order them.A top-level BeforeEach that resets state runs before every spec — which breaks an Ordered group's first-spec-sets-up-rest contract (spec 1 passes, the rest get wiped). Decorate it with OncePerOrdered so it runs once per independent unit: still per-spec for normal specs, but once around each Ordered container (like a BeforeAll).
BeforeEach(OncePerOrdered, func() {
libraryClient = library.NewClient()
snapshot := libraryClient.TakeSnapshot()
DeferCleanup(libraryClient.RestoreSnapshot, snapshot)
})Applies to BeforeEach/JustBeforeEach/AfterEach/JustAfterEach only — not ReportBeforeEach/ReportAfterEach (reporting is always per-spec).
You cannot mark an individual spec inside an Ordered container Serial. To make a whole ordered group run serially, put both decorators on the container: Describe("...", Ordered, Serial, func(){...}).
Ordered and a single It with By steps (ginkgo:writing-specs) solve the same "dependent flow" problem. Prefer one It + By by default — it stays fully parallelizable and independent. Reach for Ordered when you want each step reported as its own spec, or genuinely need BeforeAll once-per-group setup. Either way, use Ordered only when needed — it gives up internal parallelism.
SpecPriority(int) (default 0, higher runs earlier, may be negative) is a scheduling hint — e.g. "boulders first, then sand" in big suites. Honored per-spec under --randomize-all, otherwise per outermost container. Anti-pattern: do not use it to impose a full deterministic order — that's what Ordered is for, and it defeats randomization's whole purpose. → ginkgo:decorators.
The stance: retries are explicit technical debt. Default to none — debug the flake; it's usually telling you something about your architecture. Ginkgo gives you tools to both expose flakes and (reluctantly) tolerate them.
ginkgo --until-it-fails -p --randomize-all # loop forever until something breaks — best flake hunter
ginkgo --repeat=N # run 1+N times, stop at first failure (CI-safe)--until-it-fails compiles once and reruns indefinitely, so it's for local hunting, not CI; --repeat=N is the CI-safe bounded version. Note --repeat=N runs 1+N times — and Ginkgo is not compatible with go test --count; use --repeat. → ginkgo:ci. Granular per-spec version: MustPassRepeatedly(N) (must pass N times in a row).
ginkgo --flake-attempts=3 # retry any failing spec up to 3x; a later pass = flaky, not failedPer-spec: FlakeAttempts(N) decorator (CLI overrides it). On a pass-after-retry the suite stays green but reports the spec as flaky.
FlakeAttempts × Ordered: a failure in an It reruns just that It (not BeforeAll/AfterAll); a failure in a BeforeAll runs the AfterAll to clean up, then reruns the BeforeAll.
ginkgo:overview.ginkgo:debugging-failures.ginkgo:decorators.f2d0f65
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.