Skip to content

Commit 623a0a0

Browse files
author
Mat Jones
committed
add typescript implementation of Do.try pattern
1 parent 27a8580 commit 623a0a0

5 files changed

Lines changed: 465 additions & 0 deletions

File tree

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { ResultErrorRecord } from "../..//view-models/result-error-record";
2+
import { Factory } from "rosie";
3+
import { FactoryType } from "./factory-type";
4+
5+
// -------------------------------------------------------------------------------------------------
6+
// #region Factory
7+
// -------------------------------------------------------------------------------------------------
8+
9+
const ResultErrorRecordFactory = Factory.define<ResultErrorRecord>(
10+
FactoryType.ResultErrorRecord,
11+
ResultErrorRecord
12+
)
13+
.sequence("key", (i: number) => `TEST_ERROR_KEY_${i}`)
14+
.sequence("message", (i: number) => `Test error message ${i}`);
15+
16+
// #endregion Factory
17+
18+
// -------------------------------------------------------------------------------------------------
19+
// #region Exports
20+
// -------------------------------------------------------------------------------------------------
21+
22+
export { ResultErrorRecordFactory };
23+
24+
// #endregion Exports
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { ResultRecord } from "../../view-models/result-record";
2+
import { Factory } from "rosie";
3+
import { FactoryType } from "./factory-type";
4+
5+
// -------------------------------------------------------------------------------------------------
6+
// #region Factory
7+
// -------------------------------------------------------------------------------------------------
8+
9+
const ResultRecordFactory = Factory.define<ResultRecord<any>>(
10+
FactoryType.ResultRecord,
11+
ResultRecord
12+
);
13+
14+
// #endregion Factory
15+
16+
// -------------------------------------------------------------------------------------------------
17+
// #region Exports
18+
// -------------------------------------------------------------------------------------------------
19+
20+
export { ResultRecordFactory };
21+
22+
// #endregion Exports

