Getting Started

Atata Framework - C#/.NET web test automation full featured framework based on Selenium WebDriver. It uses fluent page object pattern. Atata repository is open source and hosted on GitHub under the Apache License 2.0.

Framework basically consists of the following concepts:

  • AtataContext
    • Configuration (using fluent builder or JSON)
  • Components
    • Controls
    • Page objects
    • Control list
  • Attributes
    • Attributes of control search - basically, element locators, like [FindById], [FindByName], [FindByXPath], etc.
    • Trigger attributes - functionality that is automatically executed in response to certain events on a particular component. For example, when a click on button occurs it may be defined that a wait should be executed.
    • Behavior attributes - change the way the particular actions are executed. For example, specify the click behavior for a specific button by adding [ClickUsingScript] to perform the click using JavaScript, instead of default IWebElement.Click() way.
    • Settings attributes - set settings for control finding, culture, value format, etc.
  • Verification functionality

There are 2 options to create a project in Visual Studio for automated testing using Atata Framework.

Install via Atata Templates

To get started, install Atata Templates Visual Studio extension.

The extension provides the following templates:

  • Project templates:
    • Atata NUnit Basic Test Project (.NET Core)
    • Atata NUnit Basic Test Project (.NET Framework)
    • Atata NUnit Advanced Test Project (.NET Core)
    • Atata Components Library (.NET Standard)
    • Atata Components Library (.NET Framework)
  • Item templates:
    • Atata Page Object
    • Atata Base Page Object
    • Atata Control
    • Atata Trigger
    • Atata NUnit Test Fixture
    • Atata NUnit Base Test Fixture

Create Project

When extension is installed, you can create a project of one of Atata project types. In Visual Studio:

  1. Go to File/New/Project… or File/Add/New Project… (to add to existing solution)
  2. Type Atata into search box or choose Atata in “project types” drop-down
  3. Choose template (e.g.: Atata NUnit Advanced Test Project (.NET Core)) and specify project name and location

Atata Templates project

Project References

The project is created with NuGet package references:

Configuration

You don’t need to configure specific browser driver packages, as a project is by default configured to automatically download appropriate driver, by use of Atata.WebDriverSetup package.

In the created project you can specify your testing site base URL and appropriate driver in SetUpFixture.cs or Atata.local.json class, depending on type of project (basic or advanced).

AtataContext.GlobalConfiguration
    .UseChrome()
        .WithArguments("start-maximized")
    .UseBaseUrl("SITE_URL")
    //...
{
  "baseUrl": "https://atata.io/"
  // Other environment specific configuration properties can be added here.
}

Test Fixtures

The created project also contains ready to use SampleTests.cs fixture, which can be either modified or removed:

using Atata;
using NUnit.Framework;

namespace AtataUITests1
{
    public class SampleTests : UITestFixture
    {
        [Test]
        public void SampleTest()
        {
            Go.To<OrdinaryPage>()
                .PageTitle.Should.Contain("Atata");
        }
    }
}

Further test fixture classes are recommended to inherit from UITestFixture, or just choose “Atata NUnit Test Fixture” item template in “Add New Item Window”.

Change .NET Version

By default, “Atata NUnit Basic Test Project (.NET Core)” and “Atata NUnit Advanced Test Project (.NET Core)” project templates create a project with .NET Core 2.1 version.

To change the version to .NET Core 3.1 or .NET 5:

  1. Open project .csproj file.
  2. Change the value of <TargetFramework> tag from netcoreapp2.1 to either netcoreapp3.1 or net5.0.
    <Project Sdk="Microsoft.NET.Sdk">
       
      <PropertyGroup>
        <TargetFramework>net5.0</TargetFramework>
      </PropertyGroup>
       
      <!-- ... -->
       
    </Project>
    

Install via NuGet

It is a more custom approach to create Atata testing project. To get started just add Atata NuGet package to the project of Class Library (.NET Framework, .NET Core or .NET 5+) type in Visual Studio.

PM> Install-Package Atata

The Atata package depends on the following packages, which are added automatically:

You might also need to install Atata.WebDriverSetup package for auto-setup of browser drivers, e.g. chromedriver, geckodriver, etc. This is a recommended option. Alternatively, you can install a driver package for specific browser: Selenium.WebDriver.ChromeDriver, Selenium.WebDriver.IEDriver, etc. But be aware to keep version synchronization of browser and driver.

You are also free to select any test engine framework: NUnit, Xunit, MSTest, SpecFlow, etc.

