2019-05-21 10:10:07 +02:00
using System ;
2019-09-10 10:03:24 +02:00
using System.Globalization ;
2019-05-13 11:42:20 +02:00
using System.IO ;
2020-06-28 10:55:27 +02:00
using System.Linq ;
2019-09-10 10:03:24 +02:00
using System.Threading.Tasks ;
2022-03-02 19:21:38 +01:00
using BTCPayServer.Abstractions.Extensions ;
2020-11-17 13:46:23 +01:00
using BTCPayServer.Abstractions.Models ;
2019-09-10 10:03:24 +02:00
using BTCPayServer.Lightning ;
using BTCPayServer.Lightning.CLightning ;
2020-02-24 14:36:15 +01:00
using BTCPayServer.Views.Manage ;
2020-09-16 08:54:09 +02:00
using BTCPayServer.Views.Server ;
2019-09-10 10:03:24 +02:00
using BTCPayServer.Views.Stores ;
2020-04-28 08:06:28 +02:00
using BTCPayServer.Views.Wallets ;
2021-01-25 17:22:58 +01:00
using Microsoft.Extensions.Configuration ;
2020-06-28 10:55:27 +02:00
using NBitcoin ;
2022-02-17 09:58:56 +01:00
using NBitcoin.RPC ;
2020-06-28 10:55:27 +02:00
using OpenQA.Selenium ;
using OpenQA.Selenium.Chrome ;
2021-10-20 07:34:04 +02:00
using OpenQA.Selenium.Support.UI ;
2021-12-31 08:59:02 +01:00
using Xunit ;
2019-05-13 11:42:20 +02:00
namespace BTCPayServer.Tests
{
public class SeleniumTester : IDisposable
{
2019-09-11 09:22:41 +02:00
public IWebDriver Driver { get ; set ; }
public ServerTester Server { get ; set ; }
2021-01-22 17:49:26 +01:00
public WalletId WalletId { get ; set ; }
2019-05-13 11:42:20 +02:00
2021-01-25 14:10:19 +01:00
public string StoreId { get ; set ; }
2021-02-17 04:14:29 +01:00
public static readonly TimeSpan ImplicitWait = TimeSpan . FromSeconds ( 5 ) ;
2021-01-25 17:22:58 +01:00
2019-10-07 09:04:25 +02:00
public async Task StartAsync ( )
2019-05-13 11:42:20 +02:00
{
2021-09-09 14:51:28 +02:00
Server . PayTester . NoCSP = true ;
2019-10-07 09:04:25 +02:00
await Server . StartAsync ( ) ;
2021-01-25 17:22:58 +01:00
2021-01-25 15:01:53 +01:00
var windowSize = ( Width : 1200 , Height : 1000 ) ;
2021-01-25 17:22:58 +01:00
var builder = new ConfigurationBuilder ( ) ;
2021-01-26 10:22:17 +01:00
builder . AddUserSecrets ( "AB0AC1DD-9D26-485B-9416-56A33F268117" ) ;
2021-01-25 17:22:58 +01:00
var config = builder . Build ( ) ;
// Run `dotnet user-secrets set RunSeleniumInBrowser true` to run tests in browser
var runInBrowser = config [ "RunSeleniumInBrowser" ] = = "true" ;
2021-01-27 09:35:14 +01:00
// Reset this using `dotnet user-secrets remove RunSeleniumInBrowser`
2021-01-25 15:01:53 +01:00
2021-02-17 15:50:04 +01:00
var chromeDriverPath = config [ "ChromeDriverDirectory" ] ? ? ( Server . PayTester . InContainer ? "/usr/bin" : Directory . GetCurrentDirectory ( ) ) ;
2022-05-20 02:35:31 +02:00
2021-01-27 09:35:14 +01:00
var options = new ChromeOptions ( ) ;
if ( ! runInBrowser )
2019-09-10 10:03:24 +02:00
{
2021-01-27 09:35:14 +01:00
options . AddArguments ( "headless" ) ;
2020-01-12 05:54:06 +01:00
}
2021-01-27 09:35:14 +01:00
options . AddArguments ( $"window-size={windowSize.Width}x{windowSize.Height}" ) ;
options . AddArgument ( "shm-size=2g" ) ;
2021-05-19 04:39:27 +02:00
options . AddArgument ( "start-maximized" ) ;
2021-09-22 14:31:44 +02:00
if ( Server . PayTester . InContainer )
{
2022-05-09 07:13:51 +02:00
// Shot in the dark to fix https://stackoverflow.com/questions/53902507/unknown-error-session-deleted-because-of-page-crash-from-unknown-error-cannot
options . AddArgument ( "--disable-dev-shm-usage" ) ;
2021-09-22 14:31:44 +02:00
Driver = new OpenQA . Selenium . Remote . RemoteWebDriver ( new Uri ( "http://selenium:4444/wd/hub" ) , new RemoteSessionSettings ( options ) ) ;
var containerIp = File . ReadAllText ( "/etc/hosts" ) . Split ( '\n' , StringSplitOptions . RemoveEmptyEntries ) . Last ( )
. Split ( '\t' , StringSplitOptions . RemoveEmptyEntries ) [ 0 ] . Trim ( ) ;
2021-11-22 09:16:08 +01:00
TestLogs . LogInformation ( $"Selenium: Container's IP {containerIp}" ) ;
2021-09-22 14:31:44 +02:00
ServerUri = new Uri ( Server . PayTester . ServerUri . AbsoluteUri . Replace ( $"http://{Server.PayTester.HostName}" , $"http://{containerIp}" , StringComparison . OrdinalIgnoreCase ) , UriKind . Absolute ) ;
}
else
{
var cds = ChromeDriverService . CreateDefaultService ( chromeDriverPath ) ;
cds . EnableVerboseLogging = true ;
cds . Port = Utils . FreeTcpPort ( ) ;
cds . HostName = "127.0.0.1" ;
cds . Start ( ) ;
Driver = new ChromeDriver ( cds , options ,
// A bit less than test timeout
TimeSpan . FromSeconds ( 50 ) ) ;
ServerUri = Server . PayTester . ServerUri ;
}
2021-05-19 04:39:27 +02:00
Driver . Manage ( ) . Window . Maximize ( ) ;
2021-01-25 17:22:58 +01:00
2021-11-22 09:16:08 +01:00
TestLogs . LogInformation ( $"Selenium: Using {Driver.GetType()}" ) ;
TestLogs . LogInformation ( $"Selenium: Browsing to {ServerUri}" ) ;
TestLogs . LogInformation ( $"Selenium: Resolution {Driver.Manage().Window.Size}" ) ;
2019-11-06 06:31:45 +01:00
GoToRegister ( ) ;
2019-05-14 11:35:22 +02:00
Driver . AssertNoError ( ) ;
2019-05-13 11:42:20 +02:00
}
2021-12-31 08:59:02 +01:00
2022-07-06 14:14:55 +02:00
public void PayInvoice ( bool mine = false )
2022-02-10 04:24:28 +01:00
{
Driver . FindElement ( By . Id ( "FakePayment" ) ) . Click ( ) ;
2022-07-06 14:14:55 +02:00
if ( mine )
{
MineBlockOnInvoiceCheckout ( ) ;
}
}
public void MineBlockOnInvoiceCheckout ( )
{
Driver . FindElement ( By . CssSelector ( "#mine-block button" ) ) . Click ( ) ;
2022-02-10 04:24:28 +01:00
}
2021-09-22 14:31:44 +02:00
/// <summary>
/// Use this ServerUri when trying to browse with selenium
/// Because for some reason, the selenium container can't resolve the tests container domain name
/// </summary>
public Uri ServerUri ;
2021-02-12 04:21:29 +01:00
internal IWebElement FindAlertMessage ( StatusMessageModel . StatusSeverity severity = StatusMessageModel . StatusSeverity . Success )
{
2021-12-31 08:59:02 +01:00
return FindAlertMessage ( new [ ] { severity } ) ;
2021-10-18 05:37:59 +02:00
}
internal IWebElement FindAlertMessage ( params StatusMessageModel . StatusSeverity [ ] severity )
{
var className = string . Join ( ", " , severity . Select ( statusSeverity = > $".alert-{StatusMessageModel.ToString(statusSeverity)}" ) ) ;
2021-11-24 12:25:14 +01:00
IWebElement el ;
try
{
2021-11-26 07:02:30 +01:00
var elements = Driver . FindElements ( By . CssSelector ( className ) ) ;
el = elements . FirstOrDefault ( e = > e . Displayed ) ;
if ( el is null )
el = elements . FirstOrDefault ( ) ;
if ( el is null )
el = Driver . WaitForElement ( By . CssSelector ( className ) ) ;
2021-11-24 12:25:14 +01:00
}
catch ( NoSuchElementException )
{
el = Driver . WaitForElement ( By . CssSelector ( className ) ) ;
}
2021-02-12 04:21:29 +01:00
if ( el is null )
2021-02-17 04:14:29 +01:00
throw new NoSuchElementException ( $"Unable to find {className}" ) ;
2021-11-26 07:02:30 +01:00
if ( ! el . Displayed )
throw new ElementNotVisibleException ( $"{className} is present, but not displayed: {el.GetAttribute(" id ")} - Text: {el.Text}" ) ;
2021-02-12 04:21:29 +01:00
return el ;
}
2019-11-16 07:20:54 +01:00
2019-05-14 16:33:46 +02:00
public string Link ( string relativeLink )
{
2021-09-22 14:31:44 +02:00
return ServerUri . AbsoluteUri . WithoutEndingSlash ( ) + relativeLink . WithStartingSlash ( ) ;
2019-05-14 16:33:46 +02:00
}
2019-05-13 11:42:20 +02:00
2019-11-06 06:31:45 +01:00
public void GoToRegister ( )
{
2021-01-28 10:08:22 +01:00
Driver . Navigate ( ) . GoToUrl ( Link ( "/register" ) ) ;
2019-11-06 06:31:45 +01:00
}
2021-01-22 17:49:26 +01:00
2019-05-13 11:42:20 +02:00
public string RegisterNewUser ( bool isAdmin = false )
{
2019-09-19 12:17:20 +02:00
var usr = RandomUtils . GetUInt256 ( ) . ToString ( ) . Substring ( 64 - 20 ) + "@a.com" ;
2021-11-22 09:16:08 +01:00
TestLogs . LogInformation ( $"User: {usr} with password 123456" ) ;
2019-05-13 11:42:20 +02:00
Driver . FindElement ( By . Id ( "Email" ) ) . SendKeys ( usr ) ;
Driver . FindElement ( By . Id ( "Password" ) ) . SendKeys ( "123456" ) ;
Driver . FindElement ( By . Id ( "ConfirmPassword" ) ) . SendKeys ( "123456" ) ;
2019-05-14 16:33:46 +02:00
if ( isAdmin )
Driver . FindElement ( By . Id ( "IsAdmin" ) ) . Click ( ) ;
2019-05-13 11:42:20 +02:00
Driver . FindElement ( By . Id ( "RegisterButton" ) ) . Click ( ) ;
Driver . AssertNoError ( ) ;
2022-02-21 05:21:33 +01:00
CreatedUser = usr ;
2019-05-13 11:42:20 +02:00
return usr ;
}
2022-02-21 05:21:33 +01:00
string CreatedUser ;
public TestAccount AsTestAccount ( )
{
return new TestAccount ( Server ) { RegisterDetails = new Models . AccountViewModels . RegisterViewModel ( ) { Password = "123456" , Email = CreatedUser } } ;
}
2019-05-13 11:42:20 +02:00
2021-10-26 13:55:13 +02:00
public ( string storeName , string storeId ) CreateNewStore ( bool keepId = true )
2019-05-13 11:42:20 +02:00
{
2022-01-13 09:08:15 +01:00
// If there's no store yet, there is no dropdown toggle
if ( Driver . PageSource . Contains ( "id=\"StoreSelectorToggle\"" ) )
{
Driver . FindElement ( By . Id ( "StoreSelectorToggle" ) ) . Click ( ) ;
}
Driver . WaitForElement ( By . Id ( "StoreSelectorCreate" ) ) . Click ( ) ;
2021-01-22 17:49:26 +01:00
var name = "Store" + RandomUtils . GetUInt64 ( ) ;
2022-02-10 04:24:28 +01:00
TestLogs . LogInformation ( $"Created store {name}" ) ;
2021-03-10 15:53:01 +01:00
Driver . WaitForElement ( By . Id ( "Name" ) ) . SendKeys ( name ) ;
Driver . WaitForElement ( By . Id ( "Create" ) ) . Click ( ) ;
2022-01-13 09:08:15 +01:00
Driver . FindElement ( By . Id ( "StoreNav-StoreSettings" ) ) . Click ( ) ;
2022-01-18 02:19:27 +01:00
Driver . FindElement ( By . Id ( $"SectionNav-{StoreNavPages.General.ToString()}" ) ) . Click ( ) ;
2021-10-26 13:55:13 +02:00
var storeId = Driver . WaitForElement ( By . Id ( "Id" ) ) . GetAttribute ( "value" ) ;
if ( keepId )
StoreId = storeId ;
return ( name , storeId ) ;
2019-05-13 11:42:20 +02:00
}
2022-11-24 00:53:32 +01:00
public void EnableCheckoutV2 ( bool bip21 = false )
{
GoToStore ( StoreNavPages . CheckoutAppearance ) ;
Driver . SetCheckbox ( By . Id ( "UseNewCheckout" ) , true ) ;
Driver . WaitForElement ( By . Id ( "OnChainWithLnInvoiceFallback" ) ) ;
Driver . SetCheckbox ( By . Id ( "OnChainWithLnInvoiceFallback" ) , bip21 ) ;
Driver . FindElement ( By . Id ( "Save" ) ) . Click ( ) ;
}
2022-02-10 04:24:28 +01:00
public Mnemonic GenerateWallet ( string cryptoCode = "BTC" , string seed = "" , bool? importkeys = null , bool isHotWallet = false , ScriptPubKeyType format = ScriptPubKeyType . Segwit )
2019-12-05 18:56:40 +01:00
{
2021-08-03 07:27:04 +02:00
var isImport = ! string . IsNullOrEmpty ( seed ) ;
2022-01-19 12:58:02 +01:00
GoToWalletSettings ( cryptoCode ) ;
2021-03-02 11:06:04 +01:00
// Replace previous wallet case
2021-02-17 04:14:29 +01:00
if ( Driver . PageSource . Contains ( "id=\"ChangeWalletLink\"" ) )
2021-02-11 11:48:54 +01:00
{
2021-11-11 06:30:19 +01:00
Driver . FindElement ( By . Id ( "ActionsDropdownToggle" ) ) . Click ( ) ;
Driver . WaitForElement ( By . Id ( "ChangeWalletLink" ) ) . Click ( ) ;
2021-09-07 04:55:53 +02:00
Driver . WaitForElement ( By . Id ( "ConfirmInput" ) ) . SendKeys ( "REPLACE" ) ;
Driver . FindElement ( By . Id ( "ConfirmContinue" ) ) . Click ( ) ;
2021-02-11 11:48:54 +01:00
}
2021-08-03 07:27:04 +02:00
if ( isImport )
2021-02-11 11:48:54 +01:00
{
2021-11-22 09:16:08 +01:00
TestLogs . LogInformation ( "Progressing with existing seed" ) ;
2021-02-17 04:14:29 +01:00
Driver . FindElement ( By . Id ( "ImportWalletOptionsLink" ) ) . Click ( ) ;
Driver . FindElement ( By . Id ( "ImportSeedLink" ) ) . Click ( ) ;
2021-02-11 11:48:54 +01:00
Driver . FindElement ( By . Id ( "ExistingMnemonic" ) ) . SendKeys ( seed ) ;
2022-02-10 04:24:28 +01:00
Driver . SetCheckbox ( By . Id ( "SavePrivateKeys" ) , isHotWallet ) ;
2021-02-11 11:48:54 +01:00
}
2021-08-03 07:27:04 +02:00
else
{
2022-02-10 04:24:28 +01:00
var option = isHotWallet ? "Hotwallet" : "Watchonly" ;
2021-11-22 09:16:08 +01:00
TestLogs . LogInformation ( $"Generating new seed ({option})" ) ;
2021-08-03 07:27:04 +02:00
Driver . FindElement ( By . Id ( "GenerateWalletLink" ) ) . Click ( ) ;
Driver . FindElement ( By . Id ( $"Generate{option}Link" ) ) . Click ( ) ;
}
2021-02-11 11:48:54 +01:00
2021-01-22 17:49:26 +01:00
Driver . FindElement ( By . Id ( "ScriptPubKeyType" ) ) . Click ( ) ;
Driver . FindElement ( By . CssSelector ( $"#ScriptPubKeyType option[value={format}]" ) ) . Click ( ) ;
2021-12-31 08:59:02 +01:00
2021-05-19 04:39:27 +02:00
Driver . ToggleCollapse ( "AdvancedSettings" ) ;
2022-02-10 04:24:28 +01:00
if ( importkeys is bool v )
Driver . SetCheckbox ( By . Id ( "ImportKeysToRPC" ) , v ) ;
2021-02-17 12:34:49 +01:00
Driver . FindElement ( By . Id ( "Continue" ) ) . Click ( ) ;
2021-02-11 11:48:54 +01:00
2021-08-03 07:27:04 +02:00
if ( isImport )
2019-12-05 18:56:40 +01:00
{
2021-08-03 07:27:04 +02:00
// Confirm addresses
Driver . FindElement ( By . Id ( "Confirm" ) ) . Click ( ) ;
2019-12-05 18:56:40 +01:00
}
2021-08-03 07:27:04 +02:00
else
{
// Seed backup
FindAlertMessage ( ) ;
if ( string . IsNullOrEmpty ( seed ) )
{
seed = Driver . FindElements ( By . Id ( "RecoveryPhrase" ) ) . First ( ) . GetAttribute ( "data-mnemonic" ) ;
}
// Confirm seed backup
Driver . FindElement ( By . Id ( "confirm" ) ) . Click ( ) ;
Driver . FindElement ( By . Id ( "submit" ) ) . Click ( ) ;
}
2021-12-31 08:59:02 +01:00
2020-06-24 03:34:09 +02:00
WalletId = new WalletId ( StoreId , cryptoCode ) ;
2020-03-23 07:46:54 +01:00
return new Mnemonic ( seed ) ;
2019-12-05 18:56:40 +01:00
}
2021-01-22 17:49:26 +01:00
2021-12-31 14:02:53 +01:00
/// <summary>
/// Assume to be in store's settings
/// </summary>
/// <param name="cryptoCode"></param>
/// <param name="derivationScheme"></param>
2019-09-10 10:03:24 +02:00
public void AddDerivationScheme ( string cryptoCode = "BTC" , string derivationScheme = "xpub661MyMwAqRbcGABgHMUXDzPzH1tU7eZaAaJQXhDXsSxsqyQzQeU6kznNfSuAyqAK9UaWSaZaMFdNiY5BCF4zBPAzSnwfUAwUhwttuAKwfRX-[legacy]" )
2019-05-13 11:42:20 +02:00
{
2022-02-10 04:17:15 +01:00
if ( ! Driver . PageSource . Contains ( $"Setup {cryptoCode} Wallet" ) )
{
GoToWalletSettings ( cryptoCode ) ;
}
2022-01-13 09:08:15 +01:00
2021-02-17 04:14:29 +01:00
Driver . FindElement ( By . Id ( "ImportWalletOptionsLink" ) ) . Click ( ) ;
Driver . FindElement ( By . Id ( "ImportXpubLink" ) ) . Click ( ) ;
2021-02-11 11:48:54 +01:00
Driver . FindElement ( By . Id ( "DerivationScheme" ) ) . SendKeys ( derivationScheme ) ;
2021-01-22 17:49:26 +01:00
Driver . FindElement ( By . Id ( "Continue" ) ) . Click ( ) ;
2021-01-25 14:10:19 +01:00
Driver . FindElement ( By . Id ( "Confirm" ) ) . Click ( ) ;
2021-01-22 17:49:26 +01:00
FindAlertMessage ( ) ;
2019-05-13 11:42:20 +02:00
}
2020-01-12 05:54:06 +01:00
2021-12-31 14:02:53 +01:00
public void AddLightningNode ( )
{
AddLightningNode ( null , null , true ) ;
}
2022-01-19 03:52:05 +01:00
2021-12-31 14:02:53 +01:00
public void AddLightningNode ( LightningConnectionType ? connectionType = null , bool test = true )
2019-09-10 10:03:24 +02:00
{
2021-12-31 14:02:53 +01:00
AddLightningNode ( null , connectionType , test ) ;
}
2022-01-19 03:52:05 +01:00
2021-12-31 14:02:53 +01:00
public void AddLightningNode ( string cryptoCode = null , LightningConnectionType ? connectionType = null , bool test = true )
{
cryptoCode ? ? = "BTC" ;
2022-02-10 04:17:15 +01:00
if ( ! Driver . PageSource . Contains ( "Connect to a Lightning node" ) )
2021-10-29 08:25:43 +02:00
{
2022-02-10 04:17:15 +01:00
GoToLightningSettings ( ) ;
2021-10-29 08:25:43 +02:00
}
2021-03-31 13:23:36 +02:00
var connectionString = connectionType switch
{
LightningConnectionType . Charge = >
$"type=charge;server={Server.MerchantCharge.Client.Uri.AbsoluteUri};allowinsecure=true" ,
LightningConnectionType . CLightning = >
2021-12-31 08:59:02 +01:00
$"type=clightning;server={((CLightningClient)Server.MerchantLightningD).Address.AbsoluteUri}" ,
2021-03-31 13:23:36 +02:00
LightningConnectionType . LndREST = >
$"type=lnd-rest;server={Server.MerchantLnd.Swagger.BaseUrl};allowinsecure=true" ,
_ = > null
} ;
if ( connectionString = = null )
{
Assert . True ( Driver . FindElement ( By . Id ( "LightningNodeType-Internal" ) ) . Enabled , "Usage of the internal Lightning node is disabled." ) ;
Driver . FindElement ( By . CssSelector ( "label[for=\"LightningNodeType-Internal\"]" ) ) . Click ( ) ;
}
2019-09-10 10:03:24 +02:00
else
2021-03-31 13:23:36 +02:00
{
Driver . FindElement ( By . CssSelector ( "label[for=\"LightningNodeType-Custom\"]" ) ) . Click ( ) ;
2021-11-24 10:54:43 +01:00
Driver . WaitForElement ( By . Id ( "ConnectionString" ) ) . Clear ( ) ;
2021-03-31 13:23:36 +02:00
Driver . FindElement ( By . Id ( "ConnectionString" ) ) . SendKeys ( connectionString ) ;
2021-10-26 13:55:13 +02:00
if ( test )
{
Driver . FindElement ( By . Id ( "test" ) ) . Click ( ) ;
Assert . Contains ( "Connection to the Lightning node successful." , FindAlertMessage ( ) . Text ) ;
}
2021-04-19 16:21:50 +02:00
}
2021-03-31 13:23:36 +02:00
2021-04-20 12:23:50 +02:00
Driver . FindElement ( By . Id ( "save" ) ) . Click ( ) ;
2021-04-20 03:55:41 +02:00
Assert . Contains ( $"{cryptoCode} Lightning node updated." , FindAlertMessage ( ) . Text ) ;
2021-04-16 15:31:09 +02:00
var enabled = Driver . FindElement ( By . Id ( $"{cryptoCode}LightningEnabled" ) ) ;
if ( enabled . Text = = "Enable" )
{
enabled . Click ( ) ;
Assert . Contains ( $"{cryptoCode} Lightning payments are now enabled for this store." , FindAlertMessage ( ) . Text ) ;
}
2019-09-10 10:03:24 +02:00
}
2019-05-13 11:42:20 +02:00
2021-11-22 09:16:08 +01:00
public Logging . ILog TestLogs = > Server . TestLogs ;
2021-12-11 04:32:23 +01:00
public void ClickOnAllSectionLinks ( )
2019-05-13 11:42:20 +02:00
{
2021-12-11 04:32:23 +01:00
var links = Driver . FindElements ( By . CssSelector ( "#SectionNav .nav-link" ) ) . Select ( c = > c . GetAttribute ( "href" ) ) . ToList ( ) ;
2019-05-15 09:00:03 +02:00
Driver . AssertNoError ( ) ;
2019-05-13 11:42:20 +02:00
foreach ( var l in links )
{
2021-11-22 09:16:08 +01:00
TestLogs . LogInformation ( $"Checking no error on {l}" ) ;
2019-05-13 11:42:20 +02:00
Driver . Navigate ( ) . GoToUrl ( l ) ;
Driver . AssertNoError ( ) ;
}
}
public void Dispose ( )
{
if ( Driver ! = null )
{
try
{
2021-01-22 17:49:26 +01:00
Driver . Quit ( ) ;
2019-05-13 11:42:20 +02:00
}
2021-01-25 14:10:19 +01:00
catch
{
// ignored
}
2019-05-13 11:42:20 +02:00
Driver . Dispose ( ) ;
}
2021-01-25 14:10:19 +01:00
Server ? . Dispose ( ) ;
2019-05-13 11:42:20 +02:00
}
2019-05-14 16:33:46 +02:00
internal void AssertNotFound ( )
{
2020-02-01 09:29:08 +01:00
Assert . Contains ( "404 - Page not found</h1>" , Driver . PageSource ) ;
2019-05-14 16:33:46 +02:00
}
2021-12-11 04:32:23 +01:00
internal void AssertAccessDenied ( )
{
2022-01-07 13:12:31 +01:00
Assert . Contains ( "- Denied</h" , Driver . PageSource ) ;
2021-12-11 04:32:23 +01:00
}
2019-07-01 05:39:25 +02:00
public void GoToHome ( )
2019-05-14 16:33:46 +02:00
{
2021-09-22 14:31:44 +02:00
Driver . Navigate ( ) . GoToUrl ( ServerUri ) ;
2019-05-14 16:33:46 +02:00
}
2019-07-01 05:39:25 +02:00
public void Logout ( )
2019-05-14 16:33:46 +02:00
{
2022-06-20 15:43:24 +02:00
if ( ! Driver . PageSource . Contains ( "id=\"Nav-Logout\"" ) )
{
Driver . Navigate ( ) . GoToUrl ( ServerUri ) ;
}
2022-01-07 17:25:28 +01:00
Driver . FindElement ( By . Id ( "Nav-Account" ) ) . Click ( ) ;
Driver . FindElement ( By . Id ( "Nav-Logout" ) ) . Click ( ) ;
2019-05-14 16:33:46 +02:00
}
2019-07-01 05:39:25 +02:00
2022-02-07 13:18:22 +01:00
public void LogIn ( string user , string password )
2019-07-01 05:39:25 +02:00
{
Driver . FindElement ( By . Id ( "Email" ) ) . SendKeys ( user ) ;
Driver . FindElement ( By . Id ( "Password" ) ) . SendKeys ( password ) ;
Driver . FindElement ( By . Id ( "LoginButton" ) ) . Click ( ) ;
2020-10-17 22:53:07 +02:00
}
2019-09-03 13:11:36 +02:00
2022-01-18 02:19:27 +01:00
public void GoToStore ( StoreNavPages storeNavPage = StoreNavPages . General )
2021-12-31 14:02:53 +01:00
{
GoToStore ( null , storeNavPage ) ;
}
2022-01-13 09:08:15 +01:00
2022-01-18 02:19:27 +01:00
public void GoToStore ( string storeId , StoreNavPages storeNavPage = StoreNavPages . General )
2019-09-03 13:11:36 +02:00
{
2022-01-13 09:08:15 +01:00
if ( storeId is not null )
2022-02-10 04:24:28 +01:00
{
2021-12-31 14:02:53 +01:00
GoToUrl ( $"/stores/{storeId}/" ) ;
2022-02-10 04:24:28 +01:00
StoreId = storeId ;
2022-02-17 09:58:56 +01:00
if ( WalletId ! = null )
WalletId = new WalletId ( storeId , WalletId . CryptoCode ) ;
2022-02-10 04:24:28 +01:00
}
2022-01-13 09:08:15 +01:00
Driver . FindElement ( By . Id ( "StoreNav-StoreSettings" ) ) . Click ( ) ;
2021-01-22 17:49:26 +01:00
2022-01-18 02:19:27 +01:00
if ( storeNavPage ! = StoreNavPages . General )
2019-09-10 10:03:24 +02:00
{
2022-01-18 02:19:27 +01:00
switch ( storeNavPage )
2021-12-11 04:32:23 +01:00
{
2022-01-18 02:19:27 +01:00
case StoreNavPages . Dashboard :
case StoreNavPages . Payouts :
case StoreNavPages . PayButton :
case StoreNavPages . PullPayments :
Driver . FindElement ( By . Id ( $"StoreNav-{storeNavPage.ToString()}" ) ) . Click ( ) ;
break ;
default :
Driver . FindElement ( By . Id ( $"SectionNav-{storeNavPage.ToString()}" ) ) . Click ( ) ;
break ;
2021-12-11 04:32:23 +01:00
}
2019-09-10 10:03:24 +02:00
}
2019-09-03 13:11:36 +02:00
}
2022-01-18 02:19:27 +01:00
2022-01-19 12:58:02 +01:00
public void GoToWalletSettings ( string cryptoCode = "BTC" )
2021-11-11 06:30:19 +01:00
{
2022-01-19 12:58:02 +01:00
Driver . FindElement ( By . Id ( $"StoreNav-Wallet{cryptoCode}" ) ) . Click ( ) ;
2022-02-17 10:07:41 +01:00
if ( Driver . PageSource . Contains ( "id=\"WalletNav-Settings\"" ) )
2021-12-31 08:36:38 +01:00
{
2022-02-17 10:07:41 +01:00
Driver . FindElement ( By . Id ( "WalletNav-Settings" ) ) . Click ( ) ;
2021-12-31 08:36:38 +01:00
}
2021-11-11 06:30:19 +01:00
}
2021-12-31 14:02:53 +01:00
public void GoToLightningSettings ( string cryptoCode = "BTC" )
2021-11-11 06:30:19 +01:00
{
2021-12-31 14:02:53 +01:00
Driver . FindElement ( By . Id ( $"StoreNav-Lightning{cryptoCode}" ) ) . Click ( ) ;
2022-01-19 03:52:05 +01:00
// if Lightning is already set up we need to navigate to the settings
if ( Driver . PageSource . Contains ( "id=\"SectionNav-LightningSettings\"" ) )
{
Driver . FindElement ( By . Id ( "SectionNav-LightningSettings" ) ) . Click ( ) ;
}
2021-12-31 14:02:53 +01:00
}
public void SelectStoreContext ( string storeId )
{
Driver . FindElement ( By . Id ( "StoreSelectorToggle" ) ) . Click ( ) ;
Driver . FindElement ( By . Id ( $"StoreSelectorMenuItem-{storeId}" ) ) . Click ( ) ;
2021-11-11 06:30:19 +01:00
}
2022-02-17 09:58:56 +01:00
public void GoToInvoiceCheckout ( string invoiceId = null )
2019-09-03 13:11:36 +02:00
{
2022-02-10 04:24:28 +01:00
invoiceId ? ? = InvoiceId ;
2021-12-11 04:32:23 +01:00
Driver . FindElement ( By . Id ( "StoreNav-Invoices" ) ) . Click ( ) ;
2019-09-03 13:11:36 +02:00
Driver . FindElement ( By . Id ( $"invoice-checkout-{invoiceId}" ) ) . Click ( ) ;
2019-09-10 10:03:24 +02:00
CheckForJSErrors ( ) ;
2019-09-03 13:11:36 +02:00
}
2020-01-12 05:54:06 +01:00
2021-12-31 08:36:38 +01:00
public void GoToInvoice ( string id )
2019-09-10 10:03:24 +02:00
{
2021-12-31 08:36:38 +01:00
GoToUrl ( $"/invoices/{id}/" ) ;
}
public void GoToInvoices ( string storeId = null )
{
2021-12-31 14:02:53 +01:00
if ( storeId is null )
{
2022-01-19 03:52:05 +01:00
Driver . FindElement ( By . Id ( "StoreNav-Invoices" ) ) . Click ( ) ;
2021-12-31 14:02:53 +01:00
}
else
{
GoToUrl ( storeId = = null ? "/invoices/" : $"/stores/{storeId}/invoices/" ) ;
2022-02-10 04:24:28 +01:00
StoreId = storeId ;
2021-12-31 14:02:53 +01:00
}
2019-09-10 10:03:24 +02:00
}
2020-06-28 10:55:27 +02:00
public void GoToProfile ( ManageNavPages navPages = ManageNavPages . Index )
2020-02-24 14:36:15 +01:00
{
2022-04-08 11:58:01 +02:00
Driver . WaitForAndClick ( By . Id ( "Nav-Account" ) ) ;
Driver . WaitForAndClick ( By . Id ( "Nav-ManageAccount" ) ) ;
2020-02-24 14:36:15 +01:00
if ( navPages ! = ManageNavPages . Index )
{
2022-04-08 11:58:01 +02:00
Driver . WaitForAndClick ( By . Id ( $"SectionNav-{navPages.ToString()}" ) ) ;
2020-02-24 14:36:15 +01:00
}
}
public void GoToLogin ( )
{
2021-12-31 08:36:38 +01:00
GoToUrl ( "/login" ) ;
2020-02-24 14:36:15 +01:00
}
2019-09-10 10:03:24 +02:00
2021-12-31 14:02:53 +01:00
public string CreateInvoice ( decimal? amount = 100 ,
string currency = "USD" ,
string refundEmail = "" ,
string defaultPaymentMethod = null ,
bool? requiresRefundEmail = null ,
StatusMessageModel . StatusSeverity expectedSeverity = StatusMessageModel . StatusSeverity . Success
)
{
return CreateInvoice ( null , amount , currency , refundEmail , defaultPaymentMethod , requiresRefundEmail , expectedSeverity ) ;
}
2021-09-01 05:21:44 +02:00
public string CreateInvoice (
2021-12-31 08:59:02 +01:00
string storeId ,
decimal? amount = 100 ,
string currency = "USD" ,
2021-09-01 05:21:44 +02:00
string refundEmail = "" ,
2021-10-26 13:55:13 +02:00
string defaultPaymentMethod = null ,
2021-10-27 16:32:56 +02:00
bool? requiresRefundEmail = null ,
2021-10-26 13:55:13 +02:00
StatusMessageModel . StatusSeverity expectedSeverity = StatusMessageModel . StatusSeverity . Success
2021-09-01 05:21:44 +02:00
)
2019-09-10 10:03:24 +02:00
{
2021-12-31 08:36:38 +01:00
GoToInvoices ( storeId ) ;
2022-02-10 04:24:28 +01:00
2021-01-22 17:49:26 +01:00
Driver . FindElement ( By . Id ( "CreateNewInvoice" ) ) . Click ( ) ;
2021-08-03 10:03:00 +02:00
if ( amount is decimal v )
Driver . FindElement ( By . Id ( "Amount" ) ) . SendKeys ( v . ToString ( CultureInfo . InvariantCulture ) ) ;
2019-09-10 10:03:24 +02:00
var currencyEl = Driver . FindElement ( By . Id ( "Currency" ) ) ;
currencyEl . Clear ( ) ;
currencyEl . SendKeys ( currency ) ;
Driver . FindElement ( By . Id ( "BuyerEmail" ) ) . SendKeys ( refundEmail ) ;
2022-01-14 09:48:15 +01:00
if ( defaultPaymentMethod is not null )
2021-10-20 07:34:04 +02:00
new SelectElement ( Driver . FindElement ( By . Name ( "DefaultPaymentMethod" ) ) ) . SelectByValue ( defaultPaymentMethod ) ;
2021-10-27 16:32:56 +02:00
if ( requiresRefundEmail is bool )
new SelectElement ( Driver . FindElement ( By . Name ( "RequiresRefundEmail" ) ) ) . SelectByValue ( requiresRefundEmail = = true ? "1" : "2" ) ;
2020-09-17 11:37:49 +02:00
Driver . FindElement ( By . Id ( "Create" ) ) . Click ( ) ;
2021-10-26 13:55:13 +02:00
var statusElement = FindAlertMessage ( expectedSeverity ) ;
2022-02-10 04:24:28 +01:00
var inv = expectedSeverity = = StatusMessageModel . StatusSeverity . Success ? statusElement . Text . Split ( " " ) [ 1 ] : null ;
InvoiceId = inv ;
TestLogs . LogInformation ( $"Created invoice {inv}" ) ;
return inv ;
2019-09-10 10:03:24 +02:00
}
2022-02-10 04:24:28 +01:00
string InvoiceId ;
2019-09-10 10:03:24 +02:00
2022-02-17 09:58:56 +01:00
public async Task < string > FundStoreWallet ( WalletId walletId = null , int coins = 1 , decimal denomination = 1 m )
2020-03-30 08:31:30 +02:00
{
2020-06-24 03:34:09 +02:00
walletId ? ? = WalletId ;
2020-04-28 08:06:28 +02:00
GoToWallet ( walletId , WalletsNavPages . Receive ) ;
2020-03-30 08:31:30 +02:00
Driver . FindElement ( By . Id ( "generateButton" ) ) . Click ( ) ;
2022-05-20 02:35:31 +02:00
var addressStr = Driver . FindElement ( By . Id ( "address" ) ) . GetAttribute ( "value" ) ;
2020-03-30 08:31:30 +02:00
var address = BitcoinAddress . Create ( addressStr , ( ( BTCPayNetwork ) Server . NetworkProvider . GetNetwork ( walletId . CryptoCode ) ) . NBitcoinNetwork ) ;
2021-01-22 17:49:26 +01:00
for ( var i = 0 ; i < coins ; i + + )
2020-03-30 08:31:30 +02:00
{
2022-02-17 09:58:56 +01:00
bool mined = false ;
retry :
try
{
await Server . ExplorerNode . SendToAddressAsync ( address , Money . Coins ( denomination ) ) ;
}
catch ( RPCException ) when ( ! mined )
{
mined = true ;
await Server . ExplorerNode . GenerateAsync ( 1 ) ;
goto retry ;
}
2020-03-30 08:31:30 +02:00
}
2022-02-17 09:58:56 +01:00
Driver . Navigate ( ) . Refresh ( ) ;
2022-07-04 06:20:08 +02:00
Driver . FindElement ( By . Id ( "CancelWizard" ) ) . Click ( ) ;
2022-02-17 09:58:56 +01:00
return addressStr ;
2020-03-30 08:31:30 +02:00
}
2020-06-28 10:55:27 +02:00
2019-09-10 10:03:24 +02:00
private void CheckForJSErrors ( )
{
//wait for seleniun update: https://stackoverflow.com/questions/57520296/selenium-webdriver-3-141-0-driver-manage-logs-availablelogtypes-throwing-syste
2021-04-19 16:21:50 +02:00
// var errorStrings = new List<string>
// {
// "SyntaxError",
// "EvalError",
// "ReferenceError",
// "RangeError",
// "TypeError",
// "URIError"
2020-01-12 05:54:06 +01:00
// };
//
// var jsErrors = Driver.Manage().Logs.GetLog(LogType.Browser).Where(x => errorStrings.Any(e => x.Message.Contains(e)));
//
// if (jsErrors.Any())
// {
2021-11-22 09:16:08 +01:00
// TestLogs.LogInformation("JavaScript error(s):" + Environment.NewLine + jsErrors.Aggregate("", (s, entry) => s + entry.Message + Environment.NewLine));
2020-01-12 05:54:06 +01:00
// }
// Assert.Empty(jsErrors);
2019-09-10 10:03:24 +02:00
}
2020-06-24 03:34:09 +02:00
public void GoToWallet ( WalletId walletId = null , WalletsNavPages navPages = WalletsNavPages . Send )
2020-03-23 07:46:54 +01:00
{
2020-06-24 03:34:09 +02:00
walletId ? ? = WalletId ;
2021-09-22 14:31:44 +02:00
Driver . Navigate ( ) . GoToUrl ( new Uri ( ServerUri , $"wallets/{walletId}" ) ) ;
2022-02-18 02:55:54 +01:00
if ( navPages = = WalletsNavPages . PSBT )
{
Driver . FindElement ( By . Id ( "WalletNav-Send" ) ) . Click ( ) ;
Driver . FindElement ( By . Id ( "PSBT" ) ) . Click ( ) ;
}
else if ( navPages ! = WalletsNavPages . Transactions )
2020-04-28 08:06:28 +02:00
{
2022-02-17 10:07:41 +01:00
Driver . FindElement ( By . Id ( $"WalletNav-{navPages}" ) ) . Click ( ) ;
2020-04-28 08:06:28 +02:00
}
2020-03-23 07:46:54 +01:00
}
2020-10-05 09:39:49 +02:00
public void GoToUrl ( string relativeUrl )
{
2021-09-22 14:31:44 +02:00
Driver . Navigate ( ) . GoToUrl ( new Uri ( ServerUri , relativeUrl ) ) ;
2020-10-05 09:39:49 +02:00
}
2021-04-19 16:21:50 +02:00
2020-09-16 08:54:09 +02:00
public void GoToServer ( ServerNavPages navPages = ServerNavPages . Index )
{
2021-12-11 04:32:23 +01:00
Driver . FindElement ( By . Id ( "Nav-ServerSettings" ) ) . Click ( ) ;
2020-09-16 08:54:09 +02:00
if ( navPages ! = ServerNavPages . Index )
{
2021-12-11 04:32:23 +01:00
Driver . FindElement ( By . Id ( $"SectionNav-{navPages}" ) ) . Click ( ) ;
2020-09-16 08:54:09 +02:00
}
}
2019-05-13 11:42:20 +02:00
}
}