@@ -33,41 +33,34 @@ var _ api.BrowserType = &BrowserType{}
33
33
// BrowserType provides methods to launch a Chrome browser instance or connect to an existing one.
34
34
// It's the entry point for interacting with the browser.
35
35
type BrowserType struct {
36
- Ctx context. Context
37
- CancelFn context. CancelFunc
38
- hooks * common. Hooks
39
- fieldNameMapper * common. FieldNameMapper
40
- vu k6modules. VU
41
-
42
- execPath string // path to the Chromium executable
43
- storage * storage.Dir // stores temporary data for the extension and user
36
+ // FIXME: This is only exported because testBrowser needs it. Contexts
37
+ // shouldn't be stored on structs if we can avoid it.
38
+ Ctx context. Context
39
+ vu k6modules. VU
40
+ hooks * common. Hooks
41
+ k6Metrics * k6ext. CustomMetrics
42
+ execPath string // path to the Chromium executable
43
+ storage * storage.Dir // stores temporary data for the extension and user
44
44
}
45
45
46
- // NewBrowserType returns a new Chrome browser type.
47
- // Before returning a new browser type:
48
- // - Initializes the extension-wide context
49
- // - Initializes the goja runtime.
50
- func NewBrowserType (ctx context.Context ) api.BrowserType {
46
+ // NewBrowserType registers our custom k6 metrics, creates method mappings on
47
+ // the goja runtime, and returns a new Chrome browser type.
48
+ func NewBrowserType (vu k6modules.VU ) api.BrowserType {
51
49
var (
52
- vu = k6ext .GetVU (ctx )
53
50
rt = vu .Runtime ()
54
51
hooks = common .NewHooks ()
55
52
)
56
53
57
- // Create the extension master context.
58
- // If this context is cancelled we'll initiate an extension wide cancellation and shutdown.
59
- extensionCtx , extensionCancelFn := context .WithCancel (ctx )
60
- extensionCtx = common .WithHooks (extensionCtx , hooks )
61
-
54
+ // NOTE: vu.InitEnv() *must* be called from the script init scope,
55
+ // otherwise it will return nil.
56
+ k6m := k6ext .RegisterCustomMetrics (vu .InitEnv ().Registry )
62
57
b := BrowserType {
63
- Ctx : extensionCtx ,
64
- CancelFn : extensionCancelFn ,
65
- hooks : hooks ,
66
- fieldNameMapper : common .NewFieldNameMapper (),
67
- vu : vu ,
68
- storage : & storage.Dir {},
58
+ vu : vu ,
59
+ hooks : hooks ,
60
+ k6Metrics : k6m ,
61
+ storage : & storage.Dir {},
69
62
}
70
- rt .SetFieldNameMapper (b . fieldNameMapper )
63
+ rt .SetFieldNameMapper (common . NewFieldNameMapper () )
71
64
72
65
return & b
73
66
}
@@ -118,34 +111,42 @@ func (b *BrowserType) ExecutablePath() (execPath string) {
118
111
return ""
119
112
}
120
113
114
+ func (b * BrowserType ) initContext () context.Context {
115
+ ctx := k6ext .WithVU (b .vu .Context (), b .vu )
116
+ ctx = k6ext .WithCustomMetrics (ctx , b .k6Metrics )
117
+ ctx = common .WithHooks (ctx , b .hooks )
118
+ return ctx
119
+ }
120
+
121
121
// Launch allocates a new Chrome browser process and returns a new api.Browser value,
122
122
// which can be used for controlling the Chrome browser.
123
123
func (b * BrowserType ) Launch (opts goja.Value ) api.Browser {
124
+ ctx := b .initContext ()
124
125
launchOpts := common .NewLaunchOptions ()
125
- if err := launchOpts .Parse (b . Ctx , opts ); err != nil {
126
- k6ext .Panic (b . Ctx , "parsing launch options: %w" , err )
126
+ if err := launchOpts .Parse (ctx , opts ); err != nil {
127
+ k6ext .Panic (ctx , "parsing launch options: %w" , err )
127
128
}
128
- b . Ctx = common .WithLaunchOptions (b . Ctx , launchOpts )
129
+ ctx = common .WithLaunchOptions (ctx , launchOpts )
129
130
130
- bp , err := b .launch (launchOpts )
131
+ bp , err := b .launch (ctx , launchOpts )
131
132
if err != nil {
132
133
err = & k6ext.UserFriendlyError {
133
134
Err : err ,
134
135
Timeout : launchOpts .Timeout ,
135
136
}
136
- k6ext .Panic (b . Ctx , "%w" , err )
137
+ k6ext .Panic (ctx , "%w" , err )
137
138
}
138
139
139
140
return bp
140
141
}
141
142
142
- func (b * BrowserType ) launch (opts * common.LaunchOptions ) (* common.Browser , error ) {
143
+ func (b * BrowserType ) launch (ctx context. Context , opts * common.LaunchOptions ) (* common.Browser , error ) {
143
144
envs := make ([]string , 0 , len (opts .Env ))
144
145
for k , v := range opts .Env {
145
146
envs = append (envs , fmt .Sprintf ("%s=%s" , k , v ))
146
147
}
147
148
148
- logger , err := makeLogger (b . Ctx , opts )
149
+ logger , err := makeLogger (ctx , opts )
149
150
if err != nil {
150
151
return nil , fmt .Errorf ("setting up logger: %w" , err )
151
152
}
@@ -159,7 +160,7 @@ func (b *BrowserType) launch(opts *common.LaunchOptions) (*common.Browser, error
159
160
}
160
161
flags ["user-data-dir" ] = dataDir .Dir
161
162
162
- go func (ctx context.Context ) {
163
+ go func (c context.Context ) {
163
164
defer func () {
164
165
if err := dataDir .Cleanup (); err != nil {
165
166
logger .Errorf ("BrowserType:Launch" , "cleaning up the user data directory: %v" , err )
@@ -170,21 +171,26 @@ func (b *BrowserType) launch(opts *common.LaunchOptions) (*common.Browser, error
170
171
// guarantee the cleanup we would need to orchestrate
171
172
// it correctly which https://github.com/grafana/k6/issues/2432
172
173
// will enable once it's complete.
173
- <- ctx .Done ()
174
- }(b . Ctx )
174
+ <- c .Done ()
175
+ }(ctx )
175
176
176
- browserProc , err := b .allocate (opts , flags , envs , dataDir , logger )
177
+ browserProc , err := b .allocate (ctx , opts , flags , envs , dataDir , logger )
177
178
if browserProc == nil {
178
179
return nil , fmt .Errorf ("launching browser: %w" , err )
179
180
}
180
181
181
182
browserProc .AttachLogger (logger )
182
183
184
+ // If this context is cancelled we'll initiate an extension wide
185
+ // cancellation and shutdown.
186
+ browserCtx , browserCtxCancel := context .WithCancel (ctx )
183
187
// attach the browser process ID to the context
184
188
// so that we can kill it afterward if it lingers
185
189
// see: k6ext.Panic function.
186
- b .Ctx = k6ext .WithProcessID (b .Ctx , browserProc .Pid ())
187
- browser , err := common .NewBrowser (b .Ctx , b .CancelFn , browserProc , opts , logger )
190
+ browserCtx = k6ext .WithProcessID (browserCtx , browserProc .Pid ())
191
+ b .Ctx = browserCtx
192
+ browser , err := common .NewBrowser (browserCtx , browserCtxCancel ,
193
+ browserProc , opts , logger )
188
194
if err != nil {
189
195
return nil , fmt .Errorf ("launching browser: %w" , err )
190
196
}
@@ -206,9 +212,11 @@ func (b *BrowserType) Name() string {
206
212
207
213
// allocate starts a new Chromium browser process and returns it.
208
214
func (b * BrowserType ) allocate (
209
- opts * common.LaunchOptions , flags map [string ]interface {}, env []string , dataDir * storage.Dir , logger * log.Logger ,
215
+ ctx context.Context , opts * common.LaunchOptions ,
216
+ flags map [string ]interface {}, env []string , dataDir * storage.Dir ,
217
+ logger * log.Logger ,
210
218
) (_ * common.BrowserProcess , rerr error ) {
211
- ctx , cancel := context .WithTimeout (b . Ctx , opts .Timeout )
219
+ ctx , cancel := context .WithTimeout (ctx , opts .Timeout )
212
220
defer func () {
213
221
if rerr != nil {
214
222
cancel ()
0 commit comments