NUnit Project Configuration

In addition to Atata NuGet package, add the following packages:

Then add 2 C# class files.

The first SetUpFixture class sets the global Atata configuration, like which browser driver to use, basic URL, etc. Then it sets up an appropriate driver executable for the browser to use.

SetUpFixture.cs

using Atata;
using NUnit.Framework;

namespace SampleApp.UITests
{
    [SetUpFixture]
    public class SetUpFixture
    {
        [OneTimeSetUp]
        public void GlobalSetUp()
        {
            AtataContext.GlobalConfiguration
                .UseChrome()
                    .WithArguments("start-maximized")
                .UseBaseUrl("https://atata.io/")
                .UseCulture("en-US")
                .UseAllNUnitFeatures();

            AtataContext.GlobalConfiguration.AutoSetUpDriverToUse();
        }
    }
}

The second UITestFixture class is the base class for all test fixture classes that have UI tests. It just starts an Atata session before the test run and closes it after the test is finished.

SetUpFixture.cs

using Atata;
using NUnit.Framework;

namespace SampleApp.UITests
{
    [TestFixture]
    [Parallelizable(ParallelScope.Self)]
    public class UITestFixture
    {
        [SetUp]
        public void SetUp()
        {
            AtataContext.Configure().Build();
        }

        [TearDown]
        public void TearDown()
        {
            AtataContext.Current?.CleanUp();
        }
    }
}

Xunit Project Configuration

Check out Xunit Atata sample project.

MSTest Project Configuration

Check out MSTest Atata sample project.

SpecFlow Project Configuration

Check out SpecFlow Atata sample project.

.NET Core Configuration

.NET Core, as well as .NET Framework 4.0+ and .NET 5.0+, is supported and you are able to use Atata package in .NET Core 2.1+ test project. You can also create .NET Standard 2.0+ library project for Atata components package. But there are few issues below that may require extra configuration comparing to .NET Framework, if you feel that you faced one of them.

WebDriver .NET Core Performance Issue

There is a bug in Selenium WebDriver since v3.6.0 for .NET Core 2.0+: each WebDriver request takes extra 1 second. It makes execution of WebDriver actions very slow. The fix is added within Atata package. Use WithFixOfCommandExecutionDelay driver configurational method to get around of this bug.

AtataContext.GlobalConfiguration
    .UseChrome()
        .WithFixOfCommandExecutionDelay();

It is equivalent to:

AtataContext.GlobalConfiguration
    .UseChrome()
        .WithHostName("127.0.0.1");

Using Atata.Configuration.Json:

{
  "driver": {
    "type": "chrome",
    "service": {
      "hostName": "127.0.0.1"
    }
  }
}

Check the fix details: #101 Fix command execution delay of WebDriver for .NET Core 2.0.

WebDriver .NET Core Driver Path Issue

If you use specific NuGet package for driver setup, like Selenium.WebDriver.ChromeDriver, WebDriver doesn’t look for driver (e.g., “chromedriver.exe”) in application build folder in .NET Core 2.1 version. Use WithLocalDriverPath driver configurational method if you use .NET Core 2.1 project that uses driver as a project package (hosted in the same build directory).

AtataContext.GlobalConfiguration
    .UseChrome()
        .WithLocalDriverPath();

Using Atata.Configuration.Json:

{
  "driver": {
    "type": "chrome",
    "service": {
      "driverPath": "{basedir}"
    }
  }
}

Check the fix details: #102 Add WithLocalDriverPath method to DriverAtataContextBuilder<TBuilder, TService, TOptions>.

Running Tests Using Visual Studio

For test detection in “Test Explorer” VS panel, .NET Core requires Microsoft.NET.Test.Sdk package to be added to the project that contains tests (no matter NUnit, xUnit, MSTest, etc.).

Lat’s create a simple test automation project example with a test for Sign In page.

Create Project

In Visual Studio create a project using Installation instructions.

Set Atata base URL to "https://demo.atata.io/" either in SetUpFixture.cs or Atata.local.json file.

Define Page Object Class

SignInPage.cs

using Atata;

namespace AtataDemo.UITests
{
    using _ = SignInPage;

    [Url("signin")]
    [VerifyH1]
    public class SignInPage : Page<_>
    {
        public TextInput<_> Email { get; private set; }

        public PasswordInput<_> Password { get; private set; }

        public Button<_> SignIn { get; private set; }
    }
}

