Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Add robust unit tests #25

Merged
merged 5 commits into from
Dec 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,4 @@ public/
.topcoderrc

# package-lock.json vary while installing on different operating system
package-lock.json
package-lock.json
144 changes: 78 additions & 66 deletions bin/topcoder-cli.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,75 @@
#!/usr/bin/env node

const program = require('commander')
const { Command } = require('commander')
const submissionHandler = require('../src/commands/submit')
const payHandler = require('../src/commands/pay')
const configHandler = require('../src/commands/config')
const fetchSubmissionHandler = require('../src/commands/fetchSubmissions')
const fetchArtifactsHandler = require('../src/commands/fetchArtifacts')
const logger = require('../src/common/logger')

const docs = {
submit: `\nEither use CLI parameters or Create a file .topcoderrc in JSON ` +
`format with below details\n` +
`{\n` +
` "memberId": "<Topcoder memberId",\n` +
` "challengeIds": [\n` +
` "30095545" // at least one item here\n` +
` ],\n` +
` "username": "<Topcoder username>",\n` +
` "password": "<Topcoder password>",\n` +
` "m2m": {\n` +
` "client_id": "<Client ID for M2M authentication>",\n` +
` "client_secret": "<Client Secret for M2M authentication>"\n` +
` }\n` +
`}\n` +
`and execute command \`topcoder submit\` to submit the contents of ` +
`current working directory except .topcoderrc file to the challenge.\n` +
`You'd need either the m2m config or the username and password, but ` +
`not both.`,
'fetch-submissions': `\nUse CLI parameters or create a file .topcoderrc in JSON format with below details\n` +
`{\n` +
` "memberId": "<Topcoder memberId",\n` +
` "challengeId": "<Topcoder challengeId",\n` +
` "submissionId": "<Topcoder submissionId",\n` +
` "latest": true,\n` +
` "username": "<Topcoder username>",\n` +
` "password": "<Topcoder password>",\n` +
` "m2m": {\n` +
` "client_id": "<Client ID for M2M authentication>",\n` +
` "client_secret": "<Client Secret for M2M authentication>"\n` +
` }\n` +
`}\n` +
`and execute command \`topcoder fetch-submissions\` to fetch submissions ` +
`for a challenge and save them.\n` +
`You may specify the m2m config or the username and password config, ` +
`but not both.\n` +
`If the submissionId parameter is provided, you must not provide the ` +
`memberId or the latest parameters.\n` +
`The challengeId parameter is always required.`,
'fetch-artifacts': `\nUse CLI parameters or create a file .topcoderrc in JSON format ` +
`with below details\n` +
`{\n` +
` "submissionId": "<Topcoder submissionId>",\n` +
` "legacySubmissionId": "<Topcoder legacySubmissionId>",\n` +
` "username": "<Topcoder username>",\n` +
` "password": "<Topcoder password>",\n` +
` "m2m": {\n` +
` "client_id": "<Client ID for M2M authentication>",\n` +
` "client_secret": "<Client Secret for M2M authentication>"\n` +
` }\n` +
`}\n` +
`and execute command \`topcoder fetch-artifacts\` to fetch submissions for` +
` a challenge and save them.\n` +
`You may specify the m2m config or the username and password config, ` +
`but not both.\n` +
`If the submissionId parameter is provided, you must not provide the the ` +
`legacySubmissionId parameters, and vice-versa.`

}

const program = new Command()

