Skip to content

Commit 90a87dd

Browse files
committed
Add jest junit reporter to report xml results for all jest tests
1 parent 8c42eb1 commit 90a87dd

File tree

6 files changed

+117
-20
lines changed

6 files changed

+117
-20
lines changed

.vscode/launch.json

+4-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
"${workspaceFolder}/**",
4242
"!**/node_modules/**"
4343
],
44-
"preLaunchTask": "buildDev"
44+
"preLaunchTask": "buildDev",
45+
"internalConsoleOptions": "openOnSessionStart"
4546
},
4647
{
4748
"name": "Launch Current File BasicRazorApp2_1 Integration Tests",
@@ -69,7 +70,8 @@
6970
"${workspaceFolder}/**",
7071
"!**/node_modules/**"
7172
],
72-
"preLaunchTask": "buildDev"
73+
"preLaunchTask": "buildDev",
74+
"internalConsoleOptions": "openOnSessionStart"
7375
},
7476
{
7577
"name": "Omnisharp: Launch Current File Integration Tests",

jest.config.ts

+4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ const config: Config = {
1414
'<rootDir>/omnisharptest/omnisharpUnitTests/jest.config.ts',
1515
'<rootDir>/omnisharptest/omnisharpIntegrationTests/jest.config.ts',
1616
],
17+
// Reporters are a global jest configuration property and cannot be set in the project jest config.
18+
// This configuration will create a 'junit.xml' file in the output directory, no matter which test project is running.
19+
// In order to not overwrite test results in CI, we configure a unique output file name in the gulp testTasks.
20+
reporters: ['default', ['jest-junit', { outputDirectory: '<rootDir>/out/' }]],
1721
};
1822

1923
export default config;

package-lock.json

+75
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@
130130
"@typescript-eslint/eslint-plugin": "^5.61.0",
131131
"@typescript-eslint/parser": "^5.61.0",
132132
"@vscode/test-electron": "2.3.4",
133+
"@vscode/vsce": "2.21.0",
133134
"archiver": "5.3.0",
134135
"del": "3.0.0",
135136
"eslint": "^8.43.0",
@@ -147,6 +148,7 @@
147148
"gulp": "4.0.2",
148149
"jest": "^29.6.2",
149150
"jest-cli": "^29.6.4",
151+
"jest-junit": "^16.0.0",
150152
"js-yaml": ">=3.13.1",
151153
"minimatch": "3.0.5",
152154
"mock-http-server": "1.4.2",
@@ -159,7 +161,6 @@
159161
"ts-node": "9.1.1",
160162
"typescript": "^5.1.6",
161163
"unzipper": "0.10.11",
162-
"@vscode/vsce": "2.21.0",
163164
"vscode-oniguruma": "^1.6.1",
164165
"vscode-textmate": "^6.0.0",
165166
"vscode-uri": "^3.0.7",

tasks/testTasks.ts

