Skills

Writing Specs

Author good Ginkgo specs, container nodes (Describe/Context/When), subject nodes...

Install

npx skills add onsi/ginkgo --skill writing-specs -g -a claude-code -y
Repository
onsi/ginkgo9.1k
Category
Testing
Updated
26d ago
License
MIT
Context cost
Mediumabout 1,841 tokens
Runs scripts
No, instructions only

What it does

Author good Ginkgo specs, container nodes (Describe/Context/When), subject nodes (It/Specify), setup/cleanup nodes (BeforeEach, JustBeforeEach, AfterEach, DeferCleanup, BeforeSuite/AfterSuite), the "declare in container, initialize in BeforeEach" rule, separating creation from configuration, reusable test helpers with GinkgoHelper()/GinkgoHelperGo(), and By/GinkgoWriter output. Use when writing or reviewing specs or extracting a test helper. Covers the tree-construction-time pitfalls (no assertions/init/loop-capture in container bodies).

Writing Ginkgo specs

Assumes Ginkgo is wired into the suite (ginkgo:setup) and you know the two-phase model (ginkgo:overview). Docs: https://onsi.github.io/ginkgo/#writing-specs.

The shape of a spec

var _ = Describe("Books", func() {
	var book *books.Book          // declare here...

	BeforeEach(func() {
		book = &books.Book{        // ...initialize here, fresh per spec
			Title:  "Les Miserables",
			Author: "Victor Hugo",
			Pages:  2783,
		}
		Expect(book.IsValid()).To(BeTrue()) // assertions in setup are fine
	})

	Describe("categorizing", func() {
		Context("with more than 300 pages", func() {
			It("is a novel", func() {
				Expect(book.Category()).To(Equal(books.CategoryNovel))
			})
		})
	})
})
  • Containers (Describe/Context/When) organize; they're identical, pick the one that reads as a sentence. Subjects (It/Specify) hold the assertions; one spec runs per It.
  • The spec's full name is the concatenation of every container text plus the It text, write them to read as a phrase.

The rule that prevents most bugs: declare in container, initialize in setup

Container bodies run once, at tree-construction time (ginkgo:overview). So:

  • Declare shared variables in the container body (var book *books.Book).
  • Initialize them in BeforeEach so each spec gets a clean copy.
// WRONG, runs once at construction; every spec shares & pollutes one book
var _ = Describe("Books", func() {
	book := &books.Book{Pages: 2783}   // initialized at construction time
	It("mutates", func() { book.Pages = 0 })
	It("expects 2783", func() { Expect(book.Pages).To(Equal(2783)) }) // flaky under randomization
})

The same trap explains: no assertions in container bodies (they fire at construction, with no spec active) and no expensive/stateful work in container bodies. If you see logic directly inside a Describe/Context/When body, it almost always belongs in a BeforeEach.

Read the whole SKILL.md on GitHub

More in Testing