@@ -10,6 +10,7 @@ import test, {
1010import nock from "nock" ;
1111import * as sinon from "sinon" ;
1212
13+ import { ActionState } from "./action-common" ;
1314import { ActionsEnv , ActionsEnvVars , getActionVersion } from "./actions-util" ;
1415import { AnalysisKind } from "./analyses" ;
1516import * as apiClient from "./api-client" ;
@@ -188,6 +189,82 @@ export function getTestActionsEnv(): ActionsEnv {
188189 } ;
189190}
190191
192+ /**
193+ * Wraps a function that accepts an `ActionEnv` for testing in different environments.
194+ */
195+ export class TestEnv < Args extends readonly any [ ] , R > {
196+ private readonly fn : ( state : ActionState , ...args : Args ) => R ;
197+ private args ?: Args ;
198+ private state : ActionState ;
199+
200+ constructor (
201+ fn : ( state : ActionState , ...args : Args ) => R ,
202+ args ?: Args ,
203+ initialState ?: ActionState ,
204+ ) {
205+ this . fn = fn ;
206+ this . args = args ;
207+ this . state = initialState || {
208+ logger : new RecordingLogger ( ) ,
209+ env : getTestEnv ( ) ,
210+ features : createFeatures ( [ ] ) ,
211+ } ;
212+ }
213+
214+ private clone ( ) : TestEnv < Args , R > {
215+ return new TestEnv ( this . fn , this . args , { ...this . state } ) ;
216+ }
217+
218+ public getState ( ) : ActionState {
219+ return this . state ;
220+ }
221+
222+ public getArgs ( ) : Args | undefined {
223+ return this . args ;
224+ }
225+
226+ public withArgs ( ...args : Args ) {
227+ const result = this . clone ( ) ;
228+ result . args = args ;
229+ return result ;
230+ }
231+
232+ public withFeatures ( enabled : Feature [ ] ) : TestEnv < Args , R > {
233+ const result = this . clone ( ) ;
234+ result . state . features = createFeatures ( enabled ) ;
235+ return result ;
236+ }
237+
238+ public withEnv ( env : Env ) : TestEnv < Args , R > {
239+ const result = this . clone ( ) ;
240+ result . state . env = env ;
241+ return result ;
242+ }
243+
244+ call ( ) : R {
245+ if ( ! this . args ) {
246+ throw new Error ( "Trying to call function in TestEnv without arguments." ) ;
247+ }
248+ return this . fn ( this . state , ...this . args ) ;
249+ }
250+
251+ public passes < T > (
252+ assertion : ( makeCall : ( ) => R ) => T | Promise < T > ,
253+ ) : T | Promise < T > {
254+ return assertion ( ( ) => {
255+ const result = this . call ( ) ;
256+ return result ;
257+ } ) ;
258+ }
259+ }
260+
261+ /** Utility function to construct a `TestEnv`. */
262+ export function callee < Args extends readonly any [ ] , R > (
263+ fn : ( state : ActionState , ...args : Args ) => R ,
264+ ) : TestEnv < Args , R > {
265+ return new TestEnv ( fn ) ;
266+ }
267+
191268/**
192269 * Default values for environment variables typically set in an Actions
193270 * environment. Tests can override individual variables by passing them in the
0 commit comments