+25-9
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ gulp.task('test:razor', async () => {
2121

2222
const razorIntegrationTestProjects = ['BasicRazorApp2_1'];
2323
for (const projectName of razorIntegrationTestProjects) {
24-
gulp.task(`test:razorintegration:${projectName}`, async () => runIntegrationTest(projectName, /* razor */ true));
24+
gulp.task(`test:razorintegration:${projectName}`, async () =>
25+
runIntegrationTest(projectName, 'razorIntegrationTests', `Razor Test Integration ${projectName}`)
26+
);
2527
}
2628

2729
gulp.task(
@@ -41,10 +43,10 @@ const omnisharpIntegrationTestProjects = ['singleCsproj', 'slnWithCsproj', 'slnF
4143

4244
for (const projectName of omnisharpIntegrationTestProjects) {
4345
gulp.task(`omnisharptest:integration:${projectName}:stdio`, async () =>
44-
runOmnisharpJestIntegrationTest(projectName, 'stdio')
46+
runOmnisharpJestIntegrationTest(projectName, 'stdio', `OmniSharp Test Integration ${projectName} STDIO}`)
4547
);
4648
gulp.task(`omnisharptest:integration:${projectName}:lsp`, async () =>
47-
runOmnisharpJestIntegrationTest(projectName, 'lsp')
49+
runOmnisharpJestIntegrationTest(projectName, 'lsp', `OmniSharp Test Integration ${projectName} LSP}`)
4850
);
4951
gulp.task(
5052
`omnisharptest:integration:${projectName}`,
@@ -73,7 +75,9 @@ gulp.task('test:unit', async () => {
7375

7476
const integrationTestProjects = ['slnWithCsproj'];
7577
for (const projectName of integrationTestProjects) {
76-
gulp.task(`test:integration:${projectName}`, async () => runIntegrationTest(projectName));
78+
gulp.task(`test:integration:${projectName}`, async () =>
79+
runIntegrationTest(projectName, 'integrationTests', `Test Integration ${projectName}`)
80+
);
7781
}
7882

7983
gulp.task(
@@ -83,7 +87,7 @@ gulp.task(
8387

8488
gulp.task('test', gulp.series('test:unit', 'test:integration', 'test:razor', 'test:razorintegration'));
8589

86-
async function runOmnisharpJestIntegrationTest(testAssetName: string, engine: 'stdio' | 'lsp') {
90+
async function runOmnisharpJestIntegrationTest(testAssetName: string, engine: 'stdio' | 'lsp', suiteName: string) {
8791
const workspaceFile = `omnisharp${engine === 'lsp' ? '_lsp' : ''}_${testAssetName}.code-workspace`;
8892
const testFolder = path.join('omnisharptest', 'omnisharpIntegrationTests');
8993

@@ -96,26 +100,28 @@ async function runOmnisharpJestIntegrationTest(testAssetName: string, engine: 's
96100
CODE_DISABLE_EXTENSIONS: 'true',
97101
};
98102

99-
await runJestIntegrationTest(testAssetName, testFolder, workspaceFile, env);
103+
await runJestIntegrationTest(testAssetName, testFolder, workspaceFile, suiteName, env);
100104
}
101105

102-
async function runIntegrationTest(testAssetName: string, razor = false) {
106+
async function runIntegrationTest(testAssetName: string, testFolderName: string, suiteName: string) {
103107
const vscodeWorkspaceFileName = `lsp_tools_host_${testAssetName}.code-workspace`;
104-
const testFolder = path.join('test', razor ? 'razorIntegrationTests' : 'integrationTests');
105-
return await runJestIntegrationTest(testAssetName, testFolder, vscodeWorkspaceFileName);
108+
const testFolder = path.join('test', testFolderName);
109+
return await runJestIntegrationTest(testAssetName, testFolder, vscodeWorkspaceFileName, suiteName);
106110
}
107111

108112
/**
109113
* Runs jest based integration tests.
110114
* @param testAssetName the name of the test asset
111115
* @param testFolderName the relative path (from workspace root)
112116
* @param workspaceFileName the name of the vscode workspace file to use.
117+
* @param suiteName a unique name for the test suite being run.
113118
* @param env any environment variables needed.
114119
*/
115120
async function runJestIntegrationTest(
116121
testAssetName: string,
117122
testFolderName: string,
118123
workspaceFileName: string,
124+
suiteName: string,
119125
env: NodeJS.ProcessEnv = {}
120126
) {
121127
// Test assets are always in a testAssets folder inside the integration test folder.
@@ -143,6 +149,10 @@ async function runJestIntegrationTest(
143149
env.CODE_EXTENSIONS_PATH = rootPath;
144150
env.EXTENSIONS_TESTS_PATH = vscodeRunnerPath;
145151

152+
// Configure the file and suite name in CI to avoid having multiple test runs stomp on each other.
153+
env.JEST_JUNIT_OUTPUT_NAME = getJUnitFileName(suiteName);
154+
env.JEST_SUITE_NAME = suiteName;
155+
146156
const result = await spawnNode([launcherPath, '--enable-source-maps'], { env, cwd: rootPath });
147157

148158
if (result.code === null || result.code > 0) {
@@ -154,6 +164,8 @@ async function runJestIntegrationTest(
154164
}
155165

156166
async function runJestTest(project: string) {
167+
process.env.JEST_JUNIT_OUTPUT_NAME = getJUnitFileName(project);
168+
process.env.JEST_SUITE_NAME = project;
157169
const configPath = path.join(rootPath, 'jest.config.ts');
158170
const { results } = await jest.runCLI(
159171
{
@@ -168,3 +180,7 @@ async function runJestTest(project: string) {
168180
throw new Error('Tests failed.');
169181
}
170182
}
183+
184+
function getJUnitFileName(suiteName: string) {
185+
return `${suiteName.replaceAll(' ', '_')}_junit.xml`;
186+
}

test/runIntegrationTests.ts

+7-8
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,18 @@ export async function runIntegrationTests(projectName: string) {
2424
verbose: true,
2525
} as Config.Argv;
2626

27-
let filter: string;
2827
if (process.env.TEST_FILE_FILTER) {
29-
// If we have just a file, run that with runTestsByPath.
30-
jestConfig.runTestsByPath = true;
28+
// If we have just a file, run that with an explicit match.
3129
jestConfig.testMatch = [process.env.TEST_FILE_FILTER];
32-
filter = process.env.TEST_FILE_FILTER;
33-
} else {
34-
filter = projectName;
3530
}
3631

37-
const { results } = await jest.runCLI(jestConfig, [filter]);
32+
const { results } = await jest.runCLI(jestConfig, [projectName]);
3833

3934
if (!results.success) {
40-
throw new Error('Tests failed.');
35+
console.log('Tests failed.');
4136
}
37+
38+
// Explicitly exit the process - VSCode likes to write a bunch of cancellation errors to the console after this
39+
// which make it look like the tests always fail. We're done with the tests at this point, so just exit.
40+
process.exit(results.success ? 0 : 1);
4241
}

0 commit comments

Comments
 (0)