# Tables And Dynamic Specs

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

- Repository: https://github.com/onsi/ginkgo (9071 stars)
- Category: Engineering
- License: MIT
- Last updated: 2026-10-09
- Runs scripts: no, instructions only

## Install

Claude Code: `npx skills add onsi/ginkgo --skill tables-and-dynamic-specs -g -a claude-code -y`
Codex: `npx skills add onsi/ginkgo --skill tables-and-dynamic-specs -g -a codex -y`
Cursor: `npx skills add onsi/ginkgo --skill tables-and-dynamic-specs -g -a cursor -y`
Gemini CLI: `npx skills add onsi/ginkgo --skill tables-and-dynamic-specs -g -a gemini-cli -y`
Claude Code plugin marketplace: `/plugin marketplace add onsi/ginkgo`

## Description

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.

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

# 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 `It`s.

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

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

```go
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!
)

The rest: https://github.com/onsi/ginkgo/blob/HEAD/plugins/ginkgo/skills/tables-and-dynamic-specs/SKILL.md
