Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d524a84

Browse files
imcaizhengsharathkumaranbu
authored andcommittedDec 16, 2019
Add robust unit tests (#25)
Robust unit tests
1 parent 316521d commit d524a84

27 files changed

+1918
-227
lines changed
 

‎.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,4 @@ public/
142142
.topcoderrc
143143

144144
# package-lock.json vary while installing on different operating system
145-
package-lock.json
145+
package-lock.json

‎bin/topcoder-cli.js

Lines changed: 78 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,75 @@
11
#!/usr/bin/env node
22

3-
const program = require('commander')
3+
const { Command } = require('commander')
44
const submissionHandler = require('../src/commands/submit')
55
const payHandler = require('../src/commands/pay')
66
const configHandler = require('../src/commands/config')
77
const fetchSubmissionHandler = require('../src/commands/fetchSubmissions')
88
const fetchArtifactsHandler = require('../src/commands/fetchArtifacts')
99
const logger = require('../src/common/logger')
1010

11+
const docs = {
12+
submit: `\nEither use CLI parameters or Create a file .topcoderrc in JSON ` +
13+
`format with below details\n` +
14+
`{\n` +
15+
` "memberId": "<Topcoder memberId",\n` +
16+
` "challengeIds": [\n` +
17+
` "30095545" // at least one item here\n` +
18+
` ],\n` +
19+
` "username": "<Topcoder username>",\n` +
20+
` "password": "<Topcoder password>",\n` +
21+
` "m2m": {\n` +
22+
` "client_id": "<Client ID for M2M authentication>",\n` +
23+
` "client_secret": "<Client Secret for M2M authentication>"\n` +
24+
` }\n` +
25+
`}\n` +
26+
`and execute command \`topcoder submit\` to submit the contents of ` +
27+
`current working directory except .topcoderrc file to the challenge.\n` +
28+
`You'd need either the m2m config or the username and password, but ` +
29+
`not both.`,
30+
'fetch-submissions': `\nUse CLI parameters or create a file .topcoderrc in JSON format with below details\n` +
31+
`{\n` +
32+
` "memberId": "<Topcoder memberId",\n` +
33+
` "challengeId": "<Topcoder challengeId",\n` +
34+
` "submissionId": "<Topcoder submissionId",\n` +
35+
` "latest": true,\n` +
36+
` "username": "<Topcoder username>",\n` +
37+
` "password": "<Topcoder password>",\n` +
38+
` "m2m": {\n` +
39+
` "client_id": "<Client ID for M2M authentication>",\n` +
40+
` "client_secret": "<Client Secret for M2M authentication>"\n` +
41+
` }\n` +
42+
`}\n` +
43+
`and execute command \`topcoder fetch-submissions\` to fetch submissions ` +
44+
`for a challenge and save them.\n` +
45+
`You may specify the m2m config or the username and password config, ` +
46+
`but not both.\n` +
47+
`If the submissionId parameter is provided, you must not provide the ` +
48+
`memberId or the latest parameters.\n` +
49+
`The challengeId parameter is always required.`,
50+
'fetch-artifacts': `\nUse CLI parameters or create a file .topcoderrc in JSON format ` +
51+
`with below details\n` +
52+
`{\n` +
53+
` "submissionId": "<Topcoder submissionId>",\n` +
54+
` "legacySubmissionId": "<Topcoder legacySubmissionId>",\n` +
55+
` "username": "<Topcoder username>",\n` +
56+
` "password": "<Topcoder password>",\n` +
57+
` "m2m": {\n` +
58+
` "client_id": "<Client ID for M2M authentication>",\n` +
59+
` "client_secret": "<Client Secret for M2M authentication>"\n` +
60+
` }\n` +
61+
`}\n` +
62+
`and execute command \`topcoder fetch-artifacts\` to fetch submissions for` +
63+
` a challenge and save them.\n` +
64+
`You may specify the m2m config or the username and password config, ` +
65+
`but not both.\n` +
66+
`If the submissionId parameter is provided, you must not provide the the ` +
67+
`legacySubmissionId parameters, and vice-versa.`
68+
69+
}
70+
71+
const program = new Command()
72+
1173
// Overall help text which will be displayed after usage information
1274
program.on('--help', () => {
1375
console.log('\nTopcoder CLI to interact with Topcoder systems\n')
@@ -30,26 +92,7 @@ program
3092
)
3193
.option('--dev', 'Points to Topcoder development environment')
3294
.on('--help', () => {
33-
console.log(
34-
`\nEither use CLI parameters or Create a file .topcoderrc in JSON ` +
35-
`format with below details\n` +
36-
`{\n` +
37-
` "memberId": "<Topcoder memberId",\n` +
38-
` "challengeIds": [\n` +
39-
` "30095545" // at least one item here\n` +
40-
` ],\n` +
41-
` "username": "<Topcoder username>",\n` +
42-
` "password": "<Topcoder password>",\n` +
43-
` "m2m": {\n` +
44-
` "client_id": "<Client ID for M2M authentication>",\n` +
45-
` "client_secret": "<Client Secret for M2M authentication>"\n` +
46-
` }\n` +
47-
`}\n` +
48-
`and execute command \`topcoder submit\` to submit the contents of ` +
49-
`current working directory except .topcoderrc file to the challenge.\n` +
50-
`You'd need either the m2m config or the username and password, but ` +
51-
`not both.`
52-
)
95+
console.log(docs.submit)
5396
})
5497
.action(async args => {
5598
try {
@@ -82,28 +125,7 @@ program
82125
.option('-l, --latest', 'fetch only the latest submission of each member')
83126
.option('--dev', 'Points to Topcoder development environment')
84127
.on('--help', () => {
85-
console.log(
86-
`\nUse CLI parameters or create a file .topcoderrc in JSON format with below details\n` +
87-
`{\n` +
88-
` "memberId": "<Topcoder memberId",\n` +
89-
` "challengeId": "<Topcoder challengeId",\n` +
90-
` "submissionId": "<Topcoder submissionId",\n` +
91-
` "latest": true,\n` +
92-
` "username": "<Topcoder username>",\n` +
93-
` "password": "<Topcoder password>",\n` +
94-
` "m2m": {\n` +
95-
` "client_id": "<Client ID for M2M authentication>",\n` +
96-
` "client_secret": "<Client Secret for M2M authentication>"\n` +
97-
` }\n` +
98-
`}\n` +
99-
`and execute command \`topcoder fetch-submissions\` to fetch submissions ` +
100-
`for a challenge and save them.\n` +
101-
`You may specify the m2m config or the username and password config, ` +
102-
`but not both.\n` +
103-
`If the submissionId parameter is provided, you must not provide the ` +
104-
`memberId or the latest parameters.\n` +
105-
`The challengeId parameter is always required.`
106-
)
128+
console.log(docs['fetch-submissions'])
107129
})
108130
.action(async args => {
109131
try {
@@ -132,24 +154,7 @@ program
132154
.option('--dev', 'Points to Topcoder development environment')
133155
.on('--help', () => {
134156
console.log(
135-
`\nUse CLI parameters or create a file .topcoderrc in JSON format ` +
136-
`with below details\n` +
137-
`{\n` +
138-
` "submissionId": "<Topcoder submissionId>",\n` +
139-
` "legacySubmissionId": "<Topcoder legacySubmissionId>",\n` +
140-
` "username": "<Topcoder username>",\n` +
141-
` "password": "<Topcoder password>",\n` +
142-
` "m2m": {\n` +
143-
` "client_id": "<Client ID for M2M authentication>",\n` +
144-
` "client_secret": "<Client Secret for M2M authentication>"\n` +
145-
` }\n` +
146-
`}\n` +
147-
`and execute command \`topcoder fetch-artifacts\` to fetch submissions for` +
148-
` a challenge and save them.\n` +
149-
`You may specify the m2m config or the username and password config, ` +
150-
`but not both.\n` +
151-
`If the submissionId parameter is provided, you must not provide the the ` +
152-
`legacySubmissionId parameters, and vice-versa.`
157+
docs['fetch-artifacts']
153158
)
154159
})
155160
.action(async args => {
@@ -186,7 +191,7 @@ program
186191
if (args.dev) {
187192
process.env.NODE_ENV = 'dev'
188193
}
189-
payHandler.handleCommand(args)
194+
payHandler.handleCommand(program.args)
190195
})
191196

192197
// error on unknown commands
@@ -199,9 +204,16 @@ program.on('command:*', function () {
199204
process.exit(1)
200205
})
201206

202-
program.parse(process.argv)
207+
/* istanbul ignore next */
208+
if (!module.parent) {
209+
program.parse(process.argv)
210+
// If the CLI is invoked without any command, display help
211+
if (process.argv.length < 3) {
212+
program.help()
213+
}
214+
}
203215

204-
// If the CLI is invoked without any command, display help
205-
if (process.argv.length < 3) {
206-
program.help()
216+
module.exports = {
217+
program,
218+
docs
207219
}

‎config/prod.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ module.exports = {
88
process.env.TC_MEMBERS_API || 'https://api.topcoder.com/v3/members',
99
SUBMISSION_API_URL:
1010
process.env.TEST_SUBMISSION_API_URL ||
11-
'https://api.topcoder.com/v5/submissions',
11+
'https://api.topcoder.com/v5',
1212
AUTH0_URL: process.env.AUTH0_URL || 'https://topcoder.auth0.com/oauth/token',
1313
TC_AUTHN_URL:
1414
process.env.TC_AUTHN_URL || 'https://topcoder.auth0.com/oauth/ro',

‎docs/Development.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ The following parameters can be set in config files or in env variables:
1919
| TC_CLIENT_V2CONNECTION | CLIENT_V2CONNECTION | TC-User-Database | TC client connection protocol |
2020
| AUTH0_AUDIENCE | AUTH0_AUDIENCE | https://m2m.topcoder.com/ | AUTH0 Audience (For M2M) |
2121

22+
# Configuration for Test
23+
Configuration for test is at `test/common/testConfig.js`.
24+
The following parameters can be set in config files or in env variables:
25+
26+
| Property | Environment varible | Default value | Description |
27+
| --- | --- | --- | --- |
28+
| WAIT_TIME | WAIT_TIME | 500 | Waiting time for the CLI tool to process subcommands. Increase the value if needed |
29+
2230
# Publish the package to npm
2331
- Create a npm account on https://www.npmjs.com/signup if you don't have one.
2432
- Use the account to sign in via cli: `npm login`

‎package.json

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"lint": "standard",
88
"lint:fix": "standard --fix",
99
"format": "prettier-standard \"src/**/*.js\" \"bin/**/*.js\" \"test/**/*.js\" \"config/**/*.js\"",
10-
"test": "mocha --require test/prepare.js -t 20000 test/unit.test.js --exit",
10+
"test": "mocha --require test/prepare.js -t 20000 test/*.test.js --exit",
1111
"test:cov": "nyc --reporter=html --reporter=text npm test"
1212
},
1313
"dependencies": {
@@ -23,7 +23,9 @@
2323
"lodash": "^4.17.15",
2424
"moment": "^2.24.0",
2525
"prompts": "^2.2.1",
26+
"stream-mock": "^2.0.5",
2627
"superagent": "^5.0.5",
28+
"uuid": "^3.3.3",
2729
"winston": "^3.2.1"
2830
},
2931
"bin": {
@@ -41,17 +43,24 @@
4143
"homepage": "https://topcoder-platform.github.io/topcoder-cli/",
4244
"devDependencies": {
4345
"chai": "^4.2.0",
46+
"delay": "^4.3.0",
4447
"mocha": "^6.1.4",
4548
"mocha-prepare": "^0.1.0",
49+
"mock-require": "^3.0.3",
4650
"nock": "^10.0.6",
4751
"nyc": "^14.1.1",
4852
"prettier-standard": "^16.0.0",
49-
"sinon": "^7.5.0",
5053
"standard": "^13.1.0"
5154
},
5255
"standard": {
5356
"env": {
5457
"mocha": true
5558
}
59+
},
60+
"nyc": {
61+
"exclude": [
62+
"test/**",
63+
"src/common/logger.js"
64+
]
5665
}
5766
}

‎src/commands/pay.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
const prompts = require('prompts')
2+
const logger = require('../common/logger')
23

34
/**
45
* Handles the "pay" command
56
* @param {Array} args Arguments
67
*/
78
function handleCommand (args) {
8-
const options = args[args.length - 1].opts()
9+
const options = args[0].opts()
910
const challengeDetails = [
1011
{
1112
type: 'text',
@@ -41,7 +42,7 @@ function handleCommand (args) {
4142
const response = await prompts(challengeDetails)
4243
// respose + options.copilot (copilot payment money) contains total
4344
// information needed to send request to API.
44-
console.log(response)
45+
logger.info(response)
4546
// => response => { username, age, about }
4647
}
4748
promptQuestions()

‎src/common/helper.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ const submissionApi = require('@topcoder-platform/topcoder-submission-api-wrappe
55
const logger = require('./logger')
66
const configService = require('../services/configService')
77

8-
let submissionApiClient = null
9-
108
const defaultAuthSchema = Joi.object({
119
username: Joi.string(),
1210
password: Joi.string(),
@@ -87,9 +85,6 @@ async function readFromRCFile (filename, cliParams, schema, validCLIParams) {
8785
}
8886

8987
function getAPIClient (userName, password, m2m) {
90-
if (submissionApiClient) {
91-
return submissionApiClient
92-
}
9388
const config = require('../config')()
9489
let clientConfig
9590
if (userName && password) {
@@ -113,7 +108,7 @@ function getAPIClient (userName, password, m2m) {
113108
clientConfig.AUTH0_CLIENT_ID = m2m.client_id
114109
clientConfig.AUTH0_CLIENT_SECRET = m2m.client_secret
115110
}
116-
submissionApiClient = submissionApi(clientConfig)
111+
const submissionApiClient = submissionApi(clientConfig)
117112
return submissionApiClient
118113
}
119114

‎src/services/configService.js

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ async function addToConfigFile (key, value) {
5151

5252
let config = ini.parse('')
5353
try {
54-
config = readFromConfigFile()
54+
config = await readFromConfigFile()
5555
} catch (error) {
5656
// catching .tcconfig file not found error here.
5757
logger.info('Topcoder config file not found, creating file in' + homedir)
@@ -66,19 +66,15 @@ async function addToConfigFile (key, value) {
6666
* @param {String} keyToBeDeleted Property key (to be deleted)
6767
*/
6868
async function deleteFromConfigFile (keyToBeDeleted) {
69-
const config = readFromConfigFile()
70-
let isDeleted = false
71-
72-
isDeleted = _.unset(config, keyToBeDeleted)
73-
74-
if (isDeleted) {
75-
await fs.writeFile(configPath, ini.stringify(config))
76-
logger.info(
77-
`${keyToBeDeleted} is removed from the config file successfully.`
78-
)
79-
} else {
80-
throw new Error(`${keyToBeDeleted} is not found in the config fle.`)
69+
const config = await readFromConfigFile()
70+
if (_.isUndefined(_.get(config, keyToBeDeleted))) {
71+
throw new Error(`${keyToBeDeleted} is not found in the config file.`)
8172
}
73+
_.unset(config, keyToBeDeleted)
74+
await fs.writeFile(configPath, ini.stringify(config))
75+
logger.info(
76+
`${keyToBeDeleted} is removed from the config file successfully.`
77+
)
8278
}
8379

8480
module.exports = {

0 commit comments

Comments
 (0)
This repository has been archived.