SignInPage is a page object class that is marked with a few attributes:

  • [Url("signin")] - sets the relative URL of the page to be navigated to.
  • [VerifyH1] - upon page initialization verifies that the page contains <h1> HTML element with “Sign In” text.

Default element search of Email and Password controls is performed by label. Default search of SignIn button is performed by its text.

Implement Test

SignInTests.cs

using Atata;
using NUnit.Framework;

namespace AtataDemo.UITests
{
    [TestFixture]
    public class SignInTests : UITestFixture
    {
        [Test]
        public void SignIn()
        {
            Go.To<SignInPage>()
                .Email.Set("admin@mail.com")
                .Password.Set("abc123")
                .SignIn.Click();
        }
    }
}

View Log

The above sample SignIn test generates the following log to NUnit output:

2021-05-26 15:57:26.4090  INFO Starting test: SignIn
2021-05-26 15:57:26.4364 TRACE > Set up AtataContext
2021-05-26 15:57:26.4380 TRACE - Set: BaseUrl=https://demo.atata.io/
2021-05-26 15:57:26.4398 TRACE - Set: ElementFindTimeout=5s; ElementFindRetryInterval=0.5s
2021-05-26 15:57:26.4399 TRACE - Set: WaitingTimeout=5s; WaitingRetryInterval=0.5s
2021-05-26 15:57:26.4400 TRACE - Set: VerificationTimeout=5s; VerificationRetryInterval=0.5s
2021-05-26 15:57:26.4404 TRACE - Set: Culture=en-US
2021-05-26 15:57:26.4544 TRACE - Set: DriverService=ChromeDriverService on port 61540
2021-05-26 15:57:27.3656 TRACE - Set: Driver=ChromeDriver (alias=chrome)
2021-05-26 15:57:27.3672 TRACE < Set up AtataContext (0.930s)
2021-05-26 15:57:27.4218  INFO Go to "Sign In" page
2021-05-26 15:57:27.4735  INFO Go to URL "https://demo.atata.io/signin"
2021-05-26 15:57:28.6264 TRACE > Execute trigger VerifyH1Attribute { Index=-1, Case=Title, Match=Equals } on Init against "Sign In" page
2021-05-26 15:57:28.6508  INFO - > Assert: "Sign In" <h1> heading should exist
2021-05-26 15:57:28.6868 TRACE - - > Find visible element by XPath ".//h1[normalize-space(.) = 'Sign In']" in ChromeDriver
2021-05-26 15:57:29.4000 TRACE - - < Find visible element by XPath ".//h1[normalize-space(.) = 'Sign In']" in ChromeDriver (0.712s) >> Element { Id=fd4252fa-62b9-47c1-8471-dce2b4747cfc }
2021-05-26 15:57:29.4003  INFO - < Assert: "Sign In" <h1> heading should exist (0.749s)
2021-05-26 15:57:29.4006 TRACE < Execute trigger VerifyH1Attribute { Index=-1, Case=Title, Match=Equals } on Init against "Sign In" page (0.774s)
2021-05-26 15:57:29.4090  INFO > Set "admin@mail.com" to "Email" text input
2021-05-26 15:57:29.4119 TRACE - > Execute behavior ValueSetUsingClearAndSendKeysAttribute against "Email" text input
2021-05-26 15:57:29.4188 TRACE - - > Find visible element by XPath ".//label[normalize-space(.) = 'Email']" in ChromeDriver
2021-05-26 15:57:29.4493 TRACE - - < Find visible element by XPath ".//label[normalize-space(.) = 'Email']" in ChromeDriver (0.030s) >> Element { Id=74cce3ab-0486-4e11-b200-657f4a31ddf0 }
2021-05-26 15:57:29.4667 TRACE - - > Find visible element by XPath ".//*[normalize-space(@id) = 'email']/descendant-or-self::input[@type='text' or not(@type)]" in ChromeDriver
2021-05-26 15:57:29.4943 TRACE - - < Find visible element by XPath ".//*[normalize-space(@id) = 'email']/descendant-or-self::input[@type='text' or not(@type)]" in ChromeDriver (0.027s) >> Element { Id=b8e8eb61-4753-4377-b4c7-31264684a100 }
2021-05-26 15:57:29.4953 TRACE - - > Clear element { Id=b8e8eb61-4753-4377-b4c7-31264684a100 }
2021-05-26 15:57:29.5344 TRACE - - < Clear element { Id=b8e8eb61-4753-4377-b4c7-31264684a100 } (0.039s)
2021-05-26 15:57:29.5352 TRACE - - > Send keys "admin@mail.com" to element { Id=b8e8eb61-4753-4377-b4c7-31264684a100 }
2021-05-26 15:57:29.6095 TRACE - - < Send keys "admin@mail.com" to element { Id=b8e8eb61-4753-4377-b4c7-31264684a100 } (0.074s)
2021-05-26 15:57:29.6097 TRACE - < Execute behavior ValueSetUsingClearAndSendKeysAttribute against "Email" text input (0.197s)
2021-05-26 15:57:29.6099  INFO < Set "admin@mail.com" to "Email" text input (0.200s)
2021-05-26 15:57:29.6101  INFO > Set "abc123" to "Password" password input
2021-05-26 15:57:29.6103 TRACE - > Execute behavior ValueSetUsingClearAndSendKeysAttribute against "Password" password input
2021-05-26 15:57:29.6154 TRACE - - > Find visible element by XPath ".//label[normalize-space(.) = 'Password']" in ChromeDriver
2021-05-26 15:57:29.6464 TRACE - - < Find visible element by XPath ".//label[normalize-space(.) = 'Password']" in ChromeDriver (0.031s) >> Element { Id=c0f43431-994d-4a9d-8313-309c4f44c311 }
2021-05-26 15:57:29.6582 TRACE - - > Find visible element by XPath ".//*[normalize-space(@id) = 'password']/descendant-or-self::input[@type='password']" in ChromeDriver
2021-05-26 15:57:29.6878 TRACE - - < Find visible element by XPath ".//*[normalize-space(@id) = 'password']/descendant-or-self::input[@type='password']" in ChromeDriver (0.029s) >> Element { Id=969b203a-2203-4065-b6c7-4f5b76bafc3b }
2021-05-26 15:57:29.6883 TRACE - - > Clear element { Id=969b203a-2203-4065-b6c7-4f5b76bafc3b }
2021-05-26 15:57:29.7327 TRACE - - < Clear element { Id=969b203a-2203-4065-b6c7-4f5b76bafc3b } (0.044s)
2021-05-26 15:57:29.7330 TRACE - - > Send keys "abc123" to element { Id=969b203a-2203-4065-b6c7-4f5b76bafc3b }
2021-05-26 15:57:29.7865 TRACE - - < Send keys "abc123" to element { Id=969b203a-2203-4065-b6c7-4f5b76bafc3b } (0.053s)
2021-05-26 15:57:29.7871 TRACE - < Execute behavior ValueSetUsingClearAndSendKeysAttribute against "Password" password input (0.176s)
2021-05-26 15:57:29.7874  INFO < Set "abc123" to "Password" password input (0.177s)
2021-05-26 15:57:29.7894  INFO > Click "Sign In" button
2021-05-26 15:57:29.7920 TRACE - > Execute behavior ClickUsingClickMethodAttribute against "Sign In" button
2021-05-26 15:57:29.7949 TRACE - - > Find visible element by XPath ".//*[self::input[@type='button' or @type='submit' or @type='reset'] or self::button][normalize-space(.) = 'Sign In' or normalize-space(@value) = 'Sign In']" in ChromeDriver
2021-05-26 15:57:29.8221 TRACE - - < Find visible element by XPath ".//*[self::input[@type='button' or @type='submit' or @type='reset'] or self::button][normalize-space(.) = 'Sign In' or normalize-space(@value) = 'Sign In']" in ChromeDriver (0.027s) >> Element { Id=601f78f6-e3b6-4af0-aceb-2b36b4ac5a9c }
2021-05-26 15:57:29.8230 TRACE - - > Click element { Id=601f78f6-e3b6-4af0-aceb-2b36b4ac5a9c }
2021-05-26 15:57:29.9348 TRACE - - < Click element { Id=601f78f6-e3b6-4af0-aceb-2b36b4ac5a9c } (0.111s)
2021-05-26 15:57:29.9351 TRACE - < Execute behavior ClickUsingClickMethodAttribute against "Sign In" button (0.143s)
2021-05-26 15:57:29.9353  INFO < Click "Sign In" button (0.145s)
2021-05-26 15:57:29.9579  INFO > Clean up AtataContext
2021-05-26 15:57:30.1255  INFO < Clean up AtataContext (0.167s)
2021-05-26 15:57:30.1259  INFO Finished test (3.773s)
2021-05-26 15:57:30.1262  INFO Pure test execution time: 2.571s

