Skip to content

Commit c3b8275

Browse files
authored
Merge pull request #98 from quantori/BAP-98-create-project-template-for-behaviour.automation
Bap 98 create project template for behaviour.automation
2 parents c6aa24d + 777d6af commit c3b8275

File tree

16 files changed

+479
-0
lines changed

16 files changed

+479
-0
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"$schema": "http://json.schemastore.org/template",
3+
"author": "Quantori LLC",
4+
"classifications": [
5+
"BDD",
6+
"Automation"
7+
],
8+
"identity": "BDDTemplate",
9+
"name": "Template for Behavioral Automation Framework",
10+
"sourceName": "Behavioral.Automation.Template",
11+
"shortName": "bddautomation",
12+
"tags": {
13+
"language": "C#",
14+
"type": "project"
15+
},
16+
"sources": [
17+
{
18+
"modifiers": [
19+
{
20+
"exclude": [ ".vs/**", "**/**.feature.cs", "**.nuspec" ]
21+
}
22+
]
23+
}
24+
]
25+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"BASE_URL": "http://localhost:4200/",
3+
"TEST_EMAIL": "",
4+
"TEST_PASSWORD": "",
5+
"BASE_AUTH_URL": "",
6+
"BROWSER_PARAMS": "--window-size=1920,1080",
7+
"ACCESS_CLIPBOARD": false,
8+
"DOWNLOAD_PATH": "",
9+
"SEARCH_ATTRIBUTE": "id",
10+
"BAUTH_LOGIN": "",
11+
"BAUTH_PWD": "",
12+
"BAUTH_IGNORE": "true",
13+
"BROWSER_BINARY_LOCATION" : ""
14+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net6.0</TargetFramework>
5+
<IsPackable>false</IsPackable>
6+
<Authors>Quantori Inc.</Authors>
7+
<Description>Demo project that can be used as example of test configuration.</Description>
8+
<RepositoryUrl>https://github.com/quantori/Behavioral.Automation</RepositoryUrl>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="Behavioral.Automation" Version="1.8.0" />
13+
</ItemGroup>
14+
15+
<ItemGroup>
16+
<None Update="AutomationConfig.json">
17+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
18+
</None>
19+
</ItemGroup>
20+
21+
</Project>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using Behavioral.Automation.Services;
2+
using Behavioral.Automation.Services.Mapping.Contract;
3+
4+
namespace Behavioral.Automation.Template.Bindings.ElementStorage
5+
{
6+
public class UserInterfaceBuilder : UserInterfaceBuilderBase
7+
{
8+
public UserInterfaceBuilder(IScopeMarkupMapper mapper)
9+
: base(mapper)
10+
{
11+
12+
}
13+
14+
public override void Build()
15+
{
16+
using (var mappingPipe = Mapper.GetGlobalMappingPipe())
17+
{
18+
mappingPipe.Register("input").Alias("input")
19+
.With("searchInput").As("Search");
20+
21+
mappingPipe.Register("input").Alias("button")
22+
.With("searchButton").As("Magnifying glass");
23+
24+
mappingPipe.Register("h1")
25+
.With("firstHeading").As("Page header");
26+
}
27+
}
28+
}
29+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
using Behavioral.Automation.Elements;
3+
using Behavioral.Automation.FluentAssertions;
4+
using Behavioral.Automation.Model;
5+
using Behavioral.Automation.Services;
6+
using OpenQA.Selenium;
7+
8+
namespace Behavioral.Automation.Template.Bindings.ElementWrappers
9+
{
10+
public sealed class TextElementWrapper : WebElementWrapper, ITextElementWrapper
11+
{
12+
public TextElementWrapper([NotNull] IWebElementWrapper wrapper, string caption, [NotNull] IDriverService driverService)
13+
: base(() => wrapper.Element, caption, driverService) { }
14+
15+
public void EnterString(string input)
16+
{
17+
Assert.ShouldBecome(() => Enabled, true,
18+
new AssertionBehavior(AssertionType.Continuous, false),
19+
$"{Caption} is not enabled");
20+
Element.SendKeys(input);
21+
Driver.RemoveFocusFromActiveElement();
22+
}
23+
24+
public void ClearInput()
25+
{
26+
Assert.ShouldBecome(() => Enabled, true,
27+
new AssertionBehavior(AssertionType.Continuous, false),
28+
$"{Caption} is not enabled");
29+
30+
while (Element.GetAttribute("value").Length > 0)
31+
{
32+
Element.SendKeys(Keys.Backspace);
33+
}
34+
Driver.RemoveFocusFromActiveElement();
35+
}
36+
}
37+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
using Behavioral.Automation.Elements;
2+
using Behavioral.Automation.FluentAssertions;
3+
using Behavioral.Automation.Services;
4+
using OpenQA.Selenium;
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Diagnostics.CodeAnalysis;
8+
9+
namespace Behavioral.Automation.Template.Bindings.ElementWrappers
10+
{
11+
public class WebElementWrapper : IWebElementWrapper
12+
{
13+
private readonly Func<IWebElement> _elementSelector;
14+
private readonly IDriverService _driverService;
15+
16+
public WebElementWrapper([NotNull] Func<IWebElement> elementSelector, [NotNull] string caption, [NotNull] IDriverService driverService)
17+
{
18+
_elementSelector = elementSelector;
19+
_driverService = driverService;
20+
Caption = caption;
21+
}
22+
23+
public string Caption { get; }
24+
25+
public IWebElement Element => _elementSelector();
26+
27+
public string Text => Element.Text;
28+
29+
public string GetAttribute(string attribute) => Element.GetAttribute(attribute);
30+
31+
public void Click()
32+
{
33+
MouseHover();
34+
Assert.ShouldGet(() => Enabled);
35+
_driverService.MouseClick();
36+
}
37+
38+
public void MouseHover()
39+
{
40+
Assert.ShouldBecome(() => Enabled, true, $"{Caption} is disabled");
41+
_driverService.ScrollTo(Element);
42+
}
43+
44+
public void SendKeys(string text)
45+
{
46+
Assert.ShouldBecome(() => Enabled, true, $"{Caption} is disabled");
47+
Element.SendKeys(text);
48+
}
49+
50+
public bool Displayed => Element != null && Element.Displayed;
51+
52+
public bool Enabled => Displayed && Element.Enabled && AriaEnabled;
53+
54+
public string Tooltip
55+
{
56+
get
57+
{
58+
var matTooltip = GetAttribute("matTooltip");
59+
if (matTooltip != null)
60+
{
61+
return matTooltip;
62+
}
63+
var ngReflectTip = GetAttribute("ng-reflect-message"); //some elements have their tooltips' texts stored inside 'ng-reflect-message' attribute
64+
if (ngReflectTip != null)
65+
{
66+
return ngReflectTip;
67+
}
68+
69+
return GetAttribute("aria-label"); //some elements have their tooltips' texts stored inside 'aria-label' attribute
70+
}
71+
}
72+
73+
public bool Stale
74+
{
75+
get
76+
{
77+
try
78+
{
79+
// Calling any method forces a staleness check
80+
var elementEnabled = Element.Enabled;
81+
return false;
82+
}
83+
catch (StaleElementReferenceException)
84+
{
85+
return true;
86+
}
87+
}
88+
}
89+
90+
public IEnumerable<IWebElementWrapper> FindSubElements(By locator, string caption)
91+
{
92+
var elements = Assert.ShouldGet(() => Element.FindElements(locator));
93+
return ElementsToWrappers(elements, caption);
94+
}
95+
96+
private IEnumerable<IWebElementWrapper> ElementsToWrappers(IEnumerable<IWebElement> elements, string caption)
97+
{
98+
foreach (var element in elements)
99+
{
100+
var wrapper = new WebElementWrapper(() => element, caption, _driverService);
101+
yield return wrapper;
102+
}
103+
}
104+
105+
protected IDriverService Driver => _driverService;
106+
107+
private bool AriaEnabled
108+
{
109+
get
110+
{
111+
switch (Element.GetAttribute("aria-disabled"))
112+
{
113+
case null:
114+
case "false":
115+
return true;
116+
}
117+
118+
return false;
119+
}
120+
}
121+
}
122+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using Behavioral.Automation.FluentAssertions;
2+
using Behavioral.Automation.Services;
3+
using Behavioral.Automation.Template.Bindings.ElementStorage;
4+
using BoDi;
5+
using TechTalk.SpecFlow;
6+
using Behavioral.Automation;
7+
using Behavioral.Automation.Template.Bindings.Services;
8+
9+
namespace Behavioral.Automation.Template.Bindings.Hooks
10+
{
11+
[Binding]
12+
public class Bootstrapper
13+
{
14+
private readonly IObjectContainer _objectContainer;
15+
private readonly ITestRunner _runner;
16+
private readonly DemoTestServicesBuilder _servicesBuilder;
17+
private readonly BrowserRunner _browserRunner;
18+
19+
public Bootstrapper(IObjectContainer objectContainer, ITestRunner runner, BrowserRunner browserRunner)
20+
{
21+
_objectContainer = objectContainer;
22+
_runner = runner;
23+
_browserRunner = browserRunner;
24+
_servicesBuilder = new DemoTestServicesBuilder(objectContainer, new TestServicesBuilder(_objectContainer));
25+
}
26+
27+
[AfterScenario]
28+
public void CloseBrowser()
29+
{
30+
_browserRunner.CloseBrowser();
31+
}
32+
33+
[BeforeScenario(Order = 0)]
34+
public void Bootstrap()
35+
{
36+
Assert.SetRunner(_runner);
37+
_objectContainer.RegisterTypeAs<UserInterfaceBuilder, IUserInterfaceBuilder>();
38+
_servicesBuilder.Build();
39+
_browserRunner.OpenChrome();
40+
}
41+
}
42+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using BoDi;
2+
using Behavioral.Automation;
3+
4+
namespace Behavioral.Automation.Template.Bindings.Services
5+
{
6+
internal class DemoTestServicesBuilder
7+
{
8+
private readonly IObjectContainer _objectContainer;
9+
private readonly TestServicesBuilder _servicesBuilder;
10+
11+
internal DemoTestServicesBuilder(IObjectContainer objectContainer, TestServicesBuilder servicesBuilder)
12+
{
13+
_objectContainer = objectContainer;
14+
_servicesBuilder = servicesBuilder;
15+
}
16+
17+
internal void Build()
18+
{
19+
_servicesBuilder.Build();
20+
}
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using Behavioral.Automation.Template.Bindings.ElementWrappers;
2+
using Behavioral.Automation.Elements;
3+
using Behavioral.Automation.Services;
4+
using JetBrains.Annotations;
5+
using TechTalk.SpecFlow;
6+
7+
namespace Behavioral.Automation.Template.Bindings.StepArgumentTransformations
8+
{
9+
[Binding]
10+
class ElementTransformations
11+
{
12+
private readonly IDriverService _driverService;
13+
private readonly IElementSelectionService _selectionService;
14+
15+
public ElementTransformations(
16+
[NotNull] IDriverService driverService,
17+
[NotNull] IElementSelectionService selectionService)
18+
{
19+
_driverService = driverService;
20+
_selectionService = selectionService;
21+
}
22+
23+
[StepArgumentTransformation]
24+
public IWebElementWrapper FindElement([NotNull] string caption)
25+
{
26+
return new WebElementWrapper(() => _selectionService.Find(caption),
27+
caption,
28+
_driverService);
29+
}
30+
31+
[StepArgumentTransformation("(.*)")]
32+
public ITextElementWrapper FindTextElement([NotNull] IWebElementWrapper element)
33+
{
34+
return new TextElementWrapper(element, element.Caption, _driverService);
35+
}
36+
}
37+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net6.0</TargetFramework>
5+
<Authors>Quantori Inc.</Authors>
6+
<Description>Specflow scenarios for demonstration of Behavioral.Automation framework features and testing.</Description>
7+
<Copyright>Quantori Inc.</Copyright>
8+
<RepositoryUrl>https://github.com/quantori/Behavioral.Automation</RepositoryUrl>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
13+
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="96.0.4664.4500" />
14+
<PackageReference Include="SpecFlow" Version="3.9.40" />
15+
<PackageReference Include="SpecFlow.NUnit" Version="3.9.40" />
16+
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
17+
</ItemGroup>
18+
19+
<ItemGroup>
20+
<None Update="specflow.json">
21+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
22+
</None>
23+
</ItemGroup>
24+
25+
<ItemGroup>
26+
<ProjectReference Include="..\Behavioral.Automation.Template.Bindings\Behavioral.Automation.Template.Bindings.csproj" />
27+
</ItemGroup>
28+
29+
</Project>

0 commit comments

Comments
 (0)