diff --git a/jest.config.json b/jest.config.json index 21e90b8..2796b3f 100644 --- a/jest.config.json +++ b/jest.config.json @@ -6,5 +6,6 @@ "collectCoverage": true, "coverageReporters": ["json", "lcov", "text", "clover", "json-summary"], "reporters": ["default", "jest-junit", "jest-md-dashboard"], - "coverageDirectory": "coverage" + "coverageDirectory": "coverage", + "setupFiles": ["dotenv/config"] } diff --git a/src/adapters/supabase/helpers/wallet.ts b/src/adapters/supabase/helpers/wallet.ts index 6833d38..505ff6b 100644 --- a/src/adapters/supabase/helpers/wallet.ts +++ b/src/adapters/supabase/helpers/wallet.ts @@ -99,7 +99,7 @@ export class Wallet extends Super { } const { data, error } = await this.supabase.from("wallets").select("*").eq("id", userData.wallet_id).maybeSingle(); - return { data: data as WalletRow, error }; + return { data, error }; } private async _updateWalletId(walletId: number, userId: number) { @@ -168,7 +168,7 @@ export class Wallet extends Super { if (walletData.location_id === null) { throw new Error("Location ID is null"); } - logger.info("Enriching wallet location metadata", locationMetaData); + logger.debug("Enriching wallet location metadata", locationMetaData); return this.supabase.from("locations").update(locationMetaData).eq("id", walletData.location_id); } } diff --git a/src/handlers/command-parser.ts b/src/handlers/command-parser.ts index a7fbec4..a14d29f 100644 --- a/src/handlers/command-parser.ts +++ b/src/handlers/command-parser.ts @@ -18,10 +18,10 @@ export class CommandParser { .version(packageJson.version); program.configureOutput({ async writeOut(str: string) { - await context.logger.info(str); + context.logger.debug(str); }, async writeErr(str: string) { - await context.logger.error(str); + context.logger.warn(str); }, getErrHelpWidth(): number { return 0; diff --git a/src/plugin.ts b/src/plugin.ts index 8d3418e..5a7f04b 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -25,24 +25,32 @@ export async function plugin(inputs: PluginInputs, env: Env) { }, async info(message: unknown, ...optionalParams: unknown[]) { console.log(message, ...optionalParams); - await octokit.issues.createComment({ - owner: context.payload.repository.owner.login, - issue_number: context.payload.issue.number, - repo: context.payload.repository.name, - body: `\`\`\`diff\n${message}`, - }); + try { + await octokit.issues.createComment({ + owner: context.payload.repository.owner.login, + issue_number: context.payload.issue.number, + repo: context.payload.repository.name, + body: `\`\`\`diff\n${message}`, + }); + } catch (e) { + console.error("Failed to post info comment", e); + } }, warn(message: unknown, ...optionalParams: unknown[]) { console.warn(message, ...optionalParams); }, async error(message: unknown, ...optionalParams: unknown[]) { console.error(message, ...optionalParams); - await octokit.issues.createComment({ - owner: context.payload.repository.owner.login, - issue_number: context.payload.issue.number, - repo: context.payload.repository.name, - body: `\`\`\`diff\n- ${message} ${optionalParams}`, - }); + try { + await octokit.issues.createComment({ + owner: context.payload.repository.owner.login, + issue_number: context.payload.issue.number, + repo: context.payload.repository.name, + body: `\`\`\`diff\n- ${message} ${optionalParams}`, + }); + } catch (e) { + console.error("Failed to post error comment", e); + } }, fatal(message: unknown, ...optionalParams: unknown[]) { console.error(message, ...optionalParams); diff --git a/src/types/environment.d.ts b/src/types/environment.d.ts new file mode 100644 index 0000000..a91a509 --- /dev/null +++ b/src/types/environment.d.ts @@ -0,0 +1,10 @@ +declare global { + namespace NodeJS { + interface ProcessEnv { + SUPABASE_KEY: string; + SUPABASE_URL: string; + } + } +} + +export {}; diff --git a/tests/__mocks__/db-seed.json b/tests/__mocks__/db-seed.json new file mode 100644 index 0000000..aedea38 --- /dev/null +++ b/tests/__mocks__/db-seed.json @@ -0,0 +1,15 @@ +{ + "users": [ + { + "id": 1, + "login": "ubiquibot", + "wallet_id": 1 + } + ], + "wallets": [ + { + "id": 1, + "address": "0x0000000000000000000000000000000000000001" + } + ] +} diff --git a/tests/__mocks__/db.ts b/tests/__mocks__/db.ts index 7df690c..e0119b8 100644 --- a/tests/__mocks__/db.ts +++ b/tests/__mocks__/db.ts @@ -5,8 +5,13 @@ import { factory, primaryKey } from "@mswjs/data"; * Creates an object that can be used as a db to persist data within tests */ export const db = factory({ + wallets: { + id: primaryKey(Number), + address: String, + }, users: { id: primaryKey(Number), - name: String, + login: String, + wallet_id: Number, }, }); diff --git a/tests/__mocks__/handlers.ts b/tests/__mocks__/handlers.ts index 0d31c3c..9912ead 100644 --- a/tests/__mocks__/handlers.ts +++ b/tests/__mocks__/handlers.ts @@ -5,7 +5,36 @@ import { db } from "./db"; * Intercepts the routes and returns a custom payload */ export const handlers = [ - http.get("https://api.ubiquity.com/users", () => { - return HttpResponse.json(db.users.getAll()); + http.get(`${process.env.SUPABASE_URL}/rest/v1/users*`, ({ request }) => { + const url = new URL(request.url); + const id = url.searchParams.get("id"); + + if (!id) { + return HttpResponse.text("", { status: 400 }); + } + const idNumber = Number(id.match(/\d+/)?.[0]); + return HttpResponse.json(db.users.findFirst({ where: { id: { equals: idNumber } } })); + }), + http.get(`${process.env.SUPABASE_URL}/rest/v1/wallets*`, ({ request }) => { + const url = new URL(request.url); + const id = url.searchParams.get("id"); + + if (!id) { + return HttpResponse.text("", { status: 400 }); + } + const idNumber = Number(id.match(/\d+/)?.[0]); + return HttpResponse.json(db.wallets.findFirst({ where: { id: { equals: idNumber } } })); + }), + http.patch(`${process.env.SUPABASE_URL}/rest/v1/wallets*`, async ({ request }) => { + const url = new URL(request.url); + const id = url.searchParams.get("id"); + + if (!id) { + return HttpResponse.text("", { status: 400 }); + } + const idNumber = Number(id.match(/\d+/)?.[0]); + const data = (await request.json()) as object; + return HttpResponse.json(db.wallets.update({ data, where: { id: { equals: idNumber } } })); }), + http.post("https://api.github.com/repos/:owner/:repo/issues/:id/comments", () => HttpResponse.json()), ]; diff --git a/tests/__mocks__/payloads/comment-created.json b/tests/__mocks__/payloads/comment-created.json new file mode 100644 index 0000000..10aa9f1 --- /dev/null +++ b/tests/__mocks__/payloads/comment-created.json @@ -0,0 +1,246 @@ +{ + "action": "created", + "issue": { + "url": "https://api.github.com/repos/ubiquibot/command-wallet/issues/5", + "repository_url": "https://api.github.com/repos/ubiquibot/command-wallet", + "labels_url": "https://api.github.com/repos/ubiquibot/command-wallet/issues/5/labels{/name}", + "comments_url": "https://api.github.com/repos/ubiquibot/command-wallet/issues/5/comments", + "events_url": "https://api.github.com/repos/ubiquibot/command-wallet/issues/5/events", + "html_url": "https://github.com/ubiquibot/command-wallet/issues/5", + "id": 2297627819, + "node_id": "I_kwDOLy-Pv86I8wSr", + "number": 5, + "title": "New issue", + "user": { + "login": "ubiquibot", + "id": 1, + "node_id": "MDQ6VXNlcjk4MDcwMDg=", + "avatar_url": "https://avatars.githubusercontent.com/u/1?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ubiquibot", + "html_url": "https://github.com/ubiquibot", + "followers_url": "https://api.github.com/users/ubiquibot/followers", + "following_url": "https://api.github.com/users/ubiquibot/following{/other_user}", + "gists_url": "https://api.github.com/users/ubiquibot/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ubiquibot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ubiquibot/subscriptions", + "organizations_url": "https://api.github.com/users/ubiquibot/orgs", + "repos_url": "https://api.github.com/users/ubiquibot/repos", + "events_url": "https://api.github.com/users/ubiquibot/events{/privacy}", + "received_events_url": "https://api.github.com/users/ubiquibot/received_events", + "type": "User", + "site_admin": false + }, + "labels": [], + "state": "open", + "locked": false, + "assignee": null, + "assignees": [], + "milestone": null, + "comments": 34, + "created_at": "2024-05-15T11:22:48Z", + "updated_at": "2024-05-19T11:54:24Z", + "closed_at": null, + "author_association": "CONTRIBUTOR", + "active_lock_reason": null, + "body": "Another issue.", + "reactions": { + "url": "https://api.github.com/repos/ubiquibot/command-wallet/issues/5/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "timeline_url": "https://api.github.com/repos/ubiquibot/command-wallet/issues/5/timeline", + "performed_via_github_app": null, + "state_reason": null + }, + "comment": { + "url": "https://api.github.com/repos/ubiquibot/command-wallet/issues/comments/2119208855", + "html_url": "https://github.com/ubiquibot/command-wallet/issues/5#issuecomment-2119208855", + "issue_url": "https://api.github.com/repos/ubiquibot/command-wallet/issues/5", + "id": 2119208855, + "node_id": "IC_kwDOLy-Pv85-UI-X", + "user": { + "login": "ubiquibot", + "id": 1, + "node_id": "MDQ6VXNlcjk4MDcwMDg=", + "avatar_url": "https://avatars.githubusercontent.com/u/1?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ubiquibot", + "html_url": "https://github.com/ubiquibot", + "followers_url": "https://api.github.com/users/ubiquibot/followers", + "following_url": "https://api.github.com/users/ubiquibot/following{/other_user}", + "gists_url": "https://api.github.com/users/ubiquibot/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ubiquibot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ubiquibot/subscriptions", + "organizations_url": "https://api.github.com/users/ubiquibot/orgs", + "repos_url": "https://api.github.com/users/ubiquibot/repos", + "events_url": "https://api.github.com/users/ubiquibot/events{/privacy}", + "received_events_url": "https://api.github.com/users/ubiquibot/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2024-05-19T11:54:23Z", + "updated_at": "2024-05-19T11:54:23Z", + "author_association": "CONTRIBUTOR", + "body": "/query @ubiquibot", + "reactions": { + "url": "https://api.github.com/repos/ubiquibot/command-wallet/issues/comments/2119208855/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null + }, + "repository": { + "id": 791646143, + "node_id": "R_kgDOLy-Pvw", + "name": "bot", + "full_name": "ubiquibot/command-wallet", + "private": false, + "owner": { + "login": "ubiquibot", + "id": 159901852, + "node_id": "O_kgDOCYfonA", + "avatar_url": "https://avatars.githubusercontent.com/u/159901852?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ubiquibot", + "html_url": "https://github.com/ubiquibot", + "followers_url": "https://api.github.com/users/ubiquibot/followers", + "following_url": "https://api.github.com/users/ubiquibot/following{/other_user}", + "gists_url": "https://api.github.com/users/ubiquibot/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ubiquibot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ubiquibot/subscriptions", + "organizations_url": "https://api.github.com/users/ubiquibot/orgs", + "repos_url": "https://api.github.com/users/ubiquibot/repos", + "events_url": "https://api.github.com/users/ubiquibot/events{/privacy}", + "received_events_url": "https://api.github.com/users/ubiquibot/received_events", + "type": "Organization", + "site_admin": false + }, + "html_url": "https://github.com/ubiquibot/command-wallet", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/ubiquibot/command-wallet", + "forks_url": "https://api.github.com/repos/ubiquibot/command-wallet/forks", + "keys_url": "https://api.github.com/repos/ubiquibot/command-wallet/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/ubiquibot/command-wallet/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/ubiquibot/command-wallet/teams", + "hooks_url": "https://api.github.com/repos/ubiquibot/command-wallet/hooks", + "issue_events_url": "https://api.github.com/repos/ubiquibot/command-wallet/issues/events{/number}", + "events_url": "https://api.github.com/repos/ubiquibot/command-wallet/events", + "assignees_url": "https://api.github.com/repos/ubiquibot/command-wallet/assignees{/user}", + "branches_url": "https://api.github.com/repos/ubiquibot/command-wallet/branches{/branch}", + "tags_url": "https://api.github.com/repos/ubiquibot/command-wallet/tags", + "blobs_url": "https://api.github.com/repos/ubiquibot/command-wallet/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/ubiquibot/command-wallet/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/ubiquibot/command-wallet/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/ubiquibot/command-wallet/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/ubiquibot/command-wallet/statuses/{sha}", + "languages_url": "https://api.github.com/repos/ubiquibot/command-wallet/languages", + "stargazers_url": "https://api.github.com/repos/ubiquibot/command-wallet/stargazers", + "contributors_url": "https://api.github.com/repos/ubiquibot/command-wallet/contributors", + "subscribers_url": "https://api.github.com/repos/ubiquibot/command-wallet/subscribers", + "subscription_url": "https://api.github.com/repos/ubiquibot/command-wallet/subscription", + "commits_url": "https://api.github.com/repos/ubiquibot/command-wallet/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/ubiquibot/command-wallet/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/ubiquibot/command-wallet/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/ubiquibot/command-wallet/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/ubiquibot/command-wallet/contents/{+path}", + "compare_url": "https://api.github.com/repos/ubiquibot/command-wallet/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/ubiquibot/command-wallet/merges", + "archive_url": "https://api.github.com/repos/ubiquibot/command-wallet/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/ubiquibot/command-wallet/downloads", + "issues_url": "https://api.github.com/repos/ubiquibot/command-wallet/issues{/number}", + "pulls_url": "https://api.github.com/repos/ubiquibot/command-wallet/pulls{/number}", + "milestones_url": "https://api.github.com/repos/ubiquibot/command-wallet/milestones{/number}", + "notifications_url": "https://api.github.com/repos/ubiquibot/command-wallet/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/ubiquibot/command-wallet/labels{/name}", + "releases_url": "https://api.github.com/repos/ubiquibot/command-wallet/releases{/id}", + "deployments_url": "https://api.github.com/repos/ubiquibot/command-wallet/deployments", + "created_at": "2024-04-25T05:19:30Z", + "updated_at": "2024-05-19T09:47:02Z", + "pushed_at": "2024-05-19T09:46:59Z", + "git_url": "git://github.com/ubiquibot/command-wallet.git", + "ssh_url": "git@github.com:ubiquibot/command-wallet.git", + "clone_url": "https://github.com/ubiquibot/command-wallet.git", + "svn_url": "https://github.com/ubiquibot/command-wallet", + "homepage": null, + "size": 56, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": false, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 1, + "license": null, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 0, + "open_issues": 1, + "watchers": 0, + "default_branch": "main", + "custom_properties": {} + }, + "organization": { + "login": "ubiquibot", + "id": 159901852, + "node_id": "O_kgDOCYfonA", + "url": "https://api.github.com/orgs/ubiquibot", + "repos_url": "https://api.github.com/orgs/ubiquibot/repos", + "events_url": "https://api.github.com/orgs/ubiquibot/events", + "hooks_url": "https://api.github.com/orgs/ubiquibot/hooks", + "issues_url": "https://api.github.com/orgs/ubiquibot/issues", + "members_url": "https://api.github.com/orgs/ubiquibot/members{/member}", + "public_members_url": "https://api.github.com/orgs/ubiquibot/public_members{/member}", + "avatar_url": "https://avatars.githubusercontent.com/u/159901852?v=4", + "description": null + }, + "sender": { + "login": "ubiquibot", + "id": 1, + "node_id": "MDQ6VXNlcjk4MDcwMDg=", + "avatar_url": "https://avatars.githubusercontent.com/u/1?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/ubiquibot", + "html_url": "https://github.com/ubiquibot", + "followers_url": "https://api.github.com/users/ubiquibot/followers", + "following_url": "https://api.github.com/users/ubiquibot/following{/other_user}", + "gists_url": "https://api.github.com/users/ubiquibot/gists{/gist_id}", + "starred_url": "https://api.github.com/users/ubiquibot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/ubiquibot/subscriptions", + "organizations_url": "https://api.github.com/users/ubiquibot/orgs", + "repos_url": "https://api.github.com/users/ubiquibot/repos", + "events_url": "https://api.github.com/users/ubiquibot/events{/privacy}", + "received_events_url": "https://api.github.com/users/ubiquibot/received_events", + "type": "User", + "site_admin": false + }, + "installation": { + "id": 48381972, + "node_id": "MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uNDgzODE5NzI=" + } +} diff --git a/tests/__mocks__/users-get.json b/tests/__mocks__/users-get.json deleted file mode 100644 index 59f0200..0000000 --- a/tests/__mocks__/users-get.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "id": 1, - "name": "user1" - }, - { - "id": 2, - "name": "user2" - } -] diff --git a/tests/main.test.ts b/tests/main.test.ts index 7967004..c0a50ea 100644 --- a/tests/main.test.ts +++ b/tests/main.test.ts @@ -1,22 +1,56 @@ +import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, jest } from "@jest/globals"; +import { plugin } from "../src/plugin"; +import { PluginInputs } from "../src/types"; import { db } from "./__mocks__/db"; import { server } from "./__mocks__/node"; -import usersGet from "./__mocks__/users-get.json"; -import { expect, describe, beforeAll, beforeEach, afterAll, afterEach, it } from "@jest/globals"; +import commentCreatedPayload from "./__mocks__/payloads/comment-created.json"; +import dbSeed from "./__mocks__/db-seed.json"; beforeAll(() => server.listen()); afterEach(() => server.resetHandlers()); afterAll(() => server.close()); +jest.mock("ethers", () => ({ + ethers: { + JsonRpcProvider: jest.fn(() => ({ + resolveName: jest.fn(async () => "0x0000000000000000000000000000000000000001"), + })), + }, +})); + describe("User tests", () => { beforeEach(() => { - for (const item of usersGet) { - db.users.create(item); + for (const dbTable of Object.keys(dbSeed)) { + const tableName = dbTable as keyof typeof dbSeed; + for (const dbRow of dbSeed[tableName]) { + db[tableName].create(dbRow); + } } }); - it("Should fetch all the users", async () => { - const res = await fetch("https://api.ubiquity.com/users"); - const data = await res.json(); - expect(data).toMatchObject(usersGet); + it("Should link a wallet", async () => { + const spy = jest.spyOn(console, "log"); + await plugin( + { + eventName: "issue_comment.created", + ref: "", + authToken: "", + stateId: "", + settings: { registerWalletWithVerification: false }, + eventPayload: { + ...commentCreatedPayload, + comment: { + ...commentCreatedPayload.comment, + body: "/wallet ubiquibot.eth", + }, + }, + } as PluginInputs, + { SUPABASE_URL: process.env.SUPABASE_URL, SUPABASE_KEY: process.env.SUPABASE_KEY } + ); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenLastCalledWith("+ Successfully registered wallet address", { + address: "0x0000000000000000000000000000000000000001", + sender: "ubiquibot", + }); }); });