mirror of https://github.com/coder/code-server.git
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:
parent
77296c7187
commit
91cabbc246
|
@ -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,
|
||||||
|
|
|
@ -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'.`,
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
Loading…
Reference in New Issue