| 
1 |  | -import { list, map, SCHEMA, struct } from "@smithy/core/schema";  | 
 | 1 | +import { error, list, map, op, SCHEMA, struct, TypeRegistry } from "@smithy/core/schema";  | 
2 | 2 | import { HttpRequest, HttpResponse } from "@smithy/protocol-http";  | 
3 |  | -import type { SchemaRef } from "@smithy/types";  | 
4 |  | -import { describe, expect, test as it } from "vitest";  | 
 | 3 | +import { ResponseMetadata, RetryableTrait, SchemaRef } from "@smithy/types";  | 
 | 4 | +import { beforeEach, describe, expect, test as it } from "vitest";  | 
5 | 5 | 
 
  | 
6 | 6 | import { cbor } from "./cbor";  | 
7 | 7 | import { dateToTag } from "./parseCborBody";  | 
@@ -273,4 +273,92 @@ describe(SmithyRpcV2CborProtocol.name, () => {  | 
273 | 273 |       });  | 
274 | 274 |     }  | 
275 | 275 |   });  | 
 | 276 | + | 
 | 277 | +  describe("error handling", () => {  | 
 | 278 | +    const protocol = new SmithyRpcV2CborProtocol({ defaultNamespace: "ns" });  | 
 | 279 | + | 
 | 280 | +    const operation = op(  | 
 | 281 | +      "ns",  | 
 | 282 | +      "OperationWithModeledException",  | 
 | 283 | +      {},  | 
 | 284 | +      struct("ns", "Input", 0, [], []),  | 
 | 285 | +      struct("ns", "Output", 0, [], [])  | 
 | 286 | +    );  | 
 | 287 | + | 
 | 288 | +    const errorResponse = new HttpResponse({  | 
 | 289 | +      statusCode: 400,  | 
 | 290 | +      headers: {},  | 
 | 291 | +      body: cbor.serialize({  | 
 | 292 | +        __type: "ns#ModeledException",  | 
 | 293 | +        modeledProperty: "oh no",  | 
 | 294 | +      }),  | 
 | 295 | +    });  | 
 | 296 | + | 
 | 297 | +    const serdeContext = {};  | 
 | 298 | + | 
 | 299 | +    class ServiceBaseException extends Error {  | 
 | 300 | +      public readonly $fault: "client" | "server" = "client";  | 
 | 301 | +      public $response?: HttpResponse;  | 
 | 302 | +      public $retryable?: RetryableTrait;  | 
 | 303 | +      public $metadata: ResponseMetadata = {  | 
 | 304 | +        httpStatusCode: 400,  | 
 | 305 | +      };  | 
 | 306 | +    }  | 
 | 307 | + | 
 | 308 | +    class ModeledExceptionCtor extends ServiceBaseException {  | 
 | 309 | +      public modeledProperty: string = "";  | 
 | 310 | +    }  | 
 | 311 | + | 
 | 312 | +    beforeEach(() => {  | 
 | 313 | +      TypeRegistry.for("ns").destroy();  | 
 | 314 | +    });  | 
 | 315 | + | 
 | 316 | +    it("should throw the schema error ctor if one exists", async () => {  | 
 | 317 | +      // this is for modeled exceptions.  | 
 | 318 | + | 
 | 319 | +      TypeRegistry.for("ns").register(  | 
 | 320 | +        "ns#ModeledException",  | 
 | 321 | +        error("ns", "ModeledException", 0, ["modeledProperty"], [0], ModeledExceptionCtor)  | 
 | 322 | +      );  | 
 | 323 | +      TypeRegistry.for("ns").register(  | 
 | 324 | +        "smithy.ts.sdk.synthetic.ns#BaseServiceException",  | 
 | 325 | +        error("smithy.ts.sdk.synthetic.ns", "BaseServiceException", 0, [], [], ServiceBaseException)  | 
 | 326 | +      );  | 
 | 327 | + | 
 | 328 | +      try {  | 
 | 329 | +        await protocol.deserializeResponse(operation, serdeContext as any, errorResponse);  | 
 | 330 | +      } catch (e) {  | 
 | 331 | +        expect(e).toBeInstanceOf(ModeledExceptionCtor);  | 
 | 332 | +        expect((e as ModeledExceptionCtor).modeledProperty).toEqual("oh no");  | 
 | 333 | +        expect(e).toBeInstanceOf(ServiceBaseException);  | 
 | 334 | +      }  | 
 | 335 | +      expect.assertions(3);  | 
 | 336 | +    });  | 
 | 337 | + | 
 | 338 | +    it("should throw a base error if available in the namespace, when no error schema is modeled", async () => {  | 
 | 339 | +      // this is the expected fallback case for all generated clients.  | 
 | 340 | + | 
 | 341 | +      TypeRegistry.for("ns").register(  | 
 | 342 | +        "smithy.ts.sdk.synthetic.ns#BaseServiceException",  | 
 | 343 | +        error("smithy.ts.sdk.synthetic.ns", "BaseServiceException", 0, [], [], ServiceBaseException)  | 
 | 344 | +      );  | 
 | 345 | + | 
 | 346 | +      try {  | 
 | 347 | +        await protocol.deserializeResponse(operation, serdeContext as any, errorResponse);  | 
 | 348 | +      } catch (e) {  | 
 | 349 | +        expect(e).toBeInstanceOf(ServiceBaseException);  | 
 | 350 | +      }  | 
 | 351 | +      expect.assertions(1);  | 
 | 352 | +    });  | 
 | 353 | + | 
 | 354 | +    it("should fall back to a generic JS Error as a last resort", async () => {  | 
 | 355 | +      // this shouldn't happen, but in case the type registry is mutated incorrectly.  | 
 | 356 | +      try {  | 
 | 357 | +        await protocol.deserializeResponse(operation, serdeContext as any, errorResponse);  | 
 | 358 | +      } catch (e) {  | 
 | 359 | +        expect(e).toBeInstanceOf(Error);  | 
 | 360 | +      }  | 
 | 361 | +      expect.assertions(1);  | 
 | 362 | +    });  | 
 | 363 | +  });  | 
276 | 364 | });  | 
0 commit comments