Fix tests, remove duplicate tests

This commit is contained in:
Dennis Reimann
2024-04-05 18:17:06 +02:00
parent d2e9ec9494
commit 6245ecc8f4
4 changed files with 411 additions and 552 deletions

View File

@@ -1,11 +1,10 @@
using System;
using System.Threading.Tasks;
using BTCPayServer.Client.Models;
using BTCPayServer.Payments;
using BTCPayServer.Tests.Logging;
using BTCPayServer.Views.Stores;
using NBitcoin;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
using Xunit;
using Xunit.Abstractions;
@@ -20,37 +19,9 @@ namespace BTCPayServer.Tests
{
}
[Fact(Timeout = TestTimeout)]
public async Task CanUseLanguageDropdown()
{
using var s = CreateSeleniumTester();
await s.StartAsync();
s.GoToRegister();
s.RegisterNewUser();
s.CreateNewStore();
s.AddDerivationScheme();
var invoiceId = s.CreateInvoice();
s.GoToInvoiceCheckout(invoiceId);
Assert.True(s.Driver.FindElement(By.Id("DefaultLang")).FindElements(By.TagName("option")).Count > 1);
var payWithTextEnglish = s.Driver.FindElement(By.Id("pay-with-text")).Text;
var prettyDropdown = s.Driver.FindElement(By.Id("prettydropdown-DefaultLang"));
prettyDropdown.Click();
await Task.Delay(200);
prettyDropdown.FindElement(By.CssSelector("[data-value=\"da-DK\"]")).Click();
await Task.Delay(1000);
Assert.NotEqual(payWithTextEnglish, s.Driver.FindElement(By.Id("pay-with-text")).Text);
s.Driver.Navigate().GoToUrl(s.Driver.Url + "?lang=da-DK");
Assert.NotEqual(payWithTextEnglish, s.Driver.FindElement(By.Id("pay-with-text")).Text);
s.Driver.Quit();
}
[Fact(Timeout = TestTimeout)]
[Trait("Lightning", "Lightning")]
public async Task CanSetDefaultPaymentMethod()
public async Task CanConfigureCheckout()
{
using var s = CreateSeleniumTester();
s.Server.ActivateLightning();
@@ -59,37 +30,403 @@ namespace BTCPayServer.Tests
s.RegisterNewUser(true);
s.CreateNewStore();
s.AddLightningNode();
s.AddDerivationScheme();
// Use non-legacy derivation scheme
s.AddDerivationScheme("BTC", "tpubDD79XF4pzhmPSJ9AyUay9YbXAeD1c6nkUqC32pnKARJH6Ja5hGUfGc76V82ahXpsKqN6UcSGXMkzR34aZq4W23C6DAdZFaVrzWqzj24F8BC");
var invoiceId = s.CreateInvoice(defaultPaymentMethod: "BTC-LN");
// Configure store url
var storeUrl = "https://satoshisteaks.com/";
var supportUrl = "https://support.satoshisteaks.com/{InvoiceId}/";
s.GoToStore();
s.Driver.FindElement(By.Id("StoreWebsite")).SendKeys(storeUrl);
s.Driver.FindElement(By.Id("Save")).Click();
Assert.Contains("Store successfully updated", s.FindAlertMessage().Text);
s.GoToStore(StoreNavPages.CheckoutAppearance);
s.Driver.WaitForAndClick(By.Id("Presets"));
s.Driver.WaitForAndClick(By.Id("Presets_InStore"));
Assert.True(s.Driver.SetCheckbox(By.Id("ShowPayInWalletButton"), true));
s.Driver.FindElement(By.Id("SupportUrl")).SendKeys(supportUrl);
s.Driver.FindElement(By.Id("Save")).SendKeys(Keys.Enter);
Assert.Contains("Store successfully updated", s.FindAlertMessage().Text);
// Top up/zero amount invoices
var invoiceId = s.CreateInvoice(amount: null);
s.GoToInvoiceCheckout(invoiceId);
Assert.Equal("Lightning", s.Driver.FindElement(By.ClassName("payment__currencies")).Text);
s.Driver.Quit();
}
Assert.Equal(2, s.Driver.FindElements(By.CssSelector(".payment-method")).Count);
Assert.Contains("Bitcoin", s.Driver.FindElement(By.CssSelector(".payment-method.active")).Text);
Assert.Contains("LNURL", s.Driver.FindElement(By.CssSelector(".payment-method:nth-child(2)")).Text);
var qrValue = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-qr-value");
var clipboard = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-clipboard");
var payUrl = s.Driver.FindElement(By.Id("PayInWallet")).GetAttribute("href");
var address = s.Driver.FindElement(By.CssSelector("#Address_BTC-CHAIN .truncate-center-start")).Text;
Assert.StartsWith("bcrt", s.Driver.FindElement(By.CssSelector("#Address_BTC-CHAIN .truncate-center-start")).Text);
Assert.DoesNotContain("lightning=", payUrl);
Assert.Equal($"bitcoin:{address}", payUrl);
Assert.Equal($"bitcoin:{address}", clipboard);
Assert.Equal($"bitcoin:{address.ToUpperInvariant()}", qrValue);
s.Driver.ElementDoesNotExist(By.Id("Lightning_BTC-CHAIN"));
[Fact(Timeout = TestTimeout)]
[Trait("Lightning", "Lightning")]
public async Task CanUseLightningSatsFeature()
{
using var s = CreateSeleniumTester();
s.Server.ActivateLightning();
await s.StartAsync();
s.GoToRegister();
s.RegisterNewUser(true);
s.CreateNewStore();
s.AddLightningNode();
// Details should show exchange rate
s.Driver.ToggleCollapse("PaymentDetails");
s.Driver.ElementDoesNotExist(By.Id("PaymentDetails-TotalPrice"));
s.Driver.ElementDoesNotExist(By.Id("PaymentDetails-TotalFiat"));
s.Driver.ElementDoesNotExist(By.Id("PaymentDetails-AmountDue"));
Assert.Contains("$", s.Driver.FindElement(By.Id("PaymentDetails-ExchangeRate")).Text);
Assert.Contains("sat/byte", s.Driver.FindElement(By.Id("PaymentDetails-RecommendedFee")).Text);
// Switch to LNURL
s.Driver.FindElement(By.CssSelector(".payment-method:nth-child(2)")).Click();
TestUtils.Eventually(() =>
{
payUrl = s.Driver.FindElement(By.Id("PayInWallet")).GetAttribute("href");
Assert.StartsWith("lightning:lnurl", payUrl);
Assert.StartsWith("lnurl", s.Driver.WaitForElement(By.CssSelector("#Lightning_BTC-CHAIN .truncate-center-start")).Text);
s.Driver.ElementDoesNotExist(By.Id("Address_BTC-CHAIN"));
});
// Default payment method
s.GoToHome();
invoiceId = s.CreateInvoice(21000, "SATS", defaultPaymentMethod: "BTC-LN");
s.GoToInvoiceCheckout(invoiceId);
Assert.Equal(2, s.Driver.FindElements(By.CssSelector(".payment-method")).Count);
Assert.Contains("Lightning", s.Driver.WaitForElement(By.CssSelector(".payment-method.active")).Text);
Assert.Contains("Bitcoin", s.Driver.WaitForElement(By.CssSelector(".payment-method")).Text);
qrValue = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-qr-value");
clipboard = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-clipboard");
payUrl = s.Driver.FindElement(By.Id("PayInWallet")).GetAttribute("href");
address = s.Driver.FindElement(By.CssSelector("#Lightning_BTC-LN .truncate-center-start")).Text;
Assert.Equal($"lightning:{address}", payUrl);
Assert.Equal($"lightning:{address}", clipboard);
Assert.Equal($"lightning:{address.ToUpperInvariant()}", qrValue);
s.Driver.ElementDoesNotExist(By.Id("Address_BTC-CHAIN"));
// Lightning amount in sats
Assert.Contains("BTC", s.Driver.FindElement(By.Id("AmountDue")).Text);
s.GoToHome();
s.GoToLightningSettings();
s.Driver.SetCheckbox(By.Id("LightningAmountInSatoshi"), true);
s.Driver.FindElement(By.Id("save")).Click();
Assert.Contains("BTC Lightning settings successfully updated", s.FindAlertMessage().Text);
var invoiceId = s.CreateInvoice(10, "USD", "a@g.com");
s.GoToInvoiceCheckout(invoiceId);
Assert.Contains("sats", s.Driver.FindElement(By.ClassName("buyerTotalLine")).Text);
Assert.Contains("sats", s.Driver.FindElement(By.Id("AmountDue")).Text);
// Details should not show exchange rate
s.Driver.ToggleCollapse("PaymentDetails");
s.Driver.ElementDoesNotExist(By.Id("PaymentDetails-ExchangeRate"));
s.Driver.ElementDoesNotExist(By.Id("PaymentDetails-TotalFiat"));
s.Driver.ElementDoesNotExist(By.Id("PaymentDetails-RecommendedFee"));
Assert.Contains("21 000 sats", s.Driver.FindElement(By.Id("PaymentDetails-AmountDue")).Text);
Assert.Contains("21 000 sats", s.Driver.FindElement(By.Id("PaymentDetails-TotalPrice")).Text);
// Expire
var expirySeconds = s.Driver.FindElement(By.Id("ExpirySeconds"));
expirySeconds.Clear();
expirySeconds.SendKeys("3");
s.Driver.FindElement(By.Id("Expire")).Click();
TestUtils.Eventually(() =>
{
var paymentInfo = s.Driver.WaitForElement(By.Id("PaymentInfo"));
Assert.Contains("This invoice will expire in", paymentInfo.Text);
Assert.DoesNotContain("Please send", paymentInfo.Text);
});
TestUtils.Eventually(() =>
{
var expiredSection = s.Driver.FindElement(By.Id("unpaid"));
Assert.True(expiredSection.Displayed);
Assert.Contains("Invoice Expired", expiredSection.Text);
Assert.Contains("resubmit a payment", expiredSection.Text);
Assert.DoesNotContain("This invoice expired with partial payment", expiredSection.Text);
});
Assert.True(s.Driver.ElementDoesNotExist(By.Id("ContactLink")));
Assert.True(s.Driver.ElementDoesNotExist(By.Id("ReceiptLink")));
Assert.Equal(storeUrl, s.Driver.FindElement(By.Id("StoreLink")).GetAttribute("href"));
// Expire paid partial
s.GoToHome();
invoiceId = s.CreateInvoice(2100, "EUR");
s.GoToInvoiceCheckout(invoiceId);
await Task.Delay(200);
address = s.Driver.FindElement(By.CssSelector("#Address_BTC-CHAIN .truncate-center-start")).Text;
var amountFraction = "0.00001";
await s.Server.ExplorerNode.SendToAddressAsync(BitcoinAddress.Create(address, Network.RegTest),
Money.Parse(amountFraction));
await s.Server.ExplorerNode.GenerateAsync(1);
expirySeconds = s.Driver.FindElement(By.Id("ExpirySeconds"));
expirySeconds.Clear();
expirySeconds.SendKeys("3");
s.Driver.FindElement(By.Id("Expire")).Click();
TestUtils.Eventually(() =>
{
var paymentInfo = s.Driver.WaitForElement(By.Id("PaymentInfo"));
Assert.Contains("The invoice hasn't been paid in full.", paymentInfo.Text);
Assert.Contains("Please send", paymentInfo.Text);
});
TestUtils.Eventually(() =>
{
var expiredSection = s.Driver.FindElement(By.Id("unpaid"));
Assert.True(expiredSection.Displayed);
Assert.Contains("Invoice Expired", expiredSection.Text);
Assert.Contains("This invoice expired with partial payment", expiredSection.Text);
Assert.DoesNotContain("resubmit a payment", expiredSection.Text);
});
var contactLink = s.Driver.FindElement(By.Id("ContactLink"));
Assert.Equal("Contact us", contactLink.Text);
Assert.Matches(supportUrl.Replace("{InvoiceId}", invoiceId), contactLink.GetAttribute("href"));
Assert.True(s.Driver.ElementDoesNotExist(By.Id("ReceiptLink")));
Assert.Equal(storeUrl, s.Driver.FindElement(By.Id("StoreLink")).GetAttribute("href"));
// Test payment
s.GoToHome();
invoiceId = s.CreateInvoice();
s.GoToInvoiceCheckout(invoiceId);
// Details
s.Driver.ToggleCollapse("PaymentDetails");
var details = s.Driver.FindElement(By.CssSelector(".payment-details"));
Assert.Contains("Total Price", details.Text);
Assert.Contains("Total Fiat", details.Text);
Assert.Contains("Exchange Rate", details.Text);
Assert.Contains("Amount Due", details.Text);
Assert.Contains("Recommended Fee", details.Text);
Assert.Contains("$", s.Driver.FindElement(By.Id("PaymentDetails-ExchangeRate")).Text);
Assert.Contains("$", s.Driver.FindElement(By.Id("PaymentDetails-TotalFiat")).Text);
Assert.Contains("BTC", s.Driver.FindElement(By.Id("PaymentDetails-AmountDue")).Text);
Assert.Contains("BTC", s.Driver.FindElement(By.Id("PaymentDetails-TotalPrice")).Text);
// Pay partial amount
await Task.Delay(200);
s.Driver.FindElement(By.Id("test-payment-amount")).Clear();
s.Driver.FindElement(By.Id("test-payment-amount")).SendKeys("0.00001");
// Fake Pay
TestUtils.Eventually(() =>
{
s.Driver.FindElement(By.Id("FakePayment")).Click();
s.Driver.FindElement(By.Id("mine-block")).Click();
var paymentInfo = s.Driver.WaitForElement(By.Id("PaymentInfo"));
Assert.Contains("The invoice hasn't been paid in full", paymentInfo.Text);
Assert.Contains("Please send", paymentInfo.Text);
});
s.Driver.Navigate().Refresh();
// Pay full amount
s.PayInvoice();
// Processing
TestUtils.Eventually(() =>
{
var processingSection = s.Driver.WaitForElement(By.Id("processing"));
Assert.True(processingSection.Displayed);
Assert.Contains("Payment Received", processingSection.Text);
Assert.Contains("Your payment has been received and is now processing", processingSection.Text);
});
s.Driver.FindElement(By.Id("confetti"));
// Mine
s.MineBlockOnInvoiceCheckout();
TestUtils.Eventually(() =>
{
Assert.Contains("Mined 1 block",
s.Driver.WaitForElement(By.Id("CheatSuccessMessage")).Text);
});
// Settled
TestUtils.Eventually(() =>
{
var settledSection = s.Driver.WaitForElement(By.Id("settled"));
Assert.True(settledSection.Displayed);
Assert.Contains("Invoice Paid", settledSection.Text);
});
s.Driver.FindElement(By.Id("confetti"));
s.Driver.FindElement(By.Id("ReceiptLink"));
Assert.True(s.Driver.ElementDoesNotExist(By.Id("ContactLink")));
Assert.Equal(storeUrl, s.Driver.FindElement(By.Id("StoreLink")).GetAttribute("href"));
// BIP21
s.GoToHome();
s.GoToStore(StoreNavPages.CheckoutAppearance);
s.Driver.SetCheckbox(By.Id("OnChainWithLnInvoiceFallback"), true);
s.Driver.SetCheckbox(By.Id("LightningAmountInSatoshi"), false);
s.Driver.FindElement(By.Id("Save")).Click();
Assert.Contains("Store successfully updated", s.FindAlertMessage().Text);
invoiceId = s.CreateInvoice();
s.GoToInvoiceCheckout(invoiceId);
Assert.Empty(s.Driver.FindElements(By.CssSelector(".payment-method")));
Assert.Contains("BTC", s.Driver.FindElement(By.Id("AmountDue")).Text);
qrValue = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-qr-value");
clipboard = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-clipboard");
payUrl = s.Driver.FindElement(By.Id("PayInWallet")).GetAttribute("href");
var copyAddressOnchain = s.Driver.FindElement(By.CssSelector("#Address_BTC-CHAIN .truncate-center-start")).Text;
var copyAddressLightning = s.Driver.FindElement(By.CssSelector("#Lightning_BTC-CHAIN .truncate-center-start")).Text;
Assert.StartsWith($"bitcoin:{copyAddressOnchain}?amount=", payUrl);
Assert.Contains("?amount=", payUrl);
Assert.Contains("&lightning=", payUrl);
Assert.StartsWith("bcrt", copyAddressOnchain);
Assert.StartsWith("lnbcrt", copyAddressLightning);
Assert.StartsWith($"bitcoin:{copyAddressOnchain.ToUpperInvariant()}?amount=", qrValue);
Assert.Contains("&lightning=LNBCRT", qrValue);
Assert.Contains("&lightning=lnbcrt", clipboard);
Assert.Equal(clipboard, payUrl);
// Check details
s.Driver.ToggleCollapse("PaymentDetails");
Assert.Contains("1 BTC = ", s.Driver.FindElement(By.Id("PaymentDetails-ExchangeRate")).Text);
Assert.Contains("$", s.Driver.FindElement(By.Id("PaymentDetails-ExchangeRate")).Text);
Assert.Contains("$", s.Driver.FindElement(By.Id("PaymentDetails-TotalFiat")).Text);
Assert.Contains("BTC", s.Driver.FindElement(By.Id("PaymentDetails-AmountDue")).Text);
Assert.Contains("BTC", s.Driver.FindElement(By.Id("PaymentDetails-TotalPrice")).Text);
// Switch to amount displayed in sats
s.GoToHome();
s.GoToStore(StoreNavPages.CheckoutAppearance);
s.Driver.SetCheckbox(By.Id("LightningAmountInSatoshi"), true);
s.Driver.FindElement(By.Id("Save")).Click();
Assert.Contains("Store successfully updated", s.FindAlertMessage().Text);
s.GoToInvoiceCheckout(invoiceId);
Assert.Contains("sats", s.Driver.FindElement(By.Id("AmountDue")).Text);
// Check details
s.Driver.ToggleCollapse("PaymentDetails");
Assert.Contains("1 sat = ", s.Driver.FindElement(By.Id("PaymentDetails-ExchangeRate")).Text);
Assert.Contains("$", s.Driver.FindElement(By.Id("PaymentDetails-ExchangeRate")).Text);
Assert.Contains("$", s.Driver.FindElement(By.Id("PaymentDetails-TotalFiat")).Text);
Assert.Contains("sats", s.Driver.FindElement(By.Id("PaymentDetails-AmountDue")).Text);
Assert.Contains("sats", s.Driver.FindElement(By.Id("PaymentDetails-TotalPrice")).Text);
// BIP21 with LN as default payment method
s.GoToHome();
invoiceId = s.CreateInvoice(defaultPaymentMethod: "BTC-LN");
s.GoToInvoiceCheckout(invoiceId);
Assert.Empty(s.Driver.FindElements(By.CssSelector(".payment-method")));
payUrl = s.Driver.FindElement(By.Id("PayInWallet")).GetAttribute("href");
Assert.StartsWith("bitcoin:", payUrl);
Assert.Contains("&lightning=lnbcrt", payUrl);
// Check details
s.Driver.ToggleCollapse("PaymentDetails");
Assert.Contains("1 sat = ", s.Driver.FindElement(By.Id("PaymentDetails-ExchangeRate")).Text);
Assert.Contains("$", s.Driver.FindElement(By.Id("PaymentDetails-ExchangeRate")).Text);
Assert.Contains("$", s.Driver.FindElement(By.Id("PaymentDetails-TotalFiat")).Text);
Assert.Contains("sats", s.Driver.FindElement(By.Id("PaymentDetails-AmountDue")).Text);
Assert.Contains("sats", s.Driver.FindElement(By.Id("PaymentDetails-TotalPrice")).Text);
// Ensure LNURL is enabled
s.GoToHome();
s.GoToLightningSettings();
Assert.True(s.Driver.FindElement(By.Id("LNURLEnabled")).Selected);
// BIP21 with top-up invoice
invoiceId = s.CreateInvoice(amount: null);
s.GoToInvoiceCheckout(invoiceId);
Assert.Empty(s.Driver.FindElements(By.CssSelector(".payment-method")));
qrValue = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-qr-value");
clipboard = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-clipboard");
payUrl = s.Driver.FindElement(By.Id("PayInWallet")).GetAttribute("href");
copyAddressOnchain = s.Driver.FindElement(By.CssSelector("#Address_BTC-CHAIN .truncate-center-start")).Text;
copyAddressLightning = s.Driver.FindElement(By.CssSelector("#Lightning_BTC-CHAIN .truncate-center-start")).Text;
Assert.StartsWith($"bitcoin:{copyAddressOnchain}", payUrl);
Assert.Contains("?lightning=lnurl", payUrl);
Assert.DoesNotContain("amount=", payUrl);
Assert.StartsWith("bcrt", copyAddressOnchain);
Assert.StartsWith("lnurl", copyAddressLightning);
Assert.StartsWith($"bitcoin:{copyAddressOnchain.ToUpperInvariant()}?lightning=LNURL", qrValue);
Assert.Contains($"bitcoin:{copyAddressOnchain}?lightning=lnurl", clipboard);
Assert.Equal(clipboard, payUrl);
// Check details
s.Driver.ToggleCollapse("PaymentDetails");
Assert.Contains("1 sat = ", s.Driver.FindElement(By.Id("PaymentDetails-ExchangeRate")).Text);
Assert.Contains("$", s.Driver.FindElement(By.Id("PaymentDetails-ExchangeRate")).Text);
s.Driver.ElementDoesNotExist(By.Id("PaymentDetails-TotalFiat"));
s.Driver.ElementDoesNotExist(By.Id("PaymentDetails-AmountDue"));
s.Driver.ElementDoesNotExist(By.Id("PaymentDetails-TotalPrice"));
// Expiry message should not show amount for top-up invoice
expirySeconds = s.Driver.FindElement(By.Id("ExpirySeconds"));
expirySeconds.Clear();
expirySeconds.SendKeys("5");
s.Driver.FindElement(By.Id("Expire")).Click();
TestUtils.Eventually(() =>
{
var paymentInfo = s.Driver.WaitForElement(By.Id("PaymentInfo"));
Assert.Contains("This invoice will expire in", paymentInfo.Text);
Assert.Contains("00:0", paymentInfo.Text);
Assert.DoesNotContain("Please send", paymentInfo.Text);
});
// Configure countdown timer
s.GoToHome();
invoiceId = s.CreateInvoice();
s.GoToHome();
s.GoToStore(StoreNavPages.CheckoutAppearance);
var displayExpirationTimer = s.Driver.FindElement(By.Id("DisplayExpirationTimer"));
Assert.Equal("5", displayExpirationTimer.GetAttribute("value"));
displayExpirationTimer.Clear();
displayExpirationTimer.SendKeys("10");
s.Driver.FindElement(By.Id("Save")).Click();
Assert.Contains("Store successfully updated", s.FindAlertMessage().Text);
s.GoToInvoiceCheckout(invoiceId);
var paymentInfo = s.Driver.FindElement(By.Id("PaymentInfo"));
Assert.False(paymentInfo.Displayed);
Assert.DoesNotContain("This invoice will expire in", paymentInfo.Text);
expirySeconds = s.Driver.FindElement(By.Id("ExpirySeconds"));
expirySeconds.Clear();
expirySeconds.SendKeys("599");
s.Driver.FindElement(By.Id("Expire")).Click();
TestUtils.Eventually(() =>
{
paymentInfo = s.Driver.WaitForElement(By.Id("PaymentInfo"));
Assert.True(paymentInfo.Displayed);
Assert.Contains("This invoice will expire in", paymentInfo.Text);
Assert.Contains("09:5", paymentInfo.Text);
});
// Disable LNURL again
s.GoToHome();
s.GoToLightningSettings();
s.Driver.SetCheckbox(By.Id("LNURLEnabled"), false);
s.Driver.ScrollTo(By.Id("save"));
s.Driver.FindElement(By.Id("save")).Click();
Assert.Contains("BTC Lightning settings successfully updated", s.FindAlertMessage().Text);
// Test:
// - NFC/LNURL-W available with just Lightning
// - BIP21 works correctly even though Lightning is default payment method
s.GoToHome();
invoiceId = s.CreateInvoice(defaultPaymentMethod: "BTC-LN");
s.GoToInvoiceCheckout(invoiceId);
Assert.Empty(s.Driver.FindElements(By.CssSelector(".payment-method")));
payUrl = s.Driver.FindElement(By.Id("PayInWallet")).GetAttribute("href");
Assert.StartsWith("bitcoin:", payUrl);
Assert.Contains("&lightning=lnbcrt", payUrl);
// Language Switch
var languageSelect = new SelectElement(s.Driver.FindElement(By.Id("DefaultLang")));
Assert.Equal("English", languageSelect.SelectedOption.Text);
Assert.Equal("View Details", s.Driver.FindElement(By.Id("DetailsToggle")).Text);
Assert.DoesNotContain("lang=", s.Driver.Url);
languageSelect.SelectByText("Deutsch");
Assert.Equal("Details anzeigen", s.Driver.FindElement(By.Id("DetailsToggle")).Text);
Assert.Contains("lang=de", s.Driver.Url);
s.Driver.Navigate().Refresh();
languageSelect = new SelectElement(s.Driver.WaitForElement(By.Id("DefaultLang")));
Assert.Equal("Deutsch", languageSelect.SelectedOption.Text);
Assert.Equal("Details anzeigen", s.Driver.FindElement(By.Id("DetailsToggle")).Text);
languageSelect.SelectByText("English");
Assert.Equal("View Details", s.Driver.FindElement(By.Id("DetailsToggle")).Text);
Assert.Contains("lang=en", s.Driver.Url);
}
[Fact(Timeout = TestTimeout)]
public async Task CanUseJSModal()
public async Task CanUseCheckoutAsModal()
{
using var s = CreateSeleniumTester();
await s.StartAsync();
@@ -102,24 +439,24 @@ namespace BTCPayServer.Tests
var invoice = await s.Server.PayTester.InvoiceRepository.GetInvoice(invoiceId);
s.Driver.Navigate()
.GoToUrl(new Uri(s.ServerUri, $"tests/index.html?invoice={invoiceId}"));
TestUtils.Eventually(() =>
{
Assert.True(s.Driver.FindElement(By.Name("btcpay")).Displayed);
});
s.Driver.WaitUntilAvailable(By.Name("btcpay"));
var frameElement = s.Driver.FindElement(By.Name("btcpay"));
Assert.True(frameElement.Displayed);
var iframe = s.Driver.SwitchTo().Frame(frameElement);
iframe.WaitUntilAvailable(By.Id("Checkout"));
await s.Server.ExplorerNode.SendToAddressAsync(BitcoinAddress.Create(invoice
.GetPaymentPrompt(PaymentTypes.CHAIN.GetPaymentMethodId("BTC"))
.Destination, Network.RegTest),
new Money(0.001m, MoneyUnit.BTC));
IWebElement closebutton = null;
TestUtils.Eventually(() =>
{
var frameElement = s.Driver.FindElement(By.Name("btcpay"));
var iframe = s.Driver.SwitchTo().Frame(frameElement);
closebutton = iframe.FindElement(By.ClassName("close-action"));
Assert.True(closebutton.Displayed);
var closeButton = iframe.FindElement(By.Id("close"));
Assert.True(closeButton.Displayed);
closeButton.Click();
});
closebutton.Click();
s.Driver.AssertElementNotFound(By.Name("btcpay"));
Assert.Equal(s.Driver.Url,
new Uri(s.ServerUri, $"tests/index.html?invoice={invoiceId}").ToString());

View File

@@ -1,466 +0,0 @@
using System;
using System.Threading.Tasks;
using BTCPayServer.Payments;
using BTCPayServer.Views.Stores;
using NBitcoin;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
using Xunit;
using Xunit.Abstractions;
namespace BTCPayServer.Tests
{
[Trait("Selenium", "Selenium")]
[Collection(nameof(NonParallelizableCollectionDefinition))]
public class CheckoutV2Tests : UnitTestBase
{
private const int TestTimeout = TestUtils.TestTimeout;
public CheckoutV2Tests(ITestOutputHelper helper) : base(helper)
{
}
[Fact(Timeout = TestTimeout)]
[Trait("Lightning", "Lightning")]
public async Task CanConfigureCheckout()
{
using var s = CreateSeleniumTester();
s.Server.ActivateLightning();
await s.StartAsync();
s.GoToRegister();
s.RegisterNewUser(true);
s.CreateNewStore();
s.AddLightningNode();
// Use non-legacy derivation scheme
s.AddDerivationScheme("BTC", "tpubDD79XF4pzhmPSJ9AyUay9YbXAeD1c6nkUqC32pnKARJH6Ja5hGUfGc76V82ahXpsKqN6UcSGXMkzR34aZq4W23C6DAdZFaVrzWqzj24F8BC");
// Configure store url
var storeUrl = "https://satoshisteaks.com/";
var supportUrl = "https://support.satoshisteaks.com/{InvoiceId}/";
s.GoToStore();
s.Driver.FindElement(By.Id("StoreWebsite")).SendKeys(storeUrl);
s.Driver.FindElement(By.Id("Save")).Click();
Assert.Contains("Store successfully updated", s.FindAlertMessage().Text);
s.GoToStore(StoreNavPages.CheckoutAppearance);
s.Driver.WaitForAndClick(By.Id("Presets"));
s.Driver.WaitForAndClick(By.Id("Presets_InStore"));
Assert.True(s.Driver.SetCheckbox(By.Id("ShowPayInWalletButton"), true));
s.Driver.FindElement(By.Id("SupportUrl")).SendKeys(supportUrl);
s.Driver.FindElement(By.Id("Save")).SendKeys(Keys.Enter);
Assert.Contains("Store successfully updated", s.FindAlertMessage().Text);
// Top up/zero amount invoices
var invoiceId = s.CreateInvoice(amount: null);
s.GoToInvoiceCheckout(invoiceId);
Assert.Equal(2, s.Driver.FindElements(By.CssSelector(".payment-method")).Count);
Assert.Contains("Bitcoin", s.Driver.FindElement(By.CssSelector(".payment-method.active")).Text);
Assert.Contains("LNURL", s.Driver.FindElement(By.CssSelector(".payment-method:nth-child(2)")).Text);
var qrValue = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-qr-value");
var clipboard = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-clipboard");
var payUrl = s.Driver.FindElement(By.Id("PayInWallet")).GetAttribute("href");
var address = s.Driver.FindElement(By.CssSelector("#Address_BTC-CHAIN .truncate-center-start")).Text;
Assert.StartsWith("bcrt", s.Driver.FindElement(By.CssSelector("#Address_BTC-CHAIN .truncate-center-start")).Text);
Assert.DoesNotContain("lightning=", payUrl);
Assert.Equal($"bitcoin:{address}", payUrl);
Assert.Equal($"bitcoin:{address}", clipboard);
Assert.Equal($"bitcoin:{address.ToUpperInvariant()}", qrValue);
s.Driver.ElementDoesNotExist(By.Id("Lightning_BTC-CHAIN"));
// Details should show exchange rate
s.Driver.ToggleCollapse("PaymentDetails");
s.Driver.ElementDoesNotExist(By.Id("PaymentDetails-TotalPrice"));
s.Driver.ElementDoesNotExist(By.Id("PaymentDetails-TotalFiat"));
s.Driver.ElementDoesNotExist(By.Id("PaymentDetails-AmountDue"));
Assert.Contains("$", s.Driver.FindElement(By.Id("PaymentDetails-ExchangeRate")).Text);
Assert.Contains("sat/byte", s.Driver.FindElement(By.Id("PaymentDetails-RecommendedFee")).Text);
// Switch to LNURL
s.Driver.FindElement(By.CssSelector(".payment-method:nth-child(2)")).Click();
TestUtils.Eventually(() =>
{
payUrl = s.Driver.FindElement(By.Id("PayInWallet")).GetAttribute("href");
Assert.StartsWith("lightning:lnurl", payUrl);
Assert.StartsWith("lnurl", s.Driver.WaitForElement(By.CssSelector("#Lightning_BTC-CHAIN .truncate-center-start")).Text);
s.Driver.ElementDoesNotExist(By.Id("Address_BTC-CHAIN"));
});
// Default payment method
s.GoToHome();
invoiceId = s.CreateInvoice(21000, "SATS", defaultPaymentMethod: "BTC-LN");
s.GoToInvoiceCheckout(invoiceId);
Assert.Equal(2, s.Driver.FindElements(By.CssSelector(".payment-method")).Count);
Assert.Contains("Lightning", s.Driver.WaitForElement(By.CssSelector(".payment-method.active")).Text);
Assert.Contains("Bitcoin", s.Driver.WaitForElement(By.CssSelector(".payment-method")).Text);
qrValue = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-qr-value");
clipboard = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-clipboard");
payUrl = s.Driver.FindElement(By.Id("PayInWallet")).GetAttribute("href");
address = s.Driver.FindElement(By.CssSelector("#Lightning_BTC-LN .truncate-center-start")).Text;
Assert.Equal($"lightning:{address}", payUrl);
Assert.Equal($"lightning:{address}", clipboard);
Assert.Equal($"lightning:{address.ToUpperInvariant()}", qrValue);
s.Driver.ElementDoesNotExist(By.Id("Address_BTC-CHAIN"));
// Lightning amount in sats
Assert.Contains("BTC", s.Driver.FindElement(By.Id("AmountDue")).Text);
s.GoToHome();
s.GoToLightningSettings();
s.Driver.SetCheckbox(By.Id("LightningAmountInSatoshi"), true);
s.Driver.FindElement(By.Id("save")).Click();
Assert.Contains("BTC Lightning settings successfully updated", s.FindAlertMessage().Text);
s.GoToInvoiceCheckout(invoiceId);
Assert.Contains("sats", s.Driver.FindElement(By.Id("AmountDue")).Text);
// Details should not show exchange rate
s.Driver.ToggleCollapse("PaymentDetails");
s.Driver.ElementDoesNotExist(By.Id("PaymentDetails-ExchangeRate"));
s.Driver.ElementDoesNotExist(By.Id("PaymentDetails-TotalFiat"));
s.Driver.ElementDoesNotExist(By.Id("PaymentDetails-RecommendedFee"));
Assert.Contains("21 000 sats", s.Driver.FindElement(By.Id("PaymentDetails-AmountDue")).Text);
Assert.Contains("21 000 sats", s.Driver.FindElement(By.Id("PaymentDetails-TotalPrice")).Text);
// Expire
var expirySeconds = s.Driver.FindElement(By.Id("ExpirySeconds"));
expirySeconds.Clear();
expirySeconds.SendKeys("3");
s.Driver.FindElement(By.Id("Expire")).Click();
TestUtils.Eventually(() =>
{
var paymentInfo = s.Driver.WaitForElement(By.Id("PaymentInfo"));
Assert.Contains("This invoice will expire in", paymentInfo.Text);
Assert.DoesNotContain("Please send", paymentInfo.Text);
});
TestUtils.Eventually(() =>
{
var expiredSection = s.Driver.FindElement(By.Id("unpaid"));
Assert.True(expiredSection.Displayed);
Assert.Contains("Invoice Expired", expiredSection.Text);
Assert.Contains("resubmit a payment", expiredSection.Text);
Assert.DoesNotContain("This invoice expired with partial payment", expiredSection.Text);
});
Assert.True(s.Driver.ElementDoesNotExist(By.Id("ContactLink")));
Assert.True(s.Driver.ElementDoesNotExist(By.Id("ReceiptLink")));
Assert.Equal(storeUrl, s.Driver.FindElement(By.Id("StoreLink")).GetAttribute("href"));
// Expire paid partial
s.GoToHome();
invoiceId = s.CreateInvoice(2100, "EUR");
s.GoToInvoiceCheckout(invoiceId);
await Task.Delay(200);
address = s.Driver.FindElement(By.CssSelector("#Address_BTC-CHAIN .truncate-center-start")).Text;
var amountFraction = "0.00001";
await s.Server.ExplorerNode.SendToAddressAsync(BitcoinAddress.Create(address, Network.RegTest),
Money.Parse(amountFraction));
await s.Server.ExplorerNode.GenerateAsync(1);
expirySeconds = s.Driver.FindElement(By.Id("ExpirySeconds"));
expirySeconds.Clear();
expirySeconds.SendKeys("3");
s.Driver.FindElement(By.Id("Expire")).Click();
TestUtils.Eventually(() =>
{
var paymentInfo = s.Driver.WaitForElement(By.Id("PaymentInfo"));
Assert.Contains("The invoice hasn't been paid in full.", paymentInfo.Text);
Assert.Contains("Please send", paymentInfo.Text);
});
TestUtils.Eventually(() =>
{
var expiredSection = s.Driver.FindElement(By.Id("unpaid"));
Assert.True(expiredSection.Displayed);
Assert.Contains("Invoice Expired", expiredSection.Text);
Assert.Contains("This invoice expired with partial payment", expiredSection.Text);
Assert.DoesNotContain("resubmit a payment", expiredSection.Text);
});
var contactLink = s.Driver.FindElement(By.Id("ContactLink"));
Assert.Equal("Contact us", contactLink.Text);
Assert.Matches(supportUrl.Replace("{InvoiceId}", invoiceId), contactLink.GetAttribute("href"));
Assert.True(s.Driver.ElementDoesNotExist(By.Id("ReceiptLink")));
Assert.Equal(storeUrl, s.Driver.FindElement(By.Id("StoreLink")).GetAttribute("href"));
// Test payment
s.GoToHome();
invoiceId = s.CreateInvoice();
s.GoToInvoiceCheckout(invoiceId);
// Details
s.Driver.ToggleCollapse("PaymentDetails");
var details = s.Driver.FindElement(By.CssSelector(".payment-details"));
Assert.Contains("Total Price", details.Text);
Assert.Contains("Total Fiat", details.Text);
Assert.Contains("Exchange Rate", details.Text);
Assert.Contains("Amount Due", details.Text);
Assert.Contains("Recommended Fee", details.Text);
Assert.Contains("$", s.Driver.FindElement(By.Id("PaymentDetails-ExchangeRate")).Text);
Assert.Contains("$", s.Driver.FindElement(By.Id("PaymentDetails-TotalFiat")).Text);
Assert.Contains("BTC", s.Driver.FindElement(By.Id("PaymentDetails-AmountDue")).Text);
Assert.Contains("BTC", s.Driver.FindElement(By.Id("PaymentDetails-TotalPrice")).Text);
// Pay partial amount
await Task.Delay(200);
s.Driver.FindElement(By.Id("test-payment-amount")).Clear();
s.Driver.FindElement(By.Id("test-payment-amount")).SendKeys("0.00001");
// Fake Pay
TestUtils.Eventually(() =>
{
s.Driver.FindElement(By.Id("FakePayment")).Click();
s.Driver.FindElement(By.Id("mine-block")).Click();
var paymentInfo = s.Driver.WaitForElement(By.Id("PaymentInfo"));
Assert.Contains("The invoice hasn't been paid in full", paymentInfo.Text);
Assert.Contains("Please send", paymentInfo.Text);
});
s.Driver.Navigate().Refresh();
// Pay full amount
s.PayInvoice();
// Processing
TestUtils.Eventually(() =>
{
var processingSection = s.Driver.WaitForElement(By.Id("processing"));
Assert.True(processingSection.Displayed);
Assert.Contains("Payment Received", processingSection.Text);
Assert.Contains("Your payment has been received and is now processing", processingSection.Text);
});
s.Driver.FindElement(By.Id("confetti"));
// Mine
s.MineBlockOnInvoiceCheckout();
TestUtils.Eventually(() =>
{
Assert.Contains("Mined 1 block",
s.Driver.WaitForElement(By.Id("CheatSuccessMessage")).Text);
});
// Settled
TestUtils.Eventually(() =>
{
var settledSection = s.Driver.WaitForElement(By.Id("settled"));
Assert.True(settledSection.Displayed);
Assert.Contains("Invoice Paid", settledSection.Text);
});
s.Driver.FindElement(By.Id("confetti"));
s.Driver.FindElement(By.Id("ReceiptLink"));
Assert.True(s.Driver.ElementDoesNotExist(By.Id("ContactLink")));
Assert.Equal(storeUrl, s.Driver.FindElement(By.Id("StoreLink")).GetAttribute("href"));
// BIP21
s.GoToHome();
s.GoToStore(StoreNavPages.CheckoutAppearance);
s.Driver.SetCheckbox(By.Id("OnChainWithLnInvoiceFallback"), true);
s.Driver.SetCheckbox(By.Id("LightningAmountInSatoshi"), false);
s.Driver.FindElement(By.Id("Save")).Click();
Assert.Contains("Store successfully updated", s.FindAlertMessage().Text);
invoiceId = s.CreateInvoice();
s.GoToInvoiceCheckout(invoiceId);
Assert.Empty(s.Driver.FindElements(By.CssSelector(".payment-method")));
Assert.Contains("BTC", s.Driver.FindElement(By.Id("AmountDue")).Text);
qrValue = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-qr-value");
clipboard = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-clipboard");
payUrl = s.Driver.FindElement(By.Id("PayInWallet")).GetAttribute("href");
var copyAddressOnchain = s.Driver.FindElement(By.CssSelector("#Address_BTC-CHAIN .truncate-center-start")).Text;
var copyAddressLightning = s.Driver.FindElement(By.CssSelector("#Lightning_BTC-CHAIN .truncate-center-start")).Text;
Assert.StartsWith($"bitcoin:{copyAddressOnchain}?amount=", payUrl);
Assert.Contains("?amount=", payUrl);
Assert.Contains("&lightning=", payUrl);
Assert.StartsWith("bcrt", copyAddressOnchain);
Assert.StartsWith("lnbcrt", copyAddressLightning);
Assert.StartsWith($"bitcoin:{copyAddressOnchain.ToUpperInvariant()}?amount=", qrValue);
Assert.Contains("&lightning=LNBCRT", qrValue);
Assert.Contains("&lightning=lnbcrt", clipboard);
Assert.Equal(clipboard, payUrl);
// Check details
s.Driver.ToggleCollapse("PaymentDetails");
Assert.Contains("1 BTC = ", s.Driver.FindElement(By.Id("PaymentDetails-ExchangeRate")).Text);
Assert.Contains("$", s.Driver.FindElement(By.Id("PaymentDetails-ExchangeRate")).Text);
Assert.Contains("$", s.Driver.FindElement(By.Id("PaymentDetails-TotalFiat")).Text);
Assert.Contains("BTC", s.Driver.FindElement(By.Id("PaymentDetails-AmountDue")).Text);
Assert.Contains("BTC", s.Driver.FindElement(By.Id("PaymentDetails-TotalPrice")).Text);
// Switch to amount displayed in sats
s.GoToHome();
s.GoToStore(StoreNavPages.CheckoutAppearance);
s.Driver.SetCheckbox(By.Id("LightningAmountInSatoshi"), true);
s.Driver.FindElement(By.Id("Save")).Click();
Assert.Contains("Store successfully updated", s.FindAlertMessage().Text);
s.GoToInvoiceCheckout(invoiceId);
Assert.Contains("sats", s.Driver.FindElement(By.Id("AmountDue")).Text);
// Check details
s.Driver.ToggleCollapse("PaymentDetails");
Assert.Contains("1 sat = ", s.Driver.FindElement(By.Id("PaymentDetails-ExchangeRate")).Text);
Assert.Contains("$", s.Driver.FindElement(By.Id("PaymentDetails-ExchangeRate")).Text);
Assert.Contains("$", s.Driver.FindElement(By.Id("PaymentDetails-TotalFiat")).Text);
Assert.Contains("sats", s.Driver.FindElement(By.Id("PaymentDetails-AmountDue")).Text);
Assert.Contains("sats", s.Driver.FindElement(By.Id("PaymentDetails-TotalPrice")).Text);
// BIP21 with LN as default payment method
s.GoToHome();
invoiceId = s.CreateInvoice(defaultPaymentMethod: "BTC-LN");
s.GoToInvoiceCheckout(invoiceId);
Assert.Empty(s.Driver.FindElements(By.CssSelector(".payment-method")));
payUrl = s.Driver.FindElement(By.Id("PayInWallet")).GetAttribute("href");
Assert.StartsWith("bitcoin:", payUrl);
Assert.Contains("&lightning=lnbcrt", payUrl);
// Check details
s.Driver.ToggleCollapse("PaymentDetails");
Assert.Contains("1 sat = ", s.Driver.FindElement(By.Id("PaymentDetails-ExchangeRate")).Text);
Assert.Contains("$", s.Driver.FindElement(By.Id("PaymentDetails-ExchangeRate")).Text);
Assert.Contains("$", s.Driver.FindElement(By.Id("PaymentDetails-TotalFiat")).Text);
Assert.Contains("sats", s.Driver.FindElement(By.Id("PaymentDetails-AmountDue")).Text);
Assert.Contains("sats", s.Driver.FindElement(By.Id("PaymentDetails-TotalPrice")).Text);
// Ensure LNURL is enabled
s.GoToHome();
s.GoToLightningSettings();
Assert.True(s.Driver.FindElement(By.Id("LNURLEnabled")).Selected);
// BIP21 with top-up invoice
invoiceId = s.CreateInvoice(amount: null);
s.GoToInvoiceCheckout(invoiceId);
Assert.Empty(s.Driver.FindElements(By.CssSelector(".payment-method")));
qrValue = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-qr-value");
clipboard = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-clipboard");
payUrl = s.Driver.FindElement(By.Id("PayInWallet")).GetAttribute("href");
copyAddressOnchain = s.Driver.FindElement(By.CssSelector("#Address_BTC-CHAIN .truncate-center-start")).Text;
copyAddressLightning = s.Driver.FindElement(By.CssSelector("#Lightning_BTC-CHAIN .truncate-center-start")).Text;
Assert.StartsWith($"bitcoin:{copyAddressOnchain}", payUrl);
Assert.Contains("?lightning=lnurl", payUrl);
Assert.DoesNotContain("amount=", payUrl);
Assert.StartsWith("bcrt", copyAddressOnchain);
Assert.StartsWith("lnurl", copyAddressLightning);
Assert.StartsWith($"bitcoin:{copyAddressOnchain.ToUpperInvariant()}?lightning=LNURL", qrValue);
Assert.Contains($"bitcoin:{copyAddressOnchain}?lightning=lnurl", clipboard);
Assert.Equal(clipboard, payUrl);
// Check details
s.Driver.ToggleCollapse("PaymentDetails");
Assert.Contains("1 sat = ", s.Driver.FindElement(By.Id("PaymentDetails-ExchangeRate")).Text);
Assert.Contains("$", s.Driver.FindElement(By.Id("PaymentDetails-ExchangeRate")).Text);
s.Driver.ElementDoesNotExist(By.Id("PaymentDetails-TotalFiat"));
s.Driver.ElementDoesNotExist(By.Id("PaymentDetails-AmountDue"));
s.Driver.ElementDoesNotExist(By.Id("PaymentDetails-TotalPrice"));
// Expiry message should not show amount for top-up invoice
expirySeconds = s.Driver.FindElement(By.Id("ExpirySeconds"));
expirySeconds.Clear();
expirySeconds.SendKeys("5");
s.Driver.FindElement(By.Id("Expire")).Click();
TestUtils.Eventually(() =>
{
var paymentInfo = s.Driver.WaitForElement(By.Id("PaymentInfo"));
Assert.Contains("This invoice will expire in", paymentInfo.Text);
Assert.Contains("00:0", paymentInfo.Text);
Assert.DoesNotContain("Please send", paymentInfo.Text);
});
// Configure countdown timer
s.GoToHome();
invoiceId = s.CreateInvoice();
s.GoToHome();
s.GoToStore(StoreNavPages.CheckoutAppearance);
var displayExpirationTimer = s.Driver.FindElement(By.Id("DisplayExpirationTimer"));
Assert.Equal("5", displayExpirationTimer.GetAttribute("value"));
displayExpirationTimer.Clear();
displayExpirationTimer.SendKeys("10");
s.Driver.FindElement(By.Id("Save")).Click();
Assert.Contains("Store successfully updated", s.FindAlertMessage().Text);
s.GoToInvoiceCheckout(invoiceId);
var paymentInfo = s.Driver.FindElement(By.Id("PaymentInfo"));
Assert.False(paymentInfo.Displayed);
Assert.DoesNotContain("This invoice will expire in", paymentInfo.Text);
expirySeconds = s.Driver.FindElement(By.Id("ExpirySeconds"));
expirySeconds.Clear();
expirySeconds.SendKeys("599");
s.Driver.FindElement(By.Id("Expire")).Click();
TestUtils.Eventually(() =>
{
paymentInfo = s.Driver.WaitForElement(By.Id("PaymentInfo"));
Assert.True(paymentInfo.Displayed);
Assert.Contains("This invoice will expire in", paymentInfo.Text);
Assert.Contains("09:5", paymentInfo.Text);
});
// Disable LNURL again
s.GoToHome();
s.GoToLightningSettings();
s.Driver.SetCheckbox(By.Id("LNURLEnabled"), false);
s.Driver.ScrollTo(By.Id("save"));
s.Driver.FindElement(By.Id("save")).Click();
Assert.Contains("BTC Lightning settings successfully updated", s.FindAlertMessage().Text);
// Test:
// - NFC/LNURL-W available with just Lightning
// - BIP21 works correctly even though Lightning is default payment method
s.GoToHome();
invoiceId = s.CreateInvoice(defaultPaymentMethod: "BTC-LN");
s.GoToInvoiceCheckout(invoiceId);
Assert.Empty(s.Driver.FindElements(By.CssSelector(".payment-method")));
payUrl = s.Driver.FindElement(By.Id("PayInWallet")).GetAttribute("href");
Assert.StartsWith("bitcoin:", payUrl);
Assert.Contains("&lightning=lnbcrt", payUrl);
// Language Switch
var languageSelect = new SelectElement(s.Driver.FindElement(By.Id("DefaultLang")));
Assert.Equal("English", languageSelect.SelectedOption.Text);
Assert.Equal("View Details", s.Driver.FindElement(By.Id("DetailsToggle")).Text);
Assert.DoesNotContain("lang=", s.Driver.Url);
languageSelect.SelectByText("Deutsch");
Assert.Equal("Details anzeigen", s.Driver.FindElement(By.Id("DetailsToggle")).Text);
Assert.Contains("lang=de", s.Driver.Url);
s.Driver.Navigate().Refresh();
languageSelect = new SelectElement(s.Driver.WaitForElement(By.Id("DefaultLang")));
Assert.Equal("Deutsch", languageSelect.SelectedOption.Text);
Assert.Equal("Details anzeigen", s.Driver.FindElement(By.Id("DetailsToggle")).Text);
languageSelect.SelectByText("English");
Assert.Equal("View Details", s.Driver.FindElement(By.Id("DetailsToggle")).Text);
Assert.Contains("lang=en", s.Driver.Url);
}
[Fact(Timeout = TestTimeout)]
public async Task CanUseCheckoutAsModal()
{
using var s = CreateSeleniumTester();
await s.StartAsync();
s.GoToRegister();
s.RegisterNewUser();
s.CreateNewStore();
s.GoToStore();
s.AddDerivationScheme();
var invoiceId = s.CreateInvoice(0.001m, "BTC", "a@x.com");
var invoice = await s.Server.PayTester.InvoiceRepository.GetInvoice(invoiceId);
s.Driver.Navigate()
.GoToUrl(new Uri(s.ServerUri, $"tests/index.html?invoice={invoiceId}"));
s.Driver.WaitUntilAvailable(By.Name("btcpay"));
var frameElement = s.Driver.FindElement(By.Name("btcpay"));
Assert.True(frameElement.Displayed);
var iframe = s.Driver.SwitchTo().Frame(frameElement);
iframe.WaitUntilAvailable(By.Id("Checkout"));
await s.Server.ExplorerNode.SendToAddressAsync(BitcoinAddress.Create(invoice
.GetPaymentPrompt(PaymentTypes.CHAIN.GetPaymentMethodId("BTC"))
.Destination, Network.RegTest),
new Money(0.001m, MoneyUnit.BTC));
TestUtils.Eventually(() =>
{
var closeButton = iframe.FindElement(By.Id("close"));
Assert.True(closeButton.Displayed);
closeButton.Click();
});
s.Driver.AssertElementNotFound(By.Name("btcpay"));
Assert.Equal(s.Driver.Url,
new Uri(s.ServerUri, $"tests/index.html?invoice={invoiceId}").ToString());
}
}
}

View File

@@ -250,11 +250,11 @@ namespace BTCPayServer.Tests
await s.StartAsync();
s.RegisterNewUser(true);
var receiver = s.CreateNewStore();
s.GenerateWallet("BTC", "", true, true, ScriptPubKeyType.Segwit);
s.GenerateWallet("BTC", "", true, true);
var receiverWalletId = new WalletId(receiver.storeId, "BTC");
var sender = s.CreateNewStore();
s.GenerateWallet("BTC", "", true, true, ScriptPubKeyType.Segwit);
s.GenerateWallet("BTC", "", true, true);
var senderWalletId = new WalletId(sender.storeId, "BTC");
await s.Server.ExplorerNode.GenerateAsync(1);
@@ -263,8 +263,7 @@ namespace BTCPayServer.Tests
var invoiceId = s.CreateInvoice(receiver.storeId, null, "BTC");
s.GoToInvoiceCheckout(invoiceId);
var bip21 = s.Driver.FindElement(By.ClassName("payment__details__instruction__open-wallet__btn"))
.GetAttribute("href");
var bip21 = s.Driver.WaitForElement(By.Id("PayInWallet")).GetAttribute("href");
Assert.Contains($"{PayjoinClient.BIP21EndpointKey}=", bip21);
s.GoToWallet(senderWalletId, WalletsNavPages.Send);
s.Driver.FindElement(By.Id("bip21parse")).Click();
@@ -310,8 +309,7 @@ namespace BTCPayServer.Tests
//payjoin is enabled by default.
var invoiceId = s.CreateInvoice(receiver.storeId);
s.GoToInvoiceCheckout(invoiceId);
var bip21 = s.Driver.WaitForElement(By.ClassName("payment__details__instruction__open-wallet__btn"))
.GetAttribute("href");
var bip21 = s.Driver.WaitForElement(By.Id("PayInWallet")).GetAttribute("href");
Assert.Contains($"{PayjoinClient.BIP21EndpointKey}=", bip21);
s.GoToStore(receiver.storeId);
@@ -326,8 +324,7 @@ namespace BTCPayServer.Tests
invoiceId = s.CreateInvoice(receiver.storeId);
s.GoToInvoiceCheckout(invoiceId);
bip21 = s.Driver.WaitForElement(By.ClassName("payment__details__instruction__open-wallet__btn"))
.GetAttribute("href");
bip21 = s.Driver.WaitForElement(By.Id("PayInWallet")).GetAttribute("href");
Assert.Contains($"{PayjoinClient.BIP21EndpointKey}=", bip21);
s.GoToWallet(senderWalletId, WalletsNavPages.Send);
@@ -360,8 +357,7 @@ namespace BTCPayServer.Tests
//let's do it all again, except now the receiver has funds and is able to payjoin
invoiceId = s.CreateInvoice();
s.GoToInvoiceCheckout(invoiceId);
bip21 = s.Driver.WaitForElement(By.ClassName("payment__details__instruction__open-wallet__btn"))
.GetAttribute("href");
bip21 = s.Driver.WaitForElement(By.Id("PayInWallet")).GetAttribute("href");
Assert.Contains($"{PayjoinClient.BIP21EndpointKey}", bip21);
s.GoToWallet(senderWalletId, WalletsNavPages.Send);
@@ -378,7 +374,7 @@ namespace BTCPayServer.Tests
s.Driver.FindElement(By.CssSelector("button[value=payjoin]")).Click();
return Task.CompletedTask;
});
s.FindAlertMessage(StatusMessageModel.StatusSeverity.Success);
s.FindAlertMessage();
var handler = s.Server.PayTester.GetService<PaymentMethodHandlerDictionary>().GetBitcoinHandler("BTC");
await TestUtils.EventuallyAsync(async () =>
{

View File

@@ -2910,8 +2910,7 @@ namespace BTCPayServer.Tests
// Topup Invoice test
var i = s.CreateInvoice(storeId, null, cryptoCode);
s.GoToInvoiceCheckout(i);
s.Driver.WaitForElement(By.Id("copy-tab")).Click();
var lnurl = s.Driver.FindElement(By.CssSelector("input.checkoutTextbox")).GetAttribute("value");
var lnurl = s.Driver.FindElement(By.CssSelector("#Lightning_BTC-LNURL .truncate-center-start")).Text;
var parsed = LNURL.LNURL.Parse(lnurl, out var tag);
var fetchedReuqest =
Assert.IsType<LNURL.LNURLPayRequest>(await LNURL.LNURL.FetchInformation(parsed, new HttpClient()));
@@ -2947,11 +2946,9 @@ namespace BTCPayServer.Tests
s.GoToStore(storeId);
i = s.CreateInvoice(storeId, 0.0000001m, cryptoCode);
s.GoToInvoiceCheckout(i);
s.Driver.FindElement(By.ClassName("payment__currencies_noborder")).Click();
// BOLT11 is also displayed for standard invoice (not LNURL, even if it is available)
s.Driver.WaitForElement(By.Id("copy-tab")).Click();
var bolt11 = s.Driver.FindElement(By.CssSelector("input.checkoutTextbox")).GetAttribute("value");
Lightning.BOLT11PaymentRequest.Parse(bolt11, s.Server.ExplorerNode.Network);
var bolt11 = s.Driver.FindElement(By.CssSelector("#Lightning_BTC-LN .truncate-center-start")).Text;
BOLT11PaymentRequest.Parse(bolt11, s.Server.ExplorerNode.Network);
var invoiceId = s.Driver.Url.Split('/').Last();
using (var resp = await s.Server.PayTester.HttpClient.GetAsync("BTC/lnurl/pay/i/" + invoiceId))
{
@@ -2977,7 +2974,7 @@ namespace BTCPayServer.Tests
network, new HttpClient());
lnurlResponse2 = await fetchedReuqest.SendRequest(new LightMoney(0.0000001m, LightMoneyUnit.BTC),
network, new HttpClient());
//invoice amounts do no change so the paymnet request is not regenerated
//invoice amounts do no change so the payment request is not regenerated
Assert.Equal(lnurlResponse.Pr, lnurlResponse2.Pr);
await s.Server.CustomerLightningD.Pay(lnurlResponse.Pr);
Assert.Equal(new LightMoney(0.0000001m, LightMoneyUnit.BTC),
@@ -2986,12 +2983,10 @@ namespace BTCPayServer.Tests
i = s.CreateInvoice(storeId, 0.000001m, cryptoCode);
s.GoToInvoiceCheckout(i);
s.Driver.FindElement(By.ClassName("payment__currencies_noborder"));
s.GoToStore(storeId);
i = s.CreateInvoice(storeId, null, cryptoCode);
s.GoToInvoiceCheckout(i);
s.Driver.FindElement(By.ClassName("payment__currencies_noborder"));
s.GoToHome();
s.GoToLightningSettings();
@@ -3005,9 +3000,7 @@ namespace BTCPayServer.Tests
i = s.CreateInvoice(storeId, null, cryptoCode);
s.GoToInvoiceCheckout(i);
s.Driver.FindElement(By.ClassName("payment__currencies_noborder"));
s.Driver.WaitForElement(By.Id("copy-tab")).Click();
lnurl = s.Driver.FindElement(By.CssSelector("input.checkoutTextbox")).GetAttribute("value");
lnurl = s.Driver.FindElement(By.CssSelector("#Lightning_BTC-LNURL .truncate-center-start")).Text;
Assert.StartsWith("lnurlp", lnurl);
LNURL.LNURL.Parse(lnurl, out tag);
@@ -3020,8 +3013,7 @@ namespace BTCPayServer.Tests
Assert.Contains($"{cryptoCode} Lightning settings successfully updated", s.FindAlertMessage().Text);
var invForPP = s.CreateInvoice(null, cryptoCode);
s.GoToInvoiceCheckout(invForPP);
s.Driver.WaitForElement(By.Id("copy-tab")).Click();
lnurl = s.Driver.FindElement(By.CssSelector("input.checkoutTextbox")).GetAttribute("value");
lnurl = s.Driver.FindElement(By.CssSelector("#Lightning_BTC-LNURL .truncate-center-start")).Text;
LNURL.LNURL.Parse(lnurl, out tag);
// Check that pull payment has lightning option