CtrlK
BlogDocsLog inGet started
Tessl Logo

ordering-and-flakes

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

Quality

96%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

SKILL.md
Quality
Evals
Security

Ordering and flakes

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: opt out of parallelism

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: run specs in definition order

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.
  • A failing spec skips the rest of the group by default (then 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.
  • Nested containers inside an Ordered container are automatically Ordered; there's no way to un-order them.

OncePerOrdered: outer *Each setup that respects groups

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).

The Serial-inside-Ordered gotcha

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 vs one big It

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

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.

Flaky specs

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.

Expose 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).

Tolerate them (judiciously, as a last resort)

ginkgo --flake-attempts=3        # retry any failing spec up to 3x; a later pass = flaky, not failed

Per-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.

Related

  • Why independence matters in the first place → ginkgo:overview.
  • Diagnosing why a spec failed/flaked from reports → ginkgo:debugging-failures.
  • The full decorator signatures → ginkgo:decorators.
Repository
onsi/ginkgo
Last updated
First committed

Is this your skill?

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.