(args: FeaturesTestCommandInput, feature: string, testResults: TestResult[] = [])
| 107 | |
| 108 | // Executes the same Feature twice with randomized options to ensure Feature can be installed >1. |
| 109 | async function runDuplicateTest(args: FeaturesTestCommandInput, feature: string, testResults: TestResult[] = []): Promise<TestResult[]> { |
| 110 | const { collectionFolder, cliHost } = args; |
| 111 | const scenarioName = `${feature} executed twice with randomized options`; |
| 112 | |
| 113 | const featureTestFolder = path.join(collectionFolder, 'test', feature); |
| 114 | const testFileName = 'duplicate.sh'; |
| 115 | const testFilePath = path.join(featureTestFolder, testFileName); |
| 116 | if (!(await cliHost.isFile(testFilePath))) { |
| 117 | log(`Skipping duplicate test for ${feature} because '${testFilePath}' does not exist.`, { prefix: '⚠️', }); |
| 118 | return testResults; |
| 119 | } |
| 120 | |
| 121 | //Read Feature's metadata |
| 122 | const featureMetadata = await readFeatureMetadata(args, feature); |
| 123 | const options = featureMetadata.options || {}; |
| 124 | |
| 125 | // For each possible option, generate a random value for each Feature |
| 126 | const nonDefaultOptions: { [key: string]: string | boolean } = {}; |
| 127 | Object.entries(options).forEach(([key, value]) => { |
| 128 | if (value.type === 'boolean') { |
| 129 | nonDefaultOptions[key] = !value.default; |
| 130 | } |
| 131 | if (value.type === 'string' && 'proposals' in value && value?.proposals?.length) { |
| 132 | |
| 133 | // Get an index for the default value |
| 134 | let defaultValueIdx = value.default ? value.proposals.indexOf(value.default) : 0; |
| 135 | let idx = 0; |
| 136 | if (args.permitRandomization) { |
| 137 | // Select a random value that isn't the default |
| 138 | idx = Math.floor(Math.random() * value.proposals.length); |
| 139 | } |
| 140 | |
| 141 | if (idx === defaultValueIdx) { |
| 142 | idx = (idx + 1) % value.proposals.length; |
| 143 | } |
| 144 | |
| 145 | nonDefaultOptions[key] = value.proposals[idx]; |
| 146 | } |
| 147 | if (value.type === 'string' && 'enum' in value && value?.enum?.length) { |
| 148 | // Get an index for the default value |
| 149 | let defaultValueIdx = value.default ? value.enum.indexOf(value.default) : 0; |
| 150 | let idx = 0; |
| 151 | if (args.permitRandomization) { |
| 152 | // Select a random value that isn't the default |
| 153 | idx = Math.floor(Math.random() * value.enum.length); |
| 154 | } |
| 155 | |
| 156 | if (idx === defaultValueIdx) { |
| 157 | idx = (idx + 1) % value.enum.length; |
| 158 | } |
| 159 | |
| 160 | nonDefaultOptions[key] = value.enum[idx]; |
| 161 | } |
| 162 | }); |
| 163 | |
| 164 | // Default values |
| 165 | const defaultOptions = Object.entries(options).reduce((acc, [key, value]) => { |
| 166 | if (value.default === undefined) { |
no test coverage detected