(Refactor) : Converted Selenium test for CanUseWebhooks and Others to playwright (#6923)

* (Test):Converted/Added Playwright Test for CanUseAwaitProgressForInProgressPayout

Signed-off-by: Abhijay jain <Abhijay007j@gmail.com>

* (Refactor): Removed Selenium Test for CanUseAwaitProgressForInProgressPayout

Signed-off-by: Abhijay jain <Abhijay007j@gmail.com>

* (Test):Converted/Added Playwright Test for CanUseWebhooks

Signed-off-by: Abhijay jain <Abhijay007j@gmail.com>

* (Refactor): Removed Selenium Test for CanUseWebhooks

Signed-off-by: Abhijay jain <Abhijay007j@gmail.com>

---------

Signed-off-by: Abhijay jain <Abhijay007j@gmail.com>
This commit is contained in:
Abhijay Jain
2025-09-22 13:39:00 +05:30
committed by GitHub
parent 3a324e19dc
commit 5e9dca19d5
2 changed files with 171 additions and 173 deletions

View File

@@ -5,6 +5,7 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using BTCPayServer.Abstractions.Models;
using BTCPayServer.Client;
@@ -29,6 +30,7 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Playwright;
using static Microsoft.Playwright.Assertions;
using NBitcoin;
using NBitcoin.DataEncoders;
using NBitcoin.Payment;
using NBXplorer;
using NBXplorer.Models;
@@ -2004,6 +2006,174 @@ namespace BTCPayServer.Tests
}
}
[Fact]
public async Task CanUseAwaitProgressForInProgressPayout()
{
await using var s = CreatePlaywrightTester();
await s.StartAsync();
await s.RegisterNewUser(true);
await s.CreateNewStore();
await s.GenerateWallet(isHotWallet: true);
await s.FundStoreWallet(denomination: 50.0m);
await s.GoToStore(s.StoreId, StoreNavPages.PayoutProcessors);
await s.Page.ClickAsync("#Configure-BTC-CHAIN");
await s.Page.SetCheckedAsync("#ProcessNewPayoutsInstantly", true);
await s.ClickPagePrimary();
await s.GoToStore(s.StoreId, StoreNavPages.PullPayments);
await s.ClickPagePrimary();
await s.Page.FillAsync("#Name", "PP1");
await s.Page.FillAsync("#Amount", "99.0");
await s.Page.SetCheckedAsync("#AutoApproveClaims", true);
await s.ClickPagePrimary();
await s.Page.ClickAsync("text=View");
var newPage = await s.Page.Context.WaitForPageAsync();
var address = await s.Server.ExplorerNode.GetNewAddressAsync();
await newPage.FillAsync("#Destination", address.ToString());
await newPage.PressAsync("#Destination", "Enter");
await s.GoToStore(s.StoreId, StoreNavPages.Payouts);
await s.Page.ClickAsync("#InProgress-view");
// Wait for the payment processor to process the payment
await TestUtils.EventuallyAsync(async () =>
{
await s.Page.ReloadAsync();
var massActionSelect = s.Page.Locator(".mass-action-select-all[data-payout-state='InProgress']");
await Expect(massActionSelect).ToBeVisibleAsync();
});
await s.Page.ClickAsync(".mass-action-select-all[data-payout-state='InProgress']");
await s.Page.ClickAsync("#InProgress-mark-awaiting-payment");
await s.Page.ClickAsync("#AwaitingPayment-view");
var pageContent = await s.Page.ContentAsync();
Assert.Contains("PP1", pageContent);
}
[Fact]
public async Task CanUseWebhooks()
{
await using var s = CreatePlaywrightTester();
await s.StartAsync();
await s.RegisterNewUser(true);
await s.CreateNewStore();
await s.GoToStore(StoreNavPages.Webhooks);
TestLogs.LogInformation("Let's create two webhooks");
for (var i = 0; i < 2; i++)
{
await s.ClickPagePrimary();
await s.Page.FillAsync("[name='PayloadUrl']", $"http://127.0.0.1/callback{i}");
await s.Page.SelectOptionAsync("#Everything", "false");
await s.Page.ClickAsync("#InvoiceCreated");
await s.Page.ClickAsync("#InvoiceProcessing");
await s.ClickPagePrimary();
}
TestLogs.LogInformation("Let's delete one of them");
var deleteLinks = await s.Page.Locator("a:has-text('Delete')").AllAsync();
Assert.Equal(2, deleteLinks.Count);
await deleteLinks[0].ClickAsync();
await s.Page.FillAsync("#ConfirmInput", "DELETE");
await s.Page.ClickAsync("#ConfirmContinue");
deleteLinks = await s.Page.Locator("a:has-text('Delete')").AllAsync();
Assert.Single(deleteLinks);
await s.FindAlertMessage();
TestLogs.LogInformation("Let's try to update one of them");
await s.Page.ClickAsync("text=Modify");
using var server = new FakeServer();
await server.Start();
await s.Page.FillAsync("[name='PayloadUrl']", server.ServerUri.AbsoluteUri);
await s.Page.FillAsync("[name='Secret']", "HelloWorld");
await s.Page.ClickAsync("[name='update']");
await s.FindAlertMessage();
await s.Page.ClickAsync("text=Modify");
// Check which events are selected
var pageContent = await s.Page.ContentAsync();
Assert.Contains("value=\"InvoiceProcessing\" checked", pageContent);
Assert.Contains("value=\"InvoiceCreated\" checked", pageContent);
Assert.DoesNotContain("value=\"InvoiceReceivedPayment\" checked", pageContent);
await s.Page.ClickAsync("[name='update']");
await s.FindAlertMessage();
pageContent = await s.Page.ContentAsync();
Assert.Contains(server.ServerUri.AbsoluteUri, pageContent);
TestLogs.LogInformation("Let's see if we can generate an event");
await s.GoToStore();
await s.AddDerivationScheme();
await s.CreateInvoice();
var request = await server.GetNextRequest();
var headers = request.Request.Headers;
var actualSig = headers["BTCPay-Sig"].First();
var bytes = await request.Request.Body.ReadBytesAsync((int)headers.ContentLength.Value);
var expectedSig =
$"sha256={Encoders.Hex.EncodeData(NBitcoin.Crypto.Hashes.HMACSHA256(Encoding.UTF8.GetBytes("HelloWorld"), bytes))}";
Assert.Equal(expectedSig, actualSig);
request.Response.StatusCode = 200;
server.Done();
TestLogs.LogInformation("Let's make a failed event");
var invoiceId = await s.CreateInvoice();
request = await server.GetNextRequest();
request.Response.StatusCode = 404;
server.Done();
// The delivery is done asynchronously, so small wait here
await Task.Delay(500);
await s.GoToStore();
await s.Page.ClickAsync("#StoreNav-Webhooks");
await s.Page.ClickAsync("text=Modify");
var redeliverElements = await s.Page.Locator("button.redeliver").AllAsync();
// One worked, one failed
await s.Page.Locator(".icon-cross").WaitForAsync();
await s.Page.Locator(".icon-checkmark").WaitForAsync();
await redeliverElements[0].ClickAsync();
await s.FindAlertMessage();
request = await server.GetNextRequest();
request.Response.StatusCode = 404;
server.Done();
TestLogs.LogInformation("Can we browse the json content?");
await CanBrowseContentAsync(s);
await s.GoToInvoices();
await s.Page.ClickAsync($"text={invoiceId}");
await CanBrowseContentAsync(s);
var redeliverElement = s.Page.Locator("button.redeliver").First;
await redeliverElement.ClickAsync();
await s.FindAlertMessage();
request = await server.GetNextRequest();
request.Response.StatusCode = 404;
server.Done();
TestLogs.LogInformation("Let's see if we can delete store with some webhooks inside");
await s.GoToStore();
await s.Page.ClickAsync("#DeleteStore");
await s.Page.FillAsync("#ConfirmInput", "DELETE");
await s.Page.ClickAsync("#ConfirmContinue");
await s.FindAlertMessage();
}
private static async Task CanBrowseContentAsync(PlaywrightTester s)
{
await s.Page.ClickAsync(".delivery-content");
var newPage = await s.Page.Context.WaitForPageAsync();
var bodyText = await newPage.Locator("body").TextContentAsync();
JObject.Parse(bodyText);
await newPage.CloseAsync();
}
}
}

