Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
209 changes: 209 additions & 0 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
name: Tests
Copy link

Copilot AI Nov 15, 2025

Choose a reason for hiding this comment

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

Remove the UTF-8 BOM (Byte Order Mark) character at the beginning of the file. YAML files should be UTF-8 without BOM.

Suggested change
name: Tests
name: Tests

Copilot uses AI. Check for mistakes.

on:
push:
branches: [ develop, main ]
pull_request:
branches: [ develop, main ]

concurrency:
group: integration-tests-${{ github.ref }}
cancel-in-progress: true

jobs:
tests:
name: Integration Tests (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
rid: linux-x64
- os: windows-2022
rid: win-x64
- os: macos-14
rid: osx-arm64

env:
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
DOTNET_NOLOGO: 1
CI: true
ELECTRON_ENABLE_LOGGING: 1

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'

- name: Restore
run: dotnet restore -r ${{ matrix.rid }} -p:RuntimeIdentifier=${{ matrix.rid }} src/ElectronNET.IntegrationTests/ElectronNET.IntegrationTests.csproj

- name: Build
run: dotnet build --no-restore -c Release -r ${{ matrix.rid }} -p:RuntimeIdentifier=${{ matrix.rid }} src/ElectronNET.IntegrationTests/ElectronNET.IntegrationTests.csproj

- name: Install Linux GUI dependencies
if: runner.os == 'Linux'
run: |
set -e
sudo apt-get update
# Core Electron dependencies
sudo apt-get install -y xvfb \
libgtk-3-0 libnss3 libgdk-pixbuf-2.0-0 libdrm2 libgbm1 libxss1 libxtst6 libatk-bridge2.0-0 libatk1.0-0 libatspi2.0-0 libx11-xcb1 libasound2t64
- name: Run tests (Linux)
if: runner.os == 'Linux'
continue-on-error: true
run: |
mkdir -p test-results/Ubuntu
xvfb-run -a dotnet test src/ElectronNET.IntegrationTests/ElectronNET.IntegrationTests.csproj \
-c Release --no-build -r ${{ matrix.rid }} -p:RuntimeIdentifier=${{ matrix.rid }} \
--logger "trx;LogFileName=Ubuntu.trx" \
--logger "console;verbosity=detailed" \
--results-directory test-results
- name: Run tests (Windows)
if: runner.os == 'Windows'
continue-on-error: true
run: |
New-Item -ItemType Directory -Force -Path test-results/Windows | Out-Null
dotnet test src/ElectronNET.IntegrationTests/ElectronNET.IntegrationTests.csproj -c Release --no-build -r ${{ matrix.rid }} -p:RuntimeIdentifier=${{ matrix.rid }} --logger "trx;LogFileName=Windows.trx" --logger "console;verbosity=detailed" --results-directory test-results
- name: Run tests (macOS)
if: runner.os == 'macOS'
continue-on-error: true
run: |
mkdir -p test-results/macOS
dotnet test src/ElectronNET.IntegrationTests/ElectronNET.IntegrationTests.csproj -c Release --no-build -r ${{ matrix.rid }} -p:RuntimeIdentifier=${{ matrix.rid }} --logger "trx;LogFileName=macOS.trx" --logger "console;verbosity=detailed" --results-directory test-results
- name: Upload raw test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.os }}
path: test-results/*.trx
retention-days: 7

summary:
name: Test Results
runs-on: ubuntu-24.04
if: always()
needs: [tests]

permissions:
actions: read
contents: read
checks: write
pull-requests: write

steps:
- name: Download all test results
uses: actions/download-artifact@v4
with:
path: test-results

- name: Setup .NET (for CTRF conversion)
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'

- name: Install CTRF TRX→CTRF converter (dotnet tool)
run: |
dotnet new tool-manifest
dotnet tool install DotnetCtrfJsonReporter --local
- name: Convert TRX → CTRF and clean names (keep suites; set filePath=OS)
shell: bash
run: |
set -euo pipefail
mkdir -p ctrf
shopt -s globstar nullglob
conv=0
for trx in test-results/**/*.trx; do
fname="$(basename "$trx")"
os="${fname%.trx}"
outdir="ctrf/${os}"
mkdir -p "$outdir"
out="${outdir}/ctrf-report.json"
dotnet tool run DotnetCtrfJsonReporter -p "$trx" -d "$outdir" -f "ctrf-report.json"
jq --arg os "$os" '.results.tests |= map(.filePath = $os)' "$out" > "${out}.tmp" && mv "${out}.tmp" "$out"
echo "Converted & normalized $trx -> $out"
conv=$((conv+1))
done
echo "Processed $conv TRX file(s)"
- name: Publish Test Report
if: always()
uses: ctrf-io/github-test-reporter@v1
with:
report-path: 'ctrf/**/*.json'

