Skip to content

Commit 76c7848

Browse files
committed
Clean-up passes by splitting it into passes and throws
1 parent c4e86be commit 76c7848

3 files changed

Lines changed: 62 additions & 48 deletions

File tree

src/config/file.test.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ test("getConfigFileInput returns undefined by default", async (t) => {
1313
await callee(getConfigFileInput)
1414
.withArgs({})
1515
.withFeatures([Feature.ConfigFileRepositoryProperty])
16-
.passes(async (fn) => t.is(await fn(), undefined));
16+
.passes(t.is, undefined);
1717
});
1818

1919
const repositoryProperties = {
@@ -37,7 +37,7 @@ test("getConfigFileInput returns input value", async (t) => {
3737
const targetWithArgs = target
3838
.withActions(actionsEnv)
3939
.withArgs(repositoryProperties);
40-
await targetWithArgs.passes(async (fn) => t.is(await fn(), testInput));
40+
await targetWithArgs.passes(t.is, testInput);
4141

4242
// Check for the expected log message.
4343
t.true(
@@ -53,8 +53,9 @@ test("getConfigFileInput returns repository property value", async (t) => {
5353
.withFeatures([Feature.ConfigFileRepositoryProperty])
5454
.withArgs(repositoryProperties);
5555

56-
await target.passes(async (fn) =>
57-
t.is(await fn(), repositoryProperties[RepositoryPropertyName.CONFIG_FILE]),
56+
await target.passes(
57+
t.is,
58+
repositoryProperties[RepositoryPropertyName.CONFIG_FILE],
5859
);
5960

6061
// Check for the expected log message.
@@ -70,7 +71,7 @@ test("getConfigFileInput ignores empty repository property value", async (t) =>
7071
await callee(getConfigFileInput)
7172
.withFeatures([Feature.ConfigFileRepositoryProperty])
7273
.withArgs({ [RepositoryPropertyName.CONFIG_FILE]: " " })
73-
.passes(async (fn) => t.is(await fn(), undefined));
74+
.passes(t.is, undefined);
7475
});
7576

7677
test("getConfigFileInput ignores repository property value when FF is off", async (t) => {
@@ -79,7 +80,7 @@ test("getConfigFileInput ignores repository property value when FF is off", asyn
7980
.withFeatures([])
8081
.withArgs(repositoryProperties);
8182

82-
await target.passes(async (fn) => t.is(await fn(), undefined));
83+
await target.passes(t.is, undefined);
8384

8485
t.false(
8586
target

src/config/remote-file.test.ts

Lines changed: 25 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ test("parseRemoteFileAddress accepts full remote addresses", async (t) => {
5050
for (const oldFormatInput of oldFormatInputs) {
5151
await target
5252
.withArgs(oldFormatInput.input)
53-
.passes(async (fn) => t.deepEqual(await fn(), oldFormatInput.expected));
53+
.passes(t.deepEqual, oldFormatInput.expected);
5454
}
5555

5656
// New format.
@@ -78,14 +78,12 @@ test("parseRemoteFileAddress accepts full remote addresses", async (t) => {
7878
// Should fail when the FF is not enabled.
7979
await targetWithArgs
8080
.withFeatures([])
81-
.passes(async (fn) =>
82-
t.throwsAsync(fn, { instanceOf: ConfigurationError }),
83-
);
81+
.throws(t, { instanceOf: ConfigurationError });
8482

8583
// And pass when the FF is enabled.
8684
await targetWithArgs
8785
.withFeatures([Feature.NewRemoteFileAddresses])
88-
.passes(async (fn) => t.deepEqual(await fn(), newFormatInput.expected));
86+
.passes(t.deepEqual, newFormatInput.expected);
8987
}
9088
});
9189

@@ -146,14 +144,12 @@ test("parseRemoteFileAddress accepts remote address without an owner", async (t)
146144
// Should fail when the FF is not enabled.
147145
await targetWithArgs
148146
.withFeatures([])
149-
.passes(async (fn) =>
150-
t.throwsAsync(fn, { instanceOf: ConfigurationError }),
151-
);
147+
.throws(t, { instanceOf: ConfigurationError });
152148

153149
// And pass when the FF is enabled.
154150
await targetWithArgs
155151
.withFeatures([Feature.NewRemoteFileAddresses])
156-
.passes(async (fn) => t.deepEqual(await fn(), testCase.expected));
152+
.passes(t.deepEqual, testCase.expected);
157153
}
158154
});
159155

@@ -167,7 +163,7 @@ test("parseRemoteFileAddress throws for invalid `GITHUB_REPOSITORY`", async (t)
167163
await target
168164
.withEnv(env)
169165
.withFeatures([Feature.NewRemoteFileAddresses])
170-
.passes(async (fn) => t.throwsAsync(fn, { instanceOf: Error }));
166+
.throws(t, { instanceOf: Error });
171167

172168
t.assert(getRequired.calledOnceWith(ActionsEnvVars.GITHUB_REPOSITORY));
173169
});
@@ -202,32 +198,28 @@ test("parseRemoteFileAddress accepts remote address without a path", async (t) =
202198
// Should fail when the FF is not enabled.
203199
await targetWithArgs
204200
.withFeatures([])
205-
.passes(async (fn) =>
206-
t.throwsAsync(fn, { instanceOf: ConfigurationError }),
207-
);
201+
.throws(t, { instanceOf: ConfigurationError });
208202

209203
// And pass when the FF is enabled.
210204
await targetWithArgs
211205
.withFeatures([Feature.NewRemoteFileAddresses])
212-
.passes(async (fn) => t.deepEqual(await fn(), testCase.expected));
206+
.passes(t.deepEqual, testCase.expected);
213207
}
214208
});
215209

216210
test("parseRemoteFileAddress accepts remote address without a ref", async (t) => {
217211
const target = callee(parseRemoteFileAddress).withArgs("owner/repo:path");
218212

219213
// Should only accept the input if the FF is enabled.
220-
await target.withFeatures([]).passes(t.throwsAsync);
214+
await target.withFeatures([]).throws(t);
221215
await target
222216
.withFeatures([Feature.NewRemoteFileAddresses])
223-
.passes(async (fn) =>
224-
t.deepEqual(await fn(), {
225-
owner: "owner",
226-
repo: "repo",
227-
path: "path",
228-
ref: DEFAULT_CONFIG_FILE_REF,
229-
} satisfies RemoteFileAddress),
230-
);
217+
.passes(t.deepEqual, {
218+
owner: "owner",
219+
repo: "repo",
220+
path: "path",
221+
ref: DEFAULT_CONFIG_FILE_REF,
222+
} satisfies RemoteFileAddress);
231223
});
232224

233225
test("parseRemoteFileAddress rejects invalid values", async (t) => {
@@ -262,21 +254,17 @@ test("parseRemoteFileAddress rejects invalid values", async (t) => {
262254
const targetWithArgs = target.withArgs(testInput);
263255

264256
// Should throw both when the new format is and isn't accepted.
265-
await targetWithArgs.withFeatures([]).passes(async (fn) =>
266-
t.throwsAsync(fn, {
267-
instanceOf: ConfigurationError,
268-
message: errors.getConfigFileRepoOldFormatInvalidMessage(testInput),
269-
}),
270-
);
257+
await targetWithArgs.withFeatures([]).throws(t, {
258+
instanceOf: ConfigurationError,
259+
message: errors.getConfigFileRepoOldFormatInvalidMessage(testInput),
260+
});
271261
await targetWithArgs
272262
.withFeatures([Feature.NewRemoteFileAddresses])
273-
.passes(async (fn) =>
274-
t.throwsAsync(fn, {
275-
// When the new format is accepted, there are some more specific
276-
// errors in some cases. It is sufficient for us to check that
277-
// an exception is thrown.
278-
instanceOf: ConfigurationError,
279-
}),
280-
);
263+
.throws(t, {
264+
// When the new format is accepted, there are some more specific
265+
// errors in some cases. It is sufficient for us to check that
266+
// an exception is thrown.
267+
instanceOf: ConfigurationError,
268+
});
281269
}
282270
});

src/testing-utils.ts

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import path from "path";
33

44
import * as github from "@actions/github";
55
import test, {
6+
type ThrownError,
7+
type ThrowsExpectation,
68
type ExecutionContext,
79
type MacroDeclarationOptions,
810
type TestFn,
@@ -281,11 +283,34 @@ export class TestEnv<
281283
return this.fn(this.state as unknown as ActionState<Fs>, ...this.args);
282284
}
283285

284-
public passes<T>(assertion: (makeCall: () => R) => Promise<T>): Promise<T> {
285-
return assertion(() => {
286-
const result = this.call();
287-
return result;
288-
});
286+
/**
287+
* Calls the underlying function in the configured environment and passes
288+
* the result to `assertion` along with extra `assertionArgs`.
289+
*
290+
* @param assertion The assertion to apply to the result.
291+
* @param assertionArgs Extra arguments for the assertion.
292+
* @returns The result of the assertion.
293+
*/
294+
public async passes<AArgs extends readonly any[], AResult>(
295+
assertion: (val: Awaited<R>, ...assertionArgs: AArgs) => AResult,
296+
...assertionArgs: AArgs
297+
): Promise<AResult> {
298+
const result = await Promise.resolve(this.call());
299+
return assertion(result, ...assertionArgs);
300+
}
301+
302+
/**
303+
* Asserts that calling the underlying function should throw an exception.
304+
*
305+
* @param t The execution context for the assertion.
306+
* @param expectations Expectations for the error.
307+
* @returns The error that was thrown.
308+
*/
309+
public async throws<ErrorType extends ErrorConstructor | Error>(
310+
t: ExecutionContext<unknown>,
311+
expectations?: ThrowsExpectation<ErrorType>,
312+
): Promise<ThrownError<ErrorType>> {
313+
return t.throwsAsync(() => Promise.resolve(this.call()), expectations);
289314
}
290315
}
291316

0 commit comments

Comments
 (0)