Skills

Tables And Dynamic Specs

Parameterize and generate Ginkgo specs, DescribeTable/Entry table-driven specs, Entry...

Install

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

What it does

Parameterize and generate Ginkgo specs, DescribeTable/Entry table-driven specs, Entry descriptions (string, nil, closure, EntryDescription), PEntry/FEntry and per-Entry decorators, DescribeTableSubtree, generating specs in a construction-time loop, loading fixtures in TestXxx before RunSpecs, and shared-behavior closures. Use when you have repetitive specs differing only by inputs, want data-driven or generated specs, or are extracting reusable It blocks across Contexts.

Table specs and dynamically generated specs

Ginkgo gives you a DSL for table-driven specs plus idioms for generating specs from loops and data. All of it is syntactic sugar that runs during the tree-construction phase (ginkgo:overview), the gotchas all follow from that.

Perfer DescrtibeTable/DescribeTableSubtree with shared configuration over multiple repeated Its.

Docs: https://onsi.github.io/ginkgo/#table-specs.

DescribeTable + Entry

DescribeTable(desc, specFunc, ...Entry) generates one container holding one It per Entry. Entry(desc, params...), its params are passed to specFunc at run time and must match specFunc's signature (you get a clear runtime message if they don't).

DescribeTable("Extracting the author's first and last name",
	func(author string, isValid bool, firstName, lastName string) {
		book := &books.Book{Title: "My Book", Author: author, Pages: 10}
		Expect(book.IsValid()).To(Equal(isValid))
		Expect(book.AuthorFirstName()).To(Equal(firstName))
		Expect(book.AuthorLastName()).To(Equal(lastName))
	},
	Entry("both names", "Victor Hugo", true, "Victor", "Hugo"),
	Entry("one name", "Hugo", true, "", "Hugo"),
	Entry("no name", "", false, "", ""),
)

A DescribeTable is just a container, so nest it inside Describe/Context and surround it with BeforeEach, setup runs fresh before each entry's spec.

THE gotcha: Entry params are evaluated at construction time

Entry(...) arguments are evaluated when the tree is built, before any BeforeEach has run. So an Entry cannot read a variable initialized in BeforeEach; it will see the zero value (a nil map/pointer).

var shelf map[string]*books.Book
BeforeEach(func() { shelf = loadShelf() }) // runs at RUN time

// WRONG, shelf is nil when Entry is evaluated at construction time
DescribeTable("category", func(b *books.Book, c books.Category) { ... },
	Entry("novel", shelf["Les Miserables"], books.CategoryNovel), // nil pointer!
)
Read the whole SKILL.md on GitHub

More in Engineering