Skip to content

Commit

Permalink
CI for UI Tests Infrastructure Update (#88)
Browse files Browse the repository at this point in the history
CLOSE
https://linear.app/sourcegraph/issue/CODY-2816/ci-for-visual-studio-integration-tests-based-on-vsixtesting

UI Tests infrastructure (`Cody.VisualStudio.Tests`) updated to allow running them, not only locally which were running fine from the very beginning, but also using GitHub Actions.

### Fixed threading issues only seen in GitHub Actions:
- VsixTesting runner exception: `Call was Rejected By Callee` ([more about it](https://learn.microsoft.com/en-us/previous-versions/ms228772(v=vs.140)?redirectedfrom=MSDN)), caused PlaywrightTestsBase.InitializeAsync() was called multiple times, which internally tries to call VS API, when XUnit was creating instances of all involved test classes
- Removed calls to VS API from TestBase constructor, which have the same effect as above

### Other Updates
- Added logging via XUnit logger, which calls our Logger internally and gives us detailed logs from tests (including all logs that are logged in the VS Cody output pane during run-time)
- Getting IDE to the front when "Start Window" appears (call to DismissStartWindow())
- WaitForAsync() waits maximum 2 minutes (for the chat loading)
- Added CollectionBehavior.CollectionPerAssembly and DisableTestParallelization = true for XUnit

Improved PlaywrightTestsBase:
  - Introduced SemaphoreSlim() for synchronization
  - Playwright related properties (Browser, Context, Page and Playwright) are now static
  • Loading branch information
PiotrKarczmarz authored Sep 11, 2024
1 parent a524ee1 commit c93eb6e
Show file tree
Hide file tree
Showing 13 changed files with 248 additions and 95 deletions.
14 changes: 9 additions & 5 deletions .github/workflows/cake-build.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Cake Build
name: Cake Build

on:
push:
Expand All @@ -17,6 +17,9 @@ jobs:
- name: Add msbuild to PATH
uses: microsoft/[email protected]

- name: ⚙️ Prepare Visual Studio
run: '&"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\devenv.exe" /RootSuffix Exp /ResetSettings General.vssettings'

- name: Install Cake.Tool
run: dotnet tool install --global Cake.Tool

Expand All @@ -31,7 +34,8 @@ jobs:
corepack install --global [email protected]
dotnet cake
#- name: Tests
# run: |
# cd src
# dotnet cake --target Tests
- name: Tests
run: |
cd src
dotnet cake --target Tests
dotnet test .\Cody.VisualStudio.Tests\bin\Debug\Cody.VisualStudio.Tests.dll -v detailed
1 change: 1 addition & 0 deletions src/Cody.Core/Cody.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
<Compile Include="DocumentSync\IDocumentSyncActions.cs" />
<Compile Include="Infrastructure\ISecretStorageService.cs" />
<Compile Include="Infrastructure\IProgressService.cs" />
<Compile Include="Logging\ITestLogger.cs" />
<Compile Include="Workspace\IFileService.cs" />
<Compile Include="Ide\IVsVersionService.cs" />
<Compile Include="Infrastructure\WebViewsManager.cs" />
Expand Down
9 changes: 9 additions & 0 deletions src/Cody.Core/Logging/ITestLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Runtime.CompilerServices;

namespace Cody.Core.Logging
{
public interface ITestLogger
{
void WriteLog(string message, string type = "", [CallerMemberName] string callerName = "");
}
}
16 changes: 14 additions & 2 deletions src/Cody.Core/Logging/Logger.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
using System;
using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;

namespace Cody.Core.Logging
{
public class Logger: ILog
public class Logger : ILog
{
private IOutputWindowPane _outputWindowPane;
private ITestLogger _testLogger;

public Logger()
{
Expand All @@ -20,6 +21,7 @@ public void Info(string message, [CallerMemberName] string callerName = "")
// TODO: _fileLogger.Info(customMessage);
DebugWrite(customMessage);
_outputWindowPane?.Info(message, callerName);
_testLogger?.WriteLog(message, "INFO", callerName);
}

public void Debug(string message, [CallerMemberName] string callerName = "", [CallerFilePath] string callerFilePath = null)
Expand All @@ -32,6 +34,7 @@ public void Debug(string message, [CallerMemberName] string callerName = "", [Ca
// TODO: _fileLogger.Debug(customMessage);
DebugWrite(customMessage);
_outputWindowPane?.Debug(message, callerName);
_testLogger?.WriteLog(message, "DEBUG", callerName);
#endif
}

Expand All @@ -48,6 +51,7 @@ public void Warn(string message, [CallerMemberName] string callerName = "")
// TODO: _fileLogger.Warn(customMessage);
DebugWrite(message);
_outputWindowPane?.Warn(message, callerName);
_testLogger?.WriteLog(message, "WARN", callerName);
}

public void Error(string message, [CallerMemberName] string callerName = "")
Expand All @@ -57,6 +61,7 @@ public void Error(string message, [CallerMemberName] string callerName = "")
// TODO: _fileLogger.Error(customMessage);
DebugWrite(customMessage);
_outputWindowPane?.Error(message, callerName);
_testLogger?.WriteLog(message, "ERROR", callerName);
}

public void Error(string message, Exception ex, [CallerMemberName] string callerName = "")
Expand All @@ -77,6 +82,7 @@ public void Error(string message, Exception ex, [CallerMemberName] string caller
// TODO: _fileLogger.Error(originalException, customMessage);
DebugWrite(customMessage);
_outputWindowPane?.Error(outputMessage, callerName);
_testLogger?.WriteLog(message, "ERROR", callerName);
}

public Logger WithOutputPane(IOutputWindowPane outputWindowPane)
Expand All @@ -85,6 +91,12 @@ public Logger WithOutputPane(IOutputWindowPane outputWindowPane)
return this;
}

public Logger WithTestLogger(ITestLogger testLogger)
{
_testLogger = testLogger;
return this;
}

public Logger Build()
{
return this;
Expand Down
78 changes: 52 additions & 26 deletions src/Cody.VisualStudio.Tests/ChatLoggedBasicTests.cs
Original file line number Diff line number Diff line change
@@ -1,57 +1,83 @@
using EnvDTE;
using Microsoft.VisualStudio.Shell;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;

namespace Cody.VisualStudio.Tests
{
public class ChatLoggedBasicTests: PlaywrightInitializationTests
{
[VsFact(Version = VsVersion.VS2022)]
public ChatLoggedBasicTests(ITestOutputHelper output) : base(output)
{
}

//[VsFact(Version = VsVersion.VS2022)]
public async Task Loads_Properly_InLoggedState()
{
// given
await WaitForPlaywrightAsync();

// when
var text = "Prompts & Commands";
var getStarted = Page.GetByText(text);
var textContents = await getStarted.AllTextContentsAsync();
var codyPackage = await GetPackageAsync();
var settingsService = codyPackage.UserSettingsService;
var accessToken = codyPackage.UserSettingsService.AccessToken;

var text = "Cody Free or Cody Pro";
IReadOnlyList<string> textContents;
try
{
await WaitForPlaywrightAsync();
codyPackage.UserSettingsService.AccessToken += "INVALID";
await Task.Delay(TimeSpan.FromMilliseconds(500)); // wait for the Chat to response

// when

var getStarted = Page.GetByText(text);
textContents = await getStarted.AllTextContentsAsync();
}
finally
{
settingsService.AccessToken = accessToken; // make it valid
}

// then
Assert.Equal(text, textContents.First());
}

[VsFact(Version = VsVersion.VS2022)]
public async Task Solution_name_is_added_to_chat_input()
//[VsFact(Version = VsVersion.VS2022)]
public async Task Solution_Name_Is_Added_To_Chat_Input()
{
// given
OpenSolution(SolutionsPaths.GetConsoleApp1File("ConsoleApp1.sln"));
await WaitForPlaywrightAsync();

// when
var tags = await GetChatContextTags();

Assert.Equal("ConsoleApp1", tags.First().Name);
// then
Assert.Equal("ConsoleApp1", tags.Last().Name);
}

[VsFact(Version = VsVersion.VS2022)]
public async Task Active_file_name_and_line_selection_is_showing_in_chat_input()
//[VsFact(Version = VsVersion.VS2022)]
public async Task Active_File_Name_And_Line_Selection_Is_Showing_In_Chat_Input()
{
const int startLine = 3; const int endLine = 5;

// given
OpenSolution(SolutionsPaths.GetConsoleApp1File("ConsoleApp1.sln"));
await WaitForPlaywrightAsync();

// when
const int startLine = 3; const int endLine = 5;
await OpenDocument(SolutionsPaths.GetConsoleApp1File(@"ConsoleApp1\Manager.cs"), startLine, endLine);
var tags = await GetChatContextTags();

Assert.Equal("Manager.cs", tags.Last().Name);
Assert.Equal(startLine, tags.Last().StartLine);
Assert.Equal(endLine, tags.Last().EndLine);
// then
var firstTagName = tags.First().Name;
var secondTag = tags.ElementAt(1);
Assert.Equal("Manager.cs", firstTagName);
Assert.Equal(startLine, secondTag.StartLine);
Assert.Equal(endLine, secondTag.EndLine);
}

[VsFact(Version = VsVersion.VS2022)]
//[VsFact(Version = VsVersion.VS2022)]
public async Task Can_you_close_and_reopen_chat_tool_window()
{
await WaitForPlaywrightAsync();
Expand All @@ -65,22 +91,22 @@ public async Task Can_you_close_and_reopen_chat_tool_window()
Assert.True(isOpen);
}

[VsFact(Version = VsVersion.VS2022)]
//[VsFact(Version = VsVersion.VS2022)]
public async Task Does_chat_history_show_up_after_you_have_submitting_a_chat_close_and_reopen_window()
{
int num = new Random().Next();
string propt = $"How to create const with value {num}?";
var num = new Random().Next();
var prompt = $"How to create const with value {num}?";

await WaitForPlaywrightAsync();

await EnterChatTextAndSend(propt);
await EnterChatTextAndSend(prompt);
await CloseCodyChatToolWindow();

await OpenCodyChatToolWindow();
await ShowHistoryTab();
var chatHistoryEntries = await GetTodaysChatHistory();
var chatHistoryEntries = await GetTodayChatHistory();

Assert.Contains(chatHistoryEntries, x => x.Contains(propt));
Assert.Contains(chatHistoryEntries, x => x.Contains(prompt));

}
}
Expand Down
42 changes: 26 additions & 16 deletions src/Cody.VisualStudio.Tests/ChatNotLoggedStateTests.cs
Original file line number Diff line number Diff line change
@@ -1,34 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Cody.VisualStudio.Options;
using Xunit;
using Xunit.Abstractions;

namespace Cody.VisualStudio.Tests
{
public class ChatNotLoggedStateTests : PlaywrightTestsBase
{
// WIP
//[VsFact(Version = VsVersion.VS2022)]
public ChatNotLoggedStateTests(ITestOutputHelper output) : base(output)
{
}

[VsFact(Version = VsVersion.VS2022)]
public async Task Loads_Properly_InNotLoggedState()
{
// given
await GetPackageAsync();
CodyPackage.ShowOptionPage(typeof(GeneralOptionsPage));
await Task.Delay(TimeSpan.FromSeconds(1)); // HACK: properly wait for Options page
// TODO: Replace SourcegraphUrl with Token value
var accessToken = CodyPackage.GeneralOptionsViewModel.SourcegraphUrl;
CodyPackage.GeneralOptionsViewModel.SourcegraphUrl = $"{accessToken}INVALID"; // make it invalid
var codyPackage = await GetPackageAsync();
var settingsService = codyPackage.UserSettingsService;
var accessToken = codyPackage.UserSettingsService.AccessToken;

await WaitForPlaywrightAsync();


// when
var text = "Cody Free or Cody Pro";
var getStarted = Page.GetByText(text);
var textContents = await getStarted.AllTextContentsAsync();
IReadOnlyList<string> textContents;
try
{
await WaitForPlaywrightAsync();
codyPackage.UserSettingsService.AccessToken += "INVALID";
await Task.Delay(TimeSpan.FromMilliseconds(500)); // wait for the Chat to response

// when

CodyPackage.GeneralOptionsViewModel.SourcegraphUrl = $"{accessToken}"; // make it valid
var getStarted = Page.GetByText(text);
textContents = await getStarted.AllTextContentsAsync();
}
finally
{
if (accessToken != null)
settingsService.AccessToken = accessToken; // make it valid
}

// then
Assert.Equal(text, textContents.First());
Expand Down
8 changes: 4 additions & 4 deletions src/Cody.VisualStudio.Tests/CodyPackageTests.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
using System;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Navigation;
using Cody.UI.ViewModels;
using Xunit;
using Xunit.Abstractions;

namespace Cody.VisualStudio.Tests
{
public class CodyPackageTests : TestsBase
{
public CodyPackageTests(ITestOutputHelper output) : base(output)
{
}

[VsFact(Version = VsVersion.VS2022)]
public async Task CodyPackage_Loaded_OnDemand()
Expand Down
4 changes: 4 additions & 0 deletions src/Cody.VisualStudio.Tests/PlaywrightInitializationTests.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
using System.Linq;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;

namespace Cody.VisualStudio.Tests
{
public class PlaywrightInitializationTests : PlaywrightTestsBase
{
public PlaywrightInitializationTests(ITestOutputHelper output) : base(output)
{
}

[VsFact(Version = VsVersion.VS2022)]
public async Task Playwright_Connects_OvercCDP()
Expand Down
Loading

0 comments on commit c93eb6e

Please sign in to comment.