// Overall help text which will be displayed after usage information
program.on('--help', () => {
console.log('\nTopcoder CLI to interact with Topcoder systems\n')
Expand All @@ -30,26 +92,7 @@ program
)
.option('--dev', 'Points to Topcoder development environment')
.on('--help', () => {
console.log(
`\nEither use CLI parameters or Create a file .topcoderrc in JSON ` +
`format with below details\n` +
`{\n` +
` "memberId": "<Topcoder memberId",\n` +
` "challengeIds": [\n` +
` "30095545" // at least one item here\n` +
` ],\n` +
` "username": "<Topcoder username>",\n` +
` "password": "<Topcoder password>",\n` +
` "m2m": {\n` +
` "client_id": "<Client ID for M2M authentication>",\n` +
` "client_secret": "<Client Secret for M2M authentication>"\n` +
` }\n` +
`}\n` +
`and execute command \`topcoder submit\` to submit the contents of ` +
`current working directory except .topcoderrc file to the challenge.\n` +
`You'd need either the m2m config or the username and password, but ` +
`not both.`
)
console.log(docs.submit)
})
.action(async args => {
try {
Expand Down Expand Up @@ -82,28 +125,7 @@ program
.option('-l, --latest', 'fetch only the latest submission of each member')
.option('--dev', 'Points to Topcoder development environment')
.on('--help', () => {
console.log(
`\nUse CLI parameters or create a file .topcoderrc in JSON format with below details\n` +
`{\n` +
` "memberId": "<Topcoder memberId",\n` +
` "challengeId": "<Topcoder challengeId",\n` +
` "submissionId": "<Topcoder submissionId",\n` +
` "latest": true,\n` +
` "username": "<Topcoder username>",\n` +
` "password": "<Topcoder password>",\n` +
` "m2m": {\n` +
` "client_id": "<Client ID for M2M authentication>",\n` +
` "client_secret": "<Client Secret for M2M authentication>"\n` +
` }\n` +
`}\n` +
`and execute command \`topcoder fetch-submissions\` to fetch submissions ` +
`for a challenge and save them.\n` +
`You may specify the m2m config or the username and password config, ` +
`but not both.\n` +
`If the submissionId parameter is provided, you must not provide the ` +
`memberId or the latest parameters.\n` +
`The challengeId parameter is always required.`
)
console.log(docs['fetch-submissions'])
})
.action(async args => {
try {
Expand Down Expand Up @@ -132,24 +154,7 @@ program
.option('--dev', 'Points to Topcoder development environment')
.on('--help', () => {
console.log(
`\nUse CLI parameters or create a file .topcoderrc in JSON format ` +
`with below details\n` +
`{\n` +
` "submissionId": "<Topcoder submissionId>",\n` +
` "legacySubmissionId": "<Topcoder legacySubmissionId>",\n` +
` "username": "<Topcoder username>",\n` +
` "password": "<Topcoder password>",\n` +
` "m2m": {\n` +
` "client_id": "<Client ID for M2M authentication>",\n` +
` "client_secret": "<Client Secret for M2M authentication>"\n` +
` }\n` +
`}\n` +
`and execute command \`topcoder fetch-artifacts\` to fetch submissions for` +
` a challenge and save them.\n` +
`You may specify the m2m config or the username and password config, ` +
`but not both.\n` +
`If the submissionId parameter is provided, you must not provide the the ` +
`legacySubmissionId parameters, and vice-versa.`
docs['fetch-artifacts']
)
})
.action(async args => {
Expand Down Expand Up @@ -186,7 +191,7 @@ program
if (args.dev) {
process.env.NODE_ENV = 'dev'
}
payHandler.handleCommand(args)
payHandler.handleCommand(program.args)
})

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

program.parse(process.argv)
/* istanbul ignore next */
if (!module.parent) {
program.parse(process.argv)
// If the CLI is invoked without any command, display help
if (process.argv.length < 3) {
program.help()
}
}

// If the CLI is invoked without any command, display help
if (process.argv.length < 3) {
program.help()
module.exports = {
program,
docs
}
2 changes: 1 addition & 1 deletion config/prod.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module.exports = {
process.env.TC_MEMBERS_API || 'https://api.topcoder.com/v3/members',
SUBMISSION_API_URL:
process.env.TEST_SUBMISSION_API_URL ||
'https://api.topcoder.com/v5/submissions',
'https://api.topcoder.com/v5',
AUTH0_URL: process.env.AUTH0_URL || 'https://topcoder.auth0.com/oauth/token',
TC_AUTHN_URL:
process.env.TC_AUTHN_URL || 'https://topcoder.auth0.com/oauth/ro',
Expand Down
8 changes: 8 additions & 0 deletions docs/Development.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ The following parameters can be set in config files or in env variables:
| TC_CLIENT_V2CONNECTION | CLIENT_V2CONNECTION | TC-User-Database | TC client connection protocol |
| AUTH0_AUDIENCE | AUTH0_AUDIENCE | https://m2m.topcoder.com/ | AUTH0 Audience (For M2M) |

# Configuration for Test
Configuration for test is at `test/common/testConfig.js`.
The following parameters can be set in config files or in env variables:

| Property | Environment varible | Default value | Description |
| --- | --- | --- | --- |
| WAIT_TIME | WAIT_TIME | 500 | Waiting time for the CLI tool to process subcommands. Increase the value if needed |

# Publish the package to npm
- Create a npm account on https://www.npmjs.com/signup if you don't have one.
- Use the account to sign in via cli: `npm login`
Expand Down
13 changes: 11 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"lint": "standard",
"lint:fix": "standard --fix",
"format": "prettier-standard \"src/**/*.js\" \"bin/**/*.js\" \"test/**/*.js\" \"config/**/*.js\"",
"test": "mocha --require test/prepare.js -t 20000 test/unit.test.js --exit",
"test": "mocha --require test/prepare.js -t 20000 test/*.test.js --exit",
"test:cov": "nyc --reporter=html --reporter=text npm test"
},
"dependencies": {
Expand All @@ -23,7 +23,9 @@
"lodash": "^4.17.15",
"moment": "^2.24.0",
"prompts": "^2.2.1",
"stream-mock": "^2.0.5",
"superagent": "^5.0.5",
"uuid": "^3.3.3",
"winston": "^3.2.1"
},
"bin": {
Expand All @@ -41,17 +43,24 @@
"homepage": "https://topcoder-platform.github.io/topcoder-cli/",
"devDependencies": {
"chai": "^4.2.0",
"delay": "^4.3.0",
"mocha": "^6.1.4",
"mocha-prepare": "^0.1.0",
"mock-require": "^3.0.3",
"nock": "^10.0.6",
"nyc": "^14.1.1",
"prettier-standard": "^16.0.0",
"sinon": "^7.5.0",
"standard": "^13.1.0"
},
"standard": {
"env": {
"mocha": true
}
},
"nyc": {
"exclude": [
"test/**",
"src/common/logger.js"
]
}
}
5 changes: 3 additions & 2 deletions src/commands/pay.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
const prompts = require('prompts')
const logger = require('../common/logger')

/**
* Handles the "pay" command
* @param {Array} args Arguments
*/
function handleCommand (args) {
const options = args[args.length - 1].opts()
const options = args[0].opts()
const challengeDetails = [
{
type: 'text',
Expand Down Expand Up @@ -41,7 +42,7 @@ function handleCommand (args) {
const response = await prompts(challengeDetails)
// respose + options.copilot (copilot payment money) contains total
// information needed to send request to API.
console.log(response)
logger.info(response)
// => response => { username, age, about }
}
promptQuestions()
Expand Down
7 changes: 1 addition & 6 deletions src/common/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ const submissionApi = require('@topcoder-platform/topcoder-submission-api-wrappe
const logger = require('./logger')
const configService = require('../services/configService')

let submissionApiClient = null

const defaultAuthSchema = Joi.object({
username: Joi.string(),
password: Joi.string(),
Expand Down Expand Up @@ -87,9 +85,6 @@ async function readFromRCFile (filename, cliParams, schema, validCLIParams) {
}

function getAPIClient (userName, password, m2m) {
if (submissionApiClient) {
return submissionApiClient
}
const config = require('../config')()
let clientConfig
if (userName && password) {
Expand All @@ -113,7 +108,7 @@ function getAPIClient (userName, password, m2m) {
clientConfig.AUTH0_CLIENT_ID = m2m.client_id
clientConfig.AUTH0_CLIENT_SECRET = m2m.client_secret
}
submissionApiClient = submissionApi(clientConfig)
const submissionApiClient = submissionApi(clientConfig)
return submissionApiClient
}

Expand Down
22 changes: 9 additions & 13 deletions src/services/configService.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ async function addToConfigFile (key, value) {

let config = ini.parse('')
try {
config = readFromConfigFile()
config = await readFromConfigFile()
} catch (error) {
// catching .tcconfig file not found error here.
logger.info('Topcoder config file not found, creating file in' + homedir)
Expand All @@ -66,19 +66,15 @@ async function addToConfigFile (key, value) {
* @param {String} keyToBeDeleted Property key (to be deleted)
*/
async function deleteFromConfigFile (keyToBeDeleted) {
const config = readFromConfigFile()
let isDeleted = false

isDeleted = _.unset(config, keyToBeDeleted)

if (isDeleted) {
await fs.writeFile(configPath, ini.stringify(config))
logger.info(
`${keyToBeDeleted} is removed from the config file successfully.`
)
} else {
throw new Error(`${keyToBeDeleted} is not found in the config fle.`)
const config = await readFromConfigFile()
if (_.isUndefined(_.get(config, keyToBeDeleted))) {
throw new Error(`${keyToBeDeleted} is not found in the config file.`)
}
_.unset(config, keyToBeDeleted)
await fs.writeFile(configPath, ini.stringify(config))
logger.info(
`${keyToBeDeleted} is removed from the config file successfully.`
)
}

module.exports = {
Expand Down
Loading