summary: true
pull-request: false
status-check: false
status-check-name: 'Integration Tests'
use-suite-name: true
update-comment: true
always-group-by: true
overwrite-comment: true
exit-on-fail: true
group-by: 'suite'
upload-artifact: true
fetch-previous-results: true

summary-report: false
summary-delta-report: true
github-report: true
test-report: false
test-list-report: false
failed-report: true
failed-folded-report: false
skipped-report: true
suite-folded-report: true
suite-list-report: false
file-report: true
previous-results-report: true
insights-report: true
flaky-report: true
flaky-rate-report: true
fail-rate-report: false
slowest-report: false

report-order: 'summary-delta-report,failed-report,skipped-report,suite-folded-report,file-report,previous-results-report,github-report'
env:
GITHUB_TOKEN: ${{ github.token }}


- name: Create PR Comment
if: always()
uses: ctrf-io/github-test-reporter@v1
with:
report-path: 'ctrf/**/*.json'

summary: true
pull-request: true
use-suite-name: true
update-comment: true
always-group-by: true
overwrite-comment: true
upload-artifact: false

pull-request-report: true
env:
GITHUB_TOKEN: ${{ github.token }}

- name: Summary
run: echo "All matrix test jobs completed."
2 changes: 2 additions & 0 deletions src/ElectronNET.API/ElectronNetRuntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ static ElectronNetRuntime()
StartupManager.Initialize();
}

public static string ElectronExtraArguments { get; set; }

public static int? ElectronSocketPort { get; internal set; }

public static int? AspNetWebPort { get; internal set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ protected override Task StartCore()
{
var isUnPacked = ElectronNetRuntime.StartupMethod.IsUnpackaged();
var electronBinaryName = ElectronNetRuntime.ElectronExecutable;
var args = Environment.CommandLine;
var args = string.Format("{0} {1}", ElectronNetRuntime.ElectronExtraArguments, Environment.CommandLine).Trim();
this.port = ElectronNetRuntime.ElectronSocketPort;

if (!this.port.HasValue)
Expand All @@ -49,10 +49,15 @@ protected override Task StartCore()
ElectronNetRuntime.ElectronSocketPort = this.port;
}

Console.Error.WriteLine("[StartCore]: isUnPacked: {0}", isUnPacked);
Console.Error.WriteLine("[StartCore]: electronBinaryName: {0}", electronBinaryName);
Console.Error.WriteLine("[StartCore]: args: {0}", args);

this.electronProcess = new ElectronProcessActive(isUnPacked, electronBinaryName, args, this.port.Value);
this.electronProcess.Ready += this.ElectronProcess_Ready;
this.electronProcess.Stopped += this.ElectronProcess_Stopped;

Console.Error.WriteLine("[StartCore]: Before Start");
Comment on lines +52 to +60
Copy link

Copilot AI Nov 15, 2025

Choose a reason for hiding this comment

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

Remove debugging Console.Error.WriteLine statements before merging to production. These appear to be temporary diagnostic logs that should be removed or replaced with proper logging infrastructure.

Suggested change
Console.Error.WriteLine("[StartCore]: isUnPacked: {0}", isUnPacked);
Console.Error.WriteLine("[StartCore]: electronBinaryName: {0}", electronBinaryName);
Console.Error.WriteLine("[StartCore]: args: {0}", args);
this.electronProcess = new ElectronProcessActive(isUnPacked, electronBinaryName, args, this.port.Value);
this.electronProcess.Ready += this.ElectronProcess_Ready;
this.electronProcess.Stopped += this.ElectronProcess_Stopped;
Console.Error.WriteLine("[StartCore]: Before Start");
this.electronProcess = new ElectronProcessActive(isUnPacked, electronBinaryName, args, this.port.Value);
this.electronProcess.Ready += this.ElectronProcess_Ready;
this.electronProcess.Stopped += this.ElectronProcess_Stopped;

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Nov 15, 2025

Choose a reason for hiding this comment

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

Remove debugging Console.Error.WriteLine statements before merging to production. These appear to be temporary diagnostic logs that should be removed or replaced with proper logging infrastructure.

Suggested change
Console.Error.WriteLine("[StartCore]: Before Start");

Copilot uses AI. Check for mistakes.
return this.electronProcess.Start();
}

Expand Down Expand Up @@ -82,11 +87,11 @@ private void ElectronProcess_Stopped(object sender, EventArgs e)

private void HandleStopped()
{
if (this.socketBridge.State != LifetimeState.Stopped)
if (this.socketBridge != null && this.socketBridge.State != LifetimeState.Stopped)
{
this.socketBridge.Stop();
}
else if (this.electronProcess.State != LifetimeState.Stopped)
else if (this.electronProcess != null && this.electronProcess.State != LifetimeState.Stopped)
{
this.electronProcess.Stop();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading.Tasks;

/// <summary>
Expand Down Expand Up @@ -42,6 +43,11 @@ protected override Task StartCore()
var electrondir = Path.Combine(dir.FullName, ".electron");
startCmd = Path.Combine(electrondir, "node_modules", "electron", "dist", "electron");

if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
startCmd = Path.Combine(electrondir, "node_modules", "electron", "dist", "Electron.app", "Contents", "MacOS", "Electron");
}

args = $"main.js -unpackeddotnet --trace-warnings -electronforcedport={this.socketPort:D} " + this.extraArguments;
workingDir = electrondir;
}
Expand All @@ -68,22 +74,40 @@ protected override Task StopCore()

private async Task StartInternal(string startCmd, string args, string directoriy)
{
await Task.Delay(10).ConfigureAwait(false);
try
{
await Task.Delay(10).ConfigureAwait(false);

this.process = new ProcessRunner("ElectronRunner");
this.process.ProcessExited += this.Process_Exited;
this.process.Run(startCmd, args, directoriy);
Console.Error.WriteLine("[StartInternal]: startCmd: {0}", startCmd);
Console.Error.WriteLine("[StartInternal]: args: {0}", args);
Comment on lines +81 to +82
Copy link

Copilot AI Nov 15, 2025

Choose a reason for hiding this comment

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

Remove debugging Console.Error.WriteLine statements before merging to production. These appear to be temporary diagnostic logs that should be removed or replaced with proper logging infrastructure.

Copilot uses AI. Check for mistakes.

await Task.Delay(500).ConfigureAwait(false);
this.process = new ProcessRunner("ElectronRunner");
this.process.ProcessExited += this.Process_Exited;
this.process.Run(startCmd, args, directoriy);

if (!this.process.IsRunning)
{
Task.Run(() => this.TransitionState(LifetimeState.Stopped));
await Task.Delay(500).ConfigureAwait(false);

throw new Exception("Failed to launch the Electron process.");
}
Console.Error.WriteLine("[StartInternal]: after run:");
Copy link

Copilot AI Nov 15, 2025

Choose a reason for hiding this comment

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

Remove debugging Console.Error.WriteLine statements before merging to production. These appear to be temporary diagnostic logs that should be removed or replaced with proper logging infrastructure.

Copilot uses AI. Check for mistakes.

if (!this.process.IsRunning)
{
Console.Error.WriteLine("[StartInternal]: Process is not running: " + this.process.StandardError);
Console.Error.WriteLine("[StartInternal]: Process is not running: " + this.process.StandardOutput);
Comment on lines +94 to +95
Copy link

Copilot AI Nov 15, 2025

Choose a reason for hiding this comment

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

Remove debugging Console.Error.WriteLine statements before merging to production. These appear to be temporary diagnostic logs that should be removed or replaced with proper logging infrastructure.

Copilot uses AI. Check for mistakes.

this.TransitionState(LifetimeState.Ready);
Task.Run(() => this.TransitionState(LifetimeState.Stopped));

throw new Exception("Failed to launch the Electron process.");
}

this.TransitionState(LifetimeState.Ready);
}
catch (Exception ex)
{
Console.Error.WriteLine("[StartInternal]: Exception: " + this.process?.StandardError);
Console.Error.WriteLine("[StartInternal]: Exception: " + this.process?.StandardOutput);
Console.Error.WriteLine("[StartInternal]: Exception: " + ex);
Comment on lines +106 to +108
Copy link

Copilot AI Nov 15, 2025

Choose a reason for hiding this comment

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

Remove debugging Console.Error.WriteLine statements before merging to production. These appear to be temporary diagnostic logs that should be removed or replaced with proper logging infrastructure.

Copilot uses AI. Check for mistakes.
throw;
}
}

