Skip to content

Get rid of dotnet test runner#32792

Open
nightskylark wants to merge 10 commits into26_1from
kill-dotnet-runner
Open

Get rid of dotnet test runner#32792
nightskylark wants to merge 10 commits into26_1from
kill-dotnet-runner

Conversation

@nightskylark
Copy link
Contributor

@nightskylark nightskylark commented Mar 4, 2026

Summary

This PR removes the .NET dependency from the DevExtreme QUnit browser runner by replacing the legacy ASP.NET Core runner with a Node.js implementation, while preserving the existing runner behavior and endpoint contract.

Motivation

The previous runner required a .NET toolchain only for QUnit execution. This increased CI/setup complexity and made long-term maintenance harder.
The new implementation keeps the same workflow but runs fully on Node.js.

What was changed

1. Replaced legacy .NET QUnit runner with Node.js

  • Implemented a Node-based runner at packages/devextreme/testing/runner/index.js.
  • Kept legacy-compatible routes and semantics for:
    • suite/category discovery,
    • run pages (/run, /main/runall, /main/runsuite),
    • test lifecycle notifications,
    • results saving/reporting (Results.xml, misc/raw logs),
    • vector map helper endpoints,
    • static file serving.

2. Removed .NET artifacts and configuration

  • Deleted legacy C# runner sources and project files:
    • packages/devextreme/testing/runner/**/*.cs
    • packages/devextreme/testing/runner/runner.csproj
    • old MVC views and model/controller/tool files.
  • Removed obsolete solution:
    • packages/devextreme/build/build-dotnet.sln
  • Removed obsolete VSCode runner configs:
    • packages/devextreme/testing/runner/.vscode/*

3. Updated scripts and CI to be Node-only

  • packages/devextreme/testing/launch: now starts node testing/runner/index.js.
  • packages/devextreme/docker-ci.sh: runner startup switched from runner.dll to Node runner.
  • packages/devextreme/package.json: removed dotnet build from dev script.
  • .github/actions/run-qunit-tests/action.yml: removed .NET build step.
  • .github/workflows/qunit_tests.yml and packages/devextreme/project.json: removed DOTNET_* env usage.

4. Security and robustness improvements

  • Moved large inline HTML pages to dedicated templates:
    • packages/devextreme/testing/runner/templates/*.template.html
  • Added safe template rendering and escaping in Node runner.
  • Replaced dynamic string URL concatenation in getJSON with query params object for suite loading.
  • Improved cache-buster handling (DX_HTTP_CACHE) by URL-encoding values.

5. CI fixes after migration

  • Added HEAD handling for run endpoints used by readiness checks.
  • Fixed SystemJS mapping for @preact/signals-core.
  • Added fallback when theme bundles directory is missing.
  • Fixed vector map output parsing for non-JSON mode (trailing ; / assignment parsing).

6. Maintainability refactor

  • Split the monolithic runner into focused modules under packages/devextreme/testing/runner/lib/:
    • http, logger, pages, results, static, suites, templates, utils, vectormap.
  • Reduced index.js from ~1550 lines to an orchestration layer (~446 lines).

Compatibility notes

  • No intentional functional changes in test execution behavior.
  • Existing runner endpoints and overall flow are preserved.

- Created `index.template.html` for the main testing interface, including category selection and suite display.
- Added `run-all.template.html` for running all test suites with worker management and result reporting.
- Introduced `run-suite.template.html` for individual suite execution with QUnit integration and CSP support.
@nightskylark nightskylark added github_actions Pull requests that update GitHub Actions code 26_1 labels Mar 4, 2026
@nightskylark nightskylark self-assigned this Mar 4, 2026
@nightskylark nightskylark marked this pull request as ready for review March 4, 2026 21:47
@nightskylark nightskylark requested a review from a team as a code owner March 4, 2026 21:47
Copilot AI review requested due to automatic review settings March 4, 2026 21:47
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes the .NET (ASP.NET Core) dependency from the DevExtreme QUnit browser runner and replaces it with a functionally equivalent Node.js implementation. The legacy runner required a .NET 8 toolchain solely for QUnit test execution, making CI/setup unnecessarily complex.

Changes:

  • Replaces the ASP.NET Core runner (C# controllers, models, Razor views, runner.csproj, build-dotnet.sln) with a new Node.js runner (index.js + modular lib/ files), preserving all existing HTTP routes and behavior.
  • Migrates inline Razor HTML to standalone .template.html files with a custom {{{raw}}}/{{escaped}} template engine and adds safe HTML escaping.
  • Updates CI workflows, scripts, and package.json to remove all .NET build steps.

Reviewed changes

Copilot reviewed 44 out of 44 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/devextreme/testing/runner/index.js New Node.js server replacing the entire .NET runner
packages/devextreme/testing/runner/lib/vectormap.js Vector map service (spawning helper server, console app)
packages/devextreme/testing/runner/lib/utils.js Shared utilities (parsing, escaping, file I/O)
packages/devextreme/testing/runner/lib/templates.js Template renderer with escaping support
packages/devextreme/testing/runner/lib/suites.js Test suite/category discovery
packages/devextreme/testing/runner/lib/static.js Static file serving with directory listings
packages/devextreme/testing/runner/lib/results.js XML results generation and text reporting
packages/devextreme/testing/runner/lib/pages.js Page renderers (index, run-all, run-suite)
packages/devextreme/testing/runner/lib/logger.js Colored console + file logger
packages/devextreme/testing/runner/lib/http.js HTTP response helpers
packages/devextreme/testing/runner/templates/*.template.html HTML templates for runner UI pages
.github/actions/run-qunit-tests/action.yml Removed dotnet build CI step
.github/workflows/qunit_tests.yml Removed DOTNET env variables
packages/devextreme/package.json Removed dotnet build from dev script
packages/devextreme/project.json Removed DOTNET_* env pass-throughs
packages/devextreme/docker-ci.sh Updated runner startup command
packages/devextreme/testing/launch Updated to launch Node.js runner
All deleted C# files Legacy .NET runner source removed

@nightskylark nightskylark added the WIP Work in progress label Mar 5, 2026
Copilot AI review requested due to automatic review settings March 5, 2026 11:43
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 48 out of 48 changed files in this pull request and generated 2 comments.

}

export function isContinuousIntegration(): boolean {
return Boolean(process.env.CCNetWorkingDirectory ?? process.env.DEVEXTREME_TEST_CI);
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The isContinuousIntegration function uses the nullish coalescing operator ?? to check the two environment variables: Boolean(process.env.CCNetWorkingDirectory ?? process.env.DEVEXTREME_TEST_CI). The ?? operator only falls through to the right-hand side when the left side is null or undefined. If CCNetWorkingDirectory is set but empty (""), "" ?? process.env.DEVEXTREME_TEST_CI evaluates to "", and Boolean("") is false — so CI mode would not be detected even if DEVEXTREME_TEST_CI is also set.

The old C# implementation used an explicit OR: !IsNullOrEmpty(CCNetWorkingDirectory) || !IsNullOrEmpty(DEVEXTREME_TEST_CI), which correctly falls through to check DEVEXTREME_TEST_CI whenever CCNetWorkingDirectory is null, undefined, or empty.

The fix is to use the logical OR || operator instead: Boolean(process.env.CCNetWorkingDirectory || process.env.DEVEXTREME_TEST_CI).

Copilot uses AI. Check for mistakes.
Comment on lines +233 to +248
function executeVectorMapConsoleApp(
arg: string,
searchParams: URLSearchParams,
): VectorMapOutputItem[] {
const inputDirectory = `${path.join(packageRoot, 'testing', 'content', 'VectorMapData')}${path.sep}`;
const outputDirectory = path.join(inputDirectory, '__Output');
const settingsPath = path.join(inputDirectory, '_settings.js');
const processFileContentPath = path.join(inputDirectory, '_processFileContent.js');
const vectorMapUtilsNodePath = path.resolve(path.join(packageRoot, 'artifacts/js/vectormap-utils/dx.vectormaputils.node.js'));

const args = [vectorMapUtilsNodePath, inputDirectory];
const fileArgument = searchParams.get('file');
if (fileArgument !== null) {
args[1] += fileArgument;
}

Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The executeVectorMapConsoleApp function in vectormap.ts accepts an arg: string parameter (from the URL path) but never uses it in the function body. The function only uses searchParams and packageRoot to construct paths. While this matches the old C# controller behavior (the arg route parameter was also unused there), having an unused parameter in the function signature is misleading and may create confusion.

Copilot uses AI. Check for mistakes.
@nightskylark nightskylark removed the WIP Work in progress label Mar 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

26_1 github_actions Pull requests that update GitHub Actions code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants