<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: CTO UK - West Midlands</title>
    <description>The latest articles on DEV Community by CTO UK - West Midlands (ctowestmidlands).</description>
    <link>https://dev.to/ctowestmidlands</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F3820%2F8b5935c0-9fbc-401f-a219-42517c32a16b.png</url>
      <title>DEV Community: CTO UK - West Midlands</title>
      <link>https://dev.to/ctowestmidlands</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ctowestmidlands"/>
    <language>en</language>
    <item>
      <title>Why product development is the beautiful game</title>
      <dc:creator>rich_marshall</dc:creator>
      <pubDate>Fri, 21 May 2021 08:15:21 +0000</pubDate>
      <link>https://dev.to/ctowestmidlands/why-product-development-is-the-beautiful-game-30p8</link>
      <guid>https://dev.to/ctowestmidlands/why-product-development-is-the-beautiful-game-30p8</guid>
      <description>&lt;p&gt;Building Teams&lt;/p&gt;

&lt;p&gt;Firstly, I need to apologise to any football fans out there. I’m the first to admit I don’t follow the “Beautiful Game” but I keep turning back to it as a useful example. I could use many other team sports as a comparison instead but football seems to be the most universal. &lt;/p&gt;

&lt;p&gt;One of the greatest challenges and in all honesty, frustrations, I’ve experienced over the past years is the treatment of highly skilled, talented, creative people as “resources”. I can’t begin to count the number of times a financial director or project manager has asked, suggested or requested “resources to be re-assigned, so a project goes faster”. &lt;/p&gt;

&lt;p&gt;So much of this thinking dates back to the emergence of heavy-duty industrial and civil engineering projects where dockworkers would line up for selection in the morning and the one’s who could set the most rivets would be chosen that day. There is an increasing body of evidence and library of resources that demonstrate that building software products, especially those delivered in through a SaaS model, needs to be planed and managed very differently - I won’t go into the details of that here, but if you’re interested I can’t recommend &lt;a href="https://soonersaferhappier.com/"&gt;Sooner, Safer, Happier&lt;/a&gt; enough.&lt;/p&gt;

&lt;p&gt;It was during one of these many discussion that I was searching for a way to describe what they were requesting and a football team came to mind. &lt;/p&gt;

&lt;p&gt;You’ll have to bear with me, because as I said, I don’t follow football but I know for a fact there have been many examples of where “super teams” have failed. It doesn’t matter if you put the worlds 11 best players in the same team; you’re not guaranteed success. More likely you’ll get 11 individuals, all of whom want to prove they’re the best. &lt;/p&gt;

&lt;p&gt;The role of the manager is well understood in football, as is that of coach and captain. In fact all these roles are recognised as being vital to the success of a team and yet in software development, (from the outside, at least) these roles are often absent or seriously undervalued. &lt;/p&gt;

&lt;p&gt;It’s also true to say that you can’t simply move a player from another team and expect instant success. Teams are carefully selected from squads and each player within that team is selected for the role they need to play and hw their skills and talents benefit the team. Managers will also pay attention to how any player’s deficits might affects others - people always have both good and bad traits.&lt;/p&gt;

&lt;p&gt;I should all emphasise the value of cross-functional teams over silos squads of developers. Teams need to have all the skills in them, in order to be successful and you’re unlikely to find all of those skills in one person. For a football team to be successful, you need strikers, midfield, defenders and goal keepers - not to mention the coach, captain and manager roles. Product development teams are the same. 11 software developers is not going to solve the problem. You need product managers, designers, and often other subject matter experts in there too. Yes, you can get them on loan in the same way you can bring a substitute on to the pitch, but they still need to be part of the squad and know the team inside out. &lt;/p&gt;

&lt;p&gt;I’m pretty happy with this analogy so far but how much can I push it…!? The rules of football dictate 11 people on the pitch from one team. So you can’t just keep adding more people to win. Product development teams don’;t have the same rules applied  - at least officially, but there is significant evidence (start with Dunbar’s number and go from there) that there &lt;em&gt;is&lt;/em&gt; a practical upper limit to the size of a high performing team and adding more people doesn’t improve performance but often makes things worse. If you tried putting 100 players on the pitch everyone would trip over each other!  There’s also a lot to be said about how a team actually work together. It’s still common practice to attend a standup and hear from each individual what they were working on and their progress, their blockers. It’s routine to see a team have each developer working on a different problem and then request support from their peers, who are in a different context. Some might see this is giving a football team a ball each - more opportunity to score a goal! But that’s far from the actual outcome. It also increases the likelihood of an own goal and who are you going to pass to when you get tackled. In fact, it’s not even like that! It’s more akin to expecting each individual player to be on a different pitch, playing a different game and we all know how that’s going to work out. &lt;/p&gt;

&lt;p&gt;I’m pleased to say there is a growing body of evidence to shift thinking but it’s high time that we and our peers stop thinking of software engineers as being heavy engineering. That we stop using methods and languages that describe what we produce as projects like railway lines, with the idea that it’s finished when it reaches it’s destination and we can leave it for the next 100 years and most importantly, that we stop treating people with thoughts, ideas and passion as faceless resources, to be dragged and dropped at will where ever there’s a problem of a task to be completed. &lt;/p&gt;

&lt;p&gt;Instead we need to think of our products and services as more akin to the service that runs on the railways and or teams as complex, ever evolving people who need support, coaching and management to work most effectively. &lt;/p&gt;

&lt;p&gt;Sure, you can keep moving players from one team to the next or put a midfielder in goal or even send every player to have a different game but you’re not going to win the cup or the league that way and you’re probably going to get relegated pretty quickly if you try it. &lt;/p&gt;

&lt;p&gt;Header image courtesy &lt;a href=""&gt;Chris Leipelt&lt;/a&gt;&lt;/p&gt;

</description>
      <category>team</category>
    </item>
    <item>
      <title>Why you shouldn't hire clones. </title>
      <dc:creator>Adam Farrell</dc:creator>
      <pubDate>Fri, 23 Apr 2021 08:38:51 +0000</pubDate>
      <link>https://dev.to/ctowestmidlands/why-you-shouldn-t-hire-clones-343e</link>
      <guid>https://dev.to/ctowestmidlands/why-you-shouldn-t-hire-clones-343e</guid>
      <description>&lt;p&gt;We have all been there. One of your best employees hands their notice in and your stomach does a little flip as you know how important they are.&lt;/p&gt;

&lt;p&gt;You try your best to see if you can do anything to keep them but they explain this is an opportunity they can't turn down. So your attention turns to trying to find someone to replace them.&lt;/p&gt;

&lt;p&gt;You tell your recruiter we need another "Sarah"! You want someone with the exact same skills so they can come in and "hit the ground running".&lt;/p&gt;

&lt;p&gt;Is this the right approach?&lt;/p&gt;

&lt;p&gt;Pause for a moment and ask yourself why would someone move roles to do the exact same job they are doing now?&lt;/p&gt;

&lt;p&gt;Of course, this does happen sometimes, for example, if someone has been made redundant.&lt;/p&gt;

&lt;p&gt;If you did hire that person how long will it take for them to get bored doing the same thing they have done for the last 3 years? Probably not long. This will likely mean after spending 1 year to 18 months with you they start looking for something more challenging and will provide better progression opportunities.&lt;/p&gt;

&lt;p&gt;Then you are left in the same place as they were before, looking to hire someone doing the exact same job because you need them to "hit the ground running". And so the cycle continues.&lt;/p&gt;

&lt;p&gt;Still, the biggest reason I hear for people looking to move roles is so they can learn and develop. If you can't provide that to a candidate then it will cause more pain further down the line.&lt;/p&gt;

&lt;p&gt;So rather than going for a like for like replacement consider if hiring someone who perhaps doesn't have all the skills just yet but has the potential, ambition and correct attitude to attain them. If someone has something to work towards or aim for my experience is that they are far more motivated in the position.&lt;/p&gt;

&lt;p&gt;Yes, this will mean a bit more time is needed on your part but that initial investment will usually lead to a brilliant new employee. I have seen it many times where people in this scenario have gone on to be a brilliant contributor to the business and they have more loyalty and appreciation for the business as they have profited as well.&lt;/p&gt;

&lt;p&gt;So, don't just mindlessly look for clones of your previous employees.&lt;br&gt;
Look at your current roles and expectations. Are they realistic? Hire for potential.&lt;/p&gt;

</description>
      <category>hiring</category>
      <category>leadership</category>
      <category>motivation</category>
      <category>skills</category>
    </item>
    <item>
      <title>Load testing with Atata and Selenoid (Part 1)</title>
      <dc:creator>danieltallentire</dc:creator>
      <pubDate>Thu, 15 Apr 2021 22:12:04 +0000</pubDate>
      <link>https://dev.to/ctowestmidlands/load-testing-with-atata-and-selenoid-part-1-35a5</link>
      <guid>https://dev.to/ctowestmidlands/load-testing-with-atata-and-selenoid-part-1-35a5</guid>
      <description>&lt;p&gt;I'm Technical Director at &lt;a href="https://www.parkersoftware.com"&gt;Parker Software&lt;/a&gt;, a company with a long history of making market-leading &lt;a href="https://www.whoson.com"&gt;live chat&lt;/a&gt; software and &lt;a href="https://www.thinkautomation.com"&gt;automation components&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'm writing this article as part of CTO West Midlands writing group.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://atata.io"&gt;Atata&lt;/a&gt; is a great open source project created by &lt;a class="mentioned-user" href="https://dev.to/yevgeniyshunevych"&gt;@yevgeniyshunevych&lt;/a&gt; &lt;/p&gt;

&lt;h1&gt;
  
  
  Contents
&lt;/h1&gt;

&lt;p&gt;What are we doing&lt;br&gt;
Why Atata?&lt;br&gt;
The Solution&lt;/p&gt;
&lt;h1&gt;
  
  
  What is load testing normally like for WhosOn?
&lt;/h1&gt;

&lt;p&gt;Normally, we run our load tests in WhosOn using our APIs.  This allows us to simulate the volume of requests coming in to the WhosOn server, but with a cheap and easy setup.&lt;br&gt;
These are normally load tests like "1,000 concurrent chats" or "500 connected operators".&lt;/p&gt;
&lt;h2&gt;
  
  
  What is wrong with doing this?
&lt;/h2&gt;

&lt;p&gt;We've recently come across some instances where load has caused a problem, but not to do with the overall capacity. The problem has been caused by behaviours of customers and operators that cause spikes.  These spikes may cause an overload in a single component of the system, or a cascade through the system.&lt;br&gt;
The spike behaviour might not be simple - it may have multiple factors.&lt;/p&gt;

&lt;p&gt;If your load test is too simple it doesn't capture the real world behaviour of the operators.&lt;/p&gt;
&lt;h2&gt;
  
  
  What behaviour do we want to replicate?
&lt;/h2&gt;

&lt;p&gt;We would like to create a load test that can simulate a shift change using our operator web client.  During shift change, a backlog of queuing chats will build up - this could reach 100 chats in the queue, and as the new shift comes on board, logging in 50-100 users within a minute, those chats are then allocated out to the new operators. During this period, supervisors are also executing a variety of real time reports and pulling metrics against operators who are finishing up their shift, and monitoring the queue lengths to make sure that the active customers get serviced promptly.&lt;/p&gt;
&lt;h1&gt;
  
  
  Why Atata and not one of the regular load test systems like JMeter?
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;We already use Atata within our testing pipelines. Our devs are familiar with it.&lt;/li&gt;
&lt;li&gt;It allows us to easily vary our load tests, and select tests for different scenarios by altering our coded tests.&lt;/li&gt;
&lt;li&gt;It lets us execute tests in a variety of different browsers.&lt;/li&gt;
&lt;li&gt;We can record screenshots or video the results if we want to see what the experience is like.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  The solution
&lt;/h1&gt;

&lt;p&gt;As part of our Azure DevOps process, we will create a test suite that can be executed for every release.&lt;br&gt;
This will run a two stage process.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;test the overall chat system with pick up by a bot.&lt;/li&gt;
&lt;li&gt;test the client login system, with pick up by a UI automated chat agent.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We will use Selenoid to run a cluster of selenium instances in docker containers.  This could be swapped out for any selenium cluster.&lt;/p&gt;

&lt;p&gt;An XUnit test will drive the overall process, and a threshold will be set on various metrics to show whether that test was successful or not.&lt;/p&gt;

&lt;p&gt;The test will also output a test file reporting on key metrics from the cluster, including how long the chats took to be handled, end-to-end message time and similar.&lt;/p&gt;
&lt;h1&gt;
  
  
  The code
&lt;/h1&gt;

&lt;p&gt;I already started an earlier attempt at creating an Atata load test tool a few weeks ago. This was just using a basic set of browser on my box, but I ran into a lot of problems.&lt;/p&gt;

&lt;p&gt;Firstly, it killed my computer, trying to pop open new browser windows, and second, it wouldn't be easy to transfer this into the DevOps pipeline.&lt;/p&gt;
&lt;h3&gt;
  
  
  Setting up Selenoid
&lt;/h3&gt;

&lt;p&gt;I'm running on windows, so a few hoops to jump through to get Selenoid up and running:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;update docker&lt;/li&gt;
&lt;li&gt;change docker to use linux mode 
&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ub4bmzmsa4v67x83cw3.png" alt="image" width="300" height="362"&gt;
&lt;/li&gt;
&lt;li&gt;force docker to use the correct linux context and permissions
&lt;code&gt;&amp;amp; 'C:\Program Files\Docker\Docker\DockerCli.exe' -SwitchDaemon&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;download the correct version of the selenoid configuration manager from &lt;a href="https://github.com/aerokube/cm/releases"&gt;https://github.com/aerokube/cm/releases&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;./cm.exe selenoid start&lt;/code&gt; to start up selenoid&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;./cm.exe selenoid-ui start&lt;/code&gt; to start up the UI so I can see what's happening&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now we have selenoid running, we can open up the selenoid UI on localhost:8080 and see what the connection details are for selenoid:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmxc6nq64ruqgsbpegfh3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmxc6nq64ruqgsbpegfh3.png" alt="image" width="800" height="122"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Building a global context
&lt;/h3&gt;

&lt;p&gt;Based on this, and the Atata documentation, I created a global context driver implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;capabilities&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DesiredCapabilities&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetCapability&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CapabilityType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BrowserName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"chrome"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetCapability&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CapabilityType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BrowserVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"89.0"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RemoteWebDriver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://localhost:4444/wd/hub"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;AtataContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GlobalConfiguration&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseDriver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating a runner class
&lt;/h3&gt;

&lt;p&gt;Since I need to run multiple Atata instances, I don't want to launch Atata as normal from a test - I need to create some tasks that can run Atata within them and maintain a separate context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;AtataContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModeOfCurrent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AtataContextModeOfCurrent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AsyncLocal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This line of code instructs Atata to ensure that each asynchronous code block has its own instance of the Atata context.&lt;/p&gt;

&lt;h4&gt;
  
  
  Building the context
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;CreateContext&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;contextBuilder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AtataContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Configure&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;_context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;contextBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;SetupContext&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;CreateContext&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;finishTime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates the individual context for each LoadTestRunner&lt;/p&gt;

&lt;h4&gt;
  
  
  Running the test
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;AtataContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;chatPage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Go&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;To&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Survey&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"http://192.168.1.70/newchat/chat.aspx?domain=www.test.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VisitorName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetRandom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartChat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClickAndGo&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Chatting&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsCancellationRequested&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;finishTime&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;chatPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CloseWindowButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

                &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;chatPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChatReply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetRandom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SendButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This does a really simple start chat function, with only filling in the name field, sending a message every ten seconds, and closing after two minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Time to try it out
&lt;/h2&gt;

&lt;p&gt;I gave it a run, with a single session executing.&lt;br&gt;
Success! It created a session in selenoid, and completed the test successfully - I got a chat popping up.&lt;/p&gt;

&lt;p&gt;OK - time to up it to five sessions.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;FAIL&lt;/em&gt; it only launched one session, and I got a ton of errors.&lt;/p&gt;
&lt;h3&gt;
  
  
  What went wrong?
&lt;/h3&gt;

&lt;p&gt;Digging in to the debugging, I found that it is only launching one instance of the driver, not multiple as expected.&lt;/p&gt;

&lt;p&gt;I changed the global code to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;capabilities&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DesiredCapabilities&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetCapability&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CapabilityType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BrowserName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"chrome"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetCapability&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CapabilityType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BrowserVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"89.0"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;AtataContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GlobalConfiguration&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseDriver&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RemoteWebDriver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://localhost:4444/wd/hub"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This now lets me launch 5 simultaneous sessions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can it go further?
&lt;/h2&gt;

&lt;p&gt;I played around with parameters to reduce the memory and CPU usage, but the most I got working was 10 sessions - this partly seems to be to do with my IIS as well - something internally is preventing the sessions from connecting.  Indeed, during the test my box prevented a manual chat session request from loading. My cpu was maxed out, and the memory usage was very high.  This should work better in the cloud.&lt;/p&gt;

&lt;p&gt;This is the selenoid setting I used to create a new instance with limited CPU and memory usage:&lt;br&gt;
&lt;code&gt;./cm.exe selenoid start --vnc --tmpfs 248m -g "-limit 20 -mem 128 -cpu 1.0"&lt;/code&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What is next?
&lt;/h1&gt;

&lt;p&gt;For Part 2, I'm going to explore moving this into our Azure DevOps Pipeline.&lt;/p&gt;

&lt;p&gt;I need to optimise the memory usage further as well to ensure we can use more of these instances for a quick burst of testing.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>automation</category>
      <category>docker</category>
    </item>
    <item>
      <title>Burnout Timeline</title>
      <dc:creator>rich_marshall</dc:creator>
      <pubDate>Wed, 07 Apr 2021 19:32:01 +0000</pubDate>
      <link>https://dev.to/ctowestmidlands/burnout-timeline-18le</link>
      <guid>https://dev.to/ctowestmidlands/burnout-timeline-18le</guid>
      <description>&lt;p&gt;Forgive me.. I have two threads of thought concurrently running through my head. They do join up but bear with me.. &lt;/p&gt;

&lt;p&gt;A little while back I started to write a post about feeling exhausted, tired, uninspired, possibly even burnt out. It was the day after I'd resigned. Over the previous months I'd become depressed, emotional and generally fed up. Work held no interest for me and I needed to rekindle my enjoyment of life. &lt;/p&gt;

&lt;p&gt;The day I wrote the post I came to the conclusion that I was burnt-out. Work had been emotionally draining for months on end. The company was running out of money and it was becoming unclear if we'd even be able to pay the next month salary. At the same time I was expected to push the teams to deliver promises made to customers because it was our only revenue stream. On reflection, I don't think it was what is more widely recognised as burn-out but that day I felt a weight lifting from my shoulders and for the first time in months I genuinely felt &lt;em&gt;happy&lt;/em&gt;....&lt;/p&gt;

&lt;p&gt;Over the past few years I've been acting as a mentor for a very inspiring young gent who seems to have boundless energy. For the sake of this story, we'll call him Dave. Dave had got in touch with me through a bootcamp called School of Code who we both support. He was helping to teach the current cohort and I was helping with some longer term career guidance for the new recruits. When Dave got in touch he asked if I'd be his mentor. I was of course flattered but said at the outset I didn't know what I could do to help but was happy to try, if he was willing. &lt;/p&gt;

