Clean Coders know that Boolean Arguments can be dangerous and as a general rule, should be avoided. I had this thought in mind when writing a TypeScript unit test recently. I had this bit of code which is rather ugly and not immediately obvious what it was doing.
getPaymentMethodsSpy.and.callFake(() => ActionsStubs.GetPaymentMethods.fakeResponseWithPaymentCount(1)); await Payment.setPayments(""); CommonLib.setValue(Payment.fields.paymentMethod, 1);The fakeResponseWithPaymentCount sets the getPaymentMethodsSpy to generate the given number of fake existing payments for a count (1 in this case) as a response from the custom action, GetPaymentMethods. Each odd numbered payment is a bank, and each even numbered one is a credit card. So for this snippet, line 1 fakes a response of 1 Bank Payment, line 2 sets the Payment on the form, and line 3 selects that payment as the payment to use. Simple right? Not. Good luck remembering this and re-creating it for processing a Credit Card.
So how does TypeScript here help make this cleaner? Before we get there, lets do the obvious first step and refactor these statements out to a method:
async function selectExistingPayment(isBank: boolean) { getPaymentMethodsSpy.and.callFake(() => ActionsStubs.GetPaymentMethods.fakeResponseWithPaymentCount(2)); await Payment.setPayments(""); CommonLib.setValue(Payment.fields.paymentMethod, isBank ? 1 : 2); }This is way more usable, except when I’m looking at a calls site for it, it’s still really not clear:
selectExistingPayment(true); selectExistingPayment(false);What does false mean? Don’t select it? Sure, you could create an enum and define “credit card”, and “bank” as the two options, but this is just a unit test helper method. I’m not exposing it anywhere, and even if I did, that’s a lot of extra work (Ok, so it’s a tiny bit of work, but it can feel like a lot #1stWorldProblems). The simple solution TypeScript offers is string Union Types.
async function selectExistingPayment(type: "CC" | "BANK") { getPaymentMethodsSpy.and.callFake(() => ActionsStubs.GetPaymentMethods.fakeResponseWithPaymentCount(2)); await Payment.setPayments(""); CommonLib.setValue(Payment.fields.paymentMethod, type === "BANK" ? 1 : 2); }So now the calls sites look like this:
Extremely readable as to what I’m doing, and you get compile time error checking that "Dad" (or any other values besides "CC" and "BANK" ) is not a valid Existing Payment Method!
No comments:
Post a Comment