Skip to content
Closed
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
15 changes: 10 additions & 5 deletions packages/angular/cli/src/command-builder/utilities/json-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,18 +257,18 @@ function getEnumValues(
*/
function getDefaultValue(
current: json.JsonObject,
type: string,
type: ReadonlyArray<string>,
): string | number | boolean | unknown[] | undefined {
const defaultValue = current.default;
if (defaultValue === undefined) {
return undefined;
}

if (type === 'array') {
if (type.includes('array')) {
return Array.isArray(defaultValue) && defaultValue.length > 0 ? defaultValue : undefined;
}

if (typeof defaultValue === type) {
if (type.includes(typeof defaultValue)) {
return defaultValue as string | number | boolean;
}

Expand Down Expand Up @@ -343,7 +343,12 @@ export async function parseJsonSchemaToOptions(
return;
}

const [type] = types;
// Allow Yargs to infer the option type for string AND boolean options
const type =
types.length === 2 && types.includes('string') && types.includes('boolean')
? undefined
: types[0];

const $default = current.$default;
const $defaultIndex =
isJsonObject($default) && $default['$source'] === 'argv' ? $default['index'] : undefined;
Expand All @@ -362,7 +367,7 @@ export async function parseJsonSchemaToOptions(
const option: Option = {
name,
description: String(current.description ?? ''),
default: getDefaultValue(current, type),
default: getDefaultValue(current, types),
choices: enumValues?.length ? enumValues : undefined,
required,
alias: getAliases(current),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,29 @@ describe('parseJsonSchemaToOptions', () => {
});
});

it(`should not set 'type' when it is a 'string' and a 'boolean'`, async () => {
const registry = new schema.CoreSchemaRegistry();
const options = await parseJsonSchemaToOptions(
registry,
{
'type': 'object',
'properties': {
'runner': {
'type': ['string', 'boolean'],
},
},
},
false,
);

expect(options).toEqual([
jasmine.objectContaining({
name: 'runner',
type: undefined,
}),
]);
});

describe('with required positional argument', () => {
it('marks the required argument as required', async () => {
const jsonSchema = {
Expand Down
50 changes: 50 additions & 0 deletions tests/legacy-cli/e2e/tests/vitest/runner-config-option.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { ng } from '../../utils/process';
import { writeMultipleFiles } from '../../utils/fs';
import { applyVitestBuilder } from '../../utils/vitest';
import assert from 'node:assert';

export default async function () {
await applyVitestBuilder();

// Test the boolean `true` usage of `--runner-config`.
// It should log that it is searching for a config file.
const { stdout: boolTrueStdout } = await ng('test', '--runner-config');
assert.match(
boolTrueStdout,
/Automatically searching/,
'Expected an automatic search message for --runner-config',
);
assert.match(boolTrueStdout, /1 passed/, 'Expected 1 test to pass with --runner-config');

// Test the string usage of `--runner-config`.
// It should log that it is using the specified config file.
const customConfigPath = 'vitest.custom.mjs';
await writeMultipleFiles({
[customConfigPath]: `
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {

},
});
`,
});

const { stdout: stringStdout } = await ng('test', `--runner-config=${customConfigPath}`);
assert.match(
stringStdout,
/vitest\.custom\.mjs/,
'Expected a message confirming the use of the custom config file.',
);
assert.match(stringStdout, /1 passed/, 'Expected all tests to pass with string config.');

// Test the boolean `false` usage of `--runner-config`.
// It should not log any messages about searching for or using a config file.
const { stdout: boolFalseStdout } = await ng('test', '--no-runner-config');
assert.doesNotMatch(
boolFalseStdout,
/Automatically searching/,
'Should not search for a config with --no-runner-config',
);
assert.match(boolFalseStdout, /1 passed/, 'Expected 1 test to pass with --no-runner-config');
}