private void Process_Exited(object sender, EventArgs e)
Expand Down
6 changes: 6 additions & 0 deletions src/ElectronNET.API/Runtime/StartupManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,19 @@ private BuildInfo GatherBuildInfo()

if (electronAssembly == null)
{
Console.WriteLine("GatherBuildInfo: Early exit");
return buildInfo;
}

if (electronAssembly.GetName().Name == "testhost" || electronAssembly.GetName().Name == "ReSharperTestRunner")
{
Console.WriteLine("GatherBuildInfo: Detected testhost");
electronAssembly = AppDomain.CurrentDomain.GetData("ElectronTestAssembly") as Assembly ?? electronAssembly;
}
else
{
Console.WriteLine("GatherBuildInfo: No testhost detected: " + electronAssembly.GetName().Name);
Comment on lines +135 to +146
Copy link

Copilot AI Nov 15, 2025

Choose a reason for hiding this comment

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

Remove debugging Console.WriteLine statements before merging to production. These appear to be temporary diagnostic logs that should be removed or replaced with proper logging infrastructure.

Suggested change
Console.WriteLine("GatherBuildInfo: Early exit");
return buildInfo;
}
if (electronAssembly.GetName().Name == "testhost" || electronAssembly.GetName().Name == "ReSharperTestRunner")
{
Console.WriteLine("GatherBuildInfo: Detected testhost");
electronAssembly = AppDomain.CurrentDomain.GetData("ElectronTestAssembly") as Assembly ?? electronAssembly;
}
else
{
Console.WriteLine("GatherBuildInfo: No testhost detected: " + electronAssembly.GetName().Name);
return buildInfo;
}
if (electronAssembly.GetName().Name == "testhost" || electronAssembly.GetName().Name == "ReSharperTestRunner")
{
electronAssembly = AppDomain.CurrentDomain.GetData("ElectronTestAssembly") as Assembly ?? electronAssembly;
}
else
{
// No testhost detected

Copilot uses AI. Check for mistakes.
Comment on lines +135 to +146
Copy link

Copilot AI Nov 15, 2025

Choose a reason for hiding this comment

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

Remove debugging Console.WriteLine statements before merging to production. These appear to be temporary diagnostic logs that should be removed or replaced with proper logging infrastructure.

Suggested change
Console.WriteLine("GatherBuildInfo: Early exit");
return buildInfo;
}
if (electronAssembly.GetName().Name == "testhost" || electronAssembly.GetName().Name == "ReSharperTestRunner")
{
Console.WriteLine("GatherBuildInfo: Detected testhost");
electronAssembly = AppDomain.CurrentDomain.GetData("ElectronTestAssembly") as Assembly ?? electronAssembly;
}
else
{
Console.WriteLine("GatherBuildInfo: No testhost detected: " + electronAssembly.GetName().Name);
return buildInfo;
}
if (electronAssembly.GetName().Name == "testhost" || electronAssembly.GetName().Name == "ReSharperTestRunner")
{
electronAssembly = AppDomain.CurrentDomain.GetData("ElectronTestAssembly") as Assembly ?? electronAssembly;
}
else
{
// No testhost detected

Copilot uses AI. Check for mistakes.
Comment on lines +135 to +146
Copy link

Copilot AI Nov 15, 2025

Choose a reason for hiding this comment

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

Remove debugging Console.WriteLine statements before merging to production. These appear to be temporary diagnostic logs that should be removed or replaced with proper logging infrastructure.

Suggested change
Console.WriteLine("GatherBuildInfo: Early exit");
return buildInfo;
}
if (electronAssembly.GetName().Name == "testhost" || electronAssembly.GetName().Name == "ReSharperTestRunner")
{
Console.WriteLine("GatherBuildInfo: Detected testhost");
electronAssembly = AppDomain.CurrentDomain.GetData("ElectronTestAssembly") as Assembly ?? electronAssembly;
}
else
{
Console.WriteLine("GatherBuildInfo: No testhost detected: " + electronAssembly.GetName().Name);
return buildInfo;
}
if (electronAssembly.GetName().Name == "testhost" || electronAssembly.GetName().Name == "ReSharperTestRunner")
{
electronAssembly = AppDomain.CurrentDomain.GetData("ElectronTestAssembly") as Assembly ?? electronAssembly;
}
else
{

Copilot uses AI. Check for mistakes.
}

var attributes = electronAssembly.GetCustomAttributes<AssemblyMetadataAttribute>().ToList();

Expand Down
Loading
Loading