Skip to content

Commit 7b2af89

Browse files
committed
Add TestEnv class to simplify testing of ActionState-dependent functions
1 parent f86aa52 commit 7b2af89

1 file changed

Lines changed: 77 additions & 0 deletions

File tree

src/testing-utils.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import test, {
1010
import nock from "nock";
1111
import * as sinon from "sinon";
1212

13+
import { ActionState } from "./action-common";
1314
import { ActionsEnv, ActionsEnvVars, getActionVersion } from "./actions-util";
1415
import { AnalysisKind } from "./analyses";
1516
import * 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

Comments
 (0)