Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/test/node/configurations.spec.ts
13399 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
import * as fs from 'fs';
6
import * as path from 'path';
7
import { describe, expect, it } from 'vitest';
8
import { Config, ConfigKey } from '../../../platform/configuration/common/configurationService';
9
import { packageJson } from '../../../platform/env/common/packagejson';
10
11
describe('Configurations', () => {
12
it('package.json configuration contains stable, experimental, preview, and advanced sections', () => {
13
const configurationContributions = packageJson.contributes.configuration;
14
15
// Should have 4 sections
16
expect(configurationContributions, 'package.json should have exactly 4 sections').toHaveLength(4);
17
18
// Should have a stable section
19
const stableSection = configurationContributions.find(section => section.id === 'stable');
20
const preview = configurationContributions.find(section => section.id === 'preview');
21
const experimental = configurationContributions.find(section => section.id === 'experimental');
22
const advanced = configurationContributions.find(section => section.id === 'advanced');
23
24
expect(stableSection, 'stable configuration section is missing').toBeDefined();
25
expect(preview, 'preview configuration section is missing').toBeDefined();
26
expect(experimental, 'experimental configuration section is missing').toBeDefined();
27
expect(advanced, 'advanced configuration section is missing').toBeDefined();
28
});
29
30
it('package.json configuration tags are correct for each section', () => {
31
const configurationContributions = packageJson.contributes.configuration;
32
33
const stableSection = configurationContributions.find(section => section.id === 'stable')!;
34
for (const settingId of Object.keys(stableSection?.properties)) {
35
const setting = stableSection.properties[settingId];
36
expect(setting.tags ?? [], settingId).not.toContain('preview');
37
expect(setting.tags ?? [], settingId).not.toContain('experimental');
38
expect(setting.tags ?? [], settingId).not.toContain('advanced');
39
}
40
41
const previewSection = configurationContributions.find(section => section.id === 'preview')!;
42
for (const settingId of Object.keys(previewSection?.properties)) {
43
const setting = previewSection.properties[settingId];
44
expect(setting.tags ?? [], settingId).toContain('preview');
45
expect(setting.tags ?? [], settingId).not.toContain('experimental');
46
expect(setting.tags ?? [], settingId).not.toContain('advanced');
47
}
48
49
const experimentalSection = configurationContributions.find(section => section.id === 'experimental')!;
50
for (const settingId of Object.keys(experimentalSection?.properties)) {
51
const setting = experimentalSection.properties[settingId];
52
expect(setting.tags ?? [], settingId).toContain('experimental');
53
expect(setting.tags ?? [], settingId).not.toContain('preview');
54
expect(setting.tags ?? [], settingId).not.toContain('advanced');
55
}
56
57
const advancedSection = configurationContributions.find(section => section.id === 'advanced')!;
58
for (const settingId of Object.keys(advancedSection?.properties)) {
59
const setting = advancedSection.properties[settingId];
60
expect(setting.tags ?? [], settingId).toContain('advanced');
61
expect(setting.tags ?? [], settingId).not.toContain('preview');
62
}
63
});
64
65
66
it('settings in code should match package.json', () => {
67
68
const configurationsInPackageJson = packageJson.contributes.configuration.flatMap(section => Object.keys(section.properties));
69
const advancedConfigurationsInPackageJson = packageJson.contributes.configuration.filter(section => section.id === 'advanced').flatMap(section => Object.keys(section.properties));
70
const otherConfigurationsInPackageJson = packageJson.contributes.configuration.filter(section => section.id !== 'advanced').flatMap(section => Object.keys(section.properties));
71
72
// Get keys from code
73
const internalKeys = Object.values(ConfigKey.TeamInternal).map(setting => setting.fullyQualifiedId);
74
const sharedKeys = Object.values(ConfigKey.Shared).map(setting => setting.fullyQualifiedId);
75
const advancedPublicKeys = Object.values(ConfigKey.Advanced).map(setting => setting.fullyQualifiedId);
76
const otherPublicKeys = (Object.values(ConfigKey).filter(key => key !== ConfigKey.TeamInternal && key !== ConfigKey.Shared && key !== ConfigKey.Advanced && key !== ConfigKey.Deprecated) as Config<any>[]).map(setting => setting.fullyQualifiedId);
77
const registered = [...otherPublicKeys, ...advancedPublicKeys];
78
const unregistered = [...internalKeys, ...sharedKeys];
79
80
// Validate unregistered settings are not in package.json
81
unregistered.forEach(key => {
82
expect(configurationsInPackageJson, 'unregistered settings should not be defined in the package.json').not.toContain(key);
83
});
84
85
// Validate Internal settings have the correct prefix
86
internalKeys.forEach(key => {
87
expect(key, 'Internal settings must start with github.copilot.chat.advanced.').toMatch(/^github\.copilot\.chat\.advanced\./);
88
});
89
90
// Validate public settings in code are in package.json
91
otherPublicKeys.forEach(key => {
92
expect(otherConfigurationsInPackageJson, 'Setting in code is not defined in the package.json').toContain(key);
93
});
94
95
// Validate advanced settings in code are in the advanced section of package.json
96
advancedPublicKeys.forEach(key => {
97
expect(key, 'Advanced settings must not start wih github.copilot.chat.advanced.').not.toMatch(/^github\.copilot\.chat\.advanced\./);
98
if (key === ConfigKey.Advanced.DebugGitHubAuthFailWith.fullyQualifiedId) {
99
// This setting should be internal, but can't be made TeamInternal because we lose the team and internal flags as part of its testing.
100
return;
101
}
102
expect(advancedConfigurationsInPackageJson, `Advanced setting ${key} should be defined in the advanced section of package.json`).toContain(key);
103
});
104
105
// Validate settings in package.json are in code
106
configurationsInPackageJson.forEach(key => {
107
expect(registered, 'Setting in package.json is not defined in code').toContain(key);
108
});
109
});
110
111
it('prompt override string setting uses camelCase', () => {
112
const advancedSection = packageJson.contributes.configuration.find(section => section.id === 'advanced')!;
113
const promptOverrideStringKey = ConfigKey.Advanced.DebugPromptOverrideString;
114
115
expect(promptOverrideStringKey.fullyQualifiedId).toBe('github.copilot.chat.debug.promptOverrideString');
116
expect(promptOverrideStringKey.fullyQualifiedOldId).toBeUndefined();
117
expect(Object.keys(advancedSection.properties)).toContain(promptOverrideStringKey.fullyQualifiedId);
118
});
119
120
it('all localization strings in package.json are present in package.nls.json', async () => {
121
// Get all keys from package.nls.json
122
const packageJsonPath = path.join(__dirname, '../../../../package.json');
123
const packageNlsPath = path.join(__dirname, '../../../../package.nls.json');
124
const [packageJsonFileContents, packageNlsFileContents] = await Promise.all(
125
[
126
fs.promises.readFile(packageJsonPath, 'utf-8'),
127
fs.promises.readFile(packageNlsPath, 'utf-8'),
128
]
129
);
130
131
const packageNls = JSON.parse(packageNlsFileContents);
132
const nlsKeys = Object.keys(packageNls);
133
134
// Find all %key% references in package.json
135
const nlsReferences = Array.from(packageJsonFileContents.matchAll(/"%([^"]+)%"/g)).map(match => match[1]);
136
137
// Validate all references exist in package.nls.json
138
const missingKeys = nlsReferences.filter(key => !nlsKeys.includes(key));
139
if (missingKeys.length > 0) {
140
throw new Error(`Missing localization keys in package.nls.json but present in package.json: ${missingKeys.map(key => `'%${key}%'`).join(', ')}`);
141
}
142
});
143
});
144
145