&lt;p&gt;Our mentor/mentee arrangement seemed to work OK - I'd been given some instructions by someone I'd consider my mentor, though we'd never entered into a formal arrangement, on how we should engage. Above all else, she told me that a mentee should be trying to achieve something and a mentor is there to help guide them to their goal. &lt;/p&gt;

&lt;p&gt;Having agreed to a clear objective with Dave and how I could help reach that, we agreed to meet, or at least talk every few months. A few meetings in we were talking about how he was starting to feel worn out, but more concerning how he was doubting himself. I asked what he was doing that was leading to this feeling. Apart from his day job as a developer, he was also working on a side project, and also teaching a day each week at School of Code. He was also keen to shift into a more product oriented role. Wow... So I was just trying to the one full time job - Dave was determined to do 3!&lt;/p&gt;

&lt;p&gt;At this point I asked him why he was putting so much pressure on himself "because I want to achieve my objective!". I pointed out how much he was already doing and that struck me as being pretty successful already. &lt;/p&gt;

&lt;p&gt;Then I asked him; &lt;br&gt;
"How old are you?" &lt;/p&gt;

&lt;p&gt;22 he said :O&lt;/p&gt;

&lt;p&gt;And then followed something which I'd paid more attention to myself.&lt;/p&gt;

&lt;p&gt;"You're 22. Look at your career as a timeline. You started at 19, 20? Perhaps you hope to retire at 50. maybe 60. many people will need to work until they're 75. Now, look how far you are along your timeline. You've barely started your career! Give yourself a break! I didn't even start to think about my career ambition until I was into my 30s!&lt;/p&gt;

&lt;p&gt;Basically, relax, give yourself a break  - you're already doing brilliantly. Pace yourself. You need to enjoy your job and your life."&lt;/p&gt;

&lt;p&gt;I can't promise this was was exactly what I said, but I know it was close. At the time I said it, it seemed to click with Dave who gave a sigh of relief. &lt;/p&gt;

&lt;p&gt;We carried on as mentor and mentee but ended up talking less over the past year. When we did speak again, just recently he mentioned to me that he'd been using that "timeline advice" with some of the people he'd been teaching and mentoring at School of Code, among other places. I'd totally forgotten about it so asked to be reminded. He told me the number of people he'd used it with and how all of them had appreciated the context it gave them and the assurance that they didn't need to break themselves to achieve what it is they hoped for.&lt;/p&gt;

&lt;p&gt;I was chuffed to bits to hear that something I'd come up with on the spot was helping him and others and made a note to make more use of it myself in future.. &lt;/p&gt;

&lt;p&gt;This last conversation happened a few days after I resigned and felt the weight lifting from my shoulders. A few days after that I reflected; why didn't I take my own advice, dammit!?&lt;/p&gt;

&lt;p&gt;I came to realise that I'd stuck out the job I was no longer enjoying because I saw it as a stepping-stone or launchpad. Where else was I going to be a CTO at a FinTech, supposedly a prestigious industry? What else was going to help progress my career to the next step? I'd got myself stuck in that "career progression" mindset and I'd totally lost sight of enjoying what I did and importantly my life.&lt;/p&gt;

&lt;p&gt;If I'd taken a moment to look at my own career timeline, perhaps I would have seen that I'm also doing OK. That I don't need to get stressed and more importantly, I need to do something I'm going to enjoy. &lt;/p&gt;

&lt;p&gt;So you see - the threads do join up, and the result of that is I need to listen to my own advice more. &lt;/p&gt;

&lt;p&gt;The other thing I've learned is that there's always a new opportunity out there. I spend most of my professional  life encouraging others to embrace change (and get used to the idea that deploying code 20 times a day is both normal and a good thing!). Sometimes I need to believe that myself and believe in myself. &lt;/p&gt;

</description>
      <category>mentalhealth</category>
      <category>career</category>
      <category>mentoring</category>
    </item>
    <item>
      <title>Using Atata to create UI tests for user defined web forms</title>
      <dc:creator>danieltallentire</dc:creator>
      <pubDate>Fri, 26 Mar 2021 08:58:25 +0000</pubDate>
      <link>https://dev.to/ctowestmidlands/using-atata-to-create-ui-tests-for-user-defined-web-forms-4jf0</link>
      <guid>https://dev.to/ctowestmidlands/using-atata-to-create-ui-tests-for-user-defined-web-forms-4jf0</guid>
      <description>&lt;h1&gt;
  
  
  The Problem
&lt;/h1&gt;

&lt;p&gt;At Parker Software, our chat software allows for customers to create whatever inputs they want to show on the pre-chat survey, which is asked before a user enters the chat:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpkavq1i5zsifu2gv8ib1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpkavq1i5zsifu2gv8ib1.png" alt="image" width="462" height="626"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These fields can be any html field type, including simple text inputs, password fields, radio buttons and drop down lists.&lt;/p&gt;

