Skip to content
This repository was archived by the owner on May 4, 2023. It is now read-only.

Commit 5d72400

Browse files
feat: add token testing
1 parent 7e5c44a commit 5d72400

8 files changed

Lines changed: 330 additions & 74 deletions

File tree

package-lock.json

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

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"access": "public"
1616
},
1717
"scripts": {
18-
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules npx jest"
18+
"test": "cross-env NODE_ENV=test NODE_OPTIONS=--experimental-vm-modules npx jest"
1919
},
2020
"keywords": [
2121
"Codiga",
@@ -33,7 +33,7 @@
3333
"graphql-request": "^5.1.0",
3434
"inquirer": "8.2.3",
3535
"listr2": "^5.0.6",
36-
"node-fetch": "^3.3.0",
36+
"node-fetch": "^2.6.7",
3737
"yaml": "1.10.2",
3838
"yargs": "^17.6.2"
3939
},

src/codigaToken.js

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import inquirer from "inquirer";
22
import { CHECK_USER } from "../graphql/queries";
3+
import { isTestMode, SAMPLE_TOKEN, TEST_USER } from "../tests/test-utils";
34
import { codigaApiFetch } from "../utils/api";
45
import { ACTION_TOKEN_ADD } from "../utils/constants";
56
import {
@@ -16,7 +17,12 @@ import { setToken, getToken, deleteToken, store } from "../utils/store";
1617
* @param {string} apiToken the token string to check
1718
* @returns {Promise<{id: string, accountType: string, username: string}?>} the user if a valid token
1819
*/
19-
async function getUserInfoFromToken(apiToken) {
20+
export async function getUserInfoFromToken(apiToken) {
21+
// handle test case
22+
if (isTestMode && apiToken === SAMPLE_TOKEN) {
23+
return TEST_USER;
24+
}
25+
// complete the real action
2026
try {
2127
const resp = await codigaApiFetch(CHECK_USER, null, apiToken);
2228
if (resp?.user?.id) {
@@ -54,7 +60,7 @@ export async function checkCodigaToken() {
5460
" ↳ To override it, run one of the following commands:",
5561
ACTION_TOKEN_ADD
5662
);
57-
process.exit(0);
63+
process.exit(1);
5864
}
5965
} else {
6066
printInfo("No token was found.");
@@ -66,6 +72,27 @@ export async function checkCodigaToken() {
6672
}
6773
}
6874

75+
/**
76+
* Handles the answers given for the token-add command
77+
* @param {{apiToken: string}} params
78+
*/
79+
export async function handleAnswers({ apiToken }) {
80+
const user = await getUserInfoFromToken(apiToken);
81+
if (!!user) {
82+
setToken(apiToken);
83+
printSuccess(
84+
`Codiga API token added for ${user.username} (${user.accountType})`
85+
);
86+
printSuggestion(`Tokens can be found here:`, store.path);
87+
} else {
88+
printFailure("That token is not valid");
89+
printSuggestion(
90+
" ↳ Go to Codiga and create a new token:",
91+
"https://app.codiga.io/api-tokens"
92+
);
93+
}
94+
}
95+
6996
/**
7097
* Handles asking, verifying, setting and the messaging
7198
* when the `token-add` command action is run
@@ -75,7 +102,7 @@ export async function addCodigaToken() {
75102
"Create a Codiga API token:",
76103
"https://app.codiga.io/api-tokens"
77104
);
78-
inquirer
105+
await inquirer
79106
.prompt([
80107
{
81108
type: "input",
@@ -84,26 +111,8 @@ export async function addCodigaToken() {
84111
},
85112
])
86113
.then(async ({ apiToken }) => {
87-
const user = await getUserInfoFromToken(apiToken);
88-
if (!!user) {
89-
setToken(apiToken);
90-
printSuccess(
91-
`Codiga API token added for ${user.username} (${user.accountType})`
92-
);
93-
printSuggestion(`Tokens can be found here:`, store.path);
94-
process.exit(0);
95-
} else {
96-
printFailure("That token is not valid");
97-
printSuggestion(
98-
" ↳ Go to Codiga and create a new token:",
99-
"https://app.codiga.io/api-tokens"
100-
);
101-
process.exit(1);
102-
}
103-
})
104-
.catch((err) => {
105-
printFailure(err.message);
106-
process.exit(1);
114+
await handleAnswers({ apiToken });
115+
process.exit(0);
107116
});
108117
}
109118

tests/__mocks__/inquirer.js

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// place this file in __mocks__
2+
3+
let pendingAssertions;
4+
5+
exports.prompt = (prompts) => {
6+
if (!pendingAssertions) {
7+
throw new Error(
8+
`inquirer was mocked and used without pending assertions: ${prompts}`
9+
);
10+
}
11+
12+
const answers = {};
13+
let skipped = 0;
14+
prompts.forEach((prompt, i) => {
15+
if (prompt.when && !prompt.when(answers)) {
16+
skipped++;
17+
return;
18+
}
19+
20+
const setValue = (val) => {
21+
if (prompt.validate) {
22+
const res = prompt.validate(val);
23+
if (res !== true) {
24+
throw new Error(`validation failed for prompt: ${prompt}`);
25+
}
26+
}
27+
answers[prompt.name] = prompt.filter ? prompt.filter(val) : val;
28+
};
29+
30+
const a = pendingAssertions[i - skipped];
31+
32+
if (a.message) {
33+
const message =
34+
typeof prompt.message === "function"
35+
? prompt.message(answers)
36+
: prompt.message;
37+
expect(message).toContain(a.message);
38+
}
39+
40+
if (a.choices) {
41+
expect(prompt.choices.length).toBe(a.choices.length);
42+
a.choices.forEach((c, i) => {
43+
const expected = a.choices[i];
44+
if (expected) {
45+
expect(prompt.choices[i].name).toContain(expected);
46+
}
47+
});
48+
}
49+
50+
if (a.input != null) {
51+
expect(prompt.type).toBe("input");
52+
setValue(a.input);
53+
}
54+
55+
if (a.choose != null) {
56+
expect(prompt.type).toBe("list");
57+
setValue(prompt.choices[a.choose].value);
58+
}
59+
60+
if (a.check != null) {
61+
expect(prompt.type).toBe("checkbox");
62+
setValue(a.check.map((i) => prompt.choices[i].value));
63+
}
64+
65+
if (a.confirm != null) {
66+
expect(prompt.type).toBe("confirm");
67+
setValue(a.confirm);
68+
}
69+
70+
if (a.useDefault) {
71+
expect("default" in prompt).toBe(true);
72+
setValue(
73+
typeof prompt.default === "function"
74+
? prompt.default(answers)
75+
: prompt.default
76+
);
77+
}
78+
});
79+
80+
expect(prompts.length).toBe(pendingAssertions.length + skipped);
81+
pendingAssertions = null;
82+
83+
return Promise.resolve(answers);
84+
};
85+
86+
exports.expectPrompts = (assertions) => {
87+
pendingAssertions = assertions;
88+
};

tests/encoding.test.js

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
import { encodeToBase64, decodeFromBase64 } from "../utils/encoding";
22

3-
describe("Encoding", () => {
4-
const decodedCode = "const valid = true;";
5-
const encodedCode = "Y29uc3QgdmFsaWQgPSB0cnVlOw==";
3+
const decodedCode = "const valid = true;";
4+
const encodedCode = "Y29uc3QgdmFsaWQgPSB0cnVlOw==";
65

7-
test("code is encoded in base64", () => {
8-
expect(encodeToBase64(decodedCode)).toBe(encodedCode);
9-
});
6+
test("code is encoded in base64", () => {
7+
expect(encodeToBase64(decodedCode)).toBe(encodedCode);
8+
});
109

11-
test("code is decoded in base64", () => {
12-
expect(decodeFromBase64(encodedCode)).toBe(decodedCode);
13-
});
10+
test("code is decoded in base64", () => {
11+
expect(decodeFromBase64(encodedCode)).toBe(decodedCode);
1412
});

0 commit comments

Comments
 (0)