Demo atata-framework/atata-sample-app-tests UI tests application demonstrates different testing approaches and features of Atata Framework. It uses Atata Sample App (repository) as a testing website and NUnit 3 as a test engine.

Features

  • Atata test initialization and settings set-up
  • Page navigation
  • Controls finding
  • Data input and verification
  • Validation messages verification
  • Use of the triggers
  • Interaction with the pop-ups (Bootstrap modal) and alerts
  • Work with the tables
  • Logging

Sample Test

[Test]
public void User_Create()
{
    string firstName, lastName, email;
    Office office = Office.NewYork;
    Gender gender = Gender.Male;

    Login().
        New().
            ModalTitle.Should.Equal("New User").
            General.FirstName.SetRandom(out firstName).
            General.LastName.SetRandom(out lastName).
            General.Email.SetRandom(out email).
            General.Office.Set(office).
            General.Gender.Set(gender).
            Save().
        Users.Rows[x => x.FirstName == firstName && x.LastName == lastName && x.Email == email && x.Office == office].View().
            Header.Should.Equal($"{firstName} {lastName}").
            Email.Should.Equal(email).
            Office.Should.Equal(office).
            Gender.Should.Equal(gender).
            Birthday.Should.Not.Exist().
            Notes.Should.Not.Exist();
}

