Skip to content

Commit

Permalink
Add jest junit reporter to report xml results for all jest tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dibarbet committed Nov 2, 2023
1 parent 8c42eb1 commit 90a87dd
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 20 deletions.
6 changes: 4 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
"${workspaceFolder}/**",
"!**/node_modules/**"
],
"preLaunchTask": "buildDev"
"preLaunchTask": "buildDev",
"internalConsoleOptions": "openOnSessionStart"
},
{
"name": "Launch Current File BasicRazorApp2_1 Integration Tests",
Expand Down Expand Up @@ -69,7 +70,8 @@
"${workspaceFolder}/**",
"!**/node_modules/**"
],
"preLaunchTask": "buildDev"
"preLaunchTask": "buildDev",
"internalConsoleOptions": "openOnSessionStart"
},
{
"name": "Omnisharp: Launch Current File Integration Tests",
Expand Down
4 changes: 4 additions & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ const config: Config = {
'<rootDir>/omnisharptest/omnisharpUnitTests/jest.config.ts',
'<rootDir>/omnisharptest/omnisharpIntegrationTests/jest.config.ts',
],
// Reporters are a global jest configuration property and cannot be set in the project jest config.
// This configuration will create a 'junit.xml' file in the output directory, no matter which test project is running.
// In order to not overwrite test results in CI, we configure a unique output file name in the gulp testTasks.
reporters: ['default', ['jest-junit', { outputDirectory: '<rootDir>/out/' }]],
};

