Skip to content

Commit 92b6744

Browse files
authored
Add GinkgoTB() function (#1333)
This function returns a wrapper around GinkgoT() which satisfies the `testing.TB` interface. - Update fail tests with tests for GinkgoT() and GinkgoTB(). - Fix a bug where GinkgoT().Fail() was not reporting the correct line on error.
1 parent beb9507 commit 92b6744

File tree

12 files changed

+214
-20
lines changed

12 files changed

+214
-20
lines changed

docs/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5478,6 +5478,8 @@ When using Gomock you may want to run `ginkgo` with the `-trace` flag to print o
54785478
54795479
`GinkgoT()` also provides additional methods that are Ginkgo-specific. This allows rich third-party integrations to be built on top of Ginkgo - with GinkgoT() serving as a single connection point.
54805480
5481+
Similarly for third party libraries which accept a `testing.TB` interface, use the `GinkgoTB()` function. This function returns a struct wrapper around `GinkgoT()` which satisfies the `testing.TB`interface. If you need to use any Ginkgo-specific methods you can access the wrapped `GinkgoT()` instance using `GinkgoTBWrapper.GinkgoT`.
5482+
54815483
### IDE Support
54825484
Ginkgo works best from the command-line, and [`ginkgo watch`](#watching-for-changes) makes it easy to rerun tests on the command line whenever changes are detected.
54835485

dsl/core/core_dsl.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type GinkgoTestingT = ginkgo.GinkgoTestingT
2323
type GinkgoTInterface = ginkgo.GinkgoTInterface
2424
type FullGinkgoTInterface = ginkgo.FullGinkgoTInterface
2525
type SpecContext = ginkgo.SpecContext
26+
type GinkgoTBWrapper = ginkgo.GinkgoTBWrapper
2627

2728
var GinkgoWriter = ginkgo.GinkgoWriter
2829
var GinkgoLogr = ginkgo.GinkgoLogr
@@ -63,4 +64,5 @@ var BeforeAll = ginkgo.BeforeAll
6364
var AfterAll = ginkgo.AfterAll
6465
var DeferCleanup = ginkgo.DeferCleanup
6566
var GinkgoT = ginkgo.GinkgoT
67+
var GinkgoTB = ginkgo.GinkgoTB
6668
var AttachProgressReporter = ginkgo.AttachProgressReporter

dsl/dsl_suite_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ func ExtractSymbols(f *ast.File) []string {
2121
names := []string{}
2222
switch v := decl.(type) {
2323
case *ast.FuncDecl:
24-
names = append(names, v.Name.Name)
24+
if v.Recv == nil {
25+
names = append(names, v.Name.Name)
26+
}
2527
case *ast.GenDecl:
2628
switch v.Tok {
2729
case token.TYPE:

ginkgo_t_dsl.go

Lines changed: 94 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package ginkgo
22

33
import (
4+
"testing"
5+
46
"github.com/onsi/ginkgo/v2/internal/testingtproxy"
7+
"github.com/onsi/ginkgo/v2/types"
58
)
69

710
/*
@@ -15,7 +18,7 @@ correct line number associated with the failure - though you do not need to use
1518
You can learn more here: https://onsi.github.io/ginkgo/#using-third-party-libraries
1619
*/
1720
func GinkgoT(optionalOffset ...int) FullGinkgoTInterface {
18-
offset := 3
21+
offset := 1
1922
if len(optionalOffset) > 0 {
2023
offset = optionalOffset[0]
2124
}
@@ -41,21 +44,21 @@ The portion of the interface returned by GinkgoT() that maps onto methods in the
4144
type GinkgoTInterface interface {
4245
Cleanup(func())
4346
Setenv(kev, value string)
44-
Error(args ...interface{})
45-
Errorf(format string, args ...interface{})
47+
Error(args ...any)
48+
Errorf(format string, args ...any)
4649
Fail()
4750
FailNow()
4851
Failed() bool
49-
Fatal(args ...interface{})
50-
Fatalf(format string, args ...interface{})
52+
Fatal(args ...any)
53+
Fatalf(format string, args ...any)
5154
Helper()
52-
Log(args ...interface{})
53-
Logf(format string, args ...interface{})
55+
Log(args ...any)
56+
Logf(format string, args ...any)
5457
Name() string
5558
Parallel()
56-
Skip(args ...interface{})
59+
Skip(args ...any)
5760
SkipNow()
58-
Skipf(format string, args ...interface{})
61+
Skipf(format string, args ...any)
5962
Skipped() bool
6063
TempDir() string
6164
}
@@ -71,9 +74,9 @@ type FullGinkgoTInterface interface {
7174
AddReportEntryVisibilityNever(name string, args ...any)
7275

7376
//Prints to the GinkgoWriter
74-
Print(a ...interface{})
75-
Printf(format string, a ...interface{})
76-
Println(a ...interface{})
77+
Print(a ...any)
78+
Printf(format string, a ...any)
79+
Println(a ...any)
7780

7881
//Provides access to Ginkgo's color formatting, correctly configured to match the color settings specified in the invocation of ginkgo
7982
F(format string, args ...any) string
@@ -92,3 +95,82 @@ type FullGinkgoTInterface interface {
9295

9396
AttachProgressReporter(func() string) func()
9497
}
98+
99+
/*
100+
GinkgoTB() implements a wrapper that exactly matches the testing.TB interface.
101+
102+
In go 1.18 a new private() function was added to the testing.TB interface. Any function which accepts testing.TB as input needs to be passed in something that directly implements testing.TB.
103+
104+
This wrapper satisfies the testing.TB interface and intended to be used as a drop-in replacement with third party libraries that accept testing.TB.
105+
106+
Similar to GinkgoT(), GinkgoTB() takes an optional offset argument that can be used to get the
107+
correct line number associated with the failure - though you do not need to use this if you call GinkgoHelper() or GinkgoT().Helper() appropriately
108+
*/
109+
110+
func GinkgoTB(optionalOffset ...int) *GinkgoTBWrapper {
111+
offset := 2
112+
if len(optionalOffset) > 0 {
113+
offset = optionalOffset[0]
114+
}
115+
return &GinkgoTBWrapper{GinkgoT: GinkgoT(offset)}
116+
}
117+
118+
type GinkgoTBWrapper struct {
119+
testing.TB
120+
GinkgoT FullGinkgoTInterface
121+
}
122+
123+
func (g *GinkgoTBWrapper) Cleanup(f func()) {
124+
g.GinkgoT.Cleanup(f)
125+
}
126+
func (g *GinkgoTBWrapper) Error(args ...any) {
127+
g.GinkgoT.Error(args...)
128+
}
129+
func (g *GinkgoTBWrapper) Errorf(format string, args ...any) {
130+
g.GinkgoT.Errorf(format, args...)
131+
}
132+
func (g *GinkgoTBWrapper) Fail() {
133+
g.GinkgoT.Fail()
134+
}
135+
func (g *GinkgoTBWrapper) FailNow() {
136+
g.GinkgoT.FailNow()
137+
}
138+
func (g *GinkgoTBWrapper) Failed() bool {
139+
return g.GinkgoT.Failed()
140+
}
141+
func (g *GinkgoTBWrapper) Fatal(args ...any) {
142+
g.GinkgoT.Fatal(args...)
143+
}
144+
func (g *GinkgoTBWrapper) Fatalf(format string, args ...any) {
145+
g.GinkgoT.Fatalf(format, args...)
146+
}
147+
func (g *GinkgoTBWrapper) Helper() {
148+
types.MarkAsHelper(1)
149+
}
150+
func (g *GinkgoTBWrapper) Log(args ...any) {
151+
g.GinkgoT.Log(args...)
152+
}
153+
func (g *GinkgoTBWrapper) Logf(format string, args ...any) {
154+
g.GinkgoT.Logf(format, args...)
155+
}
156+
func (g *GinkgoTBWrapper) Name() string {
157+
return g.GinkgoT.Name()
158+
}
159+
func (g *GinkgoTBWrapper) Setenv(key, value string) {
160+
g.GinkgoT.Setenv(key, value)
161+
}
162+
func (g *GinkgoTBWrapper) Skip(args ...any) {
163+
g.GinkgoT.Skip(args...)
164+
}
165+
func (g *GinkgoTBWrapper) SkipNow() {
166+
g.GinkgoT.SkipNow()
167+
}
168+
func (g *GinkgoTBWrapper) Skipf(format string, args ...any) {
169+
g.GinkgoT.Skipf(format, args...)
170+
}
171+
func (g *GinkgoTBWrapper) Skipped() bool {
172+
return g.GinkgoT.Skipped()
173+
}
174+
func (g *GinkgoTBWrapper) TempDir() string {
175+
return g.GinkgoT.TempDir()
176+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package fail_fixture_test
2+
3+
import (
4+
. "github.com/onsi/ginkgo/v2"
5+
)
6+
7+
var _ = Describe("GinkgoT", func() {
8+
It("synchronous failures with GinkgoT().Fail", func() {
9+
GinkgoT().Fail()
10+
println("NEVER SEE THIS")
11+
})
12+
13+
DescribeTable("DescribeTable",
14+
func() {
15+
GinkgoT().Fail()
16+
},
17+
Entry("a TableEntry constructed by Entry"),
18+
)
19+
20+
It("tracks line numbers correctly when GinkgoT().Helper() is called", func() {
21+
ginkgoTHelper()
22+
})
23+
24+
It("tracks the actual line number when no helper is used", func() {
25+
ginkgoTNoHelper()
26+
})
27+
})
28+
29+
var ginkgoTNoHelper = func() {
30+
GinkgoT().Fail()
31+
}
32+
var ginkgoTHelper = func() {
33+
GinkgoT().Helper()
34+
GinkgoT().Fail()
35+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package fail_fixture_test
2+
3+
import (
4+
. "github.com/onsi/ginkgo/v2"
5+
)
6+
7+
var _ = Describe("GinkgoTB", func() {
8+
It("synchronous failures with GinkgoTB().Fail", func() {
9+
GinkgoTB().Fail()
10+
println("NEVER SEE THIS")
11+
})
12+
13+
DescribeTable("DescribeTable",
14+
func() {
15+
GinkgoTB().Fail()
16+
},
17+
Entry("a TableEntry constructed by Entry"),
18+
)
19+
20+
It("tracks line numbers correctly when GinkgoTB().Helper() is called", func() {
21+
ginkgoTBHelper()
22+
})
23+
24+
It("tracks the actual line number when no GinkgoTB helper is used", func() {
25+
ginkgoTBNoHelper()
26+
})
27+
})
28+
29+
var ginkgoTBNoHelper = func() {
30+
GinkgoTB().Fail()
31+
}
32+
var ginkgoTBHelper = func() {
33+
t := GinkgoTB()
34+
t.Helper()
35+
t.Fail()
36+
}

integration/_fixtures/more_ginkgo_tests_fixture/more_ginkgo_tests_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package more_ginkgo_tests_test
22

33
import (
4+
"testing"
5+
46
. "github.com/onsi/ginkgo/v2"
57
. "github.com/onsi/ginkgo/v2/integration/_fixtures/more_ginkgo_tests_fixture"
68
. "github.com/onsi/gomega"
@@ -14,4 +16,12 @@ var _ = Describe("MoreGinkgoTests", func() {
1416
It("should always pass", func() {
1517
Ω(AlwaysTrue()).Should(BeTrue())
1618
})
19+
20+
It("should match testing.TB", func() {
21+
var tbFunc = func(_ testing.TB) {
22+
Ω(AlwaysTrue()).Should(BeTrue())
23+
}
24+
25+
tbFunc(GinkgoTB())
26+
})
1727
})

integration/fail_test.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,31 @@ var _ = Describe("Failing Specs", func() {
4141
Ω(output).Should(ContainSubstring(`a helper failed`))
4242
Ω(output).Should(ContainSubstring(`fail_fixture_test.go:54`), "the code location reported for the helper failure - we're testing the call to GinkgoHelper() works as expected")
4343

44-
Ω(output).Should(ContainSubstring("0 Passed | 8 Failed"))
44+
Ω(output).Should(ContainSubstring("synchronous failures with GinkgoT().Fail"))
45+
Ω(output).Should(ContainSubstring("fail_fixture_ginkgo_t_test.go:9"))
46+
47+
Ω(output).Should(ContainSubstring("GinkgoT DescribeTable"))
48+
Ω(output).Should(ContainSubstring("fail_fixture_ginkgo_t_test.go:15"))
49+
50+
Ω(output).Should(ContainSubstring(`tracks line numbers correctly when GinkgoT().Helper() is called`))
51+
Ω(output).Should(ContainSubstring(`fail_fixture_ginkgo_t_test.go:21`), "the code location reported for the ginkgoT helper failure")
52+
53+
Ω(output).Should(ContainSubstring(`tracks the actual line number when no helper is used`))
54+
Ω(output).Should(ContainSubstring(`fail_fixture_ginkgo_t_test.go:30`), "the code location reported for the ginkgoT no helper failure")
55+
56+
Ω(output).Should(ContainSubstring("synchronous failures with GinkgoTB().Fail"))
57+
Ω(output).Should(ContainSubstring("fail_fixture_ginkgo_tb_test.go:9"))
58+
59+
Ω(output).Should(ContainSubstring("GinkgoTB DescribeTable"))
60+
Ω(output).Should(ContainSubstring("fail_fixture_ginkgo_tb_test.go:15"))
61+
62+
Ω(output).Should(ContainSubstring(`tracks line numbers correctly when GinkgoTB().Helper() is called`))
63+
Ω(output).Should(ContainSubstring(`fail_fixture_ginkgo_tb_test.go:21`), "the code location reported for the ginkgoTB helper failure")
64+
65+
Ω(output).Should(ContainSubstring(`tracks the actual line number when no GinkgoTB helper is used`))
66+
Ω(output).Should(ContainSubstring(`fail_fixture_ginkgo_tb_test.go:30`), "the code location reported for the ginkgoT no helper failure")
67+
68+
Ω(output).Should(ContainSubstring("0 Passed | 16 Failed"))
4569
})
4670
})
4771

integration/flags_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ var _ = Describe("Flags Specs", func() {
129129
output := string(session.Out.Contents())
130130

131131
Ω(output).Should(ContainSubstring("synchronous failures"))
132-
Ω(output).Should(ContainSubstring("8 Specs"))
133-
Ω(output).Should(ContainSubstring("8 Passed"))
132+
Ω(output).Should(ContainSubstring("16 Specs"))
133+
Ω(output).Should(ContainSubstring("16 Passed"))
134134
Ω(output).Should(ContainSubstring("0 Failed"))
135135
})
136136

integration/run_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ var _ = Describe("Running Specs", func() {
339339
output := string(session.Out.Contents())
340340

341341
outputLines := strings.Split(output, "\n")
342-
Ω(outputLines[0]).Should(MatchRegexp(`\[\d+\] More_ginkgo_tests Suite - 2/2 specs [%s]{2} SUCCESS! \d+(\.\d+)?[muµ]s PASS`, regexp.QuoteMeta(denoter)))
342+
Ω(outputLines[0]).Should(MatchRegexp(`\[\d+\] More_ginkgo_tests Suite - 3/3 specs [%s]{3} SUCCESS! \d+(\.\d+)?[muµ]s PASS`, regexp.QuoteMeta(denoter)))
343343
Ω(outputLines[1]).Should(ContainSubstring("Skipping ./no_tagged_tests (no test files)"))
344344
Ω(outputLines[2]).Should(MatchRegexp(`\[\d+\] Passing_ginkgo_tests Suite - 5/5 specs [%s]{5} SUCCESS! \d+(\.\d+)?[muµ]s PASS`, regexp.QuoteMeta(denoter)))
345345
Ω(output).Should(ContainSubstring("Test Suite Passed"))
@@ -352,7 +352,7 @@ var _ = Describe("Running Specs", func() {
352352
output := string(session.Out.Contents())
353353

354354
outputLines := strings.Split(output, "\n")
355-
Ω(outputLines[0]).Should(MatchRegexp(`\[\d+\] More_ginkgo_tests Suite - 2/2 specs [%s]{2} SUCCESS! \d+(\.\d+)?[muµ]s PASS`, regexp.QuoteMeta(denoter)))
355+
Ω(outputLines[0]).Should(MatchRegexp(`\[\d+\] More_ginkgo_tests Suite - 3/3 specs [%s]{3} SUCCESS! \d+(\.\d+)?[muµ]s PASS`, regexp.QuoteMeta(denoter)))
356356
Ω(outputLines[1]).Should(ContainSubstring("Skipping ./no_tagged_tests (no test files)"))
357357
Ω(outputLines[2]).Should(MatchRegexp(`\[\d+\] Passing_ginkgo_tests Suite - 5/5 specs [%s]{5} SUCCESS! \d+(\.\d+)?[muµ]s PASS`, regexp.QuoteMeta(denoter)))
358358
Ω(output).Should(ContainSubstring("Test Suite Passed"))
@@ -416,7 +416,7 @@ var _ = Describe("Running Specs", func() {
416416
Ω(outputLines[2]).Should(ContainSubstring("Failed to compile does_not_compile:"))
417417
Ω(output).Should(MatchRegexp(`\[\d+\] Failing_ginkgo_tests Suite - 2/2 specs`))
418418
Ω(output).Should(ContainSubstring(fmt.Sprintf("%s [FAILED]", denoter)))
419-
Ω(output).Should(MatchRegexp(`\[\d+\] More_ginkgo_tests Suite - 2/2 specs [%s]{2} SUCCESS! \d+(\.\d+)?[muµ]s PASS`, regexp.QuoteMeta(denoter)))
419+
Ω(output).Should(MatchRegexp(`\[\d+\] More_ginkgo_tests Suite - 3/3 specs [%s]{3} SUCCESS! \d+(\.\d+)?[muµ]s PASS`, regexp.QuoteMeta(denoter)))
420420
Ω(output).Should(ContainSubstring("Test Suite Failed"))
421421
})
422422
})

integration/verbose_and_succinct_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ var _ = Describe("Verbose And Succinct Mode", func() {
4343
output := session.Out.Contents()
4444

4545
Ω(output).Should(MatchRegexp(`\] Passing_ginkgo_tests Suite - 5/5 specs [%s]{5} SUCCESS!`, regexp.QuoteMeta(denoter)))
46-
Ω(output).Should(MatchRegexp(`\] More_ginkgo_tests Suite - 2/2 specs [%s]{2} SUCCESS!`, regexp.QuoteMeta(denoter)))
46+
Ω(output).Should(MatchRegexp(`\] More_ginkgo_tests Suite - 3/3 specs [%s]{3} SUCCESS!`, regexp.QuoteMeta(denoter)))
4747
})
4848
})
4949

internal/testingtproxy/testingtproxy_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ var _ = Describe("Testingtproxy", func() {
223223
reportToReturn.LeafNodeText = "Lewis"
224224
Ω(t.Name()).Should(Equal("C.S. Lewis"))
225225
Ω(GinkgoT().Name()).Should(ContainSubstring("supports Name"))
226+
Ω(GinkgoTB().Name()).Should(ContainSubstring("supports Name"))
226227
})
227228

228229
It("ignores Parallel", func() {

0 commit comments

Comments
 (0)