<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[The Lamp Post]]></title><description><![CDATA[A blog about life, productivity and front-end web development.]]></description><link>https://blog.kevinlamping.com/</link><image><url>https://blog.kevinlamping.com/favicon.png</url><title>The Lamp Post</title><link>https://blog.kevinlamping.com/</link></image><generator>Ghost 2.4</generator><lastBuildDate>Sun, 29 Mar 2026 03:07:52 GMT</lastBuildDate><atom:link href="https://blog.kevinlamping.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Crossing the Political Divide]]></title><description><![CDATA[<p>However much some of us may dislike Trump, we're damn lucky the shooter missed. Trump has power in politics because there are a lot of angry, scared, and ultimately unheard voices out there. Trump represents a societal illness. Not an illness for one political side or the other, but rather,</p>]]></description><link>https://blog.kevinlamping.com/crossing-the-political-divide/</link><guid isPermaLink="false">66ad639192abe706324daa3c</guid><dc:creator><![CDATA[Kevin Lamping]]></dc:creator><pubDate>Tue, 06 Aug 2024 14:47:57 GMT</pubDate><content:encoded><![CDATA[<p>However much some of us may dislike Trump, we're damn lucky the shooter missed. Trump has power in politics because there are a lot of angry, scared, and ultimately unheard voices out there. Trump represents a societal illness. Not an illness for one political side or the other, but rather, a breakdown in our society's ability to tackle the harsh realities of the world. You can take him out, but the illness remains.</p>
<p>A healthy culture is able to take complex topics such as abortion, where one side believes you're killing innocent life, and the other believes you're controlling women's bodies, and be compassionate towards the concerns of all. It knows it can't solve one side's issue without harming the other side. It seeks solutions that mitigate the pain for all, versus just offloading the pain onto someone else.</p>
<p>Ban abortion entirely, and you certainly doom a significant number of women and children to life-long poverty. Promote abortion entirely, and you tell people that fetuses are not human. Maybe you hold this view, but they don't. They truly believe you're killing innocent life, and now you've told them that doesn't matter. That would rightfully cause significant distress in someone. Either way, someone suffers.</p>
<p>Life, and the choices we're required to make, can be quite painful.</p>
<p>An unhealthy society is unable to bridge the divide, and the anger and hatred festers, until political leaders like Trump arise and gain power. They then enforce opinions on hard issues through political willpower, instead of compromise. These leaders are chosen to strong-arm answers through political force. If they fail at that, then it moves to violent force (e.g., Jan 6).</p>
<p>Right now, Trump represents strong-arming answers through political force. Him surviving this has given us more time until that turns into violent force. More time to get back to a healthier society, healthier debates and more compassionate disagreements. I may never agree with certain opinions, but I can have compassion for your viewpoint, and understand why you believe what you believe (even though you're entirely wrong :wink:)</p>
<p>If you find yourself thinking, &quot;I'll never compromise women's rights&quot; or &quot;I'm never going to be okay with murdering babies,&quot; then realize this is a reflection of this breakdown. We're defensive and unwilling to compromise, because we see no compromise available. We don't see or hear the other side's points. We strawman their view, and turn them into the enemy.</p>
<p>Compromise does not mean giving up your beliefs. It doesn't mean sacrificing that which you hold dear, or going against your values. It does mean facing the harsh challenges this existence throws at us, with compassion and an understanding that sometimes the best choice is still a tragic one. Compromise seeks to reduce pain as much as possible, but knows it can't avoid it all together. It knows that there are no hard and fast rules to life. That it all comes at some sort of cost, and the best you can do is make that cost worth it.</p>
<p>Ending Trump would not end the anger and the illness. It would only take away whatever bit of functioning form this illness is able to take through him. Ending him would transform this anger from a political force, into a violent force.</p>
<p>This does not excuse Trump from being able to hold power. I despise that he's one of our two primary options. I'm not okay with him being president again; I wasn't the first time either. But I fully believe that the way to remove him from power is through figuring out how we can build a healthier culture.</p>
<p>How can we learn to functionally disagree? How can we be entirely against a viewpoint, but also be entirely for the person with that viewpoint? It doesn't mean I'm going to stand-by while someone I disagree takes political office and makes decisions against my beliefs. Especially if those beliefs harm people I care about. I'll speak up and speak loudly.</p>
<p>But I also want to give people a chance to make decisions I don't agree with, just to see how it plays out. I do this so that I'll hear them, and they'll respond by hearing me. I want to know that they won't use political force to steamroll my concerns, and they should know I won't do the same to them.</p>
<p>Do I think we can actually learn this as a society and culture before the illness becomes fatal? Honestly, I'm not too hopeful. Culture change is far too large given how little time we have. How could I ever hope to impact society at large? If I'm entirely successful in sharing these thoughts, the best I may do is influence a few people in my small social network to re-evaluate their anger towards the other side.</p>
<p>But maybe there are folks out there who are also feeling this, who are also doing their own work to heal the culture in their circles. They're saying the same thing to their friends and family, and making small yet impactful changes. And they're counting on me, and us, to change our small little circle.</p>
<p>So this is your challenge: Are there groups of people you think as &quot;pure evil&quot;, &quot;despicable&quot;, &quot;deplorable&quot;, &quot;vermin&quot;, &quot;ignorant&quot;, &quot;sick&quot; or other such derogatory terms? Can you step back and think, &quot;what circumstances would get me to hold the beliefs they do?&quot; You certainly don't have to change your stance, but until you can answer that question with honesty and grace for the other side, spend some time learning why your opponent feels the way they do.</p>
]]></content:encoded></item><item><title><![CDATA[Announcing Web App Testing with WebdriverIO - My New Online Course!]]></title><description><![CDATA[<p>It's been several years since the initial release of <a href="https://blog.kevinlamping.com/earning-50k-in-two-and-a-half-years-selling-a-niche-online-course/">my web app testing course</a>, which I unfortunately needed to close down in early 2020 due to the content becoming very out-of-date. </p><p>Since closing it down though, I've been working on two follow up projects:</p><ul><li><a href="https://leanpub.com/webapp-testing-guidebook">The Web App Testing Guidebook</a>, an</li></ul>]]></description><link>https://blog.kevinlamping.com/announcing-web-app-testing-with-webdriverio-my-new-online-course/</link><guid isPermaLink="false">60d63e9a92abe706324da9b0</guid><category><![CDATA[Webdriverio]]></category><category><![CDATA[Testing]]></category><dc:creator><![CDATA[Kevin Lamping]]></dc:creator><pubDate>Fri, 25 Jun 2021 20:59:30 GMT</pubDate><media:content url="https://blog.kevinlamping.com/content/images/2021/06/book-cover-small.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.kevinlamping.com/content/images/2021/06/book-cover-small.jpg" alt="Announcing Web App Testing with WebdriverIO - My New Online Course!"><p>It's been several years since the initial release of <a href="https://blog.kevinlamping.com/earning-50k-in-two-and-a-half-years-selling-a-niche-online-course/">my web app testing course</a>, which I unfortunately needed to close down in early 2020 due to the content becoming very out-of-date. </p><p>Since closing it down though, I've been working on two follow up projects:</p><ul><li><a href="https://leanpub.com/webapp-testing-guidebook">The Web App Testing Guidebook</a>, an e-book which I released on LeanPub last winter</li><li><a href="https://learn.webdriver.io">Web App Testing with WebdriverIO</a>, a video course, which is currently in early access</li></ul><p>Both projects share the same content, just in a different format. The reason for this is that I wanted to get the book written first, then start working on the video course. The reason for that is that it's easier to update text content than video content. </p><p>Knowing that I'd be working on all of this in my free time, I figured that by the time I finish the content, there will be parts that are already out-of-date (which definitely happened once or twice). </p><p>So with the book, I can take the time to develop all the examples, then go back and update them once finished, then more quickly develop the videos from those examples and hopefully avoid having to re-work the content (although <a href="https://www.youtube.com/watch?v=qu6o1dYwII4">it's already had to be re-worked once</a>).</p><p>I'm currently in the middle of working on the course, with 10 videos completed and one more to go for the 'starter course'.</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/O4fE1qY09ag?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></figure><p>From there, I'll start working on the second part (there will be 3 total parts). It hopefully won't take my half a year to develop, and I have gotten into a much better rhythm with building out these videos. But still, the editing takes about a day for each video, so it'll take some effort still.</p><p>Anyway, I just wanted to make a note of it here. If you're interested in learning more about the course (or signing up <em>hint hint</em>), check out <a href="https://learn.webdriver.io">https://learn.webdriver.io</a></p><figure class="kg-card kg-image-card"><img src="https://blog.kevinlamping.com/content/images/2021/06/The-Web-App-Testing-Guidebook-Cover-Image-v1.png" class="kg-image" alt="Announcing Web App Testing with WebdriverIO - My New Online Course!"></figure>]]></content:encoded></item><item><title><![CDATA[Let Glue Dry.]]></title><description><![CDATA[<p>It's so tempting to rush through to the next step of the process before giving the current step time to set. The push is to keep moving forward with our momentum, even when the project just requires time to do nothing.</p><p>This phrase comes from <a href="https://www.youtube.com/watch?v=tQfZhdyXJ54">the fun YouTube channel of</a></p>]]></description><link>https://blog.kevinlamping.com/let-glue-dry/</link><guid isPermaLink="false">5f20e1096c72e94276b93b1e</guid><category><![CDATA[Life]]></category><category><![CDATA[Productivity]]></category><category><![CDATA[Meditation]]></category><dc:creator><![CDATA[Kevin Lamping]]></dc:creator><pubDate>Wed, 29 Jul 2020 02:39:52 GMT</pubDate><media:content url="https://blog.kevinlamping.com/content/images/2020/07/Screen-Shot-2020-07-28-at-9.39.17-PM.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.kevinlamping.com/content/images/2020/07/Screen-Shot-2020-07-28-at-9.39.17-PM.png" alt="Let Glue Dry."><p>It's so tempting to rush through to the next step of the process before giving the current step time to set. The push is to keep moving forward with our momentum, even when the project just requires time to do nothing.</p><p>This phrase comes from <a href="https://www.youtube.com/watch?v=tQfZhdyXJ54">the fun YouTube channel of Laura Kampf</a>, who has a big block with the phrase on it. Viewers of the channel find the block simple yet profound.</p><p>Let Glue Dry.</p><p>Give yourself and your projects the space to set. Don't rush the outcome. Just because the glue isn't working yet, doesn't mean it won't work if you just give it time.</p>]]></content:encoded></item><item><title><![CDATA[Comfort in, dump out]]></title><description><![CDATA[We need to ensure that only comfort and empathy moves towards those most affected. And in reverse, emotions are dumped outward onto those more able to bear them.]]></description><link>https://blog.kevinlamping.com/comfort-in-dump-out/</link><guid isPermaLink="false">5ed6ad8dfafc80663de724ed</guid><category><![CDATA[Life]]></category><dc:creator><![CDATA[Kevin Lamping]]></dc:creator><pubDate>Tue, 02 Jun 2020 23:40:51 GMT</pubDate><media:content url="https://blog.kevinlamping.com/content/images/2020/06/annie-spratt-9VpI3gQ1iUo-unsplash.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.kevinlamping.com/content/images/2020/06/annie-spratt-9VpI3gQ1iUo-unsplash.jpg" alt="Comfort in, dump out"><p>"Step back and listen."</p><p>It's a common phrase I hear among those asking for help. They talk about how frustrating it is when those in power tend to make things about themselves (e.g., the person in power would say, "It's really hard for me to know what to do." or "You should hear what happened to me.").</p><p>I was thinking about that, and why someone like myself would say the thing about it being hard or want to compare. Honestly, it <em>is</em> difficult for me to know what to do (which <a href="https://blog.kevinlamping.com/im-bad-at-diversity/">I've written about before</a>).</p><p>Why is this so familiar? Why do people have such a hard time stepping back and not making it about themselves? Well, I think it's just human nature. We want to share our experiences, and in doing so forget whose voice we're talking over.</p><p>Unfortunately, it's only natural.</p><p>Okay, I'm not excusing that behavior. Not a single bit. We have to listen; we have to give room for voices of those desperate to be heard.</p><p>How do we do that though? How do we push down that evolutionary need?</p><p>We don't.</p><p>Instead of trying to act like our personal needs don't matter, we need to shift who we're telling those needs to. Ignoring our thoughts doesn't work, but directing it at the right audience does.</p><p>I've found personal counseling to be extremely helpful in this manner. Instead of having all my troubles loaded onto the shoulders of my friends and family, I have my therapist available to bear that burden.</p><p>After all, that's what they're trained for and that's why I'm paying them... So I can be an egotistical whiney mopey messy human being; the goal being that I contain that self-centeredness to the sessions, freeing me up to be emotionally available for my community and a more empathetic human being.</p><p>I brought this up with my wife and she mentioned that it reminded her of "<a href="https://www.psychologytoday.com/us/blog/promoting-hope-preventing-suicide/201705/ring-theory-helps-us-bring-comfort-in">Circles of Grief/Ring Theory</a>". The idea is that, in a time of grief, you have those most affected in the middle of the circle, and those least affected on the outer rings.</p><p>We need to ensure that only comfort and empathy moves inward, towards those most affected. And in reverse, emotions are dumped outward onto those more able to bear them. "Comfort in, dump out."</p><p>Quoting the article I linked, ask yourself:</p><blockquote>Where I am in the circle? Given that position, what should I say, or what can I hope would be said to me? Who are people in the circle I could comfort? Who can I "dump" to?</blockquote><p>I really like this model. It recognizes the needs and unique experiences of all of us. I don't think you should ignore your own needs &amp; worries just because you're not the most affected, but I also think those who are most affected desperately need us to be there for them, and to not make it about ourselves. We've got to get this right.</p><p>I'm definitely going to work on keeping this circle model in mind throughout my life, so I'm always emotionally ready to be there when needed, helping in whatever little ways I can.</p><p><em>Header photo by <a href="https://unsplash.com/@anniespratt?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Annie Spratt</a> on <a href="https://unsplash.com/s/photos/helping-hand?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></em></p>]]></content:encoded></item><item><title><![CDATA[UI Test Automation Is an Awful, Wonderful Thing]]></title><description><![CDATA[I've spent many years in the test automation world and there's one thing that sticks out to me: It's a wonderfully terrible thing.]]></description><link>https://blog.kevinlamping.com/ui-test-automation-is-an-awful-wonderful-thing/</link><guid isPermaLink="false">5eb5b7bd94669a2ae5e23399</guid><category><![CDATA[Webdriverio]]></category><category><![CDATA[Coding]]></category><category><![CDATA[Testing]]></category><dc:creator><![CDATA[Kevin Lamping]]></dc:creator><pubDate>Fri, 08 May 2020 19:50:24 GMT</pubDate><media:content url="https://blog.kevinlamping.com/content/images/2020/05/robot.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.kevinlamping.com/content/images/2020/05/robot.jpg" alt="UI Test Automation Is an Awful, Wonderful Thing"><p>I've spent many years in the test automation world and there's one thing that sticks out to me: It's a wonderfully terrible thing.</p>
<p>It's wonderful in that it solves a very important need. Good automation can save immense amounts of time over the long run and catch bugs that would have made it to production.</p>
<p>It's terrible in that it gets used in the wrong ways, done for the very questionable reasons, and poor implementations can be a real maintainability nightmare.</p>
<p>But before I get to that, let's step back...</p>
<h2 id="whatisuserinterfaceuitestautomation">What is User Interface (UI) Test Automation?</h2>
<p>Truthfully, test automation is a lot of things. There are a multitude of programs and tools surrounding it, not to mention the various ideologies about automated testing in general (e.g., Test-driven Development vs. Behavior-driven Development).</p>
<p>Aside from that, there are also different types of tests. Here, we're focusing solely on UI automation, but there's also unit, integration, performance, accessibility, usability, you-name-it testing.</p>
<p>All of these are important to know about, and can provide as much or more value than UI testing. So why focus on UI testing?</p>
<p>Well, you don't really have an option. You can't skip accessibility testing if you want to have a site that's accessible. Equally, you can't skip UI testing if you want to have a site that's not broken.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/i/ul4y3ubjuxkvi0b2rkyk.jpg" alt="UI Test Automation Is an Awful, Wonderful Thing"></p>
<p>Truthfully, we're doing tons of UI testing. Every time someone loads up a website, they're testing the UI. When they click that button, does it make that thing happen? When I use my mobile device, does the site fit on my small screen?</p>
<p>If you have a site in production, every user is testing your UI. Hopefully for them (and you), they're not the first ones to try it out.</p>
<p>UI testing is constantly being done, just in a very labor-intensive way. Front-end developers working on the code will spend half of their day in the browser manually testing if their changes worked. If they're testing in an older browser, it will be 3/4ths of their day.</p>
<p>UI testing is the simple (hah) task of validating that the code written for the browser, actually works in that browser, along with all the other components that went into that webpage.</p>
<p>UI test automation is a way to convert those manual mouse clicks and keystrokes into coded scripts that we can run on a regular basis.</p>
<h3 id="letstalkbenefits">Let's Talk Benefits</h3>
<p>I've alluded to this before, but it's worth repeating. Here are some of the many real-world benefits of automated UI testing:</p>
<ul>
<li>Jamie, your ace front-end developer, just finished their latest task and is itching to release it. While they were careful to validate that the new functionality works, unfortunately they forgot to test whether that new code broke the zip code widget on the contact page. Lucky for you, the UI automation test caught the error, and a fix was in place before the end of the day.</li>
<li>Taylor is an awesome full-stack developer. They've got everything about their coding environment fine-tuned so that they can focus solely on pumping out fixes and new features... except for one thing: Taylor always forgets to check their code on slower, outdated computers. That's okay though, as our UI tests are configured to run on a variety of setups, and it just so happens that it caught that issue when running inside a Windows 8 environment.</li>
<li>Casey is a great product manager, but sometimes forgets to clarify the small details. This means developers can make the wrong assumption during development, which is only discovered by Casey during product demos. By adding automated tests to the mix, developers and product managers are pushed to have regular conversations on the desired behavior of certain functionality, resulting in fewer surprises later on.</li>
<li>Avery is a superb QA tester. With great attention to detail, Avery always thinks of unique ways in which the website would be seen. Unfortunately, manually testing these edge cases takes a fair amount of time to get in place. By adding automated scripts, Avery is able to programmatically generate the needed data for their tests, and allow them to run these scripts on a regular basis.</li>
</ul>
<p>These are just a few ways test automation can help. I skipped over many other benefits for the sake of time, but there's one I omitted on purpose. Many folks claim that UI tests allow you to have fewer developers/testers. While that could be an outcome of automation, I don't think it's a valuable argument.</p>
<p>In all the scenarios above, having an extra human around wouldn't have necessarily helped. That's because human's have blind spots, and many of them are the same. Teams have collective blindspots and that's difficult to get around. We naturally tend to focus on what's in front of us, forgetting about realities outside our own influence.</p>
<p>UI testing isn't about replacing humans, but rather augmenting their abilities. We use automation to shore up our limitations, allowing us to focus on our strengths.</p>
<p>Developers waste their time testing on hundreds of different devices, when they could instead let a computer do that part of the work. Your QA team wastes its time running through the same test scenario week after week, when instead they could be thinking of new and undiscovered test cases.</p>
<p>UI automation isn't about replacing humans with machines, but rather giving us more freedom to work better than machines.</p>
<p>And let's not forget, UI testing requires a fair amount of work. It's not magic (although it's okay to convince management it is). This brings me to an important consideration...</p>
<h3 id="therearealwaysdrawbacks">There Are Always Drawbacks</h3>
<p>How long do you think it takes to get a set of automated tests up and running? A week... maybe two?</p>
<p>Sure, if all you want to do is test that a page loads properly.</p>
<p>But websites are incredibly complex — the number of features we jam on a page grows each day.</p>
<p>Consider a &quot;simple&quot; homepage. Here are some things you'll want to test on it:</p>
<ul>
<li>Do all the parts look right on a laptop and desktop computer?</li>
<li>Do all the parts look right on a tablet?</li>
<li>Do all the parts look right on a phone?</li>
<li>Does the site navigation work?</li>
<li>Does the &quot;need help&quot; chatbox pop up after five seconds?</li>
<li>Does the autocomplete in the site searchbar work?</li>
<li>Does the hidden menu show after you click the menu icon?</li>
<li>Does the carousel on the homepage rotate correctly?</li>
</ul>
<p>Okay, I'll stop there. Hopefully you get my point that there's a lot to test even on a single page. A basic script that loads a page doesn't provide much reassurance.</p>
<p>So if you want to test all your functionality on all your pages, you're going to have to write a lot of code.</p>
<p>Covering all of that ground takes time. Time that could be spent on other, possibly more important, tasks.</p>
<p>And as you're writing test after test, the website your testing is going to keep changing. New features and fixes will be continuously introduced. The same feature will be tweaked again and again, causing your once-solid test suite to mysteriously start failing.</p>
<p>When the glorious day comes and you're &quot;done&quot; writing tests, you still have to maintain them. Now, there are ways to write tests to make them more maintainable, and we'll cover that throughout the examples, but there's no such thing as a future-proof test. You're always going to need to update it.</p>
<p>There's one more important point to consider.</p>
<p>While you'll breeze through some parts of test writing, expect to sink 80% of your time figuring out how to test that special 20% of your site's functionality. There are many areas of writing tests that aren't trivial. It's not as simple as calling the command to fill out a textbox and click the submit button.</p>
<p>You'll need to work with databases, integrate with third-party services and see if you can get commands to work in browsers with poor automation support. You're also going to run into instances where the way the website was coded just doesn't jibe with test automation.</p>
<p>Animations are a good example of that. How do you test that an animation works? You can fairly easily check the properties before and after an animation, but what about everything in between those two states?</p>
<p>Honestly, you'd need to do a screen recording of every frame of the animation, and compare that screen recording to a previous run to see if they match. I don't know about you, but that doesn't sound easy to me.</p>
<h3 id="simplersitesforuitesting">Simpler Sites for UI Testing</h3>
<p>If you find yourself facing a complex site that would require major work to test properly, there are other options to gain some value without too much effort.</p>
<p>Instead of testing a fully working site, you may want to create a variation of your site that represents portions of the real thing. For example, pattern libraries are a popular option out there, especially for larger websites.</p>
<p>In case you're not familiar with them, pattern libraries are essentially living demos of the components that make up a website's interface. Mailchimp has a public pattern library if you'd like to see one in action (<a href="https://ux.mailchimp.com/patterns">https://ux.mailchimp.com/patterns</a>).</p>
<p>For instance, a pattern library may contain standalone versions of the following:</p>
<ul>
<li>Site layout components like the main navigation and site footer</li>
<li>Components used across multiple pages, like buttons, form inputs, and tabs</li>
<li>Style guidelines for simple page elements like links, headings, and lists</li>
</ul>
<p>Pattern libraries are very helpful for teams, to document how the website should look and act. If you're tasked with adding a sortable table to your companies site, having a pattern library with a living example of one makes the job simple.</p>
<p>They're also useful for testers, as it gives us testable examples of individual components isolated from the complexity of the full website.</p>
<h3 id="skippingautomationissometimesthebestoption">Skipping Automation is Sometimes the Best Option</h3>
<p>Hopefully I haven't scared you away from UI test automation entirely. I only wanted to get you thinking about the whole picture.</p>
<p>And that picture should include saying, &quot;Maybe we shouldn't write test automation for that... at least not yet.&quot;</p>
<p>Let's consider a few things...</p>
<h4 id="newfeaturesarentusertested">New Features Aren't User Tested</h4>
<p>Business is booming and your team is tasked with a brand-new feature idea that management thinks the customer will love.  While it's tempting to say, &quot;Yes, and let's write tests to go side-by-side with this new feature,&quot; it might not be the right time.</p>
<p>This brand-new feature has never seen the light of day, and the second a customer sees it there's going to be something they don't like about it. If a decision is made to rework the concept based on customer feedback, all those tests you've written become useless.</p>
<p>There's no point in writing a test if you haven't user-tested your site. So before you spend time writing assertions, ensure the assumptions about the user interactions are initially put to the test.</p>
<h4 id="timewritingteststakesawayfromwritingfeatures">Time Writing Tests Takes Away from Writing Features</h4>
<p>You're not paid to write tests; tests only serve the application they're testing. If an app is useless, tests won't help.</p>
<p>If you're working on a side project for a tool that no one uses, spending time writing tests takes away from time spent on more important tasks, like getting people to use your work.</p>
<p>Users don't care whether you have good unit tests. There's no difference between an unused tool and an unused unit tested tool.</p>
<p>Let yourself have untested code. Worry about that problem when it actually becomes one.</p>
<h4 id="testsareonlyvaluablewhenyouusethem">Tests Are Only Valuable When You Use Them</h4>
<p>Don't write more tests when you're not using the ones you already have.</p>
<p>If you have 500 UI tests, but never put in the time to integrate them in your build and deployment process, you have 500 useless tests. Writing 500 more won't help.</p>
<p>Your tests should run on every code push. They should run before every deploy. Every developer on the team should see that the tests passed or failed.</p>
<p>If that's not true, you shouldn't be writing more tests, you should be taking advantage of the tests you already have.</p>
<h4 id="partsofthesitemightbebettertestedbypeople">Parts of the Site Might be Better Tested by People</h4>
<p>Remember when I said tests shouldn't replace people, but rather augment their abilities. Well, in the scenario of testing an animation, we were stuck with a really complex solution. What if we just went with manual visual validation of the effect?</p>
<p>It's okay to have some parts of your site that are too complex for automation. Grab that low-hanging fruit and leave the stuff higher in the tree for a later time when you have a ladder.</p>
<h3 id="aretestsworthitthen">Are Tests Worth It Then?</h3>
<p>I've outlined the benefits and drawbacks of test automation, including reasons to entirely skip some of it.</p>
<p>So how do you ensure you're getting more benefits than drawbacks? Focus on these two goals:</p>
<ul>
<li>Ensure you're gaining value out of every test you write</li>
<li>Ensure you're selling that value to those in charge</li>
</ul>
<p>It's really easy to get caught up in automation, trying to cover every nook and cranny of the site. But if a feature of your site doesn't provide much value, how much less value would a test for that feature be?</p>
<p>The site login component breaking... that's bad. The site's About page having a typo... not such a big deal. Sure, we'd want to fix it, but it (hopefully) won't cost the company a lot of money.</p>
<p>By focusing on gaining and selling that value, you can keep yourself honest in your test writing, and focus on what's important: having a site that's running smoothly and providing value to the user.</p>
<h2 id="learnabetterwaytotest">Learn a Better Way To Test</h2>
<p>There's a lot more to UI Test Automation than I've briefly covered here, including code!</p>
<p>In fact, this was just a short excerpt from <a href="https://leanpub.com/webapp-testing-guidebook">The Web App Testing Guidebook</a>. In the book, I cover what WebdriverIO can do and how you'll be using it day-to-day. I've built the examples around real-world scenarios that demonstrate how you would actually set things up. It's not just &quot;what&quot;, but also &quot;how to get there&quot; with reasoning around every decision. <a href="https://leanpub.com/webapp-testing-guidebook">Grab at copy today at LeanPub!</a></p>
<p><em>Header Photo by <a href="https://unsplash.com/@rocknrollmonkey">Rock'n Roll Monkey on Unsplash</a></em><br>
<em>Piano Robot Photo by <a href="https://unsplash.com/photos/U3sOwViXhkY">Franck V. on Unsplash</a></em></p>
]]></content:encoded></item><item><title><![CDATA[5 Hacks to Speed Up Your TypeScript Development]]></title><description><![CDATA[Is TypeScript slowing your Elite Coding Skillz down? Check out these 5 super pro hax to get back to the prowess you're more than capable of!]]></description><link>https://blog.kevinlamping.com/5-ways-to-speed-up-your-typescript-development/</link><guid isPermaLink="false">5e1faa8294669a2ae5e2336a</guid><category><![CDATA[Coding]]></category><category><![CDATA[satire]]></category><dc:creator><![CDATA[Kevin Lamping]]></dc:creator><pubDate>Thu, 16 Jan 2020 00:39:11 GMT</pubDate><media:content url="https://blog.kevinlamping.com/content/images/2020/01/chains-min.jpg" medium="image"/><content:encoded><![CDATA[<h2 id="1tsignore">1. <code>// @ts-ignore</code></h2>
<img src="https://blog.kevinlamping.com/content/images/2020/01/chains-min.jpg" alt="5 Hacks to Speed Up Your TypeScript Development"><p>Some pesky line of code causing your compilation problems? No worries, just throw <code>// @ts-ignore</code> on the line before and now your issues are all solved.</p>
<p><img src="https://blog.kevinlamping.com/content/images/2020/01/EJIU7u4UcAMEGyU.png" alt="5 Hacks to Speed Up Your TypeScript Development"></p>
<p>If you're feeling frisky, hack an entire file by adding <code>/* tslint:disable */</code> to the top of it and now you don't need to worry about any TypeScript issues holding you back for that entire chunk of code.</p>
<h2 id="2theanytype">2. the 'any' type</h2>
<p><a href="https://knowyourmeme.com/memes/i-dont-like-sand">I don't like types</a>. They're strict and restrictive and irritating and they get everywhere. So how do you eat your types and keep them too? Use the <code>any</code> type!</p>
<p>Say you want to create a new variable that'll probably be a <code>string</code>. Instead of typing it as such and restricting yourself from future changes, just type it as <code>any</code> and now you have free range to change things as necessary!</p>
<p>For example:</p>
<pre><code class="language-ts">const myString : any = 'down with sand';
</code></pre>
<p>Want to change that to an integer lately? If you had strictly typed it, you'd have to update the code in two places. Using <code>any</code>, you don't have to worry about that! Genius!</p>
<h2 id="3donttypevariables">3. Don't type variables</h2>
<p>I know I just talked about using <code>any</code> to avoid strict typing, but I'm going to give you a pro tip: you don't have to define any typing at all!</p>
<p>That's right, even in TypeScript, you don't actually have to type any of your scripts! I'm a huge proponent of reducing code, and this goes right along with that best practice. Compare these two lines:</p>
<pre><code class="language-ts">const myString : string = 'down with sand';
const myString = 'down with sand';
</code></pre>
<p>You can clearly see how the second line involves less complicated code than the first. Only a Java developer would prefer the former.</p>
<p>So next time your tempted to bloat your codebase with types, just don't. This one simple trick will save your bytes and bytes of code!</p>
<h2 id="4dontdefineafunctionreturntype">4. Don't define a function return type</h2>
<p>If we don't have to type our variables, then why do we have to type our function returns? Answer: we do not! HAHA</p>
<p>It's a code smell to restrict your function to a single return type. Why? Because it's extra code!</p>
<p>Compare these two functions:</p>
<pre><code class="language-ts">function sum (a: int, b: int) : int { return a + b; }
function sum (a, b) { return a + b; }
</code></pre>
<p>What's the difference between the two? An expert will happily tell you that the latter won't bind you into some pre-optimized state that can never be changed without breaking all your dependent programs. We don't want that now do we. Do we!?</p>
<h2 id="5ensurestrictisalwayssettofalseinyourtsconfig">5. Ensure 'strict' is always set to false in your tsconfig</h2>
<p>There's one caveat to all of the above. You can't improve your code with these hot hacks if you've got 'strict' set to <code>true</code> in your <code>tsconfig</code> file.</p>
<p>That's why you should never, under any circumstances, ever, not even once, set <code>strict</code> to any value other than <code>false</code>.</p>
<p>Really, ask yourself, do you want to be <code>strict</code>? That's not fun, you Debbie Downer. Let people be free and let your code have the flexibility to live in a world not held down by arbitrary restrictions.</p>
<h2 id="conclusion">Conclusion</h2>
<p>I hope these elite tricks help you in your job. TypeScript is here to stay for sure. But you don't have to let it control who you are or change your style. Follow these 5 simple hacks and you're set for instant success!</p>
<p><em>Photo by <a href="https://unsplash.com/@supersonnytje?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Sonny Ravesteijn</a> on <a href="https://unsplash.com/s/photos/chains-hack?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></em></p>]]></content:encoded></item><item><title><![CDATA[25 Projects That Changed the JavaScript Landscape over the 2010s]]></title><description><![CDATA[25 tools from the past decade shifted the way we think about our work. I reflect on why these tools impacted the industry and what made them special.]]></description><link>https://blog.kevinlamping.com/25-javascript-tools-that-changed-the-landscape-in-the-2010s/</link><guid isPermaLink="false">5e1fa1cf94669a2ae5e23357</guid><category><![CDATA[Coding]]></category><dc:creator><![CDATA[Kevin Lamping]]></dc:creator><pubDate>Wed, 15 Jan 2020 23:49:44 GMT</pubDate><media:content url="https://blog.kevinlamping.com/content/images/2020/01/tools-min.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.kevinlamping.com/content/images/2020/01/tools-min.jpg" alt="25 Projects That Changed the JavaScript Landscape over the 2010s"><p>I'm tired of &quot;Tools <em>Every</em> Developer in 2020 Must Know&quot; articles.</p>
<p>They're mostly re-used content from the previous year and only serve as clickbait to get viewers to sites with questionable motivations. They're boring, unhelpful and undistinguishable from all the others out there.</p>
<p>Yes, we all know React is an important tool to know about. Give it a rest!  Try instead to formulate a unique thought that might make others rethink the popular opinion they've heard time and time again.</p>
<p>So, how about an article not about &quot;tools developers must know&quot;, but rather, &quot;tools that changed what developers knew&quot;?</p>
<p>In this list, I'm highlighting 25 JavaScript tools that I believe changed the industry over the past decade. All are/were popular, but it isn't ordered by popularity. Instead, we're looking at how revolutionary the ideas were, and how much they impact the JavaScript landscape.</p>
<p><em>Caveat: Knowing the &quot;first publish date&quot; of a tool is difficult, so I'm focused more on when the tool was popularized than when it was first published.</em></p>
<h2 id="25istanbul">25. Istanbul</h2>
<p>Honestly, it's harder to pick out #25 than it is #1.  But I say <a href="https://istanbul.js.org/">Istanbul</a> deserves to make the list over others for two reasons:</p>
<ul>
<li>It introduced code coverage to JavaScript, which started the decade with few automated testing tools out there. Istanbul promoted the testing discipline by making the lack of it much more visible.</li>
<li>It's maintained that status as the &quot;go-to code coverage&quot; tool for the entire decade. Throughout the years, it's continued to be well-maintained and updated, which is a huge feat.</li>
</ul>
<p>Despite my opinion that code coverage is over-emphasized in importance, it's a tough argument that Istanbul hasn't benefitted the industry through better test practices.</p>
<h2 id="24prettier">24. Prettier</h2>
<p>I've used <a href="https://prettier.io/">Prettier</a> and I didn't like it. Kind of.</p>
<p>Okay, Prettier is extremely opinionated, and if that opinion is different from yours, you kind of just have to deal with it.</p>
<p>And I think that's the beauty of the tool. Bikeshedding is a real problem in dev teams, and tabs-vs-spaces arguments can quickly turn from fun to frustration when it's your daily life.</p>
<p>Prettier says &quot;Stop!&quot; to all of that. You install the tool, go with what it says, and it takes care of the rest. No options, but no frustrating &quot;Code Style Review&quot; meetings.</p>
<h2 id="23cypressio">23. CypressIO</h2>
<p>Developed in 2014, <a href="https://www.cypress.io/">CypressIO</a> has grown to become one of the most popular automated testing tools out there. That's not so revolutionary, until you realize they did it without supporting one of the most requested features out there (cross-browser testing).</p>
<p>The CypressIO team had a hunch that easy-to-write (and run) test automation was by far more important than any other feature. So that's what they focused on, to which they've had much success.</p>
<p>CypressIO is a reminder that many &quot;needs&quot; of customers are really just what they think they should want. You can be revolutionary by not doing something, allowing you to do a more important thing 10x better than before.</p>
<h2 id="22yui3">22. YUI3</h2>
<p>You may not know <a href="https://yuilibrary.com/">YUI3</a>. The library hasn't had a code commit since 2014. <a href="https://www.youtube.com/watch?v=MH7KYmGnj40">It's dead, Jim</a>. Aside from that, its main competitor was jQuery, which held market-domination for its entire life.</p>
<p>But the folks at YUI3 were one of the first ambitious groups to create an entire library aimed at solving all of the pressing problems for front-end engineers.</p>
<p>They created a module loading system before module loading systems were cool.</p>
<p>They created a unit test framework before unit test frameworks were cool.</p>
<p>They created... well, the idea was that they tried to create everything. They took a look at the entire ecosystem of the front-end and said, &quot;here's a solution.&quot;</p>
<p>All this while at a company (Yahoo!) which struggled year-over-year to get past the giant of Google.</p>
<p>YUI3 may not be remembered by most, but many developers learned many new ideas from it, myself included.</p>
<h2 id="21ionic">21. Ionic</h2>
<p>Attempts to build &quot;web-based mobile apps&quot; existed before <a href="https://ionicframework.com">Ionic</a>, but none seemed to capture the scope that Ionic has sought and achieved. Riding the furvor around Angular, Ionic offered devs like me a streamlined approach to developing mobile apps using the Angular ecosystem.</p>
<p>I'd say they've succeeded at their mission, as I was able to use Ionic to publish multiple tools to the Google Play and iOS App Store using their functionality. This may not seem like much, but it was important to me.</p>
<p>Ionic changed the landscape for front-end devs by giving us the functionality we needed to make it through the endless approval process involved in publishing a mobile app. And we were able to do it all using HTML, CSS and JS.</p>
<p>They've made a wealth of changes since I last used them a few years back, and the future for the tool looks brighter than ever. If you haven't checked out Ionic yet, take a look and see what you can do with a spare evening or two. It's really fun!</p>
<h2 id="whatscomingup">What's coming up!</h2>
<p>As much as I'd love to finish covering the other 20 tools right now, I know it's best to split this into a multi-part series. Up next are tools 20-16, all of which focused on tooling/ecosystem improvements. Can you guess what they might be?</p>
<p><em>Photo by <a href="https://unsplash.com/@toddquackenbush?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Todd Quackenbush</a> on <a href="https://unsplash.com/s/photos/tools?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></em></p>]]></content:encoded></item><item><title><![CDATA[WebdriverIO Chained Selector Quirkiness]]></title><description><![CDATA[I ran into a bit of niche issue regarding chained selectors the other day that was driving me mad trying to figure out what was wrong. ]]></description><link>https://blog.kevinlamping.com/webdriverio-chained-selector-quirkiness/</link><guid isPermaLink="false">5de54ac594669a2ae5e23346</guid><category><![CDATA[Webdriverio]]></category><dc:creator><![CDATA[Kevin Lamping]]></dc:creator><pubDate>Mon, 02 Dec 2019 18:17:27 GMT</pubDate><media:content url="https://blog.kevinlamping.com/content/images/2019/12/chains.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.kevinlamping.com/content/images/2019/12/chains.jpg" alt="WebdriverIO Chained Selector Quirkiness"><p>I ran into a bit of niche issue the other day that was driving me mad trying to figure out what was wrong.</p><p>I'm not sure how it should, or even if it should, be documented, but I figured it's worth mentioning here for anyone interested.</p><p>Basically, I have this HTML structure:</p><pre><code>&lt;div id="imageInput" class="imageComponent"&gt;
    &lt;input type="file" /&gt;
    &lt;div class="imageComponent"&gt;
        &lt;input type="file" /&gt;
    &lt;/div&gt;
&lt;/div&gt;
</code></pre><p>I want to target that second file input, but I'm using a "component" so i have a "parent" element to go off of:</p><pre><code>class ImagePicker () {
    constructor () {
        this.selector = '#imageInput'
    }

    get $origin () { return $(this.selector); }
    get $imageInput () { return this.$origin.$('.imageComponent input[type="file"]'); }
}
</code></pre><p>Strangely, that <code>$imageInput</code> element reference would fail as it selected the first input.<br>However, if I didn't use the <code>$this.origin</code> reference, and included the parent selector in my reference it works just fine:</p><pre><code>get $imageInput () { return $('#imageInput .imageComponent input[type="file"]'); }
</code></pre><p>So that doesn't make any sense, right? <code>this.$origin</code> is equal to <code>$('#imageInput')</code>, so <code>this.$origin.$('.imageComponent input[type="file"]')</code> should be the same as <code>$('#imageInput .imageComponent input[type="file"]')</code>...</p><p>But it's not.</p><p>The reason is that the chained <code>$</code> starts from the 'outside' of the origin element, so the <code>.imageComponent</code> selector matches the <code>$origin</code> element, not the child one, meaning the selector actually looks like <code>$('#imageInput.imageComponent input[type="file"]')</code> (i.e. no space between <code>#imageInput</code> and <code>.imageComponent</code>).</p><p>This functionality is normally unseen, as most HTML structures don't have a parent-child relationship that shares the same class name.</p><p><a href="https://webdriver.io/docs/selectors.html#chain-selectors">In the WebdriverIO docs</a>, it says that when you chain selectors (e.g. <code>$('.parent').$('.child')</code>, "WebdriverIO starts the query from that element" (i.e. <code>$('.parent')</code>).</p><p>I read that as "it starts looking from inside the parent element", not, "it looks at the parent element first". I don't know how I'd word it though to clear that ambiguity, otherwise I'd submit a PR to update the docs 😄 I think it's just based on an internal assumption I've already made.</p><p>I was curious how the DOMs <code>querySelector</code> functionality behaves, and it turns out it's the same. <code>document.querySelector('#imageInput').querySelector('.imageComponent input[type="file"]')</code> has the same "issue". In fact, it has its own quirkiness: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector#The_entire_hierarchy_counts">https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector#The_entire_hierarchy_counts</a></p><p>So what are my options?</p><p>An easy workaround is to change our element reference to include a second <code>.imageComponent</code> reference:</p><pre><code>get $imageInput () { return this.$origin.$('.imageComponent .imageComponent input[type="file"]'); }
</code></pre><p>I really don't like that because honestly it's an ugly selector and oddly specific.</p><p>A better fix would be to edit the HTML, but that's not always possible.</p><p>One really interesting option is <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:scope">the <code>:scope</code> pseudo-class selector</a>. It's not really useful in stylesheets, but when called on an element via <code>querySelector</code>, it matches that element. So <code>$('#imageInput').$(':scope .imageComponent input[type="file"]')</code> is the same as <code>'$('#imageInput').$('#imageInput .imageComponent input[type="file"]')'</code>.</p><p>That looks funny, so let's see how we'd use it back in our <code>$imageInput</code> element reference:</p><pre><code>get $imageInput () { return this.$origin.$(':scope .imageComponent input[type="file"]'); }
</code></pre><p>One drawback of this approach is that <code>:scope</code> is relatively unknown, so anyone reading the code would have to look it up to understand why it's being used, so you'll probably want to leave a comment about it anytime you use this.<br><br>Overall, you likely won't run into this issue, but I could see it causing trouble on things like nested menus where classes are re-used in the nested elements. One of those things that you'd never know you need to know it, until you need to know it 😆</p><p><em>Header Photo by <a href="https://unsplash.com/@neural_notworks?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Shaojie</a> on <a href="https://unsplash.com/s/photos/chain?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></em></p>]]></content:encoded></item><item><title><![CDATA[Puppeteer Vs. WebdriverIO]]></title><description><![CDATA[Both are great options; the one you choose should depend on your needs.]]></description><link>https://blog.kevinlamping.com/puppeteer-vs-webdriverio/</link><guid isPermaLink="false">5de548b794669a2ae5e23330</guid><category><![CDATA[Webdriverio]]></category><category><![CDATA[Coding]]></category><category><![CDATA[Testing]]></category><category><![CDATA[Programming]]></category><category><![CDATA[puppeteer]]></category><dc:creator><![CDATA[Kevin Lamping]]></dc:creator><pubDate>Mon, 02 Dec 2019 17:27:50 GMT</pubDate><content:encoded><![CDATA[<p>Here's my opinion on the two libraries. </p><p>Both are great options. </p><p>Puppeteer is a neat library, but it is limited to just Chrome. It also doesn't come with ready-to-go utils for third-party services like Sauce Labs or test reporters.</p><figure class="kg-card kg-embed-card"><iframe width="480" height="270" src="https://www.youtube.com/embed/6IOrp8HgnJU?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></figure><p>If you're looking at writing a simple web scraper, or have some form entry you want to automate for non-testing purposes, I'd say go with Puppeteer.</p><p>But if you're looking at writing test automation, WebdriverIO is going to give you a lot more functionality for not much more effort.</p><p>So choose the tool depending on the need you have :)</p>]]></content:encoded></item><item><title><![CDATA[Set Keyboard Focus on an Element via WebdriverIO]]></title><description><![CDATA[<p>Sometimes you need to set the focus on a specific element when running a test in WebdriverIO. For example, I recently wanted to test that pressing the 'spacebar' would toggle a setting. To do this, I needed to focus the element, then send a 'spacebar' keypress.</p><p>This is relatively easy</p>]]></description><link>https://blog.kevinlamping.com/set-keyboard-focus-on-an-element-via-webdriverio/</link><guid isPermaLink="false">5db34bd394669a2ae5e2330a</guid><category><![CDATA[Webdriverio]]></category><category><![CDATA[Testing]]></category><dc:creator><![CDATA[Kevin Lamping]]></dc:creator><pubDate>Fri, 25 Oct 2019 19:40:03 GMT</pubDate><content:encoded><![CDATA[<p>Sometimes you need to set the focus on a specific element when running a test in WebdriverIO. For example, I recently wanted to test that pressing the 'spacebar' would toggle a setting. To do this, I needed to focus the element, then send a 'spacebar' keypress.</p><p>This is relatively easy to do in WebdriverIO via the <code>browser.execute</code> command. What we'll do is run a small JavaScript snippet on the page, calling <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLOrForeignElement/focus">the built-in <code>focus</code> function</a> available on all DOM elements (note, the element must be '<a href="https://stackoverflow.com/a/1600194">focusable</a>').</p><p>Here's what the code looks like:</p><pre><code class="language-js">it('should toggle checkbox when spacebar pressed and focused on label', function () {
    const toggle = $('.someComplexToggleElement');
    
    // run javascript to put keyboard focus on checkbox label
    browser.execute(function (label) {
        label.focus();
    }, $('label'));

    // press spacebar to toggle
    browser.keys(['Space']);
    expect(toggle.getAttribute('checked')).to.equal(true);

    // toggle once more just to make sure
    browser.keys(['Space']);
    expect(toggle.getAttribute('checked')).to.equal(false);
});
</code></pre>
<p>You could even add this as a WebdriverIO command:</p><pre><code class="language-js">browser.addCommand('focus', function () {
    browser.execute(function (domElement) {
        domElement.focus();
    }, this);
}, true);
</code></pre>
<p>And then run it via:</p><pre><code class="language-js">it('should use my custom command', function () {
    $('label').focus();
})
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Why I Hate Remote Working (But Still Prefer it to an Open Office Environment)]]></title><description><![CDATA[Remote working is considered the next revolution in the workplace, but I kind of hate it. Here are six reasons why remote working can really suck.]]></description><link>https://blog.kevinlamping.com/why-i-hate-remote-working/</link><guid isPermaLink="false">5db07a8c94669a2ae5e232fd</guid><category><![CDATA[remote]]></category><category><![CDATA[working]]></category><category><![CDATA[Productivity]]></category><dc:creator><![CDATA[Kevin Lamping]]></dc:creator><pubDate>Wed, 23 Oct 2019 16:12:03 GMT</pubDate><media:content url="https://blog.kevinlamping.com/content/images/2019/10/fork.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.kevinlamping.com/content/images/2019/10/fork.jpg" alt="Why I Hate Remote Working (But Still Prefer it to an Open Office Environment)"><p>Remote working is considered the next revolution in the workplace, but I kind of hate it. What would cause me, who wrote an article titled &quot;<a href="https://blog.kevinlamping.com/-why-i-love-remote-working/">Why I Love Remote Working</a>&quot;, to say that? Honesty.</p>
<p>There are many reasons to hate remote working, and I find it important to recognize those drawbacks. By being open about the issues remote working introduces, we can better equip ourselves to grow the practice.</p>
<p>Many companies are taking a &quot;<a href="https://www.remoteonly.org/">remote-only</a>&quot; approach. Because of this growing trend, I've been able to work remotely for over 4 years. In that time, I've faced many challenges that hopefully I can provide insight on.</p>
<h2 id="remoteworkislonelybusiness">Remote work is lonely business</h2>
<p>The number one drawback of remote working is it's isolation. There are no random interactions during coffee breaks, no running to grab lunch with co-worker, and no friday afternoon nerf battles (unless you have kids at home).</p>
<p>While an introvert like myself finds solace in not being surrounded by people all day, it's unhealthy to be isolated from people for extended periods of time.</p>
<h3 id="solution">Solution</h3>
<p>I believe that companies who support remote work should absolutely pay for a coffeeshop card and/or co-working space. This can easily be justified by comparing it to the cost of having to have office space. It's a small gesture that can have a big impact on someone's mental health. Companies should have an intrinsic motivation to take care of their employees, and this is a good step towards that.</p>
<p>Also, as a remote employee, make extra effort to be part of local tech groups. Also, join non-tech, hobby-related groups in town. Make up for that missing face-to-face time to help stay connected with humanity.</p>
<h2 id="itcanleadtoalessactiveday">It can lead to a less active day</h2>
<p>The joke about remote working is that your commute is the 10 steps from the kitchen to your desk. That's great, except when those are the only steps you're getting in all day.</p>
<p>In an office setting, you're walking to/from the parking lot, to/from the bathroom and jumping from meeting to meeting. While you can certainly still have a low-level of movement overall in the day, at least you're forced to walk some sort of extended distance.</p>
<h3 id="solution">Solution</h3>
<p>Commit yourself to at least one physical activity in the middle of the workday. Don't feel guilty for spending time being active. It's your health!</p>
<p><img src="https://thepracticaldev.s3.amazonaws.com/i/s6fr5dq5kcpyr3oseycw.jpg" alt="Why I Hate Remote Working (But Still Prefer it to an Open Office Environment)"></p>
<p>Many companies offer gym memberships, so take advantage of that. Also, if your company has an on-site gym (several larger companies do), ask you manager for a similar benefit. Again, you're saving the company money in not having to provide office space for you, so they should be able to find it in the budget.</p>
<h2 id="itcanhurtyourcareerslowerpromotionsmoredifficulttobreakintomanagement">It can hurt your career (slower promotions, more difficult to break into management)</h2>
<p>In some companies, there's definitely a glass ceiling for remote workers. While the company may be okay with Individual Contributors working remote, they want their management level employees to all be co-located. This means, as a remote worker, your promotions will always be limited at that company. It's frustrating, but it is also reality in many situations.</p>
<p>Another unfortunate truth is that if you're one of the only remote workers on your team, your work won't be as visible as those in the office. This means when it comes time for promotions, managers will be thinking about those they've seen in the office producing, not those out-of-sight doing quiet work in the background. Yes, this is a management problem (as they should be promoting/rewarding their most productive employees), but it's also your responsibility to work through.</p>
<h3 id="solution">Solution</h3>
<p>Make sure you know where you want to be five years down the road. Don't rely on a big management mindset shift happening in regards to management being able to work remote. It may happen, but it's a big shift for many companies who are often afraid of that level of change.</p>
<p>Openly advocate for yourself to grow your career. Good advice in general, but absoutely necessary in this instance. I won't go into detail on what that means, because there are many great articles already written on it here and elsewhere on the internet.</p>
<p>Also, &quot;brag&quot; about your work. In chat rooms, post updates about things your working on and things that are causing trouble. Be visible there because you're not visible in the office.</p>
<h2 id="morecompetitionlesspay">More competition, less pay</h2>
<p>Remote work is amazing because it gives you the freedom to work anywhere in the world. But this also means that anyone in the world can apply for the same job you want. Since cost-of-living differs dramatically across the globe, this means you may be competing with someone who can work for significantly less income than you. As a business, they're motivated to keep expenses low, and if someone can do just as effective job as you for half the rate, they're going to take that deal.</p>
<h3 id="solution">Solution</h3>
<p>Don't be afraid to ask for the rate you need in order to live, but also consider using your freedom to move to a lower cost-of-living (COL) location. Give yourself a competitive advantage in this regard. There are some very beautiful, smaller cities across the globe. I recently moved from a large city to one a tenth of its size and I love it. The COL is about the same (it was a lower COL large city compared to NYC, etc), but the city feel so much more accessible. I'm able to bike almost anywhere around town and I never run into big-city traffic.</p>
<p><img src="https://thepracticaldev.s3.amazonaws.com/i/97zb5ufgkmjw90uel0j0.jpg" alt="Why I Hate Remote Working (But Still Prefer it to an Open Office Environment)"></p>
<p>Also, in interviews, really push your soft-skills experience. This can be a major difference between you and other applicants, and many companies will happily pay extra on the bet that they're getting a more mature employee.</p>
<p>Finally, many companies in high COL areas are looking outside their city for employees who won't break the bank in salary. Watch out for those jobs, as they'll happily pay the same or higher than local companies, since it's still cheaper than hiring in their city.</p>
<h2 id="hardertogetstartedinthemorningandendintheevening">Harder to get started in the morning and end in the evening</h2>
<p>Without a commute and walk into an official office, it can be a little difficult to make that transition from waking up to being productive. And then when the end of the day comes, it can be tempting to just fix that one last bug. You don't see everyone else in the office leaving, so you forget that you should probably head out as well.</p>
<h3 id="solution">Solution</h3>
<p>Find a morning routine that works. Pomodoro is a great option to get started. I do 10 minutes focused work with an optional 2 minute break. Many times I skip the break when I'm in a flow. But knowing that I'm only committing to 10 minutes, instead of that full 8-hour work day, makes all the difference in my getting started.</p>
<p>And at the end of the workday, remember that often, stepping away from the problem for the day can be the perfect solution. Just this morning I fixed a bug in five minutes that I was struggling with all yesterday afternoon. It was only by taking a break from the issue that I was able to break out of the unproductive debugging I was doing and see the code in a new light.</p>
<h2 id="youreconstantlyremindedofalltheworkthatneedstobedonearoundthehouse">You're constantly reminded of all the work that needs to be done around the house</h2>
<p>No one keeps their dirty laundry at the office (well, some co-workers do, but let's not talk about them). But at home, anytime you take a break, you're surrounded by all the house chores you need to get done. &quot;Let me grab a quick snack oh yeah the sink is full of dirty dishes&quot;. &quot;I'm going to take a quick break oh no the cat knocked over the magazine stack I might as well pick it up oh and who put that there, let me put that away really quick and I should really organize this drawer so it's easier to find things...&quot;</p>
<p><img src="https://thepracticaldev.s3.amazonaws.com/i/x6nrsnrqh2l4ycneofte.jpg" alt="Why I Hate Remote Working (But Still Prefer it to an Open Office Environment)"></p>
<p>You get the idea. Those are thoughts we have in an office (most of the time), since we're not surrounded by our never-ending chore list. Aside from watering a desk plant every now and then, most of the office maintenance is handed by a dedicated crew. That's not the truth at home and it can constantly take over what are supposed to your breaks.</p>
<p>And honestly, when facing a particularly tough situation at work, you might actually be motivated to do the dishes instead. Not that this isn't an effective &quot;step back&quot; strategy in some situations, you just shouldn't use it as a reason to avoid the job your paid to do.</p>
<h3 id="solution">Solution</h3>
<p>Make room for an office space. Have dedicated snacks/water in your office. Have a good break area that isn't a constant reminder of all you need to get done around the house.</p>
<p>If you don't have that as an option, get out of your house to a nearby coffeeshop, hotel lobby, car dealership (pretend your car is being worked on while you pig out on their free coffee and donunts). Stop mixing your personal workspace with your professional workspace. It'll only cause you to stress out and raise your anxiety to unproductive levels.</p>
<h2 id="ireallydoloveremoteworking">I really do love remote working</h2>
<p>Even with all of these reasons to hate it, remote working is definitely for me. There are always going to be drawbacks of certain working situations, and it's useless to deny them. If you work remotely, take a look at things that bother you and address them. Don't pretend they don't exist, like you're living in some make-believe world.</p>
<p>Remote workers, what things do you hate about the life? What solutions have you found to address them?</p>
<p>Also, <a href="https://theoatmeal.com/comics/working_home">this Oatmeal comic on the love/hate relationship with remote working</a> is fantastic!</p>
<p><em>Photo credits (via <a href="https://unsplash.com/">Unsplash</a>):<br>
<a href="https://unsplash.com/@maundytime">Fork Photo by Catt Liu</a><br>
<a href="https://unsplash.com/photos/LxGDv7VA9M">Workout Photo by Sven Mieke</a><br>
<a href="https://unsplash.com/photos/QrgRXH81DXk">City Photo by Monica Bourgeau</a><br>
<a href="https://unsplash.com/photos/OzAeZPNsLXk">Cat Photo by Max Baskakov</a></em></p>
]]></content:encoded></item><item><title><![CDATA[Come on WebdriverIO, Fail Already]]></title><description><![CDATA[<p>There are times when I'm debugging a flakey test and I can't get it to fail. Yes, that's a real problem!</p>
<p>If you're working on a test that intermittently fails, it's useful to have a snippet that will run your test again and again until it fails. This is both</p>]]></description><link>https://blog.kevinlamping.com/come-on-webdriverio-fail-already/</link><guid isPermaLink="false">5daf69a794669a2ae5e232ce</guid><category><![CDATA[Webdriverio]]></category><category><![CDATA[Testing]]></category><category><![CDATA[Programming]]></category><dc:creator><![CDATA[Kevin Lamping]]></dc:creator><pubDate>Tue, 22 Oct 2019 21:21:46 GMT</pubDate><media:content url="https://blog.kevinlamping.com/content/images/2019/10/ugh.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.kevinlamping.com/content/images/2019/10/ugh.jpg" alt="Come on WebdriverIO, Fail Already"><p>There are times when I'm debugging a flakey test and I can't get it to fail. Yes, that's a real problem!</p>
<p>If you're working on a test that intermittently fails, it's useful to have a snippet that will run your test again and again until it fails. This is both to get to the state that it's failing easier, and to prove that most likely, the bug is fixed (if it doesn't fail after 10 test runs, chances are it's no longer an issue).</p>
<p>While you could just manually re-run your test again and again until it fails, what if you're lazy like me and want to automatically restart the test if it passed?</p>
<p>Thanks to <a href="https://stackoverflow.com/questions/12967232/repeatedly-run-a-shell-command-until-it-fails">an answer via Stack Overflow</a>, you can do just this.</p>
<p>This shell function can be added to your <code>.bashrc</code> file (or<a href="https://medium.com/coding-blocks/getting-to-understand-linux-shell-s-start-up-scripts-and-the-environments-path-variable-fc672107b2d7"> whatever file your terminal program auto-loads on startup</a>)</p>
<pre><code class="language-shell">function untilfail() {
    while $@; do :; done
}
</code></pre>
<p>Then, after sourcing that file (or restarting your terminal), you can use it to run your WDIO script:</p>
<pre><code class="language-shell">$ untilfail npx wdio --spec=failingTest.js
</code></pre>
<p>Want to just run it a set number of times? <a href="https://www.shellhacks.com/linux-repeat-command-n-times-bash-loop/">Here's a different function</a> you can use:</p>
<pre><code class="language-shell">function run() {
    number=$1
    shift
    for i in `seq $number`; do
      $@
    done
}
</code></pre>
<p>To use it to run wdio 5 times, pass in the number after the command:</p>
<pre><code class="language-shell">$ run 5 npx wdio --spec=failingTest.js
</code></pre>
<p>Note that this second version won't stop running if there's a test failure. It'll keep running until you force it to stop, or it goes through the number of runs you requested.</p>
<p><em>Header Photo by <a href="https://unsplash.com/@nate_dumlao?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Nathan Dumlao</a> on <a href="https://unsplash.com/s/photos/fail?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></em></p>]]></content:encoded></item><item><title><![CDATA[What to do about Twitter...]]></title><description><![CDATA[(1/30) It should be no surprise that this is a terrible, terrible place for public debates. A thread...]]></description><link>https://blog.kevinlamping.com/what-to-do-about-twitter/</link><guid isPermaLink="false">5d9f493094669a2ae5e2324b</guid><category><![CDATA[Technology]]></category><dc:creator><![CDATA[Kevin Lamping]]></dc:creator><pubDate>Thu, 10 Oct 2019 16:13:04 GMT</pubDate><media:content url="https://blog.kevinlamping.com/content/images/2019/10/dumpster.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.kevinlamping.com/content/images/2019/10/dumpster.jpg" alt="What to do about Twitter..."><p>I'm in an abusive relationship. My partner is a controlling, jealous, nightmare. There's a good chance you're involved in this too.</p><p>Of course, I'm talking about Twitter. The social media giant that has everyone up in arms about everything.</p><p>Why is it this way though? Why do we continue to go to that platform when it's so obviously toxic? Hmm, maybe I should explain why I think it's obviously toxic (in case it's not obvious to you):</p><h2 id="everything-on-twitter-is-public">Everything on twitter is public</h2><p>This is the best/worst part of twitter. With everything being public, you can hear voices you never would have otherwise. You can meet people and form great connections.</p><p>If you're incredibly lucky.</p><p>If you're normal lucky or below, all you meet are people trying to find meaning in their life by arguing with strangers (I'm very guilty of this). A small percentage of these folks are assholes, who are mean just to be mean. Once you spot them, they're pretty easy to ignore.</p><p>But the majority of folks are smart and passionate about their cause. They see twitter as a way to make an impact and really believe that they can change lives through the medium. Which brings me to my next point:</p><h2 id="twitter-isn-t-built-for-changing-lives">Twitter isn't built for changing lives</h2><p>The short-form communication setup of twitter is a double-edged sword. Limiting thoughts to 240-character sized chunks is fantastic for encouraging people to write. Your brain knows it doesn't have to commit to a five-page thesis; it only has to type out a few sentences. </p><p>So it becomes really easy to do that. You get to say something somewhat intelligent without the overwhelming effort of a fully-fleshed out defense. It's an incredibly easy way to feel a sense of purpose.</p><p>And with that comes the other side of the blade. Assertions on twitter will always, always be poorly constructed. No matter how well stated, you can't make a claim with ample evidence and counter-arguments pre-refuted and still fit it on twitter*. </p><p>Simply stating that last sentence took up half my allotted characters. So far, this blog post would take up 10 separate tweets.</p><p>* Yes, you can do the multi-tweet thread thing that people half-read and you don't know where to respond to so the conversation is completely lost and confusing and awful. Yes, you can do that, if you really want.</p><h2 id="everyone-wants-junk-food">Everyone wants junk food</h2><p>Twitter is junk food. It tastes so fucking good sometimes. So good you'll want to spend all day consuming it.</p><p>"Hey, that person agrees with me! This is going to feel so good to retweet! Ah, I hit that retweet button now everyone who reads this is going to finally be on my side. Oh I gotta do that again!"</p><p>"Hey, that person disagrees with me! But they have a flaw in their argument because all twitter arguments are too short to not have flaws! I'm going to point this obvious fact out to them and they agree with how completely wrong they are! Oh, they responded, saying obviously they didn't mention that counter-argument because it's well-refuted with another counter-argument. But they didn't mention this other thing because no one has room for that so I'm going to point it out and they'll agree with how completely wrong they are!"</p><p>It never works. The sentences and attention spans are always too short. We just fill ourselves up with this junk discussion and end the day feeling just as empty inside as when we started. Maybe the solution for the next day is to consume just a little more, better junk, then we'll be satisfied.</p><h2 id="so-twitter-is-toxic-now-what">So twitter is toxic... now what?</h2><p>Combine an excessively-public forum with woefully truncated statements and a bunch of people seeking some form of meaning in an overwhelmingly nihilistic world, and you get twitter. </p><p>It should be absolutely no surprise to anyone that this is a terrible, terrible place for public debates. Yet we find ourselves continuing to come back to it? Why?</p><p>Because junk food tastes so good and is a hell of a lot easier to make than a full-course meal.</p><p>'Hmm, i'm a little bit hungry... should I spend an hour cooking a healthy and delicious baked chicken parmesan dinner with mashed potatoes and fresh cooked green beans on the side, or should I just grab two oreo cookies, stuff them in my mouth and savor the short but ever sweet moment...' </p><p>Here are a few alternatives to twitter:</p><ul><li>Blog posts like these</li><li>Longer-format online discussion boards</li><li>Face-to-face conversations</li></ul><p>I like blog posts. They're fun to write and I get to really think out ideas. But I can't write a blog post on my phone while I rock the baby to sleep. I also can't do it while in the waiting room for my next appointment or sitting on the can dropping a deuce. I can check twitter while doing those things though!</p><p>Also, for some reason, when writing a blog post, I want to double check everything. I treat the writing with much more respect and want to ensure I get it right. That adds yet another hour or two to the process, because there are just so many more words to adjust. I do the same thing with my tweets most of the time, but it's always limited to a sentence or two. Not three pages of text.</p><p>Online discussion boards are another good option, but they run into the same issue as with blog posts. There's just little time for this and you're still arguing with strangers on the internet. </p><p>Face-to-face conversations, even for introverts like me, are a great idea. But how do you find them or make time for them? It's difficult to get out of the house to go to a pub and talk about the [insert thing 1000 miles away] when you've got three kids who need dinner, baths, teeth-brushing, bedtime stories and to be coerced back to sleep at midnight.</p><p>All during that time, twitter is whispering in your ear "check me... check me... maybe you got a like! maybe someone retweeting that awesome thing you said! maybe you're tweet is going viral and you're missing out on all the fun!"</p><p>Then you check and you see either no responses, or if you're unlucky, some asshole has responded with a really poor counter-argument that would be so satisfying to refute. And you're hooked.</p><h2 id="where-to-go">Where to go?</h2><p>Despite all of this, twitter is useful. It can be hilariously funny. You can have good discussions with people you know on topics that aren't incendiary. That's what keeps me coming back. </p><p>But I'm wondering if that's worth the cost. The frustration at saying things and not being heard. At wanting to play devil's advocate, but getting called a bigot or hateful for doing so. There is no such thing as "for the sake of argument" on twitter. You're either for them or against them. </p><p>So for me, I want to write more on here. I want to fight the temptation to make a quick post on twitter, and commit to spending the time writing out full thoughts here. I end up investing the same amount of time, but here, I might actually get a return.</p><p>That's all. Now to post this to twitter to see if I can get any likes or retweets :)</p><p><em>Header Photo by <a href="https://unsplash.com/@kevin_butz?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Kevin Butz</a> (hah) on <a href="https://unsplash.com/s/photos/dumpster?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></em></p>]]></content:encoded></item><item><title><![CDATA[Here, There be Documentation]]></title><description><![CDATA[Client don't care about code quality, but that doesn't matter to me. So what do dragon's have to do with them anyway?]]></description><link>https://blog.kevinlamping.com/here-there-be-documentation/</link><guid isPermaLink="false">5d4890ce94669a2ae5e2322a</guid><category><![CDATA[Coding]]></category><category><![CDATA[Programming]]></category><category><![CDATA[Testing]]></category><dc:creator><![CDATA[Kevin Lamping]]></dc:creator><pubDate>Wed, 07 Aug 2019 14:16:48 GMT</pubDate><media:content url="https://blog.kevinlamping.com/content/images/2019/08/dragon.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.kevinlamping.com/content/images/2019/08/dragon.jpg" alt="Here, There be Documentation"><p>"Honestly, does the client even care if the code is formatted or not?"</p><p>Have you ever had someone tell you this? Or maybe you're guilty of repeating that line. I know I am.</p><p>"Sure, I know standards are important, but we really don't have time to worry about that right now. The client just wants this feature shipped."</p><p>That's hard to argue against. The end result is what matters, especially when working for someone else. One the other hand, the idea of standards is to allow the team to ship faster (even if it takes an up-front investment). The client definitely cares about that.</p><p>So why are we unable to connect the dots between standards and the client's satisfaction? I have a theory.</p><p>Teams know standards are important, but they don't know how to make them happen. Typically, best practices becoming someone's "thing". Unit Testing is Allison's "thing". Code semantics is Bobby's "thing". Accessibility is Rachel's "thing".</p><p>But those "things" never become part of the collective mindset. There's no team ownership, no binding vision; just a bunch of things people are individually interested in. Managers encourage individual ownership, but withhold authority to implement the needed team-wide change.</p><h3 id="an-adventure-starts">An Adventure Starts</h3><p>Let's think about what happens when individual "coding standard champions" are declared. Even when the team likes the idea, only the Champion makes the long-term changes needed to implement the solution.</p><p>Rather than addressing the lack of real buy-in from the group and the need for standards enforcement across the team, the Champion is encouraged to take individual accountability by management. This would look good on their mid-year review after all.</p><p>So the Champion goes off, fighting a huge battle to convert the codebase from the wicked ways of the past. They defeat the evil Tab dragon and travel back home with their Spaces safely in hand. It takes longer than expected, but feels good to have completed the work.</p><p>But what do they see when they arrive back home, weary from their travels?</p><p>Hundreds of new dragons hatching in the forms of poorly documented code and untested features. Why is no one dealing with these dragons before they become too big?! Oh, because it was the Champions thing. They're in charge of that.</p><p>So the Champion, still afraid to ask for real help, starts slaying these new dragons left and right. But then someone needs an outside resource and leaves the town gate open. New dragons come flooding in. Soon the Champion is overwhelmed with work, and fears another gate will be let open at any point in time, continuing the downward spiral.</p><p>So they put down their sword and the dragons take over. Someone asks months later, "Oh hey, weren't you fighting these things?" to which the Champion responds, "Yeah, but the client doesn't really care about dragons in our village, right? They just want to know the festival is going to happen and it's already a tight enough deadline."</p><h3 id="time-runs-out">Time Runs Out</h3><p>Work continues until the festival time is near. There are dragons everywhere. They're eating the food. They're burning down the tents. Everyone is frantically running around trying to repair the chaos, but no one can get a handle on it.</p><p>The client is understandably upset. They hear talk of dragons ruining their festival and want to know why. To calm the client, promises are made to eradicate the dragons causing this chaos. But the festival must be moved back a couple weeks. The client, afraid to lose their investment, accepts the proposal.</p><p>Meetings are set up defining how best to slay these creatures. Champions are declared to deal with specific colors of dragons. Joe will take the green ones. Marcy will take the red. We'll meet in two weeks to see how things are going.</p><p>So Joe and Marcy start slaying dragons left and right. They're starting to get a handle on it; even teaming up in parts of town where there are a lot of both kind. They feel refreshed to have an ally in this fight and feel like they're making real progress.</p><p>Unknown to them though, the client is upset about the delay and wants a special tent installed as repayment. But Marcy is the only one who knows how to install that type of tent and she's already busy with very important work.</p><p>Without another rational choice, management decides to bring an outside worker in who specializes in all sorts of tents. They've promised to get this one installed in under two days. And they do. A couple days later the tent is up and Marcy and Joe have finished their work. All seems well.</p><h3 id="hidden-in-plain-sight">Hidden In Plain Sight</h3><p>The night before the big celebration, Marcy is walking around the various tents double checking tie downs and ensuring no dragons are lurking in dark corners. She comes to the special tent and notices something interesting about it. The beams holding the structure up are a different type of wood.</p><p>That's strange. Normally these poles come from a specific lumber mill, known for its quality. These must be different.</p><p>As she inspects closer, she notices strange holes in the wood. Then she notices it. The entire structure is swaying uneasily in the gentle breeze.</p><p>She immediately understands what's happening. The builder used cheap, rotted lumber — Lumber that's filled with wood-boring insects. These bugs are gnawing at the material, tearing it to shreds. She runs for helps as several adult beetles fly by her ear towards a neighboring tent.</p><p>She gathers the team in an emergency meeting. They decide they must hide the issue from the client. It's too late now to rebuild the structure; they can only hope it will survive the next few days of partying. They'll pull an all-nighter working to treat the bug infestation while the client sleeps.</p><h3 id="a-terrible-success">A Terrible Success</h3><p>It works. It works so well the client wants another party. In fact, the client wants parties like this every month. What a success for the team, right?</p><p>But they know the real truth. Their fixes worked, but they were unable to stop the bugs from spreading. The adult beetles surely laid eggs in every piece of wood throughout the fairgrounds. If they don't spend every day working to treat new infestations, the bugs will once again take over.</p><p>The damage done has required special scaffolding be put in to keep the tents sturdy. It's functional, but is delicate and difficult to adjust as the client's needs shift. They've already had to tell them that the jousting arena can't be upgraded because of "structural dependencies".</p><p>Joe, Marcy, and the rest of the team, once brave adventurers setting out to explore the landscape, are now confined to the city walls in a never-ending battle with the insects. Insects they had worked so hard at the start to keep out. They used the right materials sourced from the right people made in the right way.</p><p>But the client didn't care about that. The client just wanted a tent. And now Marcy has stopped caring as well. Why worry about using quality wood when it will just end up rotted anyway? This endless bug-squashing has worn her down. She's no longer motivated to start her day. Why should she? It's nothing new... just playing wack-a-mole against the insects.</p><p>New workers are brought in as she struggles to keep up. They also don't care about quality. They just need the steady income. They're satisfied squashing bugs. Every new tent for them means more job security. So they put up as many tents as they can, using whatever materials they find lying around.</p><p>Soon, the town becomes so filled with rotted wood that it becomes impossible to keep up the fight against the insects. Word is that the client doesn't like all the beetles buzzing around from square to square. A rumor has spread that the client is looking to move to a different town and a different company. A company that promises standards and quality craftsmanship; A company like this used one to be.</p><h3 id="a-new-start">A New Start</h3><p>In one last valiant effort, the team convinces the client to tear everything down and rebuild the city. They'll use the right materials this time. In fact, they'll invest in using the latest technology. Technology that comes with built-in pesticide. The beams are built to prevent insects from nesting, so it shouldn't be an issue.</p><p>The client is convinced and work begins.</p><p>Marcy, finding fresh motivation that she hasn't felt in years, sets up several meetings to help ensure standards are in place to keep this from ever happening again. She's excited to apply what she has learned to this new project. So many new ideas to try.</p><p>Her first: we must have quality control and follow strict guidelines in how work is done. People are excited, but a little skeptical. Won't that take extra time? Isn't this project big enough?</p><p>And honestly, does the client even care if the code is formatted or not?</p><p><em>Header photo credit: https://unsplash.com/photos/vVKbHNhu2ZU</em></p>]]></content:encoded></item><item><title><![CDATA[Using WebdriverIO and Applitools to visually test your website]]></title><description><![CDATA[<p>I'm a front-end developer.</p>
<p>I love how visually appealing my job can be. I get to transform beautiful designs into fully-functioning websites.</p>
<p>But I hate how that beautifully working website can so easily turn into a mess with just a single code update.</p>
<p>I also hate how that mess can</p>]]></description><link>https://blog.kevinlamping.com/using-webdriverio-and-applitools-to-visually-test-your-website/</link><guid isPermaLink="false">5ba4180f4c78821e1889c573</guid><dc:creator><![CDATA[Kevin Lamping]]></dc:creator><pubDate>Tue, 29 Jan 2019 17:45:18 GMT</pubDate><media:content url="https://blog.kevinlamping.com/content/images/2019/05/josh-calabrese-527813-unsplash.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.kevinlamping.com/content/images/2019/05/josh-calabrese-527813-unsplash.jpg" alt="Using WebdriverIO and Applitools to visually test your website"><p>I'm a front-end developer.</p>
<p>I love how visually appealing my job can be. I get to transform beautiful designs into fully-functioning websites.</p>
<p>But I hate how that beautifully working website can so easily turn into a mess with just a single code update.</p>
<p>I also hate how that mess can hide in the metaphorical corner for days or weeks until it's finally discovered by a customer or client.</p>
<p>While many teams validate their sites through a combination of manual and automated testing, design defects often sneak in due to the complexity of visual testing.</p>
<p>Manually checking the design of every page is difficult and time consuming, and <a href="https://en.wikipedia.org/wiki/Change_blindness">humans aren't all that great at noticing small differences over large areas anyway</a>.</p>
<p>To add on to that, most automated test libraries don't have the functionality needed to address visual testing at a large scale. While Selenium-based tools can capture screenshots of the page being tested, that's not nearly enough to run an real automated visual testing suite.</p>
<p>That's why Applitools is one of my favorite tools for visual testing. It comes with a suite of features that enable teams to capture and conduct visual reviews.</p>
<p>Recently, Applitools released a new SDK for WebdriverIO, which is my Selenium test library of choice.</p>
<h2 id="waitwhatswebdriverio">Wait, what's WebdriverIO?</h2>
<p>WebdriverIO is a JavaScript library for working with Webdriver, which is the &quot;remote control&quot; interface that runs behind the scenes of Selenium.</p>
<p>WebdriverIO is not the only JavaScript-based Webdriver interface out there, but I firmly believe it's the best.</p>
<p>There are a couple of reasons for this:</p>
<h3 id="itsfrontendfriendly">It's &quot;front-end friendly&quot;</h3>
<p>Unlike a lot of Selenium tools out there, WebdriverIO is written entirely in JavaScript. Even the Selenium installation is done through an NPM module.</p>
<p>I always thought browser automation meant figuring out how to get some complex Java test suite running, which just never sounded appealing to me. As a front-end developer, my strength lies in JavaScript and CSS, and WebdriverIO encourages this.</p>
<p>Not only does WebdriverIO let me write in a language that I'm familiar with, it also integrates with the same testing tools that I use for unit tests (e.g. Mocha/Jasmine/CucumberJS).</p>
<p>I believe that Front-end developers should write tests for their code (both unit and functional). WebdriverIO makes it incredibly easy for them to do.</p>
<h3 id="itstrivesforsimplicity">It Strives for Simplicity</h3>
<p>The commands you use in your WebdriverIO tests are concise and common sense.</p>
<p>WebdriverIO eliminates the need to connect two parts together that are obviously meant for each other.</p>
<p>For example, if I want to click a button via a normal Selenium script, I would have to use two commands: One to get the element and another to click it.</p>
<p>Why? If I'm clicking something, it's obvious I'm going to need to identify it first.</p>
<p>WebdriverIO simplifies the 'click' command by accepting the element selector right in to the command, and does the work itself to create the two Webdriver actions needed.</p>
<p>That means instead of writing this:</p>
<pre><code>driver.findElement(webdriver.By.id('btnG')).click();
</code></pre>
<p>I can just write this:</p>
<pre><code>browser.click('#btnG')
</code></pre>
<p>That saves me from having to write an overly verbose test.</p>
<h3 id="ithasgreatserviceintegration">It has great service integration</h3>
<p>One of the best benefits of WebdriverIO is it's built-in service layer. The layer <a href="https://www.npmjs.com/search?q=wdio%20service">allows anyone to add on</a> to already great functionality that WebdriverIO provides.</p>
<p>For example, there's <a href="https://www.npmjs.com/package/wdio-selenium-standalone-service">a service that manages starting up and shutting down a local Selenium server for you</a>. There's another set of services that better integrate WebdriverIO with third-party Selenium services like <a href="https://www.npmjs.com/package/wdio-sauce-service">Sauce Labs</a>.</p>
<p>There's even <a href="https://www.npmjs.com/package/wdio-visual-regression-service">a service to help you do visual testing</a>.</p>
<h2 id="waitwhydoineedapplitoolsthen">Wait, why do I need Applitools then?</h2>
<p>I'm a big fan of the visual regression service that I just mentioned; it's a great little service and can help individuals start down the path of visual testing, all without too much effort.</p>
<p>But it's missing a boat-load of features that Applitools offers.</p>
<p>First, it doesn't have a test dashboard, which is critical to managing screenshots across a team of people.</p>
<p>Second, it's not &quot;smart&quot;. With Applitools, you can define different regions, letting you handle visual regression in different ways through those regions.</p>
<p>The visual regression service just doesn't contain that functionality. You're stuck fighting false positives in your testing, slowing you and your team down.</p>
<p>That's why I was excited when I heard you can combine WebdriverIO and Applitools. I knew the power of both, and would love to see them working together.</p>
<h2 id="okayletsgetgoing">Okay, let's get going</h2>
<p>The first step to getting this awesome approach in place is to write some WebdriverIO tests.</p>
<p>Assuming we're in a NodeJS project, we'll first install WebdriverIO by running the following command:</p>
<pre><code>npm install webdriverio --save-dev
</code></pre>
<p>With WebdriverIO installed in our local project folder, we can run the next command:</p>
<pre><code>npx wdio config
</code></pre>
<p>This command will ask WebdriverIO to help us configure the framework. It will ask a series of questions, to which I recorded my responses:</p>
<pre><code>? Where do you want to execute your tests? **On my local machine**
? Which framework do you want to use? **mocha**
? Shall I install the framework adapter for you? **Yes**
? Where are your test specs located? **./test/specs/**/*.js**
? Which reporter do you want to use?  **dot - https://github.com/webdriverio/wdio-dot-reporter**
? Shall I install the reporter library for you? **Yes**
? Do you want to add a service to your test setup?  **selenium-standalone - https://github.com/webdriverio/wdio-selenium-standalone-service**
? Shall I install the services for you? **Yes**
? Level of logging verbosity **silent**
? In which directory should screenshots gets saved if a command fails? **./errorShots/**
? What is the base url? **https://applitools.com**
</code></pre>
<p>Upon answering that last question, WebdriverIO will install the tools and services you requested, then create a configuration file for you (named <code>wdio.conf.js</code>). This configuration file will be used in just a minute to help WebdriverIO run your test suite.</p>
<h3 id="ourfirsttest">Our first test</h3>
<p>Before we do run anything, we need to create a file containing a test to run. Here's an sample script used to load <a href="https://applitools.com/helloworld">the Applitools Hello World page</a>, then log out the title of said page.</p>
<pre><code class="language-js">describe('my first visual test', function () {
  it('should look visually perfect', function () {
    browser.url('./helloworld');

    const pageTitle = browser.getTitle();

    console.log(`Title of page is ${pageTitle}`)
  })
});
</code></pre>
<p>This file is saved in the <code>./test/specs</code> directory, and I named it <code>visual.js</code>.</p>
<p>To execute our test, we'll go back to the command line, then run:</p>
<pre><code>npx wdio
</code></pre>
<p>This will initialize WebdriverIO, which will search the current directory for a <code>wdio.conf.js</code> file. Upon finding that file, it will load the configuration, see where we told it to look for tests, find our new file and run it. The final output will look like:</p>
<pre><code> ~/Sites/wdio-applitools-demo$ npx wdio

Title of page is Applitools
․

1 passing (10.20s)
</code></pre>
<h2 id="addinginalittleapplitools">Adding in a little Applitools</h2>
<p>While our test works, it doesn't provide a whole ton of value. All it does is log out the title of the page, which isn't that likely to contain a defect.</p>
<p>While we could write a series of tests validating any number of features, that would take a lot of effort to do. Instead, we can take advantage of the awesome functionality inside of Applitools to get a quick return on our work.</p>
<p>First, we need to install the Applitools WebdriverIO SDK. To do that, run:</p>
<pre><code>npm install '@applitools/eyes.webdriverio' --save-dev
</code></pre>
<p>Then, we'll jump back into our test file and add a few things to finish our setup.</p>
<p>First, at the top of our file, we'll load Applitools and initialize it:</p>
<pre><code class="language-js">const {Eyes, Target} = require('@applitools/eyes.webdriverio');
const eyes = new Eyes();
</code></pre>
<p>To use the Eyes SDK, you need an API Key, which you can get by registering at <a href="https://applitools.com/users/register">the Applitools site</a>. Once you have that, login and <a href="https://eyes.applitools.com/">go to the Eyes admin tool</a>. You will find the API using the following menu:</p>
<p><img src="https://blog.kevinlamping.com/content/images/2018/07/1_-wlxJt1AeygBGNJo10rV_A.png" alt="Using WebdriverIO and Applitools to visually test your website"></p>
<p>To use the key, add the following line (after the one initializing a new Eyes instance):</p>
<pre><code class="language-js">eyes.setApiKey('YOUR_API_KEY');
</code></pre>
<p>Now that we have Eyes set up, let's put it to use.</p>
<p>Since we're going to be doing some complex work, it's best to wrap all of our code in a <code>try...catch</code> block, allowing us to handle any network failures.</p>
<p>This is what our code looks like so far:</p>
<pre><code class="language-js">const {Eyes, Target} = require('@applitools/eyes.webdriverio');
const eyes = new Eyes();
eyes.setApiKey(process.env.APPLITOOLS_KEY);

describe('my first visual test', function () {
  it('should look visually perfect', async function () {
    browser.url('./helloworld');

    const pageTitle = browser.getTitle();

    console.log(`Title of page is ${pageTitle}`)

    const viewportSize = browser.getViewportSize();

    try {

    } finally {

    }
  })
});
</code></pre>
<p>Inside our <code>try</code> block, we're going to do five things:</p>
<ul>
<li>Open a new Eyes test</li>
<li>Visually check the page</li>
<li>Make a WebdriverIO call to alter the page</li>
<li>Visually check the page again</li>
<li>Close the test as it's complete</li>
</ul>
<p>Here's what all of that looks like:</p>
<pre><code class="language-js">try {
	const viewportSize = browser.getViewportSize();
	
  await eyes.open(browser, 'Hello World!', 'My first Javascript test!', viewportSize);

  await eyes.check('Main Page', Target.window());

  browser.click('button');

  await eyes.check('Click!', Target.window());

  await eyes.close();
}
</code></pre>
<p>One important thing to notice is the use of the <code>await</code> keyword. <code>await</code> is a newer bit of functionality that helps us write cleaner tests by telling NodeJS to wait until the command has finished processing.</p>
<p>In order to use the <code>await</code> keyword, we need to define the function as <code>async</code>.</p>
<p>Thankfully that's easy to do.</p>
<p>In our <code>it</code> declaration, update it to include the <code>async</code> keyword:</p>
<pre><code class="language-js">it('should look visually perfect', async function () {
</code></pre>
<h3 id="almostready">Almost ready</h3>
<p>There's one last thing to do before running our newly updated test.</p>
<p>Because tests can break and networks can have issues, if we don't catch those outages, Applitools may show a failed test as &quot;running&quot; (since it was never told it was done running).</p>
<p>To avoid this, we're going to take advantage of that <code>finally</code> block to do some test cleanup. It will look like:</p>
<pre><code class="language-js">finally {
  await eyes.abortIfNotClosed();
}
</code></pre>
<p>With all of this in place, we finally have all the parts need to run an amazing automated visual test. We'll kick it off by running the <code>npx wdio</code> command again.</p>
<p>The output is going to look about the same, but if we go to <a href="http://eyes.applitools.com/">our Applitools dashboard</a>, we'll now see the results of our visual validation:</p>
<p><img src="https://blog.kevinlamping.com/content/images/2018/07/ss1.png" alt="Using WebdriverIO and Applitools to visually test your website"></p>
<h3 id="capturingfailures">Capturing failures</h3>
<p>The first time we ran our tests, Applitools created a set of baseline images to use for future runs.</p>
<p>If things go well, our next series of tests runs will match that set of baseline images, but we should ensure our tests fail if they don't.</p>
<p>Thankfully, WebdriverIO already handles this scenario, and we can make one small change to double-check that.</p>
<p>In our <code>browser.url</code> call, let's update the page to load a slightly different view:</p>
<pre><code>browser.url('./helloworld?diff1');
</code></pre>
<p>This is a variation of the <code>Hello World</code> page, with a different number near the bottom. It's great example of a small visual change that may go undetected.</p>
<p>Running our tests again, we'll see our visual error be caught:</p>
<pre><code class="language-js">Title of page is Applitools
F

0 passing (14.90s)
1 failing

1) my first visual test should look visually perfect:
Test 'My first Javascript test!' of 'Hello World!' detected differences!. See details at: https://eyes.applitools.com/app/batches/00000251870526458572/00000251870526458181?accountId=st1DOzXoArpZcmkVYWMrt2u0G2A2gcBBAresB13CKDc110
</code></pre>
<p>We can go to the URL and see the culprit of our failure:</p>
<p><img src="https://blog.kevinlamping.com/content/images/2018/07/ss2.png" alt="Using WebdriverIO and Applitools to visually test your website"></p>
<p>At this point, we can chose to update the baseline, create a smart region for it, or mark the test as a failure and update the team.</p>
<p>If you'd like to try this out without writing the code yourself, hop on over to <a href="https://github.com/klamping/wdio-applitools-demo">the GitHub page</a>, do a <code>git clone</code> then <code>npm install</code> and finally <code>npx wdio</code>.</p>
<h3 id="summary">Summary</h3>
<p>Both Applitools and WebdriverIO are amazing tools that have so much more to offer than what I covered here. Hopefully this gets you going with both tools, allowing you to take advantage of the base functionality each one provides.</p>
<p>Header Photo Credit <a href="https://unsplash.com/@joshcala?utm_medium=referral&amp;utm_campaign=photographer-credit&amp;utm_content=creditBadge"><strong>Josh Calabrese</strong></a></p>]]></content:encoded></item></channel></rss>