Share same browser for all selenium tests

This commit is contained in:
nicolas.dorier 2019-09-11 15:36:12 +09:00
parent 7ab97311be
commit 2ce0749bb6
No known key found for this signature in database
GPG Key ID: 6618763EF09186FE
6 changed files with 477 additions and 499 deletions

View File

@ -19,12 +19,16 @@ using OpenQA.Selenium;
namespace BTCPayServer.Tests
{
[Collection("Selenium collection")]
public class AuthenticationTests
{
public AuthenticationTests(ITestOutputHelper helper)
public SeleniumTester SeleniumTester { get; }
public AuthenticationTests(ITestOutputHelper helper, SeleniumTester seleniumTester)
{
Logs.Tester = new XUnitLog(helper) {Name = "Tests"};
Logs.Tester = new XUnitLog(helper) { Name = "Tests" };
Logs.LogProvider = new XUnitLogProvider(helper);
SeleniumTester = seleniumTester;
}
[Fact]
@ -93,49 +97,45 @@ namespace BTCPayServer.Tests
[Fact]
public async Task CanUseImplicitFlow()
{
using (var s = SeleniumTester.Create())
{
s.Start();
var tester = s.Server;
var tester = SeleniumTester.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()}");
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);
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);
LogoutFlow(tester, id, s);
s.Driver.Navigate().GoToUrl(implicitAuthorizeUrl);
s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
Assert.Throws<NoSuchElementException>(() => 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);
}
LogoutFlow(tester, id, SeleniumTester);
SeleniumTester.Driver.Navigate().GoToUrl(implicitAuthorizeUrl);
SeleniumTester.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
Assert.Throws<NoSuchElementException>(() => 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);
}
void LogoutFlow(ServerTester tester, string clientId, SeleniumTester seleniumTester)
@ -145,50 +145,47 @@ namespace BTCPayServer.Tests
seleniumTester.Driver.Navigate().GoToUrl(logoutUrl);
seleniumTester.GoToHome();
Assert.Throws<NoSuchElementException>(() => seleniumTester.Driver.FindElement(By.Id("Logout")));
}
[Trait("Selenium", "Selenium")]
[Fact]
public async Task CanUseCodeFlow()
{
using (var s = SeleniumTester.Create())
{
s.Start();
var tester = s.Server;
var tester = SeleniumTester.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()
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 =
{
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()}");
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]);
},
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]);
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<KeyValuePair<string, string>>()
var httpRequest = new HttpRequestMessage(HttpMethod.Post,
new Uri(tester.PayTester.ServerUri, "/connect/token"))
{
Content = new FormUrlEncodedContent(new List<KeyValuePair<string, string>>()
{
new KeyValuePair<string, string>("grant_type",
OpenIddictConstants.GrantTypes.AuthorizationCode),
@ -197,31 +194,30 @@ namespace BTCPayServer.Tests
new KeyValuePair<string, string>("code", results["code"]),
new KeyValuePair<string, string>("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<OpenIdConnectResponse>();
string content = await response.Content.ReadAsStringAsync();
var result = JObject.Parse(content).ToObject<OpenIdConnectResponse>();
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, s);
s.Driver.Navigate().GoToUrl(authorizeUrl);
s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
Assert.Throws<NoSuchElementException>(() => 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"));
}
await TestApiAgainstAccessToken(refreshedAccessToken, tester, user);
LogoutFlow(tester, id, SeleniumTester);
SeleniumTester.Driver.Navigate().GoToUrl(authorizeUrl);
SeleniumTester.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
Assert.Throws<NoSuchElementException>(() => 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"));
}
private static async Task<string> RefreshAnAccessToken(string refreshToken, HttpClient client, string clientId,
@ -261,7 +257,7 @@ namespace BTCPayServer.Tests
{
ClientId = id,
DisplayName = id,
Permissions = {OpenIddictConstants.Permissions.GrantTypes.ClientCredentials}
Permissions = { OpenIddictConstants.Permissions.GrantTypes.ClientCredentials }
}, secret);
@ -300,7 +296,7 @@ namespace BTCPayServer.Tests
{
ClientId = id,
DisplayName = id,
Permissions = {OpenIddictConstants.Permissions.GrantTypes.Password}
Permissions = { OpenIddictConstants.Permissions.GrantTypes.Password }
}, secret);

View File

@ -15,163 +15,140 @@ using Xunit.Abstractions;
namespace BTCPayServer.Tests
{
[Trait("Selenium", "Selenium")]
[Collection("Selenium collection")]
public class CheckoutUITests
{
public CheckoutUITests(ITestOutputHelper helper)
public SeleniumTester SeleniumTester { get; }
public CheckoutUITests(ITestOutputHelper helper, SeleniumTester seleniumTester)
{
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()
{
using (var s = SeleniumTester.Create())
{
s.Start();
s.RegisterNewUser();
var store = s.CreateNewStore().storeName;
s.AddDerivationScheme();
SeleniumTester.RegisterNewUser();
var store = SeleniumTester.CreateNewStore().storeName;
SeleniumTester.AddDerivationScheme();
s.CreateInvoice(store);
SeleniumTester.CreateInvoice(store);
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();
}
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")));
}
[Fact]
public async Task CanHandleRefundEmailForm()
{
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 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();
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();
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();
await Task.Delay(1000);
s.Driver.AssertElementNotFound(By.Id("emailAddressFormInput"));
s.Driver.Navigate().Refresh();
await Task.Delay(1000);
SeleniumTester.Driver.AssertElementNotFound(By.Id("emailAddressFormInput"));
s.Driver.AssertElementNotFound(By.Id("emailAddressFormInput"));
}
SeleniumTester.Driver.Navigate().Refresh();
SeleniumTester.Driver.AssertElementNotFound(By.Id("emailAddressFormInput"));
}
[Fact]
public async Task CanUseLanguageDropdown()
{
using (var s = SeleniumTester.Create())
{
s.Start();
s.RegisterNewUser();
var store = s.CreateNewStore();
s.AddDerivationScheme("BTC");
SeleniumTester.RegisterNewUser();
var store = SeleniumTester.CreateNewStore();
SeleniumTester.AddDerivationScheme("BTC");
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();
}
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);
}
[Fact]
public void CanUsePaymentMethodDropdown()
{
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();
}
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);
}
[Fact]
public void CanUseLightningSatsFeature()
{
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);
}
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);
}
}
}