&lt;p&gt;When we setup a new theme for a customer, we want to ensure that the layout and behaviour remains the same when any updates and modifications to the core chat window take place. At the moment this is a manual process whereby the upgrade is performed, and a QA team member will run through the chat window, inspecting it from errors.  This manual process is somewhat error prone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I want to create an automated solution that can work regardless of the fields that have been set in the drop down&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We use Atata to do some of our other automated UI testing, and I wanted to have a go at using it to solve this problem. &lt;/p&gt;
&lt;h1&gt;
  
  
  What is Atata?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://atata.io"&gt;Atata&lt;/a&gt; is an automated testing framework based on Selenium.  You can use C# code to define pages as class files, then really simply set up a wide variety of tests without needing to worry about what the client side looks like.&lt;/p&gt;

&lt;p&gt;Thanks to Yevgeniy Shunevych for making Atata so awesome and putting out continuous updates and improvements.&lt;/p&gt;
&lt;h2&gt;
  
  
  What does it look like?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ed54bv4ak803i388dw0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ed54bv4ak803i388dw0.png" alt="image" width="800" height="607"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What are the challenges?
&lt;/h2&gt;

&lt;p&gt;Atata doesn't have a "dynamic" control built in - it usually requires all elements that you want to interact with to be predefined, so I will need to spend some time working on resolving that.&lt;/p&gt;
&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;I'm using Atata with XUnit - we use XUnit for all our unit testing, so Atata has to run through that - it is a little more difficult as Atata doesn't have a native XUnit adapter, but only a few extra changes are needed to integrate with XUnit's logs.&lt;/p&gt;
&lt;h1&gt;
  
  
  The code
&lt;/h1&gt;

&lt;p&gt;You can get the code at &lt;a href="https://github.com/danieltallentire/AtataDynamicForms"&gt;https://github.com/danieltallentire/AtataDynamicForms&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Attempt 1
&lt;/h2&gt;

&lt;p&gt;First, I attempted to use the ControlList class with the built in Input control.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Atata&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;AtataDynamicFormTester&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ChatStartPage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;WaitForLoadingIndicator&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatStartPage&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;ControlDefinition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ContainingClass&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"input-group"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; 
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ControlList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SurveyFields&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Chatting&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;StartChat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nf"&gt;SetRandom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
        &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;SurveyFields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
            &lt;span class="p"&gt;{&lt;/span&gt; 
                &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetRandom&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
            &lt;span class="p"&gt;}&lt;/span&gt; 

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each control on the form is wrapped in a div with the input-group class. This means we can use it with the list locator to find each of the inputs inside.&lt;/p&gt;

&lt;p&gt;This came unstuck pretty quickly. It was able to detect and find the elements in the control list, but unable to set a value on them, even with a simple text field.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempt 2
&lt;/h2&gt;

&lt;p&gt;My next attempt was to use a simple custom control to wrap the input control. In Atata a custom control is a class derived from the parent Control.&lt;/p&gt;

&lt;p&gt;The containing class now moves to part of the control definition. &lt;br&gt;
We can rely on this element existing, so we can iterate the fields.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;ControlDefinition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ContainingClass&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"input-group"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; 
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DynamicControl&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Control&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;TOwner&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PageObject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;FindByClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"form-control"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; 
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;TextInput&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SetRandom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
        &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="n"&gt;TextInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetRandom&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The list is then changed to reference it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;ControlDefinition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ContainingClass&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"input-group"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; 
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ControlList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DynamicControl&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SurveyFields&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Success!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Well... some success. This worked fine for simple fields like Name and Company.  It got unstuck when it reached an email address, trying to fill it as a random field, and completely ignored the other controls.&lt;/p&gt;

&lt;p&gt;My next thing to change was to try to switch based on the input value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SetRandom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
            &lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetRandom&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
            &lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Atata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Randomizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{0}@{0}.com"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; 
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
            &lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"03/03/2021"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"checkbox"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
            &lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
            &lt;span class="c1"&gt;// ignore &lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OK. Getting closer - this worked nicely for the email address and the date - although its a bit clunky setting the date as a string.&lt;br&gt;
Checkbox didn't work at all, and the select wasn't even detecting.&lt;/p&gt;
&lt;h2&gt;
  
  
  Attempt 3
&lt;/h2&gt;

&lt;p&gt;Looking again at the classes, I'd forgotten that &lt;em&gt;select&lt;/em&gt; elements aren't &lt;em&gt;input&lt;/em&gt; elements... d'oh!&lt;/p&gt;

