|
1 | | -import { describe, it, expect } from "vitest"; |
2 | | -import { ok, err, isOk, isErr, isErrorCode, assertOk, SorokitErrorCode } from "../shared/response"; |
| 1 | +import { describe, it, expect, expectTypeOf } from "vitest"; |
| 2 | +import { |
| 3 | + ok, |
| 4 | + err, |
| 5 | + isOk, |
| 6 | + isErr, |
| 7 | + isErrorCode, |
| 8 | + isAccountNotFound, |
| 9 | + isTxFailed, |
| 10 | + isContractError, |
| 11 | + assertOk, |
| 12 | + SorokitErrorCode, |
| 13 | +} from "../shared/response"; |
| 14 | +import type { |
| 15 | + AccountNotFoundErrorCode, |
| 16 | + ContractErrorCode, |
| 17 | + SorokitErrorResult, |
| 18 | + TxFailedErrorCode, |
| 19 | +} from "../shared/response"; |
3 | 20 |
|
4 | 21 | describe("shared/response", () => { |
5 | 22 | describe("ok()", () => { |
@@ -100,3 +117,97 @@ describe("assertOk()", () => { |
100 | 117 | ); |
101 | 118 | }); |
102 | 119 | }); |
| 120 | + |
| 121 | +describe("error-specific result type guards", () => { |
| 122 | + describe("isAccountNotFound()", () => { |
| 123 | + it("returns true for ACCOUNT_NOT_FOUND", () => { |
| 124 | + const result = err(SorokitErrorCode.ACCOUNT_NOT_FOUND, "not found"); |
| 125 | + expect(isAccountNotFound(result)).toBe(true); |
| 126 | + }); |
| 127 | + |
| 128 | + it("returns false for ok results and other error codes", () => { |
| 129 | + expect(isAccountNotFound(ok(42))).toBe(false); |
| 130 | + expect( |
| 131 | + isAccountNotFound(err(SorokitErrorCode.ACCOUNT_FETCH_FAILED, "fetch failed")), |
| 132 | + ).toBe(false); |
| 133 | + expect(isAccountNotFound(err(SorokitErrorCode.TX_SUBMIT_FAILED, "tx failed"))).toBe( |
| 134 | + false, |
| 135 | + ); |
| 136 | + }); |
| 137 | + |
| 138 | + it("narrows to the error branch with ACCOUNT_NOT_FOUND code", () => { |
| 139 | + const result = err<number>(SorokitErrorCode.ACCOUNT_NOT_FOUND, "not found"); |
| 140 | + |
| 141 | + if (isAccountNotFound(result)) { |
| 142 | + expectTypeOf(result).toEqualTypeOf<SorokitErrorResult<AccountNotFoundErrorCode>>(); |
| 143 | + expectTypeOf(result.error.code).toEqualTypeOf<SorokitErrorCode.ACCOUNT_NOT_FOUND>(); |
| 144 | + expect(result.data).toBeNull(); |
| 145 | + } |
| 146 | + }); |
| 147 | + }); |
| 148 | + |
| 149 | + describe("isTxFailed()", () => { |
| 150 | + it.each([ |
| 151 | + SorokitErrorCode.TX_BUILD_FAILED, |
| 152 | + SorokitErrorCode.TX_SIMULATE_FAILED, |
| 153 | + SorokitErrorCode.TX_SUBMIT_FAILED, |
| 154 | + ])("returns true for %s", (code) => { |
| 155 | + expect(isTxFailed(err(code, "transaction failed"))).toBe(true); |
| 156 | + }); |
| 157 | + |
| 158 | + it("returns false for ok results and non-transaction error codes", () => { |
| 159 | + expect(isTxFailed(ok(42))).toBe(false); |
| 160 | + expect(isTxFailed(err(SorokitErrorCode.TX_NOT_FOUND, "tx not found"))).toBe(false); |
| 161 | + expect(isTxFailed(err(SorokitErrorCode.ACCOUNT_NOT_FOUND, "not found"))).toBe(false); |
| 162 | + expect(isTxFailed(err(SorokitErrorCode.CONTRACT_INVOKE_FAILED, "contract"))).toBe( |
| 163 | + false, |
| 164 | + ); |
| 165 | + }); |
| 166 | + |
| 167 | + it("narrows to the error branch with transaction failure codes", () => { |
| 168 | + const result = err<string>(SorokitErrorCode.TX_BUILD_FAILED, "build failed"); |
| 169 | + |
| 170 | + if (isTxFailed(result)) { |
| 171 | + expectTypeOf(result).toEqualTypeOf<SorokitErrorResult<TxFailedErrorCode>>(); |
| 172 | + expectTypeOf(result.error.code).toEqualTypeOf<TxFailedErrorCode>(); |
| 173 | + expect(result.data).toBeNull(); |
| 174 | + } |
| 175 | + }); |
| 176 | + }); |
| 177 | + |
| 178 | + describe("isContractError()", () => { |
| 179 | + it.each([ |
| 180 | + SorokitErrorCode.CONTRACT_INVOKE_FAILED, |
| 181 | + SorokitErrorCode.CONTRACT_READ_FAILED, |
| 182 | + SorokitErrorCode.CONTRACT_PREPARE_FAILED, |
| 183 | + SorokitErrorCode.CONTRACT_SIMULATE_FAILED, |
| 184 | + ])("returns true for %s", (code) => { |
| 185 | + expect(isContractError(err(code, "contract failed"))).toBe(true); |
| 186 | + }); |
| 187 | + |
| 188 | + it("returns false for ok results and non-contract error codes", () => { |
| 189 | + expect(isContractError(ok(42))).toBe(false); |
| 190 | + expect(isContractError(err(SorokitErrorCode.TX_SUBMIT_FAILED, "tx failed"))).toBe( |
| 191 | + false, |
| 192 | + ); |
| 193 | + expect(isContractError(err(SorokitErrorCode.ACCOUNT_NOT_FOUND, "not found"))).toBe( |
| 194 | + false, |
| 195 | + ); |
| 196 | + expect(isContractError(err(SorokitErrorCode.NETWORK_ERROR, "network"))).toBe(false); |
| 197 | + }); |
| 198 | + |
| 199 | + it("narrows to the error branch with contract error codes", () => { |
| 200 | + const result = err<boolean>( |
| 201 | + SorokitErrorCode.CONTRACT_SIMULATE_FAILED, |
| 202 | + "simulate failed", |
| 203 | + ); |
| 204 | + |
| 205 | + if (isContractError(result)) { |
| 206 | + expectTypeOf(result).toEqualTypeOf<SorokitErrorResult<ContractErrorCode>>(); |
| 207 | + expectTypeOf(result.error.code).toEqualTypeOf<ContractErrorCode>(); |
| 208 | + expect(result.data).toBeNull(); |
| 209 | + } |
| 210 | + }); |
| 211 | + }); |
| 212 | +}); |
| 213 | + |
0 commit comments