diff --git a/.github/workflows/sanity-workflow.yml b/.github/workflows/sanity-workflow.yml
new file mode 100644
index 0000000..62c9a54
--- /dev/null
+++ b/.github/workflows/sanity-workflow.yml
@@ -0,0 +1,85 @@
+# This job is to test different profiles in sdk branch against full-commit id
+# This workflow targets nunit
+
+name: C-sharp Playwright SDK Test workflow on workflow_dispatch
+
+on:
+ workflow_dispatch:
+ inputs:
+ commit_sha:
+ description: 'The full commit id to build'
+ required: true
+
+jobs:
+ comment-run:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ max-parallel: 3
+ matrix:
+ dotnet: ['6.0.x', '5.0.x', '7.0.x']
+ os: [ windows-latest ]
+ name: NUnit Repo ${{ matrix.dotnet }} - ${{ matrix.os }} Sample
+ env:
+ BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
+ BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
+
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ ref: ${{ github.event.inputs.commit_sha }}
+ - uses: actions/github-script@98814c53be79b1d30f795b907e553d8679345975
+ id: status-check-in-progress
+ env:
+ job_name: NUnit Repo ${{ matrix.dotnet }} - ${{ matrix.os }} Sample
+ commit_sha: ${{ github.event.inputs.commit_sha }}
+ with:
+ github-token: ${{ github.token }}
+ script: |
+ const result = await github.rest.checks.create({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ name: process.env.job_name,
+ head_sha: process.env.commit_sha,
+ status: 'in_progress'
+ }).catch((err) => ({status: err.status, response: err.response}));
+ console.log(`The status-check response : ${result.status} Response : ${JSON.stringify(result.response)}`)
+ if (result.status !== 201) {
+ console.log('Failed to create check run')
+ }
+ - name: Setup dotnet
+ uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: ${{ matrix.dotnet }}
+
+ - name: Install dependencies
+ run: dotnet build
+
+ - name: Run sample tests
+ run: dotnet test --filter "Category=sample-test"
+
+ - name: Run local tests
+ run: dotnet test --filter "Category=sample-local-test"
+
+ - if: always()
+ uses: actions/github-script@98814c53be79b1d30f795b907e553d8679345975
+ id: status-check-completed
+ env:
+ conclusion: ${{ job.status }}
+ job_name: NUnit Repo ${{ matrix.dotnet }} - ${{ matrix.os }} Sample
+ commit_sha: ${{ github.event.inputs.commit_sha }}
+ with:
+ github-token: ${{ github.token }}
+ script: |
+ const result = await github.rest.checks.create({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ name: process.env.job_name,
+ head_sha: process.env.commit_sha,
+ status: 'completed',
+ conclusion: process.env.conclusion
+ }).catch((err) => ({status: err.status, response: err.response}));
+ console.log(`The status-check response : ${result.status} Response : ${JSON.stringify(result.response)}`)
+ if (result.status !== 201) {
+ console.log('Failed to create check run')
+ }
diff --git a/CSharp-Playwright-BrowserStack/CSharp-Playwright-BrowserStack.sln b/CSharp-Playwright-BrowserStack.sln
similarity index 88%
rename from CSharp-Playwright-BrowserStack/CSharp-Playwright-BrowserStack.sln
rename to CSharp-Playwright-BrowserStack.sln
index 9b579c6..d48a267 100644
--- a/CSharp-Playwright-BrowserStack/CSharp-Playwright-BrowserStack.sln
+++ b/CSharp-Playwright-BrowserStack.sln
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 25.0.1706.0
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharp-Playwright-BrowserStack", "CSharp-Playwright-BrowserStack.csproj", "{D309DDB3-1E3B-428B-B00B-1257F2532079}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharp-Playwright-BrowserStack", "CSharp-Playwright-BrowserStack\CSharp-Playwright-BrowserStack.csproj", "{D309DDB3-1E3B-428B-B00B-1257F2532079}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/CSharp-Playwright-BrowserStack/App.config b/CSharp-Playwright-BrowserStack/App.config
deleted file mode 100644
index 1aec018..0000000
--- a/CSharp-Playwright-BrowserStack/App.config
+++ /dev/null
@@ -1,64 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/CSharp-Playwright-BrowserStack/BrowserStackNUnitTest.cs b/CSharp-Playwright-BrowserStack/BrowserStackNUnitTest.cs
index 6c6cf8c..64dd56e 100644
--- a/CSharp-Playwright-BrowserStack/BrowserStackNUnitTest.cs
+++ b/CSharp-Playwright-BrowserStack/BrowserStackNUnitTest.cs
@@ -1,12 +1,8 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.Configuration;
-
-using Microsoft.Playwright;
+using Microsoft.Playwright;
using Newtonsoft.Json;
using NUnit.Framework;
using BrowserStack;
+using Newtonsoft.Json.Linq;
namespace CSharpPlaywrightBrowserStack
{
@@ -17,65 +13,68 @@ public class BrowserStackNUnitTest
protected IPage page;
protected string profile;
protected string environment;
+ protected string configFile;
+
private Local browserStackLocal;
- public BrowserStackNUnitTest(string profile, string environment)
+ public BrowserStackNUnitTest(string profile, string environment, string configFile)
{
this.profile = profile;
this.environment = environment;
+ this.configFile = configFile;
}
[SetUp]
public async Task Init()
{
- NameValueCollection? caps =
- ConfigurationManager.GetSection("capabilities/" + profile) as NameValueCollection;
- NameValueCollection? settings =
- ConfigurationManager.GetSection("environments/" + environment)
- as NameValueCollection;
+ // Get Configuration for correct profile
+ string currentDirectory = Directory.GetCurrentDirectory();
+ string path = Path.Combine(currentDirectory, configFile);
+ JObject config = JObject.Parse(File.ReadAllText(path));
+ if (config is null)
+ throw new Exception("Configuration not found!");
- NameValueCollection cc = (NameValueCollection) ConfigurationManager.AppSettings;
+ // Get Environment specific capabilities
+ JObject capabilitiesJsonArr = config.GetValue("environments") as JObject;
+ JObject capabilities = capabilitiesJsonArr.GetValue(environment) as JObject;
- Console.WriteLine("KAMAL " + settings + "-" + caps + "-" + profile + "-" + environment
- + cc["user"]);
+ // Get Common Capabilities
+ JObject commonCapabilities = config.GetValue("capabilities") as JObject;
- Dictionary browserstackOptions = new Dictionary
- {
- { "browserName", settings["browser"] }
- };
-
- foreach (string key in caps.AllKeys)
- {
- browserstackOptions.Add(key, caps[key]);
- }
+ // Merge Capabilities
+ capabilities.Merge(commonCapabilities);
- String username = Environment.GetEnvironmentVariable("BROWSERSTACK_USERNAME");
- if (username == null)
- {
- username = ConfigurationManager.AppSettings.Get("user");
- }
+ // Get username and accesskey
+ string? username = Environment.GetEnvironmentVariable("BROWSERSTACK_USERNAME");
+ if (username is null)
+ username = config.GetValue("user").ToString();
- String accesskey = Environment.GetEnvironmentVariable("BROWSERSTACK_ACCESS_KEY");
- if (accesskey == null)
- {
- accesskey = ConfigurationManager.AppSettings.Get("key");
- }
+ string? accessKey = Environment.GetEnvironmentVariable("BROWSERSTACK_ACCESS_KEY");
+ if (accessKey is null)
+ accessKey = config.GetValue("key").ToString();
- browserstackOptions.Add("userName", username);
- browserstackOptions.Add("accessKey", accesskey);
+ capabilities["browserstack.user"] = username;
+ capabilities["browserstack.key"] = accessKey;
- if (caps.Get("local").ToString() == "true")
+ // Start Local if browserstack.local is set to true
+ if (profile.Equals("local") && accessKey is not null)
{
+ capabilities["browserstack.local"] = true;
browserStackLocal = new Local();
- List> bsLocalArgs = new List<
- KeyValuePair
- >()
- {
- new KeyValuePair("key", accesskey)
+ List> bsLocalArgs = new List>() {
+ new KeyValuePair("key", accessKey)
};
+ foreach (var localOption in config.GetValue("localOptions") as JObject)
+ {
+ if (localOption.Value is not null)
+ {
+ bsLocalArgs.Add(new KeyValuePair(localOption.Key, localOption.Value.ToString()));
+ }
+ }
browserStackLocal.start(bsLocalArgs);
}
- string capsJson = JsonConvert.SerializeObject(browserstackOptions);
+
+ string capsJson = JsonConvert.SerializeObject(capabilities);
string cdpUrl = "wss://cdp.browserstack.com/playwright?caps=" + Uri.EscapeDataString(capsJson);
var playwright = await Playwright.CreateAsync();
@@ -86,10 +85,6 @@ public async Task Init()
[TearDown]
public async Task Cleanup()
{
- if (page != null)
- {
- page.CloseAsync();
- }
if (browser != null)
{
browser.CloseAsync();
@@ -99,5 +94,16 @@ public async Task Cleanup()
browserStackLocal.stop();
}
}
+
+ public static async Task SetStatus(IPage browserPage, bool passed)
+ {
+ if (browserPage is not null)
+ {
+ if (passed)
+ await browserPage.EvaluateAsync("_ => {}", "browserstack_executor: {\"action\": \"setSessionStatus\", \"arguments\": {\"status\":\"passed\", \"reason\": \"Test Passed!\"}}");
+ else
+ await browserPage.EvaluateAsync("_ => {}", "browserstack_executor: {\"action\": \"setSessionStatus\", \"arguments\": {\"status\":\"failed\", \"reason\": \"Test Failed!\"}}");
+ }
+ }
}
}
diff --git a/CSharp-Playwright-BrowserStack/CSharp-Playwright-BrowserStack.csproj b/CSharp-Playwright-BrowserStack/CSharp-Playwright-BrowserStack.csproj
index 0758da6..3421878 100644
--- a/CSharp-Playwright-BrowserStack/CSharp-Playwright-BrowserStack.csproj
+++ b/CSharp-Playwright-BrowserStack/CSharp-Playwright-BrowserStack.csproj
@@ -19,15 +19,21 @@
all
-
+
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
-
- Designer
-
-
+
+
+
-
-
-
-
\ No newline at end of file
+
diff --git a/CSharp-Playwright-BrowserStack/LocalTest.cs b/CSharp-Playwright-BrowserStack/LocalTest.cs
index 5201baf..c0aab93 100644
--- a/CSharp-Playwright-BrowserStack/LocalTest.cs
+++ b/CSharp-Playwright-BrowserStack/LocalTest.cs
@@ -1,24 +1,30 @@
using NUnit.Framework;
-using Microsoft.Playwright;
-using System.Text.RegularExpressions;
namespace CSharpPlaywrightBrowserStack
{
- [TestFixture("local", "chrome")]
+ [TestFixture("local", "chrome", "local.conf.json")]
[Category("sample-local-test")]
public class LocalTest : BrowserStackNUnitTest
{
- public LocalTest(string profile, string environment) : base(profile, environment) { }
+ public LocalTest(string profile, string environment, string configFile) : base(profile, environment, configFile) { }
[Test]
public async Task HealthCheck()
{
- // Navigate to the base url
- await page.GotoAsync("http://bs-local.com:45454/");
+ try
+ {
+ // Navigate to the base url
+ await page.GotoAsync("http://bs-local.com:45454/");
- // Verify if BrowserStackLocal running
- var title = await page.TitleAsync();
- StringAssert.Contains("BrowserStack Local", title);
+ // Verify if BrowserStackLocal running
+ var title = await page.TitleAsync();
+ StringAssert.Contains("BrowserStack Local", title);
+ SetStatus(page, title.Contains("BrowserStack Local"));
+ } catch (Exception)
+ {
+ SetStatus(page, false);
+ throw;
+ }
}
}
}
diff --git a/CSharp-Playwright-BrowserStack/ParallelTest.cs b/CSharp-Playwright-BrowserStack/ParallelTest.cs
index 73b39d7..2367ba0 100644
--- a/CSharp-Playwright-BrowserStack/ParallelTest.cs
+++ b/CSharp-Playwright-BrowserStack/ParallelTest.cs
@@ -2,14 +2,13 @@
namespace CSharpPlaywrightBrowserStack
{
- [TestFixture("parallel", "chrome")]
- [TestFixture("parallel", "firefox")]
- [TestFixture("parallel", "safari")]
- [TestFixture("parallel", "edge")]
+ [TestFixture("parallel", "chrome", "parallel.conf.json")]
+ [TestFixture("parallel", "playwright-firefox", "parallel.conf.json")]
+ [TestFixture("parallel", "playwright-webkit", "parallel.conf.json")]
[Parallelizable(ParallelScope.Fixtures)]
[Category("sample-parallel-test")]
public class ParallelTest : SingleTest
{
- public ParallelTest(string profile, string environment) : base(profile, environment) { }
+ public ParallelTest(string profile, string environment, string configFile) : base(profile, environment, configFile) { }
}
}
diff --git a/CSharp-Playwright-BrowserStack/README.md b/CSharp-Playwright-BrowserStack/README.md
new file mode 100644
index 0000000..141cd5e
--- /dev/null
+++ b/CSharp-Playwright-BrowserStack/README.md
@@ -0,0 +1,59 @@
+# csharp-playwright-browserstack
+Creating a sample repo for CSharp Playwright
+
+This sample elaborates the [NUnit](http://www.nunit.org/) Integration with BrowserStack.
+
+
+
+
+
+## Run Sample Build
+* Clone the repo
+* Open the solution `CSharp-Playwright-BrowserStack.sln` in Visual Studio
+* Build the solution
+* Update `browserstack.yml` file with your [BrowserStack Username and Access Key](https://www.browserstack.com/accounts/settings)
+
+### Running your tests from CLI
+- To run a single test, run test with fixture `sample-test` or test class `SingleTest`
+```sh
+dotnet test --filter "SingleTest"
+```
+- To run local tests, run test with fixture `sample-local-test` or test class `LocalTest`
+```sh
+dotnet test --filter "LocalTest"
+```
+- To run parallel tests, run test with fixture `sample-parallel-test` or test class `ParallelTest`
+```sh
+dotnet test --filter "ParallelTest"
+```
+
+ Understand how many parallel sessions you need by using our [Parallel Test Calculator](https://www.browserstack.com/automate/parallel-calculator?ref=github)
+
+## Notes
+* You can view your test results on the [BrowserStack automate dashboard](https://www.browserstack.com/automate)
+* To test on a different set of browsers, check out our [platform configurator](https://www.browserstack.com/automate/c-sharp#setting-os-and-browser)
+* You can export the environment variables for the Username and Access Key of your BrowserStack account
+
+ * For Unix-like or Mac machines:
+ ```
+ export BROWSERSTACK_USERNAME= &&
+ export BROWSERSTACK_ACCESS_KEY=
+ ```
+
+ * For Windows Cmd:
+ ```
+ set BROWSERSTACK_USERNAME=
+ set BROWSERSTACK_ACCESS_KEY=
+ ```
+
+ * For Windows Powershell:
+ ```
+ $env:BROWSERSTACK_USERNAME=
+ $env:BROWSERSTACK_ACCESS_KEY=
+ ```
+
+## Additional Resources
+* [Documentation for writing automate playwright test scripts in C#](https://www.browserstack.com/docs/automate/playwright/getting-started/c-sharp)
+* [Customizing your tests on BrowserStack](https://www.browserstack.com/automate/capabilities)
+* [Browsers & mobile devices for selenium testing on BrowserStack](https://www.browserstack.com/list-of-browsers-and-platforms?product=automate)
+* [Using REST API to access information about your tests via the command-line interface](https://www.browserstack.com/automate/rest-api)
diff --git a/CSharp-Playwright-BrowserStack/SingleTest.cs b/CSharp-Playwright-BrowserStack/SingleTest.cs
index deb4d7c..ea6d4bc 100644
--- a/CSharp-Playwright-BrowserStack/SingleTest.cs
+++ b/CSharp-Playwright-BrowserStack/SingleTest.cs
@@ -3,41 +3,51 @@
namespace CSharpPlaywrightBrowserStack
{
- [TestFixture("single", "chrome")]
+ [TestFixture("single", "chrome", "single.conf.json")]
[Category("sample-test")]
public class SingleTest : BrowserStackNUnitTest
{
- public SingleTest(string profile, string environment) : base(profile, environment) { }
+ public SingleTest(string profile, string environment, string configFile) : base(profile, environment, configFile) { }
[Test]
public async Task SearchBstackDemo()
{
- //Navigate to the bstackdemo url
- _ = await page.GotoAsync("https://bstackdemo.com/");
+ try
+ {
+ //Navigate to the bstackdemo url
+ _ = await page.GotoAsync("https://bstackdemo.com/");
- // Add the first item to cart
- await page.Locator("[id=\"\\31 \"]").GetByText("Add to Cart").ClickAsync();
- IReadOnlyList phone = await page.Locator("[id=\"\\31 \"]").Locator(".shelf-item__title").AllInnerTextsAsync();
- Console.WriteLine("Phone =>" + phone[0]);
+ // Add the first item to cart
+ await page.Locator("[id=\"\\31 \"]").GetByText("Add to Cart").ClickAsync();
+ IReadOnlyList phone = await page.Locator("[id=\"\\31 \"]").Locator(".shelf-item__title").AllInnerTextsAsync();
+ Console.WriteLine("Phone =>" + phone[0]);
- // Get the items from Cart
- IReadOnlyList quantity = await page.Locator(".bag__quantity").AllInnerTextsAsync();
- Console.WriteLine("Bag quantity =>" + quantity[0]);
+ // Get the items from Cart
+ IReadOnlyList quantity = await page.Locator(".bag__quantity").AllInnerTextsAsync();
+ Console.WriteLine("Bag quantity =>" + quantity[0]);
- // Verify if there is a shopping cart
- StringAssert.Contains("1", await page.Locator(".bag__quantity").InnerTextAsync());
+ // Verify if there is a shopping cart
+ StringAssert.Contains("1", await page.Locator(".bag__quantity").InnerTextAsync());
- //Get the handle for cart item
- ILocator cartItem = page.Locator(".shelf-item__details").Locator(".title");
+ //Get the handle for cart item
+ ILocator cartItem = page.Locator(".shelf-item__details").Locator(".title");
- // Verify if the cart has the right item
- StringAssert.Contains(await cartItem.InnerTextAsync(), string.Join(" ", phone));
- IReadOnlyList cartItemText = await cartItem.AllInnerTextsAsync();
- Console.WriteLine("Cart item => " + cartItemText[0]);
+ // Verify if the cart has the right item
+ StringAssert.Contains(await cartItem.InnerTextAsync(), string.Join(" ", phone));
+ IReadOnlyList cartItemText = await cartItem.AllInnerTextsAsync();
+ Console.WriteLine("Cart item => " + cartItemText[0]);
- Assert.Equals(cartItemText[0], phone[0]);
+ //Assert.Equals(cartItemText[0], phone[0]);
+ Assert.That(phone[0], Is.EqualTo(cartItemText[0]));
+
+ SetStatus(page, phone[0].Equals(cartItemText[0]));
+ } catch (Exception)
+ {
+ SetStatus(page, false);
+ throw;
+ }
}
}
}
diff --git a/CSharp-Playwright-BrowserStack/local.conf.json b/CSharp-Playwright-BrowserStack/local.conf.json
new file mode 100644
index 0000000..9773d50
--- /dev/null
+++ b/CSharp-Playwright-BrowserStack/local.conf.json
@@ -0,0 +1,21 @@
+{
+ "user": "BROWSERSTACK_USERNAME",
+ "key": "BROWSERSTACK_ACCESS_KEY",
+
+ "capabilities": {
+ "build": "browserstack-build-1",
+ "name": "BStack Playwright local test",
+ "browserstack.debug": true,
+ "browserstack.local": true
+ },
+
+ "environments": {
+ "chrome": {
+ "browser": "chrome"
+ }
+ },
+
+ "localOptions": {
+ "forceLocal": true
+ }
+}
diff --git a/CSharp-Playwright-BrowserStack/packages.config b/CSharp-Playwright-BrowserStack/packages.config
deleted file mode 100644
index 15fe6f2..0000000
--- a/CSharp-Playwright-BrowserStack/packages.config
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/CSharp-Playwright-BrowserStack/parallel.conf.json b/CSharp-Playwright-BrowserStack/parallel.conf.json
new file mode 100644
index 0000000..b94610b
--- /dev/null
+++ b/CSharp-Playwright-BrowserStack/parallel.conf.json
@@ -0,0 +1,23 @@
+{
+ "user": "BROWSERSTACK_USERNAME",
+ "key": "BROWSERSTACK_ACCESS_KEY",
+
+ "capabilities": {
+ "build": "browserstack-build-1",
+ "name": "BStack Playwright parallel test",
+ "browserstack.debug": true
+ },
+
+ "environments": {
+ "chrome": {
+ "browser": "chrome"
+ },
+ "playwright-webkit": {
+ "browser": "playwright-webkit"
+ },
+ "playwright-firefox": {
+ "os": "OS X",
+ "browser": "playwright-firefox"
+ }
+ }
+}
diff --git a/CSharp-Playwright-BrowserStack/single.conf.json b/CSharp-Playwright-BrowserStack/single.conf.json
new file mode 100644
index 0000000..c1aea43
--- /dev/null
+++ b/CSharp-Playwright-BrowserStack/single.conf.json
@@ -0,0 +1,16 @@
+{
+ "user": "BROWSERSTACK_USERNAME",
+ "key": "BROWSERSTACK_ACCESS_KEY",
+
+ "capabilities": {
+ "build": "browserstack-build-1",
+ "name": "BStack Playwright single test",
+ "browserstack.debug": true
+ },
+
+ "environments": {
+ "chrome": {
+ "browser": "chrome"
+ }
+ }
+}