mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 05:54:26 +01:00
(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:
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user