View File

@ -27,20 +27,42 @@ namespace BTCPayServer.Tests
{
public class SeleniumTester : IDisposable
{
public IWebDriver Driver { get; set; }
public ServerTester Server { get; set; }
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 static SeleniumTester Create([CallerMemberNameAttribute] string scope = null)
{
var server = ServerTester.Create(scope);
return new SeleniumTester()
{
Server = server
_Server = ServerTester.Create(scope)
};
}
public void Start()
void Start()
{
Server.Start();
ChromeOptions options = new ChromeOptions();
@ -56,7 +78,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
@ -77,7 +99,10 @@ namespace BTCPayServer.Tests
public string RegisterNewUser(bool isAdmin = false)
{
var usr = RandomUtils.GetUInt256().ToString() + "@a.com";
GoToHome();
if (Driver.PageSource.Contains("id=\"Logout\""))
Logout();
var usr = RandomUtils.GetUInt256().ToString().Substring(20) + "@a.com";
Driver.FindElement(By.Id("Register")).Click();
Driver.FindElement(By.Id("Email")).SendKeys(usr);
Driver.FindElement(By.Id("Password")).SendKeys("123456");

View File

@ -12,79 +12,72 @@ using System.Threading.Tasks;
namespace BTCPayServer.Tests
{
[Trait("Selenium", "Selenium")]
[Collection("Selenium collection")]
public class ChromeTests
{
public ChromeTests(ITestOutputHelper helper)
public SeleniumTester SeleniumTester { get; }
public ChromeTests(ITestOutputHelper helper, SeleniumTester seleniumTester)
{
Logs.Tester = new XUnitLog(helper) { Name = "Tests" };
Logs.LogProvider = new XUnitLogProvider(helper);
SeleniumTester = seleniumTester;
}
[Fact]
public void CanNavigateServerSettings()
{
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();
}
SeleniumTester.RegisterNewUser(true);
SeleniumTester.Driver.FindElement(By.Id("ServerSettings")).Click();
SeleniumTester.Driver.AssertNoError();
SeleniumTester.ClickOnAllSideMenus();
}
[Fact]
public void NewUserLogin()
{
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();
//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();
s.Driver.Navigate().GoToUrl(s.Link("/invoices"));
Assert.Contains("ReturnUrl=%2Finvoices", s.Driver.Url);
SeleniumTester.Driver.Navigate().GoToUrl(SeleniumTester.Link("/invoices"));
Assert.Contains("ReturnUrl=%2Finvoices", SeleniumTester.Driver.Url);
// 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 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 invoice
Assert.EndsWith("/invoices", s.Driver.Url);
// We should be redirected to invoice
Assert.EndsWith("/invoices", 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);
// Should not be able to reach server settings
SeleniumTester.Driver.Navigate().GoToUrl(SeleniumTester.Link("/server/users"));
Assert.Contains("ReturnUrl=%2Fserver%2Fusers", SeleniumTester.Driver.Url);
//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();
//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();
//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");
//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");
s.Driver.FindElement(By.Id("MySettings")).Click();
s.ClickOnAllSideMenus();
s.Driver.Quit();
}
SeleniumTester.Driver.FindElement(By.Id("MySettings")).Click();
SeleniumTester.ClickOnAllSideMenus();
}
static void LogIn(SeleniumTester s, string email)
@ -98,270 +91,239 @@ namespace BTCPayServer.Tests
[Fact]
public async Task CanUseSSHService()
{
using (var s = SeleniumTester.Create())
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<BTCPayServer.Configuration.BTCPayServerOptions>().SSHSettings.ConnectAsync())
{
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<BTCPayServer.Configuration.BTCPayServerOptions>().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();
var result = await client.RunBash("echo hello");
Assert.Equal(string.Empty, result.Error);
Assert.Equal("hello\n", result.Output);
Assert.Equal(0, result.ExitStatus);
}
SeleniumTester.Driver.Navigate().GoToUrl(SeleniumTester.Link("/server/services/ssh"));
SeleniumTester.Driver.AssertNoError();
}
[Fact]
public void CanUseDynamicDns()
{
using (var s = SeleniumTester.Create())
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"))
{
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);
// 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();
}
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()
{
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;
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;
// 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 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 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();
// 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();
// 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();
// 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();
// 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();
}
// 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();
}
[Fact]
public void CanCreateAppPoS()
{
using (var s = SeleniumTester.Create())
{
s.Start();
s.RegisterNewUser();
var store = s.CreateNewStore();
SeleniumTester.RegisterNewUser();
var store = SeleniumTester.CreateNewStore();
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();
}
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");
}
[Fact]
public void CanCreateAppCF()
{
using (var s = SeleniumTester.Create())
{
s.Start();
s.RegisterNewUser();
var store = s.CreateNewStore();
s.AddDerivationScheme();
SeleniumTester.RegisterNewUser();
var store = SeleniumTester.CreateNewStore();
SeleniumTester.AddDerivationScheme();
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();
}
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");
}
[Fact]
public void CanCreatePayRequest()
{
using (var s = SeleniumTester.Create())
{
s.Start();
s.RegisterNewUser();
s.CreateNewStore();
s.AddDerivationScheme();
SeleniumTester.RegisterNewUser();
SeleniumTester.CreateNewStore();
SeleniumTester.AddDerivationScheme();
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();
}
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");
}
[Fact]
public void CanManageWallet()
{
using (var s = SeleniumTester.Create())
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)
{
s.Start();
s.RegisterNewUser();
s.CreateNewStore();
// 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();
// 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);
// Input the seed
SeleniumTester.Driver.FindElement(By.Id("SeedOrKey")).SendKeys(signingSource + Keys.Enter);
s.Driver.FindElement(By.Id("Wallets")).Click();
s.Driver.FindElement(By.LinkText("Manage")).Click();
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)
{
// 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);
// 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);
}
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)
{
checkboxElement.Click();
}
}
SignWith(mnemonic);
var accountKey = root.Derive(new KeyPath("m/49'/0'/0'")).GetWif(Network.RegTest).ToString();
SignWith(accountKey);
}
}
}