src/utilities/do-try.test.ts

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
import { ResultRecord } from "../view-models/result-record";
2+
import {
3+
ResultErrorRecordFactory,
4+
ResultRecordFactory,
5+
StubResourceRecordFactory,
6+
} from "../tests/factories";
7+
import { Do, DoSync } from "../utilities/do-try";
8+
import { PolyfillUtils } from "../utilities/polyfill-utils";
9+
import { StubResourceRecord } from "../tests/stubs/stub-resource-record";
10+
11+
PolyfillUtils.registerPromiseFinallyPolyfill();
12+
13+
describe("do-try.ts", () => {
14+
describe("Do.try", () => {
15+
it("When validation errors occur (i.e. error is a ResultRecord), then passes typed errors to catch handler", async () => {
16+
// Arrange
17+
const workload = async () => {
18+
throw ResultRecordFactory.build({
19+
errors: [
20+
ResultErrorRecordFactory.build({
21+
key: "TEST_ERROR_KEY",
22+
message: "This is an error",
23+
}),
24+
],
25+
});
26+
};
27+
28+
// Act & Assert
29+
// since jest is using node promises, it fails the test as soon as the error
30+
// is thrown if we actually await the promise. expect.assertions(5) waits for
31+
// 5 assertions to be called.
32+
expect.assertions(5);
33+
Do.try(workload).catch(
34+
(result?: ResultRecord<any>, error?: any) => {
35+
expect(result).not.toBeUndefined();
36+
expect(result).not.toBeNull();
37+
expect(error).toBeUndefined();
38+
expect(result!.resultObject).toBeUndefined();
39+
expect(result!.errors).toHaveLength(1);
40+
}
41+
);
42+
});
43+
44+
it("When passed an async method and a Javascript error occurs, then passes along regular error", async () => {
45+
// Arrange
46+
const workload = async () => {
47+
throw Error();
48+
};
49+
50+
// Act & Assert
51+
expect.assertions(3);
52+
Do.try(workload).catch(
53+
(result?: ResultRecord<any>, error?: any) => {
54+
expect(error).not.toBeNull();
55+
expect(error).not.toBeUndefined();
56+
expect(result).toBeUndefined();
57+
}
58+
);
59+
});
60+
61+
it("When no errors occur, then catch handler is never called", async () => {
62+
// Arrange
63+
const catchHandler = jest.fn();
64+
const workload = jest.fn();
65+
66+
// Act
67+
await Do.try(workload)
68+
.catch(catchHandler)
69+
.getAwaiter();
70+
71+
// Assert
72+
expect(catchHandler).not.toHaveBeenCalled();
73+
});
74+
75+
it("When no errors occur, then finally handler is still called", async () => {
76+
// Arrange
77+
const finallyHandler = jest.fn();
78+
const workload = jest.fn();
79+
80+
// Act
81+
await Do.try(workload)
82+
.finally(finallyHandler)
83+
.getAwaiter();
84+
85+
// Assert
86+
expect(finallyHandler).toHaveBeenCalled();
87+
});
88+
89+
it("When errors occur, then finally handler is still called", async () => {
90+
// Arrange
91+
const catchHandler = jest.fn();
92+
const workload = async () => {
93+
throw Error();
94+
};
95+
let finallyCalled = false;
96+
97+
// Act & Assert
98+
Do.try(workload)
99+
.catch(catchHandler)
100+
.finally(() => {
101+
finallyCalled = true;
102+
expect(finallyCalled).toBeTrue();
103+
});
104+
});
105+
});
106+
107+
describe("DoSync.try", () => {
108+
it("When no errors occur, then .execute() returns the workload return value", () => {
109+
// Arrange
110+
const workload = () => StubResourceRecordFactory.build();
111+
112+
// Act
113+
const result = DoSync.try(workload).execute();
114+
115+
// Assert
116+
expect(result).not.toBeUndefined();
117+
expect(result).not.toBeNull();
118+
expect(result).toBeInstanceOf(StubResourceRecord);
119+
});
120+
121+
it("When Javascript errors occur, then catch handler is passed regular error and return value is undefined", () => {
122+
// Arrange
123+
const workload = () => {
124+
throw Error();
125+
};
126+
127+
// Act
128+
const result = DoSync.try(workload)
129+
.catch((result?: ResultRecord<any>, error?: any) => {
130+
expect(result).toBeUndefined();
131+
expect(error).not.toBeUndefined();
132+
expect(error).not.toBeNull();
133+
})
134+
.execute();
135+
136+
// Assert
137+
expect(result).toBeUndefined();
138+
});
139+
140+
it("When validation error occurs, then catch handler is passed ResultRecord and return value is undefined", () => {
141+
// Arrange
142+
const workload = () => {
143+
throw ResultRecordFactory.build({
144+
errors: [
145+
ResultErrorRecordFactory.build({
146+
key: "TEST_ERROR_KEY",
147+
message: "This is an error",
148+
}),
149+
],
150+
});
151+
};
152+
153+
// Act
154+
const result = DoSync.try(workload)
155+
.catch((result?: ResultRecord<any>, error?: any) => {
156+
expect(error).toBeUndefined();
157+
expect(result).not.toBeUndefined();
158+
expect(result).not.toBeNull();
159+
expect(result!.resultObject).toBeUndefined();
160+
expect(result!.errors).toHaveLength(1);
161+
})
162+
.execute();
163+
164+
// Assert
165+
expect(result).toBeUndefined();
166+
});
167+
168+
it("When errors occur, then finally handler is still called and return value is undefined", () => {
169+
// Arrange
170+
const finallyHandler = jest.fn();
171+
const workload = () => {
172+
throw Error();
173+
};
174+
175+
// Act
176+
const result = DoSync.try(workload)
177+
.finally(finallyHandler)
178+
.execute();
179+
180+
// Assert
181+
expect(result).toBeUndefined();
182+
expect(finallyHandler).toHaveBeenCalled();
183+
});
184+
185+
it("When no errors occur, then finally handler is still called and return value is not undefined", () => {
186+
// Arrange
187+
const finallyHandler = jest.fn();
188+
const workload = () => StubResourceRecordFactory.build();
189+
190+
// Act
191+
const result = DoSync.try(workload)
192+
.finally(finallyHandler)
193+
.execute();
194+
195+
// Assert
196+
expect(result).toBeInstanceOf(StubResourceRecord);
197+
expect(finallyHandler).toHaveBeenCalled();
198+
});
199+
});
200+
});

0 commit comments

Comments
 (0)