diff --git a/BTCPayServer.Tests/AuthenticationTests.cs b/BTCPayServer.Tests/AuthenticationTests.cs index 834a3e490..9b0ace868 100644 --- a/BTCPayServer.Tests/AuthenticationTests.cs +++ b/BTCPayServer.Tests/AuthenticationTests.cs @@ -19,16 +19,12 @@ using OpenQA.Selenium; namespace BTCPayServer.Tests { - [Collection("Selenium collection")] public class AuthenticationTests { - public SeleniumTester SeleniumTester { get; } - - public AuthenticationTests(ITestOutputHelper helper, SeleniumTester seleniumTester) + public AuthenticationTests(ITestOutputHelper helper) { - Logs.Tester = new XUnitLog(helper) { Name = "Tests" }; + Logs.Tester = new XUnitLog(helper) {Name = "Tests"}; Logs.LogProvider = new XUnitLogProvider(helper); - SeleniumTester = seleniumTester; } [Fact] @@ -97,45 +93,49 @@ namespace BTCPayServer.Tests [Fact] public async Task CanUseImplicitFlow() { - var tester = SeleniumTester.Server; + using (var s = SeleniumTester.Create()) + { + s.Start(); + var tester = s.Server; - var user = tester.NewAccount(); - user.GrantAccess(); - var id = Guid.NewGuid().ToString(); - var redirecturi = new Uri("http://127.0.0.1/oidc-callback"); - var openIdClient = await user.RegisterOpenIdClient( - new OpenIddictApplicationDescriptor() - { - ClientId = id, - DisplayName = id, - Permissions = { OpenIddictConstants.Permissions.GrantTypes.Implicit }, - RedirectUris = { redirecturi } - }); - var implicitAuthorizeUrl = new Uri(tester.PayTester.ServerUri, - $"connect/authorize?response_type=token&client_id={id}&redirect_uri={redirecturi.AbsoluteUri}&scope=openid&nonce={Guid.NewGuid().ToString()}"); - SeleniumTester.Driver.Navigate().GoToUrl(implicitAuthorizeUrl); - SeleniumTester.Login(user.RegisterDetails.Email, user.RegisterDetails.Password); - SeleniumTester.Driver.FindElement(By.Id("consent-yes")).Click(); - var url = SeleniumTester.Driver.Url; - var results = url.Split("#").Last().Split("&") - .ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]); - await TestApiAgainstAccessToken(results["access_token"], tester, user); - //in Implicit mode, you renew your token by hitting the same endpoint but adding prompt=none. If you are still logged in on the site, you will receive a fresh token. - var implicitAuthorizeUrlSilentModel = new Uri($"{implicitAuthorizeUrl.OriginalString}&prompt=none"); - SeleniumTester.Driver.Navigate().GoToUrl(implicitAuthorizeUrlSilentModel); - url = SeleniumTester.Driver.Url; - results = url.Split("#").Last().Split("&").ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]); - await TestApiAgainstAccessToken(results["access_token"], tester, user); + var user = tester.NewAccount(); + user.GrantAccess(); + var id = Guid.NewGuid().ToString(); + var redirecturi = new Uri("http://127.0.0.1/oidc-callback"); + var openIdClient = await user.RegisterOpenIdClient( + new OpenIddictApplicationDescriptor() + { + ClientId = id, + DisplayName = id, + Permissions = {OpenIddictConstants.Permissions.GrantTypes.Implicit}, + RedirectUris = {redirecturi} + }); + var implicitAuthorizeUrl = new Uri(tester.PayTester.ServerUri, + $"connect/authorize?response_type=token&client_id={id}&redirect_uri={redirecturi.AbsoluteUri}&scope=openid&nonce={Guid.NewGuid().ToString()}"); + s.Driver.Navigate().GoToUrl(implicitAuthorizeUrl); + s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password); + s.Driver.FindElement(By.Id("consent-yes")).Click(); + var url = s.Driver.Url; + var results = url.Split("#").Last().Split("&") + .ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]); + await TestApiAgainstAccessToken(results["access_token"], tester, user); + //in Implicit mode, you renew your token by hitting the same endpoint but adding prompt=none. If you are still logged in on the site, you will receive a fresh token. + var implicitAuthorizeUrlSilentModel = new Uri($"{implicitAuthorizeUrl.OriginalString}&prompt=none"); + s.Driver.Navigate().GoToUrl(implicitAuthorizeUrlSilentModel); + url = s.Driver.Url; + results = url.Split("#").Last().Split("&").ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]); + await TestApiAgainstAccessToken(results["access_token"], tester, user); - LogoutFlow(tester, id, SeleniumTester); - - SeleniumTester.Driver.Navigate().GoToUrl(implicitAuthorizeUrl); - SeleniumTester.Login(user.RegisterDetails.Email, user.RegisterDetails.Password); - - Assert.Throws(() => SeleniumTester.Driver.FindElement(By.Id("consent-yes"))); - results = url.Split("#").Last().Split("&") - .ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]); - await TestApiAgainstAccessToken(results["access_token"], tester, user); + LogoutFlow(tester, id, s); + + s.Driver.Navigate().GoToUrl(implicitAuthorizeUrl); + s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password); + + Assert.Throws(() => s.Driver.FindElement(By.Id("consent-yes"))); + results = url.Split("#").Last().Split("&") + .ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]); + await TestApiAgainstAccessToken(results["access_token"], tester, user); + } } void LogoutFlow(ServerTester tester, string clientId, SeleniumTester seleniumTester) @@ -145,47 +145,50 @@ namespace BTCPayServer.Tests seleniumTester.Driver.Navigate().GoToUrl(logoutUrl); seleniumTester.GoToHome(); Assert.Throws(() => seleniumTester.Driver.FindElement(By.Id("Logout"))); - + } [Trait("Selenium", "Selenium")] [Fact] public async Task CanUseCodeFlow() { - var tester = SeleniumTester.Server; + using (var s = SeleniumTester.Create()) + { + s.Start(); + var tester = s.Server; - var user = tester.NewAccount(); - user.GrantAccess(); - var id = Guid.NewGuid().ToString(); - var redirecturi = new Uri("http://127.0.0.1/oidc-callback"); - var secret = "secret"; - var openIdClient = await user.RegisterOpenIdClient( - new OpenIddictApplicationDescriptor() - { - ClientId = id, - DisplayName = id, - Permissions = + var user = tester.NewAccount(); + user.GrantAccess(); + var id = Guid.NewGuid().ToString(); + var redirecturi = new Uri("http://127.0.0.1/oidc-callback"); + var secret = "secret"; + var openIdClient = await user.RegisterOpenIdClient( + new OpenIddictApplicationDescriptor() { + ClientId = id, + DisplayName = id, + Permissions = + { OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode, OpenIddictConstants.Permissions.GrantTypes.RefreshToken - }, - RedirectUris = { redirecturi } - }, secret); - var authorizeUrl = new Uri(tester.PayTester.ServerUri, - $"connect/authorize?response_type=code&client_id={id}&redirect_uri={redirecturi.AbsoluteUri}&scope=openid offline_access&state={Guid.NewGuid().ToString()}"); - SeleniumTester.Driver.Navigate().GoToUrl(authorizeUrl); - SeleniumTester.Login(user.RegisterDetails.Email, user.RegisterDetails.Password); - SeleniumTester.Driver.FindElement(By.Id("consent-yes")).Click(); - var url = SeleniumTester.Driver.Url; - var results = url.Split("?").Last().Split("&") - .ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]); + }, + RedirectUris = {redirecturi} + }, secret); + var authorizeUrl = new Uri(tester.PayTester.ServerUri, + $"connect/authorize?response_type=code&client_id={id}&redirect_uri={redirecturi.AbsoluteUri}&scope=openid offline_access&state={Guid.NewGuid().ToString()}"); + s.Driver.Navigate().GoToUrl(authorizeUrl); + s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password); + s.Driver.FindElement(By.Id("consent-yes")).Click(); + var url = s.Driver.Url; + var results = url.Split("?").Last().Split("&") + .ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]); - var httpClient = tester.PayTester.HttpClient; + var httpClient = tester.PayTester.HttpClient; - var httpRequest = new HttpRequestMessage(HttpMethod.Post, - new Uri(tester.PayTester.ServerUri, "/connect/token")) - { - Content = new FormUrlEncodedContent(new List>() + var httpRequest = new HttpRequestMessage(HttpMethod.Post, + new Uri(tester.PayTester.ServerUri, "/connect/token")) + { + Content = new FormUrlEncodedContent(new List>() { new KeyValuePair("grant_type", OpenIddictConstants.GrantTypes.AuthorizationCode), @@ -194,30 +197,31 @@ namespace BTCPayServer.Tests new KeyValuePair("code", results["code"]), new KeyValuePair("redirect_uri", redirecturi.AbsoluteUri) }) - }; + }; - var response = await httpClient.SendAsync(httpRequest); + var response = await httpClient.SendAsync(httpRequest); - Assert.True(response.IsSuccessStatusCode); + Assert.True(response.IsSuccessStatusCode); - string content = await response.Content.ReadAsStringAsync(); - var result = JObject.Parse(content).ToObject(); + string content = await response.Content.ReadAsStringAsync(); + var result = JObject.Parse(content).ToObject(); - await TestApiAgainstAccessToken(result.AccessToken, tester, user); + await TestApiAgainstAccessToken(result.AccessToken, tester, user); - var refreshedAccessToken = await RefreshAnAccessToken(result.RefreshToken, httpClient, id, secret); + var refreshedAccessToken = await RefreshAnAccessToken(result.RefreshToken, httpClient, id, secret); - await TestApiAgainstAccessToken(refreshedAccessToken, tester, user); - - LogoutFlow(tester, id, SeleniumTester); - SeleniumTester.Driver.Navigate().GoToUrl(authorizeUrl); - SeleniumTester.Login(user.RegisterDetails.Email, user.RegisterDetails.Password); - - Assert.Throws(() => SeleniumTester.Driver.FindElement(By.Id("consent-yes"))); - results = url.Split("?").Last().Split("&") - .ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]); - Assert.True(results.ContainsKey("code")); + await TestApiAgainstAccessToken(refreshedAccessToken, tester, user); + + LogoutFlow(tester, id, s); + s.Driver.Navigate().GoToUrl(authorizeUrl); + s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password); + + Assert.Throws(() => s.Driver.FindElement(By.Id("consent-yes"))); + results = url.Split("?").Last().Split("&") + .ToDictionary(s1 => s1.Split("=")[0], s1 => s1.Split("=")[1]); + Assert.True(results.ContainsKey("code")); + } } private static async Task RefreshAnAccessToken(string refreshToken, HttpClient client, string clientId, @@ -257,7 +261,7 @@ namespace BTCPayServer.Tests { ClientId = id, DisplayName = id, - Permissions = { OpenIddictConstants.Permissions.GrantTypes.ClientCredentials } + Permissions = {OpenIddictConstants.Permissions.GrantTypes.ClientCredentials} }, secret); @@ -296,7 +300,7 @@ namespace BTCPayServer.Tests { ClientId = id, DisplayName = id, - Permissions = { OpenIddictConstants.Permissions.GrantTypes.Password } + Permissions = {OpenIddictConstants.Permissions.GrantTypes.Password} }, secret); diff --git a/BTCPayServer.Tests/CheckoutUITests.cs b/BTCPayServer.Tests/CheckoutUITests.cs index 1a7cfa227..8d0dd0d5f 100644 --- a/BTCPayServer.Tests/CheckoutUITests.cs +++ b/BTCPayServer.Tests/CheckoutUITests.cs @@ -15,140 +15,163 @@ using Xunit.Abstractions; namespace BTCPayServer.Tests { [Trait("Selenium", "Selenium")] - [Collection("Selenium collection")] public class CheckoutUITests { - public SeleniumTester SeleniumTester { get; } - - public CheckoutUITests(ITestOutputHelper helper, SeleniumTester seleniumTester) + public CheckoutUITests(ITestOutputHelper helper) { - Logs.Tester = new XUnitLog(helper) { Name = "Tests" }; + Logs.Tester = new XUnitLog(helper) {Name = "Tests"}; Logs.LogProvider = new XUnitLogProvider(helper); - SeleniumTester = seleniumTester; } - - + + [Fact] public void CanCreateInvoice() { - SeleniumTester.RegisterNewUser(); - var store = SeleniumTester.CreateNewStore().storeName; - SeleniumTester.AddDerivationScheme(); + using (var s = SeleniumTester.Create()) + { + s.Start(); + s.RegisterNewUser(); + var store = s.CreateNewStore().storeName; + s.AddDerivationScheme(); - SeleniumTester.CreateInvoice(store); + s.CreateInvoice(store); - SeleniumTester.Driver.FindElement(By.ClassName("invoice-details-link")).Click(); - SeleniumTester.Driver.AssertNoError(); - SeleniumTester.Driver.Navigate().Back(); - SeleniumTester.Driver.FindElement(By.ClassName("invoice-checkout-link")).Click(); - Assert.NotEmpty(SeleniumTester.Driver.FindElements(By.Id("checkoutCtrl"))); + s.Driver.FindElement(By.ClassName("invoice-details-link")).Click(); + s.Driver.AssertNoError(); + s.Driver.Navigate().Back(); + s.Driver.FindElement(By.ClassName("invoice-checkout-link")).Click(); + Assert.NotEmpty(s.Driver.FindElements(By.Id("checkoutCtrl"))); + s.Driver.Quit(); + } } - + [Fact] public async Task CanHandleRefundEmailForm() { - SeleniumTester.RegisterNewUser(); - var store = SeleniumTester.CreateNewStore(); - SeleniumTester.AddDerivationScheme("BTC"); - var emailAlreadyThereInvoiceId = SeleniumTester.CreateInvoice(store.storeName, 100, "USD", "a@g.com"); - SeleniumTester.GoToInvoiceCheckout(emailAlreadyThereInvoiceId); - SeleniumTester.Driver.AssertElementNotFound(By.Id("emailAddressFormInput")); - SeleniumTester.GoToHome(); - var invoiceId = SeleniumTester.CreateInvoice(store.storeName); - SeleniumTester.GoToInvoiceCheckout(invoiceId); - Assert.True(SeleniumTester.Driver.FindElement(By.Id("emailAddressFormInput")).Displayed); - SeleniumTester.Driver.FindElement(By.Id("emailAddressFormInput")).SendKeys("xxx"); - SeleniumTester.Driver.FindElement(By.Id("emailAddressForm")).FindElement(By.CssSelector("button.action-button")) - .Click(); + using (var s = SeleniumTester.Create()) + { + s.Start(); + s.RegisterNewUser(); + var store = s.CreateNewStore(); + s.AddDerivationScheme("BTC"); - Assert.True(SeleniumTester.Driver.FindElement(By.Id("emailAddressFormInput")).Displayed); - SeleniumTester.Driver.FindElement(By.Id("emailAddressFormInput")).SendKeys("@g.com"); - SeleniumTester.Driver.FindElement(By.Id("emailAddressForm")).FindElement(By.CssSelector("button.action-button")) - .Click(); + var emailAlreadyThereInvoiceId =s.CreateInvoice(store.storeName, 100, "USD", "a@g.com"); + s.GoToInvoiceCheckout(emailAlreadyThereInvoiceId); + s.Driver.AssertElementNotFound(By.Id("emailAddressFormInput")); + s.GoToHome(); + var invoiceId = s.CreateInvoice(store.storeName); + s.GoToInvoiceCheckout(invoiceId); + Assert.True(s.Driver.FindElement(By.Id("emailAddressFormInput")).Displayed); + s.Driver.FindElement(By.Id("emailAddressFormInput")).SendKeys("xxx"); + s.Driver.FindElement(By.Id("emailAddressForm")).FindElement(By.CssSelector("button.action-button")) + .Click(); + + Assert.True(s.Driver.FindElement(By.Id("emailAddressFormInput")).Displayed); + s.Driver.FindElement(By.Id("emailAddressFormInput")).SendKeys("@g.com"); + s.Driver.FindElement(By.Id("emailAddressForm")).FindElement(By.CssSelector("button.action-button")) + .Click(); - await Task.Delay(1000); - SeleniumTester.Driver.AssertElementNotFound(By.Id("emailAddressFormInput")); + await Task.Delay(1000); + s.Driver.AssertElementNotFound(By.Id("emailAddressFormInput")); + + s.Driver.Navigate().Refresh(); - SeleniumTester.Driver.Navigate().Refresh(); - - SeleniumTester.Driver.AssertElementNotFound(By.Id("emailAddressFormInput")); + s.Driver.AssertElementNotFound(By.Id("emailAddressFormInput")); + } } [Fact] public async Task CanUseLanguageDropdown() { - SeleniumTester.RegisterNewUser(); - var store = SeleniumTester.CreateNewStore(); - SeleniumTester.AddDerivationScheme("BTC"); + using (var s = SeleniumTester.Create()) + { + s.Start(); + s.RegisterNewUser(); + var store = s.CreateNewStore(); + s.AddDerivationScheme("BTC"); - var invoiceId = SeleniumTester.CreateInvoice(store.storeName); - SeleniumTester.GoToInvoiceCheckout(invoiceId); - Assert.True(SeleniumTester.Driver.FindElement(By.Id("DefaultLang")).FindElements(By.TagName("option")).Count > 1); - var payWithTextEnglish = SeleniumTester.Driver.FindElement(By.Id("pay-with-text")).Text; - - var prettyDropdown = SeleniumTester.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, SeleniumTester.Driver.FindElement(By.Id("pay-with-text")).Text); - SeleniumTester.Driver.Navigate().GoToUrl(SeleniumTester.Driver.Url + "?lang=da-DK"); - - Assert.NotEqual(payWithTextEnglish, SeleniumTester.Driver.FindElement(By.Id("pay-with-text")).Text); + var invoiceId = s.CreateInvoice(store.storeName); + 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] public void CanUsePaymentMethodDropdown() { - SeleniumTester.RegisterNewUser(); - var store = SeleniumTester.CreateNewStore(); - SeleniumTester.AddDerivationScheme("BTC"); - - //check that there is no dropdown since only one payment method is set - var invoiceId = SeleniumTester.CreateInvoice(store.storeName, 10, "USD", "a@g.com"); - SeleniumTester.GoToInvoiceCheckout(invoiceId); - SeleniumTester.Driver.FindElement(By.ClassName("payment__currencies_noborder")); - SeleniumTester.GoToHome(); - SeleniumTester.GoToStore(store.storeId); - SeleniumTester.AddDerivationScheme("LTC"); - SeleniumTester.AddLightningNode("BTC", LightningConnectionType.CLightning); - //there should be three now - invoiceId = SeleniumTester.CreateInvoice(store.storeName, 10, "USD", "a@g.com"); - SeleniumTester.GoToInvoiceCheckout(invoiceId); - var currencyDropdownButton = SeleniumTester.Driver.FindElement(By.ClassName("payment__currencies")); - Assert.Contains("BTC", currencyDropdownButton.Text); - currencyDropdownButton.Click(); - - var elements = SeleniumTester.Driver.FindElement(By.ClassName("vex-content")) - .FindElements(By.ClassName("vexmenuitem")); - Assert.Equal(3, elements.Count); - elements.Single(element => element.Text.Contains("LTC")).Click(); - currencyDropdownButton = SeleniumTester.Driver.FindElement(By.ClassName("payment__currencies")); - Assert.Contains("LTC", currencyDropdownButton.Text); - - elements = SeleniumTester.Driver.FindElement(By.ClassName("vex-content")) - .FindElements(By.ClassName("vexmenuitem")); - - elements.Single(element => element.Text.Contains("Lightning")).Click(); - - Assert.Contains("Lightning", currencyDropdownButton.Text); + using (var s = SeleniumTester.Create()) + { + s.Start(); + s.RegisterNewUser(); + var store = s.CreateNewStore(); + s.AddDerivationScheme("BTC"); + + //check that there is no dropdown since only one payment method is set + var invoiceId = s.CreateInvoice(store.storeName, 10, "USD", "a@g.com"); + s.GoToInvoiceCheckout(invoiceId); + s.Driver.FindElement(By.ClassName("payment__currencies_noborder")); + s.GoToHome(); + s.GoToStore(store.storeId); + s.AddDerivationScheme("LTC"); + s.AddLightningNode("BTC",LightningConnectionType.CLightning); + //there should be three now + invoiceId = s.CreateInvoice(store.storeName, 10, "USD", "a@g.com"); + s.GoToInvoiceCheckout(invoiceId); + var currencyDropdownButton = s.Driver.FindElement(By.ClassName("payment__currencies")); + Assert.Contains("BTC", currencyDropdownButton.Text); + currencyDropdownButton.Click(); + + var elements = s.Driver.FindElement(By.ClassName("vex-content")) + .FindElements(By.ClassName("vexmenuitem")); + Assert.Equal(3, elements.Count); + elements.Single(element => element.Text.Contains("LTC")).Click(); + currencyDropdownButton = s.Driver.FindElement(By.ClassName("payment__currencies")); + Assert.Contains("LTC", currencyDropdownButton.Text); + + elements = s.Driver.FindElement(By.ClassName("vex-content")) + .FindElements(By.ClassName("vexmenuitem")); + + elements.Single(element => element.Text.Contains("Lightning")).Click(); + + Assert.Contains("Lightning", currencyDropdownButton.Text); + + s.Driver.Quit(); + } } - + [Fact] public void CanUseLightningSatsFeature() { - SeleniumTester.RegisterNewUser(); - var store = SeleniumTester.CreateNewStore(); - SeleniumTester.AddInternalLightningNode("BTC"); - SeleniumTester.GoToStore(store.storeId, StoreNavPages.Checkout); - SeleniumTester.SetCheckbox(SeleniumTester, "LightningAmountInSatoshi", true); - var command = SeleniumTester.Driver.FindElement(By.Name("command")); - - command.ForceClick(); - var invoiceId = SeleniumTester.CreateInvoice(store.storeName, 10, "USD", "a@g.com"); - SeleniumTester.GoToInvoiceCheckout(invoiceId); - Assert.Contains("Sats", SeleniumTester.Driver.FindElement(By.ClassName("payment__currencies_noborder")).Text); + using (var s = SeleniumTester.Create()) + { + s.Start(); + s.RegisterNewUser(); + var store = s.CreateNewStore(); + s.AddInternalLightningNode("BTC"); + s.GoToStore(store.storeId, StoreNavPages.Checkout); + s.SetCheckbox(s, "LightningAmountInSatoshi", true); + var command = s.Driver.FindElement(By.Name("command")); + + command.ForceClick(); + var invoiceId = s.CreateInvoice(store.storeName, 10, "USD", "a@g.com"); + s.GoToInvoiceCheckout(invoiceId); + Assert.Contains("Sats", s.Driver.FindElement(By.ClassName("payment__currencies_noborder")).Text); + + } } } } diff --git a/BTCPayServer.Tests/SeleniumTester.cs b/BTCPayServer.Tests/SeleniumTester.cs index d4d442536..3507b6b9f 100644 --- a/BTCPayServer.Tests/SeleniumTester.cs +++ b/BTCPayServer.Tests/SeleniumTester.cs @@ -27,42 +27,20 @@ namespace BTCPayServer.Tests { public class SeleniumTester : IDisposable { - private IWebDriver _Driver; - public IWebDriver Driver - { - get - { - if (_Driver == null) - { - Start(); - } - return _Driver; - } - } - private ServerTester _Server; - public ServerTester Server - { - get - { - if (_Server == null) - { - _Server = ServerTester.Create("Default Scope"); - Start(); - } - return _Server; - } - } + public IWebDriver Driver { get; set; } + public ServerTester Server { get; set; } public static SeleniumTester Create([CallerMemberNameAttribute] string scope = null) { + var server = ServerTester.Create(scope); return new SeleniumTester() { - _Server = ServerTester.Create(scope) + Server = server }; } - void Start() + public void Start() { Server.Start(); ChromeOptions options = new ChromeOptions(); @@ -78,7 +56,7 @@ namespace BTCPayServer.Tests { options.AddArgument("no-sandbox"); } - _Driver = new ChromeDriver(Server.PayTester.InContainer ? "/usr/bin" : Directory.GetCurrentDirectory(), options); + Driver = new ChromeDriver(Server.PayTester.InContainer ? "/usr/bin" : Directory.GetCurrentDirectory(), options); if (isDebug) { //when running locally, depending on your resolution, the website may go into mobile responsive mode and screw with navigation of tests @@ -99,10 +77,7 @@ namespace BTCPayServer.Tests public string RegisterNewUser(bool isAdmin = false) { - GoToHome(); - if (Driver.PageSource.Contains("id=\"Logout\"")) - Logout(); - var usr = RandomUtils.GetUInt256().ToString().Substring(20) + "@a.com"; + var usr = RandomUtils.GetUInt256().ToString() + "@a.com"; Driver.FindElement(By.Id("Register")).Click(); Driver.FindElement(By.Id("Email")).SendKeys(usr); Driver.FindElement(By.Id("Password")).SendKeys("123456"); diff --git a/BTCPayServer.Tests/SeleniumTests.cs b/BTCPayServer.Tests/SeleniumTests.cs index 0d89c6f44..dddc218ba 100644 --- a/BTCPayServer.Tests/SeleniumTests.cs +++ b/BTCPayServer.Tests/SeleniumTests.cs @@ -12,72 +12,79 @@ using System.Threading.Tasks; namespace BTCPayServer.Tests { [Trait("Selenium", "Selenium")] - [Collection("Selenium collection")] public class ChromeTests { - public SeleniumTester SeleniumTester { get; } - - public ChromeTests(ITestOutputHelper helper, SeleniumTester seleniumTester) + public ChromeTests(ITestOutputHelper helper) { Logs.Tester = new XUnitLog(helper) { Name = "Tests" }; Logs.LogProvider = new XUnitLogProvider(helper); - SeleniumTester = seleniumTester; } [Fact] public void CanNavigateServerSettings() { - SeleniumTester.RegisterNewUser(true); - SeleniumTester.Driver.FindElement(By.Id("ServerSettings")).Click(); - SeleniumTester.Driver.AssertNoError(); - SeleniumTester.ClickOnAllSideMenus(); + using (var s = SeleniumTester.Create()) + { + s.Start(); + s.RegisterNewUser(true); + s.Driver.FindElement(By.Id("ServerSettings")).Click(); + s.Driver.AssertNoError(); + s.ClickOnAllSideMenus(); + s.Driver.Quit(); + } } [Fact] public void NewUserLogin() { - //Register & Log Out - var email = SeleniumTester.RegisterNewUser(); - SeleniumTester.Driver.FindElement(By.Id("Logout")).Click(); - SeleniumTester.Driver.AssertNoError(); - SeleniumTester.Driver.FindElement(By.Id("Login")).Click(); - SeleniumTester.Driver.AssertNoError(); + using (var s = SeleniumTester.Create()) + { + s.Start(); + //Register & Log Out + var email = s.RegisterNewUser(); + s.Driver.FindElement(By.Id("Logout")).Click(); + s.Driver.AssertNoError(); + s.Driver.FindElement(By.Id("Login")).Click(); + s.Driver.AssertNoError(); - SeleniumTester.Driver.Navigate().GoToUrl(SeleniumTester.Link("/invoices")); - Assert.Contains("ReturnUrl=%2Finvoices", SeleniumTester.Driver.Url); + s.Driver.Navigate().GoToUrl(s.Link("/invoices")); + Assert.Contains("ReturnUrl=%2Finvoices", s.Driver.Url); - // We should be redirected to login - //Same User Can Log Back In - SeleniumTester.Driver.FindElement(By.Id("Email")).SendKeys(email); - SeleniumTester.Driver.FindElement(By.Id("Password")).SendKeys("123456"); - SeleniumTester.Driver.FindElement(By.Id("LoginButton")).Click(); + // We should be redirected to login + //Same User Can Log Back In + s.Driver.FindElement(By.Id("Email")).SendKeys(email); + s.Driver.FindElement(By.Id("Password")).SendKeys("123456"); + s.Driver.FindElement(By.Id("LoginButton")).Click(); - // We should be redirected to invoice - Assert.EndsWith("/invoices", SeleniumTester.Driver.Url); + // We should be redirected to invoice + Assert.EndsWith("/invoices", s.Driver.Url); - // Should not be able to reach server settings - SeleniumTester.Driver.Navigate().GoToUrl(SeleniumTester.Link("/server/users")); - Assert.Contains("ReturnUrl=%2Fserver%2Fusers", SeleniumTester.Driver.Url); + // Should not be able to reach server settings + s.Driver.Navigate().GoToUrl(s.Link("/server/users")); + Assert.Contains("ReturnUrl=%2Fserver%2Fusers", s.Driver.Url); - //Change Password & Log Out - SeleniumTester.Driver.FindElement(By.Id("MySettings")).Click(); - SeleniumTester.Driver.FindElement(By.Id("ChangePassword")).Click(); - SeleniumTester.Driver.FindElement(By.Id("OldPassword")).SendKeys("123456"); - SeleniumTester.Driver.FindElement(By.Id("NewPassword")).SendKeys("abc???"); - SeleniumTester.Driver.FindElement(By.Id("ConfirmPassword")).SendKeys("abc???"); - SeleniumTester.Driver.FindElement(By.Id("UpdatePassword")).Click(); - SeleniumTester.Driver.FindElement(By.Id("Logout")).Click(); - SeleniumTester.Driver.AssertNoError(); + //Change Password & Log Out + s.Driver.FindElement(By.Id("MySettings")).Click(); + s.Driver.FindElement(By.Id("ChangePassword")).Click(); + s.Driver.FindElement(By.Id("OldPassword")).SendKeys("123456"); + s.Driver.FindElement(By.Id("NewPassword")).SendKeys("abc???"); + s.Driver.FindElement(By.Id("ConfirmPassword")).SendKeys("abc???"); + s.Driver.FindElement(By.Id("UpdatePassword")).Click(); + s.Driver.FindElement(By.Id("Logout")).Click(); + s.Driver.AssertNoError(); - //Log In With New Password - SeleniumTester.Driver.FindElement(By.Id("Login")).Click(); - SeleniumTester.Driver.FindElement(By.Id("Email")).SendKeys(email); - SeleniumTester.Driver.FindElement(By.Id("Password")).SendKeys("abc???"); - SeleniumTester.Driver.FindElement(By.Id("LoginButton")).Click(); - Assert.True(SeleniumTester.Driver.PageSource.Contains("Stores"), "Can't Access Stores"); + //Log In With New Password + s.Driver.FindElement(By.Id("Login")).Click(); + s.Driver.FindElement(By.Id("Email")).SendKeys(email); + s.Driver.FindElement(By.Id("Password")).SendKeys("abc???"); + s.Driver.FindElement(By.Id("LoginButton")).Click(); + Assert.True(s.Driver.PageSource.Contains("Stores"), "Can't Access Stores"); - SeleniumTester.Driver.FindElement(By.Id("MySettings")).Click(); - SeleniumTester.ClickOnAllSideMenus(); + s.Driver.FindElement(By.Id("MySettings")).Click(); + s.ClickOnAllSideMenus(); + + s.Driver.Quit(); + } } static void LogIn(SeleniumTester s, string email) @@ -91,239 +98,270 @@ namespace BTCPayServer.Tests [Fact] public async Task CanUseSSHService() { - var alice = SeleniumTester.RegisterNewUser(isAdmin: true); - SeleniumTester.Driver.Navigate().GoToUrl(SeleniumTester.Link("/server/services")); - Assert.Contains("server/services/ssh", SeleniumTester.Driver.PageSource); - using (var client = await SeleniumTester.Server.PayTester.GetService().SSHSettings.ConnectAsync()) + using (var s = SeleniumTester.Create()) { - var result = await client.RunBash("echo hello"); - Assert.Equal(string.Empty, result.Error); - Assert.Equal("hello\n", result.Output); - Assert.Equal(0, result.ExitStatus); + s.Start(); + var alice = s.RegisterNewUser(isAdmin: true); + s.Driver.Navigate().GoToUrl(s.Link("/server/services")); + Assert.Contains("server/services/ssh", s.Driver.PageSource); + using (var client = await s.Server.PayTester.GetService().SSHSettings.ConnectAsync()) + { + var result = await client.RunBash("echo hello"); + Assert.Equal(string.Empty, result.Error); + Assert.Equal("hello\n", result.Output); + Assert.Equal(0, result.ExitStatus); + } + s.Driver.Navigate().GoToUrl(s.Link("/server/services/ssh")); + s.Driver.AssertNoError(); } - SeleniumTester.Driver.Navigate().GoToUrl(SeleniumTester.Link("/server/services/ssh")); - SeleniumTester.Driver.AssertNoError(); } [Fact] public void CanUseDynamicDns() { - var alice = SeleniumTester.RegisterNewUser(isAdmin: true); - SeleniumTester.Driver.Navigate().GoToUrl(SeleniumTester.Link("/server/services")); - Assert.Contains("Dynamic DNS", SeleniumTester.Driver.PageSource); - - SeleniumTester.Driver.Navigate().GoToUrl(SeleniumTester.Link("/server/services/dynamic-dns")); - SeleniumTester.Driver.AssertNoError(); - if (SeleniumTester.Driver.PageSource.Contains("pouet.hello.com")) + using (var s = SeleniumTester.Create()) { - // Cleanup old test run - SeleniumTester.Driver.Navigate().GoToUrl(SeleniumTester.Link("/server/services/dynamic-dns/pouet.hello.com/delete")); - SeleniumTester.Driver.FindElement(By.Id("continue")).Click(); + s.Start(); + var alice = s.RegisterNewUser(isAdmin: true); + s.Driver.Navigate().GoToUrl(s.Link("/server/services")); + Assert.Contains("Dynamic DNS", s.Driver.PageSource); + + s.Driver.Navigate().GoToUrl(s.Link("/server/services/dynamic-dns")); + s.Driver.AssertNoError(); + if (s.Driver.PageSource.Contains("pouet.hello.com")) + { + // Cleanup old test run + s.Driver.Navigate().GoToUrl(s.Link("/server/services/dynamic-dns/pouet.hello.com/delete")); + s.Driver.FindElement(By.Id("continue")).Click(); + } + s.Driver.FindElement(By.Id("AddDynamicDNS")).Click(); + s.Driver.AssertNoError(); + // We will just cheat for test purposes by only querying the server + s.Driver.FindElement(By.Id("ServiceUrl")).SendKeys(s.Link("/")); + s.Driver.FindElement(By.Id("Settings_Hostname")).SendKeys("pouet.hello.com"); + s.Driver.FindElement(By.Id("Settings_Login")).SendKeys("MyLog"); + s.Driver.FindElement(By.Id("Settings_Password")).SendKeys("MyLog" + Keys.Enter); + s.Driver.AssertNoError(); + Assert.Contains("The Dynamic DNS has been successfully queried", s.Driver.PageSource); + Assert.EndsWith("/server/services/dynamic-dns", s.Driver.Url); + + // Try to do the same thing should fail (hostname already exists) + s.Driver.FindElement(By.Id("AddDynamicDNS")).Click(); + s.Driver.AssertNoError(); + s.Driver.FindElement(By.Id("ServiceUrl")).SendKeys(s.Link("/")); + s.Driver.FindElement(By.Id("Settings_Hostname")).SendKeys("pouet.hello.com"); + s.Driver.FindElement(By.Id("Settings_Login")).SendKeys("MyLog"); + s.Driver.FindElement(By.Id("Settings_Password")).SendKeys("MyLog" + Keys.Enter); + s.Driver.AssertNoError(); + Assert.Contains("This hostname already exists", s.Driver.PageSource); + + // Delete it + s.Driver.Navigate().GoToUrl(s.Link("/server/services/dynamic-dns")); + Assert.Contains("/server/services/dynamic-dns/pouet.hello.com/delete", s.Driver.PageSource); + s.Driver.Navigate().GoToUrl(s.Link("/server/services/dynamic-dns/pouet.hello.com/delete")); + s.Driver.FindElement(By.Id("continue")).Click(); + s.Driver.AssertNoError(); + + Assert.DoesNotContain("/server/services/dynamic-dns/pouet.hello.com/delete", s.Driver.PageSource); } - SeleniumTester.Driver.FindElement(By.Id("AddDynamicDNS")).Click(); - SeleniumTester.Driver.AssertNoError(); - // We will just cheat for test purposes by only querying the server - SeleniumTester.Driver.FindElement(By.Id("ServiceUrl")).SendKeys(SeleniumTester.Link("/")); - SeleniumTester.Driver.FindElement(By.Id("Settings_Hostname")).SendKeys("pouet.hello.com"); - SeleniumTester.Driver.FindElement(By.Id("Settings_Login")).SendKeys("MyLog"); - SeleniumTester.Driver.FindElement(By.Id("Settings_Password")).SendKeys("MyLog" + Keys.Enter); - SeleniumTester.Driver.AssertNoError(); - Assert.Contains("The Dynamic DNS has been successfully queried", SeleniumTester.Driver.PageSource); - Assert.EndsWith("/server/services/dynamic-dns", SeleniumTester.Driver.Url); - - // Try to do the same thing should fail (hostname already exists) - SeleniumTester.Driver.FindElement(By.Id("AddDynamicDNS")).Click(); - SeleniumTester.Driver.AssertNoError(); - SeleniumTester.Driver.FindElement(By.Id("ServiceUrl")).SendKeys(SeleniumTester.Link("/")); - SeleniumTester.Driver.FindElement(By.Id("Settings_Hostname")).SendKeys("pouet.hello.com"); - SeleniumTester.Driver.FindElement(By.Id("Settings_Login")).SendKeys("MyLog"); - SeleniumTester.Driver.FindElement(By.Id("Settings_Password")).SendKeys("MyLog" + Keys.Enter); - SeleniumTester.Driver.AssertNoError(); - Assert.Contains("This hostname already exists", SeleniumTester.Driver.PageSource); - - // Delete it - SeleniumTester.Driver.Navigate().GoToUrl(SeleniumTester.Link("/server/services/dynamic-dns")); - Assert.Contains("/server/services/dynamic-dns/pouet.hello.com/delete", SeleniumTester.Driver.PageSource); - SeleniumTester.Driver.Navigate().GoToUrl(SeleniumTester.Link("/server/services/dynamic-dns/pouet.hello.com/delete")); - SeleniumTester.Driver.FindElement(By.Id("continue")).Click(); - SeleniumTester.Driver.AssertNoError(); - - Assert.DoesNotContain("/server/services/dynamic-dns/pouet.hello.com/delete", SeleniumTester.Driver.PageSource); } [Fact] public void CanCreateStores() { - var alice = SeleniumTester.RegisterNewUser(); - var store = SeleniumTester.CreateNewStore().storeName; - SeleniumTester.AddDerivationScheme(); - SeleniumTester.Driver.AssertNoError(); - Assert.Contains(store, SeleniumTester.Driver.PageSource); - var storeUrl = SeleniumTester.Driver.Url; - SeleniumTester.ClickOnAllSideMenus(); - SeleniumTester.GoToInvoices(); - SeleniumTester.CreateInvoice(store); - SeleniumTester.Driver.FindElement(By.ClassName("invoice-details-link")).Click(); - var invoiceUrl = SeleniumTester.Driver.Url; + using (var s = SeleniumTester.Create()) + { + s.Start(); + var alice = s.RegisterNewUser(); + var store = s.CreateNewStore().storeName; + s.AddDerivationScheme(); + s.Driver.AssertNoError(); + Assert.Contains(store, s.Driver.PageSource); + var storeUrl = s.Driver.Url; + s.ClickOnAllSideMenus(); + s.GoToInvoices(); + s.CreateInvoice(store); + s.Driver.FindElement(By.ClassName("invoice-details-link")).Click(); + var invoiceUrl = s.Driver.Url; - // When logout we should not be able to access store and invoice details - SeleniumTester.Driver.FindElement(By.Id("Logout")).Click(); - SeleniumTester.Driver.Navigate().GoToUrl(storeUrl); - Assert.Contains("ReturnUrl", SeleniumTester.Driver.Url); - SeleniumTester.Driver.Navigate().GoToUrl(invoiceUrl); - Assert.Contains("ReturnUrl", SeleniumTester.Driver.Url); + // When logout we should not be able to access store and invoice details + s.Driver.FindElement(By.Id("Logout")).Click(); + s.Driver.Navigate().GoToUrl(storeUrl); + Assert.Contains("ReturnUrl", s.Driver.Url); + s.Driver.Navigate().GoToUrl(invoiceUrl); + Assert.Contains("ReturnUrl", s.Driver.Url); - // When logged we should not be able to access store and invoice details - var bob = SeleniumTester.RegisterNewUser(); - SeleniumTester.Driver.Navigate().GoToUrl(storeUrl); - Assert.Contains("ReturnUrl", SeleniumTester.Driver.Url); - SeleniumTester.Driver.Navigate().GoToUrl(invoiceUrl); - SeleniumTester.AssertNotFound(); - SeleniumTester.GoToHome(); - SeleniumTester.Logout(); + // When logged we should not be able to access store and invoice details + var bob = s.RegisterNewUser(); + s.Driver.Navigate().GoToUrl(storeUrl); + Assert.Contains("ReturnUrl", s.Driver.Url); + s.Driver.Navigate().GoToUrl(invoiceUrl); + s.AssertNotFound(); + s.GoToHome(); + s.Logout(); - // Let's add Bob as a guest to alice's store - LogIn(SeleniumTester, alice); - SeleniumTester.Driver.Navigate().GoToUrl(storeUrl + "/users"); - SeleniumTester.Driver.FindElement(By.Id("Email")).SendKeys(bob + Keys.Enter); - Assert.Contains("User added successfully", SeleniumTester.Driver.PageSource); - SeleniumTester.Logout(); + // Let's add Bob as a guest to alice's store + LogIn(s, alice); + s.Driver.Navigate().GoToUrl(storeUrl + "/users"); + s.Driver.FindElement(By.Id("Email")).SendKeys(bob + Keys.Enter); + Assert.Contains("User added successfully", s.Driver.PageSource); + s.Logout(); - // Bob should not have access to store, but should have access to invoice - LogIn(SeleniumTester, bob); - SeleniumTester.Driver.Navigate().GoToUrl(storeUrl); - Assert.Contains("ReturnUrl", SeleniumTester.Driver.Url); - SeleniumTester.Driver.Navigate().GoToUrl(invoiceUrl); - SeleniumTester.Driver.AssertNoError(); + // Bob should not have access to store, but should have access to invoice + LogIn(s, bob); + s.Driver.Navigate().GoToUrl(storeUrl); + Assert.Contains("ReturnUrl", s.Driver.Url); + s.Driver.Navigate().GoToUrl(invoiceUrl); + s.Driver.AssertNoError(); + } } - + [Fact] public void CanCreateAppPoS() { - SeleniumTester.RegisterNewUser(); - var store = SeleniumTester.CreateNewStore(); + using (var s = SeleniumTester.Create()) + { + s.Start(); + s.RegisterNewUser(); + var store = s.CreateNewStore(); - SeleniumTester.Driver.FindElement(By.Id("Apps")).Click(); - SeleniumTester.Driver.FindElement(By.Id("CreateNewApp")).Click(); - SeleniumTester.Driver.FindElement(By.Name("Name")).SendKeys("PoS" + Guid.NewGuid()); - SeleniumTester.Driver.FindElement(By.Id("SelectedAppType")).SendKeys("PointOfSale" + Keys.Enter); - SeleniumTester.Driver.FindElement(By.Id("SelectedStore")).SendKeys(store + Keys.Enter); - SeleniumTester.Driver.FindElement(By.Id("Create")).Click(); - SeleniumTester.Driver.FindElement(By.Id("EnableShoppingCart")).Click(); - SeleniumTester.Driver.FindElement(By.Id("SaveSettings")).ForceClick(); - SeleniumTester.Driver.FindElement(By.Id("ViewApp")).ForceClick(); - SeleniumTester.Driver.SwitchTo().Window(SeleniumTester.Driver.WindowHandles.Last()); - Assert.True(SeleniumTester.Driver.PageSource.Contains("Tea shop"), "Unable to create PoS"); + s.Driver.FindElement(By.Id("Apps")).Click(); + s.Driver.FindElement(By.Id("CreateNewApp")).Click(); + s.Driver.FindElement(By.Name("Name")).SendKeys("PoS" + Guid.NewGuid()); + s.Driver.FindElement(By.Id("SelectedAppType")).SendKeys("PointOfSale" + Keys.Enter); + s.Driver.FindElement(By.Id("SelectedStore")).SendKeys(store + Keys.Enter); + s.Driver.FindElement(By.Id("Create")).Click(); + s.Driver.FindElement(By.Id("EnableShoppingCart")).Click(); + s.Driver.FindElement(By.Id("SaveSettings")).ForceClick(); + s.Driver.FindElement(By.Id("ViewApp")).ForceClick(); + s.Driver.SwitchTo().Window(s.Driver.WindowHandles.Last()); + Assert.True(s.Driver.PageSource.Contains("Tea shop"), "Unable to create PoS"); + s.Driver.Quit(); + } } [Fact] public void CanCreateAppCF() { - SeleniumTester.RegisterNewUser(); - var store = SeleniumTester.CreateNewStore(); - SeleniumTester.AddDerivationScheme(); + using (var s = SeleniumTester.Create()) + { + s.Start(); + s.RegisterNewUser(); + var store = s.CreateNewStore(); + s.AddDerivationScheme(); - SeleniumTester.Driver.FindElement(By.Id("Apps")).Click(); - SeleniumTester.Driver.FindElement(By.Id("CreateNewApp")).Click(); - SeleniumTester.Driver.FindElement(By.Name("Name")).SendKeys("CF" + Guid.NewGuid()); - SeleniumTester.Driver.FindElement(By.Id("SelectedAppType")).SendKeys("Crowdfund" + Keys.Enter); - SeleniumTester.Driver.FindElement(By.Id("SelectedStore")).SendKeys(store + Keys.Enter); - SeleniumTester.Driver.FindElement(By.Id("Create")).Click(); - SeleniumTester.Driver.FindElement(By.Id("Title")).SendKeys("Kukkstarter"); - SeleniumTester.Driver.FindElement(By.CssSelector("div.note-editable.card-block")).SendKeys("1BTC = 1BTC"); - SeleniumTester.Driver.FindElement(By.Id("TargetCurrency")).SendKeys("JPY"); - SeleniumTester.Driver.FindElement(By.Id("TargetAmount")).SendKeys("700"); - SeleniumTester.Driver.FindElement(By.Id("SaveSettings")).ForceClick(); - SeleniumTester.Driver.FindElement(By.Id("ViewApp")).ForceClick(); - SeleniumTester.Driver.SwitchTo().Window(SeleniumTester.Driver.WindowHandles.Last()); - Assert.True(SeleniumTester.Driver.PageSource.Contains("Currently Active!"), "Unable to create CF"); + s.Driver.FindElement(By.Id("Apps")).Click(); + s.Driver.FindElement(By.Id("CreateNewApp")).Click(); + s.Driver.FindElement(By.Name("Name")).SendKeys("CF" + Guid.NewGuid()); + s.Driver.FindElement(By.Id("SelectedAppType")).SendKeys("Crowdfund" + Keys.Enter); + s.Driver.FindElement(By.Id("SelectedStore")).SendKeys(store + Keys.Enter); + s.Driver.FindElement(By.Id("Create")).Click(); + s.Driver.FindElement(By.Id("Title")).SendKeys("Kukkstarter"); + s.Driver.FindElement(By.CssSelector("div.note-editable.card-block")).SendKeys("1BTC = 1BTC"); + s.Driver.FindElement(By.Id("TargetCurrency")).SendKeys("JPY"); + s.Driver.FindElement(By.Id("TargetAmount")).SendKeys("700"); + s.Driver.FindElement(By.Id("SaveSettings")).ForceClick(); + s.Driver.FindElement(By.Id("ViewApp")).ForceClick(); + s.Driver.SwitchTo().Window(s.Driver.WindowHandles.Last()); + Assert.True(s.Driver.PageSource.Contains("Currently Active!"), "Unable to create CF"); + s.Driver.Quit(); + } } [Fact] public void CanCreatePayRequest() { - SeleniumTester.RegisterNewUser(); - SeleniumTester.CreateNewStore(); - SeleniumTester.AddDerivationScheme(); + using (var s = SeleniumTester.Create()) + { + s.Start(); + s.RegisterNewUser(); + s.CreateNewStore(); + s.AddDerivationScheme(); - SeleniumTester.Driver.FindElement(By.Id("PaymentRequests")).Click(); - SeleniumTester.Driver.FindElement(By.Id("CreatePaymentRequest")).Click(); - SeleniumTester.Driver.FindElement(By.Id("Title")).SendKeys("Pay123"); - SeleniumTester.Driver.FindElement(By.Id("Amount")).SendKeys("700"); - SeleniumTester.Driver.FindElement(By.Id("Currency")).SendKeys("BTC"); - SeleniumTester.Driver.FindElement(By.Id("SaveButton")).ForceClick(); - SeleniumTester.Driver.FindElement(By.Name("ViewAppButton")).SendKeys(Keys.Return); - SeleniumTester.Driver.SwitchTo().Window(SeleniumTester.Driver.WindowHandles.Last()); - Assert.True(SeleniumTester.Driver.PageSource.Contains("Amount due"), "Unable to create Payment Request"); + s.Driver.FindElement(By.Id("PaymentRequests")).Click(); + s.Driver.FindElement(By.Id("CreatePaymentRequest")).Click(); + s.Driver.FindElement(By.Id("Title")).SendKeys("Pay123"); + s.Driver.FindElement(By.Id("Amount")).SendKeys("700"); + s.Driver.FindElement(By.Id("Currency")).SendKeys("BTC"); + s.Driver.FindElement(By.Id("SaveButton")).ForceClick(); + s.Driver.FindElement(By.Name("ViewAppButton")).SendKeys(Keys.Return); + s.Driver.SwitchTo().Window(s.Driver.WindowHandles.Last()); + Assert.True(s.Driver.PageSource.Contains("Amount due"), "Unable to create Payment Request"); + s.Driver.Quit(); + } } [Fact] public void CanManageWallet() { - SeleniumTester.RegisterNewUser(); - SeleniumTester.CreateNewStore(); - - // In this test, we try to spend from a manual seed. We import the xpub 49'/0'/0', then try to use the seed - // to sign the transaction - var mnemonic = "usage fever hen zero slide mammal silent heavy donate budget pulse say brain thank sausage brand craft about save attract muffin advance illegal cabbage"; - var root = new Mnemonic(mnemonic).DeriveExtKey(); - SeleniumTester.AddDerivationScheme("BTC", "ypub6WWc2gWwHbdnAAyJDnR4SPL1phRh7REqrPBfZeizaQ1EmTshieRXJC3Z5YoU4wkcdKHEjQGkh6AYEzCQC1Kz3DNaWSwdc1pc8416hAjzqyD"); - var tx = SeleniumTester.Server.ExplorerNode.SendToAddress(BitcoinAddress.Create("bcrt1qmxg8fgnmkp354vhe78j6sr4ut64tyz2xyejel4", Network.RegTest), Money.Coins(3.0m)); - SeleniumTester.Server.ExplorerNode.Generate(1); - - SeleniumTester.Driver.FindElement(By.Id("Wallets")).Click(); - SeleniumTester.Driver.FindElement(By.LinkText("Manage")).Click(); - - SeleniumTester.ClickOnAllSideMenus(); - - // We setup the fingerprint and the account key path - SeleniumTester.Driver.FindElement(By.Id("WalletSettings")).ForceClick(); - SeleniumTester.Driver.FindElement(By.Id("AccountKeys_0__MasterFingerprint")).SendKeys("8bafd160"); - SeleniumTester.Driver.FindElement(By.Id("AccountKeys_0__AccountKeyPath")).SendKeys("m/49'/0'/0'" + Keys.Enter); - - // Check the tx sent earlier arrived - SeleniumTester.Driver.FindElement(By.Id("WalletTransactions")).ForceClick(); - var walletTransactionLink = SeleniumTester.Driver.Url; - Assert.Contains(tx.ToString(), SeleniumTester.Driver.PageSource); - - - void SignWith(string signingSource) + using (var s = SeleniumTester.Create()) { - // Send to bob - SeleniumTester.Driver.FindElement(By.Id("WalletSend")).Click(); - var bob = new Key().PubKey.Hash.GetAddress(Network.RegTest); - SetTransactionOutput(0, bob, 1); - SeleniumTester.Driver.ScrollTo(By.Id("SendMenu")); - SeleniumTester.Driver.FindElement(By.Id("SendMenu")).ForceClick(); - SeleniumTester.Driver.FindElement(By.CssSelector("button[value=seed]")).Click(); + s.Start(); + s.RegisterNewUser(); + s.CreateNewStore(); - // Input the seed - SeleniumTester.Driver.FindElement(By.Id("SeedOrKey")).SendKeys(signingSource + Keys.Enter); + // In this test, we try to spend from a manual seed. We import the xpub 49'/0'/0', then try to use the seed + // to sign the transaction + var mnemonic = "usage fever hen zero slide mammal silent heavy donate budget pulse say brain thank sausage brand craft about save attract muffin advance illegal cabbage"; + var root = new Mnemonic(mnemonic).DeriveExtKey(); + s.AddDerivationScheme("BTC", "ypub6WWc2gWwHbdnAAyJDnR4SPL1phRh7REqrPBfZeizaQ1EmTshieRXJC3Z5YoU4wkcdKHEjQGkh6AYEzCQC1Kz3DNaWSwdc1pc8416hAjzqyD"); + var tx = s.Server.ExplorerNode.SendToAddress(BitcoinAddress.Create("bcrt1qmxg8fgnmkp354vhe78j6sr4ut64tyz2xyejel4", Network.RegTest), Money.Coins(3.0m)); + s.Server.ExplorerNode.Generate(1); - // Broadcast - Assert.Contains(bob.ToString(), SeleniumTester.Driver.PageSource); - Assert.Contains("1.00000000", SeleniumTester.Driver.PageSource); - SeleniumTester.Driver.FindElement(By.CssSelector("button[value=broadcast]")).ForceClick(); - Assert.Equal(walletTransactionLink, SeleniumTester.Driver.Url); - } + s.Driver.FindElement(By.Id("Wallets")).Click(); + s.Driver.FindElement(By.LinkText("Manage")).Click(); - void SetTransactionOutput(int index, BitcoinAddress dest, decimal amount, bool subtract = false) - { - SeleniumTester.Driver.FindElement(By.Id($"Outputs_{index}__DestinationAddress")).SendKeys(dest.ToString()); - var amountElement = SeleniumTester.Driver.FindElement(By.Id($"Outputs_{index}__Amount")); - amountElement.Clear(); - amountElement.SendKeys(amount.ToString()); - var checkboxElement = SeleniumTester.Driver.FindElement(By.Id($"Outputs_{index}__SubtractFeesFromOutput")); - if (checkboxElement.Selected != subtract) + s.ClickOnAllSideMenus(); + + // We setup the fingerprint and the account key path + s.Driver.FindElement(By.Id("WalletSettings")).ForceClick(); + s.Driver.FindElement(By.Id("AccountKeys_0__MasterFingerprint")).SendKeys("8bafd160"); + s.Driver.FindElement(By.Id("AccountKeys_0__AccountKeyPath")).SendKeys("m/49'/0'/0'" + Keys.Enter); + + // Check the tx sent earlier arrived + s.Driver.FindElement(By.Id("WalletTransactions")).ForceClick(); + var walletTransactionLink = s.Driver.Url; + Assert.Contains(tx.ToString(), s.Driver.PageSource); + + + void SignWith(string signingSource) { - checkboxElement.Click(); + // Send to bob + s.Driver.FindElement(By.Id("WalletSend")).Click(); + var bob = new Key().PubKey.Hash.GetAddress(Network.RegTest); + SetTransactionOutput(0, bob, 1); + s.Driver.ScrollTo(By.Id("SendMenu")); + s.Driver.FindElement(By.Id("SendMenu")).ForceClick(); + s.Driver.FindElement(By.CssSelector("button[value=seed]")).Click(); + + // Input the seed + s.Driver.FindElement(By.Id("SeedOrKey")).SendKeys(signingSource + Keys.Enter); + + // Broadcast + Assert.Contains(bob.ToString(), s.Driver.PageSource); + Assert.Contains("1.00000000", s.Driver.PageSource); + s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).ForceClick(); + Assert.Equal(walletTransactionLink, s.Driver.Url); } + + void SetTransactionOutput(int index, BitcoinAddress dest, decimal amount, bool subtract = false) + { + s.Driver.FindElement(By.Id($"Outputs_{index}__DestinationAddress")).SendKeys(dest.ToString()); + var amountElement = s.Driver.FindElement(By.Id($"Outputs_{index}__Amount")); + amountElement.Clear(); + amountElement.SendKeys(amount.ToString()); + var checkboxElement = s.Driver.FindElement(By.Id($"Outputs_{index}__SubtractFeesFromOutput")); + if (checkboxElement.Selected != subtract) + { + checkboxElement.Click(); + } + } + SignWith(mnemonic); + var accountKey = root.Derive(new KeyPath("m/49'/0'/0'")).GetWif(Network.RegTest).ToString(); + SignWith(accountKey); } - SignWith(mnemonic); - var accountKey = root.Derive(new KeyPath("m/49'/0'/0'")).GetWif(Network.RegTest).ToString(); - SignWith(accountKey); } } } diff --git a/BTCPayServer.Tests/XUnitCollections.cs b/BTCPayServer.Tests/XUnitCollections.cs deleted file mode 100644 index e5e8367e1..000000000 --- a/BTCPayServer.Tests/XUnitCollections.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Text; -using Xunit; -using Xunit.Sdk; - -namespace BTCPayServer.Tests -{ - [CollectionDefinition("Selenium collection")] - public class SeleniumCollection : ICollectionFixture - { - // This class has no code, and is never created. Its purpose is simply - // to be the place to apply [CollectionDefinition] and all the - // ICollectionFixture<> interfaces. - } -} diff --git a/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs b/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs index abd3b5b49..601f6fd91 100644 --- a/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs +++ b/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs @@ -13,7 +13,6 @@ using BTCPayServer.Services.Invoices; using BTCPayServer.Services; using BTCPayServer.Services.Rates; using NBitcoin; -using System.Globalization; namespace BTCPayServer.Payments.Lightning { @@ -178,10 +177,10 @@ namespace BTCPayServer.Payments.Lightning if (storeBlob.LightningAmountInSatoshi && model.CryptoCode == "BTC" ) { model.CryptoCode = "Sats"; - model.BtcDue = Money.Parse(model.BtcDue).ToUnit(MoneyUnit.Satoshi).ToString(CultureInfo.InvariantCulture); - model.BtcPaid = Money.Parse(model.BtcPaid).ToUnit(MoneyUnit.Satoshi).ToString(CultureInfo.InvariantCulture); + model.BtcDue = Money.Parse(model.BtcDue).ToUnit(MoneyUnit.Satoshi).ToString(); + model.BtcPaid = Money.Parse(model.BtcPaid).ToUnit(MoneyUnit.Satoshi).ToString(); model.NetworkFee = new Money(model.NetworkFee, MoneyUnit.BTC).ToUnit(MoneyUnit.Satoshi); - model.OrderAmount = Money.Parse(model.OrderAmount).ToUnit(MoneyUnit.Satoshi).ToString(CultureInfo.InvariantCulture); + model.OrderAmount = Money.Parse(model.OrderAmount).ToUnit(MoneyUnit.Satoshi).ToString(); } } public override string GetCryptoImage(PaymentMethodId paymentMethodId)