From 0dd74c2473157c16676378f7fd19bc24d281b6e7 Mon Sep 17 00:00:00 2001 From: Lucian Hymer Date: Thu, 10 Aug 2023 09:55:22 -0700 Subject: [PATCH] moved provider utils tests to their own file --- .../__tests__/twitterAccountAge.test.ts | 41 -------- .../src/utils/__tests__/providers.test.ts | 99 +++++++++++++++++++ platforms/src/utils/providers.ts | 7 +- platforms/src/utils/simpleProvider.ts | 20 ++-- 4 files changed, 119 insertions(+), 48 deletions(-) create mode 100644 platforms/src/utils/__tests__/providers.test.ts diff --git a/platforms/src/Twitter/Providers/__tests__/twitterAccountAge.test.ts b/platforms/src/Twitter/Providers/__tests__/twitterAccountAge.test.ts index b52c1b37e8..e70cf5d0f9 100644 --- a/platforms/src/Twitter/Providers/__tests__/twitterAccountAge.test.ts +++ b/platforms/src/Twitter/Providers/__tests__/twitterAccountAge.test.ts @@ -14,8 +14,6 @@ jest.mock("../../procedures/twitterOauth", () => ({ getAuthClient: jest.fn(), })); -jest.spyOn(console, "error").mockImplementation(() => {}); - describe("TwitterAccountAgeProvider", function () { beforeEach(() => { jest.clearAllMocks(); @@ -193,43 +191,4 @@ describe("TwitterAccountAgeProvider", function () { record: undefined, }); }); - - it("should report unhandled error if result is invalid but no errors provided", async () => { - (getTwitterUserData as jest.MockedFunction).mockImplementation(() => { - return Promise.reject({ valid: false }); - }); - const provider = new TwitterAccountAgeProvider({ threshold: "730" }); - const providers = new Providers([provider]); - - const unknownErrorOne = "UNHANDLED ERROR: for type twitterAccountAgeGte#730 and address 0x0 -"; - const unknownErrorTwo = "unable to parse, not derived from Error"; - - const result = await providers._updatedVerify(mockPayload.type, mockPayload, mockContext); - - expect(console.error).toHaveBeenCalledWith(unknownErrorOne, unknownErrorTwo); - expect(result.error[0]).toEqual("There was an unexpected error during verification."); - }); - - it("should handle unexpected errors", async () => { - const unexpectedError = new Error("Unexpected error."); - (getTwitterUserData as jest.MockedFunction).mockImplementation(() => { - return Promise.reject({ valid: false, error: unexpectedError }); - }); - const provider = new TwitterAccountAgeProvider({ threshold: "730" }); - const providers = new Providers([provider]); - - const result = await providers._updatedVerify(mockPayload.type, mockPayload, mockContext); - - expect(result.valid).toEqual(false); - expect(result.error[0]).toContain("There was an unexpected error during verification."); - }); - - it("should return missing provider error if type doesn\"t exist", async () => { - const provider = new TwitterAccountAgeProvider({ threshold: "730" }); - const providers = new Providers([provider]); - - const result = await providers._updatedVerify("nonExistentType", mockPayload, mockContext); - expect(result.valid).toEqual(false); - expect(result.error).toEqual(["Missing provider"]); - }); }); diff --git a/platforms/src/utils/__tests__/providers.test.ts b/platforms/src/utils/__tests__/providers.test.ts new file mode 100644 index 0000000000..34033e7bd6 --- /dev/null +++ b/platforms/src/utils/__tests__/providers.test.ts @@ -0,0 +1,99 @@ +/* eslint-disable */ +import { RequestPayload, ProviderContext } from "@gitcoin/passport-types"; +import { ProviderExternalVerificationError } from "../../types"; +import { Providers } from "../providers"; +import { SimpleProvider, verifySimpleProvider } from "../simpleProvider"; + +jest.spyOn(console, "error").mockImplementation(() => {}); + +describe("Providers", function () { + beforeEach(() => { + jest.clearAllMocks(); + }); + + const mockContext: ProviderContext = {}; + + const mockPayload: RequestPayload = { + address: "0x0", + proofs: { + username: "test", + valid: "true", + }, + type: "Simple", + version: "", + }; + + it("should report unexpected errors even if not derived from Error", async () => { + (verifySimpleProvider as jest.MockedFunction) = jest.fn().mockImplementation(() => { + throw "I don't have an error type"; + }); + + const unknownErrorMessagePartOne = "UNHANDLED ERROR: for type Simple and address 0x0 -"; + const unknownErrorMessagePartTwo = "unable to parse, not derived from Error"; + + const provider = new SimpleProvider(); + const providers = new Providers([provider]); + const result = await providers.verify(mockPayload.type, mockPayload, mockContext); + + expect(console.error).toHaveBeenCalledWith(unknownErrorMessagePartOne, unknownErrorMessagePartTwo); + expect(result).toEqual({ + valid: false, + error: ["There was an unexpected error during verification."], + }); + }); + + it("should report unexpected error details if derived from Error", async () => { + (verifySimpleProvider as jest.MockedFunction) = jest.fn().mockImplementation(() => { + class MyError extends Error { + constructor(message: string) { + super(message); + this.name = "MyError"; + } + } + throw new MyError("I'm an unhandled error"); + }); + + const unknownErrorMessagePartOne = "UNHANDLED ERROR: for type Simple and address 0x0 -"; + + const provider = new SimpleProvider(); + const providers = new Providers([provider]); + const result = await providers.verify(mockPayload.type, mockPayload, mockContext); + + expect(console.error).toHaveBeenCalledWith(unknownErrorMessagePartOne, expect.stringContaining("MyError at")); + + expect(result).toEqual({ + valid: false, + error: [ + expect.stringContaining( + "There was an unexpected error during verification. MyError: I'm an unhandled error at" + ), + ], + }); + }); + + it("should not report expected errors", async () => { + (verifySimpleProvider as jest.MockedFunction) = jest.fn().mockImplementation(() => { + throw new ProviderExternalVerificationError("I'm an expected error"); + }); + + const provider = new SimpleProvider(); + const providers = new Providers([provider]); + const result = await providers.verify(mockPayload.type, mockPayload, mockContext); + + expect(console.error).not.toHaveBeenCalled(); + + expect(result).toEqual({ + valid: false, + error: ["I'm an expected error"], + }); + }); + + it("should return missing provider error if type doesn't exist", async () => { + const provider = new SimpleProvider(); + const providers = new Providers([provider]); + + const result = await providers.verify("nonExistentType", mockPayload, mockContext); + expect(result.valid).toEqual(false); + expect(result.error).toEqual(["Missing provider"]); + }); +}); diff --git a/platforms/src/utils/providers.ts b/platforms/src/utils/providers.ts index 2ad03adf7d..b2926f4ecd 100644 --- a/platforms/src/utils/providers.ts +++ b/platforms/src/utils/providers.ts @@ -2,7 +2,12 @@ import { Provider, ProviderExternalVerificationError, ProviderInternalVerificationError } from "../types"; import type { RequestPayload, VerifiedPayload, ProviderContext } from "@gitcoin/passport-types"; -const UPDATED_PROVIDERS = ["twitterAccountAgeGte#180", "twitterAccountAgeGte#365", "twitterAccountAgeGte#730"]; +const UPDATED_PROVIDERS = [ + "twitterAccountAgeGte#180", + "twitterAccountAgeGte#365", + "twitterAccountAgeGte#730", + "Simple", +]; function reportUnhandledError(type: string, address: string, e: unknown) { if (process.env.EXIT_ON_UNHANDLED_ERROR === "true" && process.env.NODE_ENV === "development") { diff --git a/platforms/src/utils/simpleProvider.ts b/platforms/src/utils/simpleProvider.ts index fa174ec112..57e4a73187 100644 --- a/platforms/src/utils/simpleProvider.ts +++ b/platforms/src/utils/simpleProvider.ts @@ -18,11 +18,19 @@ export class SimpleProvider implements Provider { // verify that the proof object contains valid === "true" verify(payload: RequestPayload): Promise { - return Promise.resolve({ - valid: payload?.proofs?.valid === this._options.valid, - record: { - username: payload?.proofs?.username || "", - }, - }); + return Promise.resolve(verifySimpleProvider(payload)); } } + +// This is pulled out to allow easier mocking in tests +export const verifySimpleProvider = (payload: RequestPayload): VerifiedPayload => { + const valid = payload?.proofs?.valid === "true"; + const errors = valid ? [] : ["Proof is not valid"]; + return { + valid, + errors, + record: { + username: payload?.proofs?.username || "", + }, + }; +};