View File

@@ -821,172 +821,9 @@ namespace BTCPayServer.Tests
Assert.Equal(spentOutpoint, tx.Inputs[0].PrevOut);
}
[Fact(Timeout = TestTimeout)]
public async Task CanUseWebhooks()
{
using var s = CreateSeleniumTester();
await s.StartAsync();
s.RegisterNewUser(true);
s.CreateNewStore();
s.GoToStore(StoreNavPages.Webhooks);
TestLogs.LogInformation("Let's create two webhooks");
for (var i = 0; i < 2; i++)
{
s.ClickPagePrimary();
s.Driver.FindElement(By.Name("PayloadUrl")).SendKeys($"http://127.0.0.1/callback{i}");
new SelectElement(s.Driver.FindElement(By.Id("Everything"))).SelectByValue("false");
s.Driver.FindElement(By.Id("InvoiceCreated")).Click();
s.Driver.FindElement(By.Id("InvoiceProcessing")).Click();
s.ClickPagePrimary();
}
TestLogs.LogInformation("Let's delete one of them");
var deletes = s.Driver.FindElements(By.LinkText("Delete"));
Assert.Equal(2, deletes.Count);
deletes[0].Click();
s.Driver.WaitForElement(By.Id("ConfirmInput")).SendKeys("DELETE");
s.Driver.FindElement(By.Id("ConfirmContinue")).Click();
deletes = s.Driver.FindElements(By.LinkText("Delete"));
Assert.Single(deletes);
s.FindAlertMessage();
TestLogs.LogInformation("Let's try to update one of them");
s.Driver.FindElement(By.LinkText("Modify")).Click();
using var server = new FakeServer();
await server.Start();
s.Driver.FindElement(By.Name("PayloadUrl")).Clear();
s.Driver.FindElement(By.Name("PayloadUrl")).SendKeys(server.ServerUri.AbsoluteUri);
s.Driver.FindElement(By.Name("Secret")).Clear();
s.Driver.FindElement(By.Name("Secret")).SendKeys("HelloWorld");
s.Driver.FindElement(By.Name("update")).Click();
s.FindAlertMessage();
s.Driver.FindElement(By.LinkText("Modify")).Click();
// This one should be checked
Assert.Contains("value=\"InvoiceProcessing\" checked", s.Driver.PageSource);
Assert.Contains("value=\"InvoiceCreated\" checked", s.Driver.PageSource);
// This one never been checked
Assert.DoesNotContain("value=\"InvoiceReceivedPayment\" checked", s.Driver.PageSource);
s.Driver.FindElement(By.Name("update")).Click();
s.FindAlertMessage();
Assert.Contains(server.ServerUri.AbsoluteUri, s.Driver.PageSource);
TestLogs.LogInformation("Let's see if we can generate an event");
s.GoToStore();
s.AddDerivationScheme();
s.CreateInvoice();
var request = await server.GetNextRequest();
var headers = request.Request.Headers;
var actualSig = headers["BTCPay-Sig"].First();
var bytes = await request.Request.Body.ReadBytesAsync((int)headers.ContentLength.Value);
var expectedSig =
$"sha256={Encoders.Hex.EncodeData(NBitcoin.Crypto.Hashes.HMACSHA256(Encoding.UTF8.GetBytes("HelloWorld"), bytes))}";
Assert.Equal(expectedSig, actualSig);
request.Response.StatusCode = 200;
server.Done();
TestLogs.LogInformation("Let's make a failed event");
var invoiceId = s.CreateInvoice();
request = await server.GetNextRequest();
request.Response.StatusCode = 404;
server.Done();
// The delivery is done asynchronously, so small wait here
await Task.Delay(500);
s.GoToStore(StoreNavPages.Webhooks);
s.Driver.FindElement(By.LinkText("Modify")).Click();
var elements = s.Driver.FindElements(By.ClassName("redeliver"));
// One worked, one failed
s.Driver.FindElement(By.ClassName("icon-cross"));
s.Driver.FindElement(By.ClassName("icon-checkmark"));
elements[0].Click();
s.FindAlertMessage();
request = await server.GetNextRequest();
request.Response.StatusCode = 404;
server.Done();
TestLogs.LogInformation("Can we browse the json content?");
CanBrowseContent(s);
s.GoToInvoices();
s.Driver.FindElement(By.LinkText(invoiceId)).Click();
CanBrowseContent(s);
var element = s.Driver.FindElement(By.ClassName("redeliver"));
element.Click();
s.FindAlertMessage();
request = await server.GetNextRequest();
request.Response.StatusCode = 404;
server.Done();
TestLogs.LogInformation("Let's see if we can delete store with some webhooks inside");
s.GoToStore();
s.Driver.FindElement(By.Id("DeleteStore")).Click();
s.Driver.WaitForElement(By.Id("ConfirmInput")).SendKeys("DELETE");
s.Driver.FindElement(By.Id("ConfirmContinue")).Click();
s.FindAlertMessage();
}
[Fact]
[Trait("Selenium", "Selenium")]
public async Task CanUseAwaitProgressForInProgressPayout()
{
using var s = CreateSeleniumTester();
await s.StartAsync();
s.RegisterNewUser(true);
s.CreateNewStore();
s.GenerateWallet(isHotWallet: true);
await s.FundStoreWallet(denomination: 50.0m);
s.GoToStore(s.StoreId, StoreNavPages.PayoutProcessors);
s.Driver.FindElement(By.Id("Configure-BTC-CHAIN")).Click();
s.Driver.SetCheckbox(By.Id("ProcessNewPayoutsInstantly"), true);
s.ClickPagePrimary();
s.GoToStore(s.StoreId, StoreNavPages.PullPayments);
s.ClickPagePrimary();
s.Driver.FindElement(By.Id("Name")).SendKeys("PP1");
s.Driver.FindElement(By.Id("Amount")).Clear();
s.Driver.FindElement(By.Id("Amount")).SendKeys("99.0");
s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), true);
s.ClickPagePrimary();
s.Driver.FindElement(By.LinkText("View")).Click();
s.Driver.SwitchTo().Window(s.Driver.WindowHandles.Last());
var address = await s.Server.ExplorerNode.GetNewAddressAsync();
s.Driver.FindElement(By.Id("Destination")).SendKeys(address + Keys.Enter);
s.GoToStore(s.StoreId, StoreNavPages.Payouts);
s.Driver.FindElement(By.Id("InProgress-view")).Click();
// Waiting for the payment processor to process the payment
int i = 0;
while (!s.Driver.PageSource.Contains("mass-action-select-all"))
{
s.Driver.Navigate().Refresh();
i++;
Thread.Sleep(1000);
if (i > 10)
break;
}
s.Driver.FindElement(By.ClassName("mass-action-select-all")).Click();
s.Driver.FindElement(By.Id("InProgress-mark-awaiting-payment")).Click();
s.Driver.FindElement(By.Id("AwaitingPayment-view")).Click();
Assert.Contains("PP1", s.Driver.PageSource);
}
[Fact]
[Trait("Selenium", "Selenium")]
[Trait("Lightning", "Lightning")]
@@ -2272,16 +2109,7 @@ retry:
Assert.Contains("The user is the last owner. Their role cannot be changed.", s.FindAlertMessage(StatusMessageModel.StatusSeverity.Error).Text);
}
private static void CanBrowseContent(SeleniumTester s)
{
s.Driver.FindElement(By.ClassName("delivery-content")).Click();
var windows = s.Driver.WindowHandles;
Assert.Equal(2, windows.Count);
s.Driver.SwitchTo().Window(windows[1]);
JObject.Parse(s.Driver.FindElement(By.TagName("body")).Text);
s.Driver.Close();
s.Driver.SwitchTo().Window(windows[0]);
}
private static string AssertUrlHasPairingCode(SeleniumTester s)
{