Skip to content

Commit e966d9d

Browse files
authored
feat: add npm user validity check (#659)
<!-- 👋 Hi, thanks for sending a PR to tidelift-me-up! 💖. Please fill out all fields below and make sure each item is true and [x] checked. Otherwise we may not be able to review your PR. --> ## PR Checklist - [x] Addresses an existing open issue: fixes #649 - [x] That issue was marked as [`status: accepting prs`](https://github.com/JoshuaKGoldberg/tidelift-me-up/issues?q=is%3Aopen+is%3Aissue+label%3A%22status%3A+accepting+prs%22) - [x] Steps in [CONTRIBUTING.md](https://github.com/JoshuaKGoldberg/tidelift-me-up/blob/main/.github/CONTRIBUTING.md) were taken ## Overview <!-- Description of what is changed and how the code change does that. --> This PR adds a user validity check if the API response from the npm registry API returns zero packages to differentiate between invalid npm users and valid users with zero packages. ### How It Works 1. The npm registry API is queried with the npm username input. 2. If the response contains one or more packages, result is returned as usual. (This is the "happy" case.) 3. If the response contains 0 packages, check if npm username exists using the [npm-user wrapper](https://github.com/sindresorhus/npm-user). 4. If npm username doesn't exist, return an `Invalid npm username.` error. 6. If npm username does exist but user has zero packages, return a `No packages found for npm username: ${username}.` error. ### Testing I updated the unit tests that were affected by these changes and then I ran the unit tests using `pnpm run test`. 🤖
1 parent 27c442d commit e966d9d

File tree

5 files changed

+210
-9
lines changed

5 files changed

+210
-9
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
},
4040
"dependencies": {
4141
"chalk": "^5.4.1",
42+
"npm-user": "^6.1.1",
4243
"npm-username-to-packages": "^0.1.3",
4344
"npm-whoami": "^1.1.4"
4445
},

pnpm-lock.yaml

Lines changed: 136 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/npm-user.d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
declare module "npm-user" {
2+
export default function npmUser(username: string): Promise<{
3+
avatar?: string;
4+
email?: string;
5+
github?: string;
6+
name?: string;
7+
twitter?: string;
8+
}>;
9+
}

src/tideliftMeUp.test.ts

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ vi.mock("./getPackageEstimates.js", () => ({
2525
getPackageEstimates: () => [],
2626
}));
2727

28+
const { mockNpmUser } = vi.hoisted(() => {
29+
return { mockNpmUser: vi.fn() };
30+
});
31+
32+
vi.mock("npm-user", () => {
33+
return { default: mockNpmUser };
34+
});
35+
2836
describe("tideliftMeUp", () => {
2937
it("throws an error when --username isn't provided and getNpmWhoami returns undefined", async () => {
3038
mockGetNpmWhoami.mockResolvedValue(undefined);
@@ -39,34 +47,67 @@ describe("tideliftMeUp", () => {
3947

4048
mockNpmUsernameToPackages.mockResolvedValue([]);
4149
mockGetNpmWhoami.mockRejectedValue(new Error("Should not be called."));
50+
mockNpmUser.mockRejectedValue(new TypeError("Username required"));
4251

4352
await expect(() => tideliftMeUp({ username })).rejects.toThrowError(
44-
`No packages found for npm username: ${username}.`,
53+
`Invalid npm username: ${username}.`,
4554
);
4655
});
4756

4857
it("throws an error when user is logged in but has no packages", async () => {
4958
const username = "abc123";
59+
const npmUserData = {
60+
avatar: "",
61+
email: "",
62+
github: "",
63+
name: "",
64+
twitter: "",
65+
};
5066

5167
mockNpmUsernameToPackages.mockResolvedValue([]);
5268
mockGetNpmWhoami.mockResolvedValue(username);
69+
mockNpmUser.mockResolvedValue(npmUserData);
5370

5471
await expect(() => tideliftMeUp()).rejects.toThrowError(
5572
`No packages found for npm username: ${username}.`,
5673
);
5774
});
5875

59-
it("throws an error when valid --username is provided and has no packages", async () => {
76+
it("throws an error when provided --username is valid but has no packages", async () => {
6077
const username = "abc123";
78+
const npmUserData = {
79+
avatar: "",
80+
email: "",
81+
github: "",
82+
name: "",
83+
twitter: "",
84+
};
6185

6286
mockNpmUsernameToPackages.mockResolvedValue([]);
6387
mockGetNpmWhoami.mockRejectedValue(new Error("Should not be called."));
88+
mockNpmUser.mockResolvedValue(npmUserData);
6489

6590
await expect(() => tideliftMeUp({ username })).rejects.toThrowError(
6691
`No packages found for npm username: ${username}.`,
6792
);
6893
});
6994

95+
it("throws an error when provided --username is valid but doesn't exist", async () => {
96+
const username = "nonexistent-user";
97+
98+
mockNpmUsernameToPackages.mockResolvedValue([]);
99+
mockGetNpmWhoami.mockRejectedValue(new Error("Should not be called."));
100+
mockNpmUser.mockRejectedValue(
101+
Object.assign(new Error(`User \`${username}\` could not be found`), {
102+
code: "ERR_NO_NPM_USER",
103+
}),
104+
);
105+
106+
await expect(() => tideliftMeUp({ username })).rejects.toThrowError(
107+
`Npm user not found: ${username}.`,
108+
);
109+
});
110+
70111
it("calls npmUserPackages with the npm name when the user is logged in and user has packages", async () => {
71112
const username = "abc123";
72113

0 commit comments

Comments
 (0)