In SetUp method just invoke AtataContext.Configure() method that returns AtataContextBuilder instance, then invoke configuration methods and finally invoke Build() method:

[SetUp]
public void SetUp()
{
    AtataContext.Configure().
        // TODO: Invoke configuration methods.
        Build();
}

To clean up the AtataContext do the following in the TearDown method:

[TearDown]
public void TearDown()
{
    AtataContext.Current.CleanUp();
}

It also closes web driver instance as well as a browser.

Driver

The list of driver creational methods of AtataContextBuilder:

public ChromeAtataContextBuilder

UseChrome()

Use the ChromeDriver.

public FirefoxAtataContextBuilder

UseFirefox()

Use the FirefoxDriver.

public InternetExplorerAtataContextBuilder

UseInternetExplorer()

Use the InternetExplorerDriver.

public EdgeAtataContextBuilder

UseEdge()

Use the EdgeDriver.

public SafariAtataContextBuilder

UseSafari()

Use the SafariDriver.

public OperaAtataContextBuilder

UseOpera()

Use the OperaDriver.

public RemoteDriverAtataContextBuilder

UseRemoteDriver()

Use the RemoteWebDriver.

public CustomDriverAtataContextBuilder

UseDriver(Func<RemoteWebDriver> driverFactory)

Use custom driver factory method.

public TDriverFactory

UseDriver<TDriverFactory>(TDriverFactory driverFactory)

Use the driver factory.

public AtataContextBuilder

UseDriver(string alias)

Sets the alias of the driver to use.

Driver Configuration

It is possible to configure the driver using the following methods:

public {DriverAtataContextBuilder}

WithArguments(params string[] arguments)

Adds arguments to be appended to the Chrome.exe/Opera.exe command line.

public {DriverAtataContextBuilder}

WithAlias(string alias)

Specifies the driver alias.

public {DriverAtataContextBuilder}

WithOptions(Func<{DriverOptions}> optionsCreator)

Specifies the driver options factory method.

public {DriverAtataContextBuilder}

WithOptions(Action<{DriverOptions}> optionsInitializer)

Specifies the driver options initialization method.

public {DriverAtataContextBuilder}

WithOptions(Dictionary<string, object> optionsPropertiesMap)

Specifies the properties map for the driver options.

public {DriverAtataContextBuilder}

WithCapability(string capabilityName, object capabilityValue)

Adds additional capability to the driver options.

public {DriverAtataContextBuilder}

WithDriverService(Func<{DriverService}> driverServiceCreator)

Specifies the driver service factory method.

public {DriverAtataContextBuilder}

WithDriverService(Action<{DriverService}> serviceInitializer)

Specifies the driver service initialization method.

public {DriverAtataContextBuilder}

WithDriverService(Dictionary<string, object> servicePropertiesMap)

Specifies the properties map for the driver service.

public {DriverAtataContextBuilder}

WithDriverPath(string driverPath)

Specifies the directory containing the driver executable file.

public {DriverAtataContextBuilder}

WithLocalDriverPath()

Specifies that local/current directory should be used as the directory containing the driver executable file. Uses AppDomain.CurrentDomain.BaseDirectory as driver folder path. This configuration option makes sense for .NET Core 2.0+ project that uses driver as a project package (hosted in the same build directory).

