feat(testing): add test for optionDescriptions (#4970)

* feat(testing): add test for optionDescriptions

* refactor(cli): optional arg in optionDescriptions

* feat: add more tests for optionDescriptions
This commit is contained in:
Joe Previte 2022-03-11 13:27:19 -07:00 committed by GitHub
parent 77296c7187
commit 91cabbc246
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 103 additions and 4 deletions

View File

@ -120,11 +120,11 @@ type OptionType<T> = T extends boolean
? "string[]" ? "string[]"
: "unknown" : "unknown"
type Options<T> = { export type Options<T> = {
[P in keyof T]: Option<OptionType<T[P]>> [P in keyof T]: Option<OptionType<T[P]>>
} }
const options: Options<Required<UserProvidedArgs>> = { export const options: Options<Required<UserProvidedArgs>> = {
auth: { type: AuthType, description: "The type of authentication to use." }, auth: { type: AuthType, description: "The type of authentication to use." },
password: { password: {
type: "string", type: "string",
@ -235,8 +235,8 @@ const options: Options<Required<UserProvidedArgs>> = {
}, },
} }
export const optionDescriptions = (): string[] => { export const optionDescriptions = (opts: Partial<Options<Required<UserProvidedArgs>>> = options): string[] => {
const entries = Object.entries(options).filter(([, v]) => !!v.description) const entries = Object.entries(opts).filter(([, v]) => !!v.description)
const widths = entries.reduce( const widths = entries.reduce(
(prev, [k, v]) => ({ (prev, [k, v]) => ({
long: k.length > prev.long ? k.length : prev.long, long: k.length > prev.long ? k.length : prev.long,

View File

@ -13,6 +13,11 @@ import {
shouldOpenInExistingInstance, shouldOpenInExistingInstance,
splitOnFirstEquals, splitOnFirstEquals,
toVsCodeArgs, toVsCodeArgs,
optionDescriptions,
options,
Options,
AuthType,
OptionalString,
} from "../../../src/node/cli" } from "../../../src/node/cli"
import { shouldSpawnCliProcess } from "../../../src/node/main" import { shouldSpawnCliProcess } from "../../../src/node/main"
import { generatePassword, paths } from "../../../src/node/util" import { generatePassword, paths } from "../../../src/node/util"
@ -753,3 +758,97 @@ describe("toVsCodeArgs", () => {
}) })
}) })
}) })
describe("optionDescriptions", () => {
it("should return the descriptions of all the available options", () => {
const expectedOptionDescriptions = Object.entries(options)
.flat()
.filter((item: any) => {
if (item.description) {
return item.description
}
})
.map((item: any) => item.description)
const actualOptionDescriptions = optionDescriptions()
// We need both the expected and the actual
// Both of these are string[]
// We then loop through the expectedOptionDescriptions
// and check that this expectedDescription exists in the
// actualOptionDescriptions
// To do that we need to loop through actualOptionDescriptions
// and make sure we have a substring match
expectedOptionDescriptions.forEach((expectedDescription) => {
const exists = actualOptionDescriptions.find((desc) => {
if (
desc.replace(/\n/g, " ").replace(/ /g, "").includes(expectedDescription.replace(/\n/g, " ").replace(/ /g, ""))
) {
return true
}
return false
})
expect(exists).toBeTruthy()
})
})
it("should visually align multiple options", () => {
const opts: Partial<Options<Required<UserProvidedArgs>>> = {
"cert-key": { type: "string", path: true, description: "Path to certificate key when using non-generated cert." },
"cert-host": {
type: "string",
description: "Hostname to use when generating a self signed certificate.",
},
"disable-update-check": {
type: "boolean",
description:
"Disable update check. Without this flag, code-server checks every 6 hours against the latest github release and \n" +
"then notifies you once every week that a new release is available.",
},
}
expect(optionDescriptions(opts)).toStrictEqual([
" --cert-key Path to certificate key when using non-generated cert.",
" --cert-host Hostname to use when generating a self signed certificate.",
` --disable-update-check Disable update check. Without this flag, code-server checks every 6 hours against the latest github release and
then notifies you once every week that a new release is available.`,
])
})
it("should add all valid options for enumerated types", () => {
const opts: Partial<Options<Required<UserProvidedArgs>>> = {
auth: { type: AuthType, description: "The type of authentication to use." },
}
expect(optionDescriptions(opts)).toStrictEqual([" --auth The type of authentication to use. [password, none]"])
})
it("should show if an option is deprecated", () => {
const opts: Partial<Options<Required<UserProvidedArgs>>> = {
link: {
type: OptionalString,
description: `
Securely bind code-server via our cloud service with the passed name. You'll get a URL like
https://hostname-username.coder.co at which you can easily access your code-server instance.
Authorization is done via GitHub.
`,
deprecated: true,
},
}
expect(optionDescriptions(opts)).toStrictEqual([
` --link (deprecated) Securely bind code-server via our cloud service with the passed name. You'll get a URL like
https://hostname-username.coder.co at which you can easily access your code-server instance.
Authorization is done via GitHub.`,
])
})
it("should show newlines in description", () => {
const opts: Partial<Options<Required<UserProvidedArgs>>> = {
"install-extension": {
type: "string[]",
description:
"Install or update a VS Code extension by id or vsix. The identifier of an extension is `${publisher}.${name}`.\n" +
"To install a specific version provide `@${version}`. For example: 'vscode.csharp@1.2.3'.",
},
}
expect(optionDescriptions(opts)).toStrictEqual([
` --install-extension Install or update a VS Code extension by id or vsix. The identifier of an extension is \`\${publisher}.\${name}\`.
To install a specific version provide \`@\${version}\`. For example: 'vscode.csharp@1.2.3'.`,
])
})
})