export default config;
75 changes: 75 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
"@typescript-eslint/eslint-plugin": "^5.61.0",
"@typescript-eslint/parser": "^5.61.0",
"@vscode/test-electron": "2.3.4",
"@vscode/vsce": "2.21.0",
"archiver": "5.3.0",
"del": "3.0.0",
"eslint": "^8.43.0",
Expand All @@ -147,6 +148,7 @@
"gulp": "4.0.2",
"jest": "^29.6.2",
"jest-cli": "^29.6.4",
"jest-junit": "^16.0.0",
"js-yaml": ">=3.13.1",
"minimatch": "3.0.5",
"mock-http-server": "1.4.2",
Expand All @@ -159,7 +161,6 @@
"ts-node": "9.1.1",
"typescript": "^5.1.6",
"unzipper": "0.10.11",
"@vscode/vsce": "2.21.0",
"vscode-oniguruma": "^1.6.1",
"vscode-textmate": "^6.0.0",
"vscode-uri": "^3.0.7",
Expand Down
34 changes: 25 additions & 9 deletions tasks/testTasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ gulp.task('test:razor', async () => {

const razorIntegrationTestProjects = ['BasicRazorApp2_1'];
for (const projectName of razorIntegrationTestProjects) {
gulp.task(`test:razorintegration:${projectName}`, async () => runIntegrationTest(projectName, /* razor */ true));
gulp.task(`test:razorintegration:${projectName}`, async () =>
runIntegrationTest(projectName, 'razorIntegrationTests', `Razor Test Integration ${projectName}`)
);
}

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

for (const projectName of omnisharpIntegrationTestProjects) {
gulp.task(`omnisharptest:integration:${projectName}:stdio`, async () =>
runOmnisharpJestIntegrationTest(projectName, 'stdio')
runOmnisharpJestIntegrationTest(projectName, 'stdio', `OmniSharp Test Integration ${projectName} STDIO}`)
);
gulp.task(`omnisharptest:integration:${projectName}:lsp`, async () =>
runOmnisharpJestIntegrationTest(projectName, 'lsp')
runOmnisharpJestIntegrationTest(projectName, 'lsp', `OmniSharp Test Integration ${projectName} LSP}`)
);
gulp.task(
`omnisharptest:integration:${projectName}`,
Expand Down Expand Up @@ -73,7 +75,9 @@ gulp.task('test:unit', async () => {

const integrationTestProjects = ['slnWithCsproj'];
for (const projectName of integrationTestProjects) {
gulp.task(`test:integration:${projectName}`, async () => runIntegrationTest(projectName));
gulp.task(`test:integration:${projectName}`, async () =>
runIntegrationTest(projectName, 'integrationTests', `Test Integration ${projectName}`)
);
}

gulp.task(
Expand All @@ -83,7 +87,7 @@ gulp.task(

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

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

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

await runJestIntegrationTest(testAssetName, testFolder, workspaceFile, env);
await runJestIntegrationTest(testAssetName, testFolder, workspaceFile, suiteName, env);
}

async function runIntegrationTest(testAssetName: string, razor = false) {
async function runIntegrationTest(testAssetName: string, testFolderName: string, suiteName: string) {
const vscodeWorkspaceFileName = `lsp_tools_host_${testAssetName}.code-workspace`;
const testFolder = path.join('test', razor ? 'razorIntegrationTests' : 'integrationTests');
return await runJestIntegrationTest(testAssetName, testFolder, vscodeWorkspaceFileName);
const testFolder = path.join('test', testFolderName);
return await runJestIntegrationTest(testAssetName, testFolder, vscodeWorkspaceFileName, suiteName);
}

/**
* Runs jest based integration tests.
* @param testAssetName the name of the test asset
* @param testFolderName the relative path (from workspace root)
* @param workspaceFileName the name of the vscode workspace file to use.
* @param suiteName a unique name for the test suite being run.
* @param env any environment variables needed.
*/
async function runJestIntegrationTest(
testAssetName: string,
testFolderName: string,
workspaceFileName: string,
suiteName: string,
env: NodeJS.ProcessEnv = {}
) {
// Test assets are always in a testAssets folder inside the integration test folder.
Expand Down Expand Up @@ -143,6 +149,10 @@ async function runJestIntegrationTest(
env.CODE_EXTENSIONS_PATH = rootPath;
env.EXTENSIONS_TESTS_PATH = vscodeRunnerPath;

// Configure the file and suite name in CI to avoid having multiple test runs stomp on each other.
env.JEST_JUNIT_OUTPUT_NAME = getJUnitFileName(suiteName);
env.JEST_SUITE_NAME = suiteName;

const result = await spawnNode([launcherPath, '--enable-source-maps'], { env, cwd: rootPath });

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

async function runJestTest(project: string) {
process.env.JEST_JUNIT_OUTPUT_NAME = getJUnitFileName(project);
process.env.JEST_SUITE_NAME = project;
const configPath = path.join(rootPath, 'jest.config.ts');
const { results } = await jest.runCLI(
{
Expand All @@ -168,3 +180,7 @@ async function runJestTest(project: string) {
throw new Error('Tests failed.');
}
}

function getJUnitFileName(suiteName: string) {
return `${suiteName.replaceAll(' ', '_')}_junit.xml`;
}
15 changes: 7 additions & 8 deletions test/runIntegrationTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,18 @@ export async function runIntegrationTests(projectName: string) {
verbose: true,
} as Config.Argv;

let filter: string;
if (process.env.TEST_FILE_FILTER) {
// If we have just a file, run that with runTestsByPath.
jestConfig.runTestsByPath = true;
// If we have just a file, run that with an explicit match.
jestConfig.testMatch = [process.env.TEST_FILE_FILTER];
filter = process.env.TEST_FILE_FILTER;
} else {
filter = projectName;
}

const { results } = await jest.runCLI(jestConfig, [filter]);
const { results } = await jest.runCLI(jestConfig, [projectName]);

if (!results.success) {
throw new Error('Tests failed.');
console.log('Tests failed.');
}

// Explicitly exit the process - VSCode likes to write a bunch of cancellation errors to the console after this
// which make it look like the tests always fail. We're done with the tests at this point, so just exit.
process.exit(results.success ? 0 : 1);
}

0 comments on commit 90a87dd

Please sign in to comment.