public {DriverAtataContextBuilder}

WithDriverExecutableFileName(string driverExecutableFileName)

Specifies the name of the driver executable file.

public {DriverAtataContextBuilder}

WithCommandTimeout(TimeSpan commandTimeout)

Specifies the command timeout (the maximum amount of time to wait for each command).

public {DriverAtataContextBuilder}

WithHostName(string hostName)

Specifies the host name of the service. The default value is localhost. This configuration option makes sense for .NET Core 2.0 to be set to 127.0.0.1 for IPv4 and [::1] for IPv6. There is a bug (https://github.com/dotnet/corefx/issues/24104) in .NET Core 2.0: each WebDriver request takes extra 1 second.

public {DriverAtataContextBuilder}

WithFixOfCommandExecutionDelay()

Specifies that the fix of driver’s HTTP command execution delay should be applied. Invokes WithHostName("127.0.0.1") method. This configuration option makes sense for .NET Core 2.0 that works within IPv4. There is a bug (https://github.com/dotnet/corefx/issues/24104) in .NET Core 2.0: each WebDriver request takes extra 1 second.

Usage

AtataContext.Configure().
    UseChrome().
        WithArguments("disable-extensions", "start-maximized", "disable-infobars").
    Build();

Logging

The list of logging methods of AtataContextBuilder:

public AtataContextBuilder<TLogConsumer>

AddLogConsumer<TLogConsumer>(TLogConsumer consumer)

where TLogConsumer : ILogConsumer

Adds the log consumer.

public AtataContextBuilder<ILogConsumer>

AddLogConsumer(string typeNameOrAlias)

Adds the log consumer. typeNameOrAlias can accept full type name, custom ILogConsumer alias (registered via LogConsumerAliases.Register method) or one of the predefined aliases: “trace”, “debug”, “console”, “nunit” and “nlog”.

public AtataContextBuilder<TraceLogConsumer>

AddTraceLogging()

Adds the TraceLogConsumer instance that uses System.Diagnostics.Trace class for logging.

public AtataContextBuilder<DebugLogConsumer>

AddDebugLogging()

Adds the DebugLogConsumer instance that uses System.Diagnostics.Debug class for logging.

public AtataContextBuilder<ConsoleLogConsumer>

AddConsoleLogging()

Adds the ConsoleLogConsumer instance that uses System.Console class for logging.

public AtataContextBuilder<NUnitTestContextLogConsumer>

AddNUnitTestContextLogging()

Adds the NUnitTestContextLogConsumer instance that uses NUnit.Framework.TestContext class for logging.

public AtataContextBuilder<NLogConsumer>

AddNLogLogging(string loggerName = null)

Adds the NLogConsumer instance that uses NLog.Logger class for logging.

Logging Configuration

The list of extension methods to configure ILogConsumer:

public AtataContextBuilder<TTLogConsumer>

WithoutSectionFinish<TTLogConsumer>()

Defines that the logging should not use section-like pair messages (not “Starting: {action}” and “Finished: {action} {time elapsed}”, but just “{action}”).

public AtataContextBuilder<TTLogConsumer>

WithMinLevel<TTLogConsumer>(LogLevel level)

Specifies the minimum level of the log event to write to the log. The default value is Trace.

Usage

AtataContext.Configure().
    UseChrome().
    UseNUnitTestContextLogging().
        WithoutSectionFinish().
        WithMinLevel(LogLevel.Info).
    UseDebugLogging().
        WithMinLevel(LogLevel.Debug).
    Build();

Screenshots

The list of screenshot taking methods of AtataContextBuilder:

public AtataContextBuilder<TScreenshotConsumer>

AddScreenshotConsumer<TScreenshotConsumer>(TScreenshotConsumer consumer)

where TScreenshotConsumer : IScreenshotConsumer

Adds the screenshot consumer. Is used for custom screenshot processing.

public AtataContextBuilder<IScreenshotConsumer>

AddScreenshotConsumer(string typeNameOrAlias)

Adds the screenshot consumer. typeNameOrAlias can accept full type name, custom IScreenshotConsumer alias (registered via ScreenshotConsumerAliases.Register method) or predefined “file” alias.

public AtataContextBuilder<FileScreenshotConsumer>

AddScreenshotFileSaving()

Adds the FileScreenshotConsumer instance for the screenshot saving to file.

File Screenshots Configuration

By default AddScreenshotFileSaving method configures FileScreenshotConsumer with the following settings:

  • Folder path: $@"Logs\{AtataContext.BuildStart:yyyy-MM-dd HH_mm_ss}\{AtataContext.Current.TestName}"
  • File name format: $"{screenshotInfo.Number:D2} - {screenshotInfo.PageObjectFullName}{screenshotInfo.Title?.Prepend(" - ")}"
  • Image format: Png.

The list of extension methods to configure FileScreenshotConsumer:

public AtataContextBuilder<FileScreenshotConsumer>

With(ScreenshotImageFormat imageFormat)

Specifies the image format of the file screenshot consumer.

public AtataContextBuilder<FileScreenshotConsumer>

WithFolderPath(Func<string> folderPathBuilder)

Specifies the folder path builder of the file screenshot consumer.

public AtataContextBuilder<FileScreenshotConsumer>

WithFileName(Func<ScreenshotInfo, string> fileNameBuilder)

Specifies the file name builder of the file screenshot consumer.

public AtataContextBuilder<FileScreenshotConsumer>

WithFilePath(Func<ScreenshotInfo, string> filePathBuilder)

Specifies the file path builder of the file screenshot consumer.

Usage

The below example configures FileScreenshotConsumer to use separate folder for each test:

AtataContext.Configure().
    // Do some initialization.
    AddScreenshotFileSaving().
        WithFolderPath(() => $@"Logs\{AtataContext.BuildStart:yyyy-MM-dd HH_mm_ss}\{AtataContext.Current.TestName}").
        WithFileName(screenshotInfo => $"{screenshotInfo.Number:D2} - {screenshotInfo.PageObjectFullName}{screenshotInfo.Title?.Prepend(" - ")}").
    Build();

If you need to take a screenshot only on test failure, you may configure FileScreenshotConsumer to save all screenshot files to the same folder:

AtataContext.Configure().
    // Do some initialization.
    TakeScreenshotOnNUnitError().
    AddScreenshotFileSaving().
        WithFolderPath(() => $@"Logs\{AtataContext.BuildStart:yyyy-MM-dd HH_mm_ss}").
        WithFileName(screenshotInfo => $"{AtataContext.Current.TestName} - {screenshotInfo.PageObjectFullName}").
    Build();

Other

public AtataContextBuilder

UseBaseUrl(string baseUrl)

Sets the base URL.

public AtataContextBuilder

UseCulture(CultureInfo culture)

Sets the culture. The default value is CultureInfo.CurrentCulture.

public AtataContextBuilder

UseCulture(string cultureName)

Sets the culture by the name. The default value is CultureInfo.CurrentCulture.

public AtataContextBuilder

UseTestName(string name)

Sets the name of the test.

public AtataContextBuilder

UseTestName(Func<string> testNameFactory)

Sets the factory method of the test name.

public AtataContextBuilder

UseNUnitTestName()

Defines that the name of the test should be taken from the NUnit test.

public AtataContextBuilder

UseBaseRetryTimeout(TimeSpan timeout)

Sets the base retry timeout. The default value is 5 seconds

public AtataContextBuilder

UseBaseRetryInterval(TimeSpan interval)

Sets the base retry interval. The default value is 500 milliseconds.

public AtataContextBuilder

UseElementFindTimeout(TimeSpan timeout)

Sets the element find timeout. The default value is taken from AtataBuildingContext.BaseRetryTimeout, which is equal to 5 seconds by default.

public AtataContextBuilder

UseElementFindRetryInterval(TimeSpan interval)

Sets the element find retry interval. The default value is taken from AtataBuildingContext.BaseRetryInterval, which is equal to 500 milliseconds by default.

public AtataContextBuilder

UseWaitingTimeout(TimeSpan timeout)

Sets the waiting timeout. The default value is taken from AtataBuildingContext.BaseRetryTimeout, which is equal to 5 seconds by default.

public AtataContextBuilder

UseWaitingRetryInterval(TimeSpan interval)

Sets the waiting retry interval. The default value is taken from AtataBuildingContext.BaseRetryInterval, which is equal to 500 milliseconds by default.

public AtataContextBuilder

UseVerificationTimeout(TimeSpan timeout)

Sets the verification timeout. The default value is taken from AtataBuildingContext.BaseRetryTimeout, which is equal to 5 seconds by default.

public AtataContextBuilder

UseVerificationRetryInterval(TimeSpan interval)

Sets the verification retry interval. The default value is taken from AtataBuildingContext.BaseRetryInterval, which is equal to 500 milliseconds by default.

public AtataContextBuilder

OnBuilding(Action action)

Adds the action to perform during AtataContext building. It will be executed at the beginning of the build after the log is set up.

public AtataContextBuilder

OnBuilt(Action action)

Adds the action to perform after AtataContext building. It will be executed at the end of the build after the driver is created.

public AtataContextBuilder

OnDriverCreated(Action<RemoteWebDriver> action)

Adds the action to perform after the driver is created.

public AtataContextBuilder

OnDriverCreated(Action action)

Adds the action to perform after the driver is created.

public AtataContextBuilder

OnCleanUp(Action action)

Adds the action to perform during AtataContext cleanup.

public AtataContextBuilder

LogNUnitError()

Defines that an error occurred during the NUnit test execution should be added to the log during the cleanup.

public AtataContextBuilder

TakeScreenshotOnNUnitError(string title = "Failed")

Defines that an error occurred during the NUnit test execution should be captured by a screenshot during the cleanup.

public AtataContextBuilder

UseAssertionExceptionType(Type exceptionType)

Sets the type of the assertion exception. The default value is typeof(Atata.AssertionException).

public AtataContextBuilder

UseAssertionExceptionType<TException>()

Sets the type of the assertion exception. The default value is typeof(Atata.AssertionException).

public AtataContextBuilder

Clear()

Clears the BuildingContext.

public AtataContext

Build()

Builds the AtataContext instance and sets it to AtataContext.Current property.

Go

The page object navigation starts with Go static class. It provides a set of static methods for navigation.

Methods

public static T

To<T>(T pageObject = null, string url = null, bool navigate = true, bool temporarily = false)

where T : PageObject<T>

Navigates to the specified page object.

public static T

ToWindow<T>(T pageObject, string windowName, bool temporarily = false)

where T : PageObject<T>

Navigates to the window with the specified page object by name.

public static T

ToWindow<T>(string windowName, bool temporarily = false)

where T : PageObject<T>

Navigates to the window by name.

public static T

ToNextWindow<T>(T pageObject = null, bool temporarily = false)

where T : PageObject<T>

Navigates to the next window with the specified page object.

public static T

ToPreviousWindow<T>(T pageObject = null, bool temporarily = false)

where T : PageObject<T>

Navigates to the previous window with the specified page object.

public static void

ToUrl(string url)

Navigates to the specified URL.

Usage

Go.To<HomePage>().
    Header.Should.Equal("Home");

Go.To<AboutPage>(url: "about").
    Header.Should.Equal("About");

Transition

The transition from one page object to another is implemented via controls: Button, Link and Clickable. Also the transition can be specified via adding INavigable<,> interface to the custom control.

Example

For example, having 3 simple pages on the site:

  • Users” page with users table and “New” link that navigates to the user editor page. Clicking on the user row redirects to the “User Details” page.
  • User Editor” page that contains “Name” input field, “Save” and “Cancel” buttons that redirect back to “Users” page.
  • User Details” page containing the name of the user.

UsersPage.cs

using Atata;

namespace SampleApp.UITests
{
    using _ = UsersPage;

    [Url("users")]
    public class UsersPage : Page<_>
    {
        public Link<UserEditorPage, _> New { get; private set; }

        public Table<UserTableRow, _> Users { get; private set; }

        public class UserTableRow : TableRow<_>, INavigable<UserDetailsPage, _>
        {
            public Text<_> Name { get; private set; }
        }
    }
}

UserEditorPage.cs

using Atata;

namespace SampleApp.UITests
{
    using _ = UserEditorPage;

    public class UserEditorPage : Page<_>
    {
        public TextInput<_> Name { get; private set; }

        public Button<UsersPage, _> Save { get; private set; }

        public Button<UsersPage, _> Cancel { get; private set; }
    }
}

UserDetailsPage.cs

using Atata;

namespace SampleApp.UITests
{
    using _ = UserDetailsPage;

    public class UserDetailsPage : Page<_>
    {
        public H1<_> Name { get; private set; }
    }
}

Usage

string userName;

Go.To<UsersPage>().
    New.ClickAndGo(). // Navigates to UserEditorPage.
        Name.SetRandom(out userName). // Sets the random value to Name field and stores it to userName variable.
        Save.ClickAndGo(). // Clicking the Save button navigates back to UsersPage.
    Users.Rows[x => x.Name == userName].ClickAndGo(). // Clicking the row navigates to UserDetailsPage.
        Name.Should.Equal(userName);