&lt;p&gt;I had a play around, and found that I could add multiple elements in to the class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;FindByClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"form-control"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; 
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Input&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;FindById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"fld"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; 
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;TermFindSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TargetAttributeType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FindByIdAttribute&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;Match&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TermMatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartsWith&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; 
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;CheckBox&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Checkbox&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;FindByClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"form-control"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; 
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And it wouldn't error out for the missing ones in the cases where the control didn't contain those elements, however if I tried to access the control &lt;em&gt;Input&lt;/em&gt; on a select element it would throw an exception (rightly, because the Input doesn't exist).&lt;/p&gt;

&lt;p&gt;I found that I could create a check to see if the element was found by checking for the Exists property with the IsSafely flag set:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Checkbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SearchOptions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;IsSafely&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This caused a slowdown, so this lead me to the final code with a predefined timeout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;ControlDefinition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ContainingClass&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"form-group"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DynamicControl&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Control&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;TOwner&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PageObject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;FindByClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"form-control"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Timeout&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Input&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// checkboxes aren't wrapped by a nice form-control wrapper, so have to use a different search method&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;FindById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"fld"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Timeout&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;TermFindSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TargetAttributeType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FindByIdAttribute&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;Match&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TermMatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartsWith&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;CheckBox&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Checkbox&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;FindByXPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".//*[contains(concat(' ', normalize-space(@class), ' '), ' form-control ')]/descendant-or-self::input[@type='date']"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Timeout&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DateInput&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;DateInput&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;FindByClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"form-control"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Timeout&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SetRandom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Checkbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SearchOptions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;IsSafely&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Checkbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SearchOptions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;IsSafely&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Atata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Randomizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DateInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SearchOptions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;IsSafely&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;DateInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetRandom&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SearchOptions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;IsSafely&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetRandom&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Atata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Randomizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{0}@{0}.com"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
                        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="c1"&gt;// ignore&lt;/span&gt;
                        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;           
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I needed to use a manual XPath search for the date input - this was because Atata by default allows for date inputs to be a normal text input with a mask, so was also picking up the default text boxes as date fields too.&lt;/p&gt;

&lt;p&gt;I had to add a new randomizer to make the DateInput SetRandom work.&lt;br&gt;
Now I've got the chat window starting nicely.&lt;/p&gt;

&lt;p&gt;The containing class was actually incorrect in my earlier examples, and I changed it to form-group - this was caused by the checkboxes not being inside an input-group div.&lt;/p&gt;

&lt;p&gt;Just enabling screenshotting in the places I want them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;FillPrechatSurvey&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Go&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;To&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ChatStartPage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"http://localhost/newchat/chat.aspx?domain=www.parkersoftware.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Screenshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Start Chat"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetRandom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Screenshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Filled Out"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartChat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ClickAndGo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Screenshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Chatting"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CloseWindowButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Screenshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Finished"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the results:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq9o06cftjnpkyqmvmv90.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq9o06cftjnpkyqmvmv90.png" alt="image" width="695" height="182"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What next?
&lt;/h1&gt;

&lt;p&gt;In order to make this good for production I've got to do some little tweaks - making the resolution and the URL something that can be passed in as an environment variable so it can be run inside DevOps.  This is reasonably straight forward.&lt;/p&gt;

&lt;p&gt;In the longer term, I want to be able to configure some built in routes and selections to validate that the data sent in the set random is what is received by the server.  The WhosOn Echo Bot can send the data back, but I'll have to save the output somehow with SetRandom.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update
&lt;/h2&gt;

&lt;p&gt;Yevgeniy suggested some refactorings to make my rough code a little neater:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;ControlDefinition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ContainingClass&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"form-group"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;FindFirst&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TargetAllChildren&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DynamicControl&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Control&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;TOwner&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PageObject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// checkboxes aren't wrapped by a nice form-control wrapper, so have to use a different search method&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;FindById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TermMatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartsWith&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"fld"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;CheckBox&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Checkbox&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DateInput&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;DateInput&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;EmailInput&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;EmailInput&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;TextInput&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOwner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;TextInput&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SetRandom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Checkbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsPresent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Checkbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsPresent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Atata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Randomizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EmailInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsPresent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;EmailInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Randomizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{0}@{0}.com"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TextInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsPresent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;TextInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetRandom&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DateInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsPresent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;DateInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetRandom&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Changing the inputs to use IsPresent is much more succinct.&lt;br&gt;
Adding the top level attribute for TargetAllChildren means that the class name isn't required.&lt;/p&gt;

&lt;p&gt;Using TextInput instead of date input means that the order can be changed to allow a better ordering, and get the correct text or date input.&lt;/p&gt;

&lt;p&gt;For this to work I had to add an EmailInput as well to catch type='email'&lt;/p&gt;

</description>
      <category>testing</category>
      <category>selenium</category>
      <category>csharp</category>
      <category>atata</category>
    </item>
    <item>
      <title>First 90 days as a new CTO</title>
      <dc:creator>rich_marshall</dc:creator>
      <pubDate>Fri, 12 Mar 2021 09:08:33 +0000</pubDate>
      <link>https://dev.to/ctowestmidlands/first-90-days-as-a-new-cto-519p</link>
      <guid>https://dev.to/ctowestmidlands/first-90-days-as-a-new-cto-519p</guid>
      <description>&lt;p&gt;A few weeks ago there was a question posed in a slack group: "If you could go back to your first day in the role what are the 3 pieces of advice you would tell yourself?"&lt;/p&gt;

&lt;p&gt;There were some really helpful responses in there: "Read a lot of books and speak to other CTOs as early as possible"; "Spend more time thinking and less time doing in the first 90 days"; "Believe in yourself - there’s a reason why they asked YOU to be CTO" - that last one was my suggestion, but as an evergreen sufferer of imposter syndrome, I have to keep reminding myself. &lt;/p&gt;

&lt;p&gt;The question got me thinking though. Pithy advice is certainly helpful, but where do you go from there? So beyond the advice, what's my plan to hit the ground running in my next leadership role? This post is partly me sharing my thoughts but is also a request for peer review - I'd love to hear back on what I've missed, what I'm over emphasising - so please feel free to post back and comment. I should share my assumptions here too - the team is somewhere between 10 and 50 people and a new leader is being hired because the company is growing or because they want to trigger change.&lt;/p&gt;

&lt;p&gt;Starting a new role is an opportunity to start with a clean sheet, to take all the things you've learned to date and and try and apply them in what feels like a more sensible approach and order. So here's my 90 day plan - what's missing, what's un-necessary? Where am I setting a trap for myself?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Day 0 - introduce myself

&lt;ul&gt;
&lt;li&gt;Tell the team about who I am, what I believe in and how I like to work. Give the team a chance to mentally prepare themselves for my arrival. Importantly share my intentions with them. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Day 1  - (organise to) meet the team, listen. Hear what they have to say. What do they love, what bugs them? What insight can I gain from them?

&lt;ul&gt;
&lt;li&gt;Meet with all of them and make notes - individual notes for each person. &lt;/li&gt;
&lt;li&gt;Make sure I have time after each person to write up my notes and digest what they've said&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Week 1 - Establish my place in the company

&lt;ul&gt;
&lt;li&gt;Establish what my peer leadership group needs from me, what expectations do they have - "role descriptions' are rarely well defined at this point. &lt;/li&gt;
&lt;li&gt;Form an engineering leadership group, if there isn't one - this will likely be my go-to team as I learn the ropes.&lt;/li&gt;
&lt;li&gt;Start to lay-out the common working patterns&lt;/li&gt;
&lt;li&gt;Describe the culture that I'm looking to build&lt;/li&gt;
&lt;li&gt;Start to establish team principles and purpose&lt;/li&gt;
&lt;li&gt;Measure, or identify the tools that will allow us to measure&lt;/li&gt;
&lt;li&gt;Build trust with the team and show them how I plan to work with them in future&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Month 1 - Establish frameworks for how I want to support and grow people

&lt;ul&gt;
&lt;li&gt;Agree principles. Share them, adopt them, refere to them at every point&lt;/li&gt;
&lt;li&gt;Share any feedback or insights already learned&lt;/li&gt;
&lt;li&gt;Start to create framework for professional and personal development - there are some great examples out there for re-use. E.g. Basecamp and Gitlab company handbooks. &lt;/li&gt;
&lt;li&gt;Check-in with peer leaders. How am I shaping up? What am I missing?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Quarter 1 - "Standardise" on measurements, learning and feedback

&lt;ul&gt;
&lt;li&gt;Socialising what we're learning from measurements, use this to establish what's working well and what needs improving&lt;/li&gt;
&lt;li&gt;Forming tactical and strategic plans&lt;/li&gt;
&lt;li&gt;Team check-ins - how am I doing?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Taking those tips into account too, I don't plan to change things in a hurry, unless I really need to - the first 90 days are about learning and listening.&lt;/p&gt;

&lt;p&gt;I've mentioned measurement in there a few times. I'm really interested in knowing how the teams are performing, not so I can make them work harder, but so we can learn to work smarter. I think Accelerate is a fantastic book that goes into the science of high performing teams. Measuring how we're performing as a team is vital in being able to learn and improve. Likewise I'll be looking to resolve specific pain points. Over the past 18 months, Team Topologies has become my "go-to" when trying to understand what's not working well and how we can think about improving it. It's a tool box of patterns to describe and promote people working well together within teams, and how different teams should work together and importantly know how and when not to work together. I also believe strongly in teams being given purpose and empowered to achieve their goals. Distilling company values into more readily consumable principles is an important part of making this possible while ensuring there is still consistency across those teams. I've found Simon Sinek, especially in "The infinite game" and "start with the why" brings purpose and clarity to my thinking and provides a valuable anchor when I need to take a step back and reset. &lt;/p&gt;

&lt;p&gt;Finally, there was another piece of advice which was given, and I still can't decide if I totally agree: "your team is the exec team now, not the development team". If there's one thing I've learned in my current role is that if the exec don't act as a team, then you're not going to be effective as a business, so I agree the exec team is absolutely your team.. and yet I can't help think that the tech team is &lt;em&gt;also&lt;/em&gt; my team. If I have the vision, they're the people that make it possible. If I have a problem, they're the people that are likely to solve it. If we're not in it together, working towards out purposes then we're all just "me" or "them" and that's not the path to success either. For me it's got to be "us" all the way, so thank you but I'm in both teams now :)&lt;/p&gt;

</description>
      <category>leadership</category>
      <category>career</category>
      <category>technology</category>
    </item>
  </channel>
</rss>