View File

@ -0,0 +1,17 @@
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<SeleniumTester>
{
// 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.
}
}

View File

@ -13,6 +13,7 @@ using BTCPayServer.Services.Invoices;
using BTCPayServer.Services;
using BTCPayServer.Services.Rates;
using NBitcoin;
using System.Globalization;
namespace BTCPayServer.Payments.Lightning
{
@ -177,10 +178,10 @@ namespace BTCPayServer.Payments.Lightning
if (storeBlob.LightningAmountInSatoshi && model.CryptoCode == "BTC" )
{
model.CryptoCode = "Sats";
model.BtcDue = Money.Parse(model.BtcDue).ToUnit(MoneyUnit.Satoshi).ToString();
model.BtcPaid = Money.Parse(model.BtcPaid).ToUnit(MoneyUnit.Satoshi).ToString();
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.NetworkFee = new Money(model.NetworkFee, MoneyUnit.BTC).ToUnit(MoneyUnit.Satoshi);
model.OrderAmount = Money.Parse(model.OrderAmount).ToUnit(MoneyUnit.Satoshi).ToString();
model.OrderAmount = Money.Parse(model.OrderAmount).ToUnit(MoneyUnit.Satoshi).ToString(CultureInfo.InvariantCulture);
}
}
public override string GetCryptoImage(PaymentMethodId paymentMethodId)