<?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:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Courtney Zhan on Medium]]></title>
        <description><![CDATA[Stories by Courtney Zhan on Medium]]></description>
        <link>https://medium.com/@courtneyzhan?source=rss-c55af017bb81------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*yqGcU7doDotY8XP_68oh2w.jpeg</url>
            <title>Stories by Courtney Zhan on Medium</title>
            <link>https://medium.com/@courtneyzhan?source=rss-c55af017bb81------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 08:55:08 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@courtneyzhan/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Mac Desktop App Test Automation with Appium. Part-1: Introduction]]></title>
            <link>https://courtneyzhan.medium.com/mac-desktop-app-test-automation-with-appium-part-1-introduction-8b1dcdf6f0ec?source=rss-c55af017bb81------2</link>
            <guid isPermaLink="false">https://medium.com/p/8b1dcdf6f0ec</guid>
            <category><![CDATA[desktop-automation]]></category>
            <category><![CDATA[automated-testing]]></category>
            <category><![CDATA[test-automation]]></category>
            <dc:creator><![CDATA[Courtney Zhan]]></dc:creator>
            <pubDate>Sat, 14 Nov 2026 21:24:20 GMT</pubDate>
            <atom:updated>2026-11-14T21:24:20.411Z</atom:updated>
            <content:encoded><![CDATA[<h4>Desktop app test automation is often overlooked and remains a rare capability, but it can be quite useful.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*mq8M-Gbh6qHvNE4-.png" /><figcaption>Image generated by ChatGPT</figcaption></figure><p>E2E test automation can generally be divided into the following categories:</p><ol><li><strong>Web Test Automation</strong> — Automating web applications using frameworks such as Selenium WebDriver and Playwright.</li><li><strong>Mobile Test Automation</strong> — The de facto framework is Appium, together with platform-specific drivers such as XCUITestDriver for iOS and Espresso or UIAutomator2 Drivers for Android.</li><li><strong>API Test Automation</strong> — Automating the testing of APIs, typically covering protocols and architectures such as SOAP and REST.</li><li><strong>Desktop Application Test Automation</strong> — Automating native desktop applications. Appium, together with platform-specific drivers, is a commonly used approach</li></ol><p>In this article series, I will introduce Desktop app test automation on macOS platform.</p><h3>Why Desktop App Test Automation?</h3><p>Compared with web, mobile, and API test automation, desktop application test automation is rarely discussed or given much attention. One simple reason is that it is considerably more challenging. If achieving reliable web test automation is already difficult, desktop application test automation can be even more challenging.</p><p>Some people may argue that modern application development is increasingly focused on web and mobile applications. So, why bother learning desktop application test automation?</p><p>This observation is valid. However, it does not mean desktop application test automation is no longer relevant or useful.</p><p>The reality is that a significant proportion of work is still performed on desktop computers. The ability to automate desktop applications and repetitive desktop tasks can therefore deliver substantial benefits.</p><p>This is particularly relevant in the age of AI, where combining AI capabilities with desktop automation opens up new opportunities to automate workflows, driving agents, improve productivity, and reduce manual effort.</p><p>In other words, desktop application test automation is not just about testing desktop software. It also provides valuable foundations for automating the desktop environment itself.</p><p>Just imagine being at work when your colleagues see you click a single button to automate a routine task that they perform manually every day, completing it much faster and more reliably.</p><h3>Desktop Application Test Automation Is Different from Web Test Automation</h3><p>Web test automation benefits from a common, universally adopted standard established by the W3C. As a result, although different automation frameworks may be used, the underlying automation approaches are largely similar.</p><p>Desktop test automation, however, doesn’t have an equivalent common standard. Consequently, implementation approaches can vary significantly across operating systems and platforms.</p><p>Even when using the same automation framework, such as Appium, different platform-specific drivers can introduce substantial differences in capabilities, implementation, and behaviour.</p><p>Therefore, discussions about desktop application test automation need to be platform-specific rather than treating desktop automation as a single, unified approach.</p><h3>The Driver Landscape for Desktop Automation</h3><p>Even within Windows desktop application automation, several drivers have emerged, including:</p><ul><li>WinAppDriver (deprecated)</li><li><a href="https://github.com/appium/appium-windows-driver">Windows Driver</a></li><li><a href="https://github.com/AutomateThePlanet/appium-novawindows-driver/">NovaWindows Driver</a></li><li><a href="https://github.com/appium/appium-wincore-driver">WinCore Driver</a></li></ul><p>Each driver may offer different capabilities and exhibit different behaviours, meaning that the choice of driver can significantly influence the automation implementation.</p><p>The situation is comparatively straightforward for macOS desktop application automation, where there is essentially one established Appium driver: <a href="https://github.com/appium/appium-mac2-driver"><strong>Mac2 Driver</strong></a>.</p><p>In the upcoming articles, I’ll show you how to set up Appium and develop automation scripts to test desktop applications on macOS.</p><p>Related reading:</p><ul><li>My books:<br>- <a href="https://courtneyzhan.gumroad.com/l/web-test-automation-in-action-volume-1">Web Test Automation in Action: Volume 1</a><br>- <a href="https://leanpub.com/effective-web-test-automation-selenium-junit/">Effective Web Test Automation with Selenium WebDriver and JUnit</a><br>- <a href="https://leanpub.com/practical-web-test-automation-with-playwright-pytest">Practical Web Test Automation with Playwright and Pytest</a></li><li>My “<a href="https://www.educative.io/courses/discover-ruby-programming-through-fun-examples">Discover Ruby Programming Through Fun Examples</a>” interactive course on Educative</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8b1dcdf6f0ec" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Execution Speed in E2E Test Automation Clarified]]></title>
            <link>https://courtneyzhan.medium.com/execution-speed-in-e2e-test-automation-clarified-70da55a72fe3?source=rss-c55af017bb81------2</link>
            <guid isPermaLink="false">https://medium.com/p/70da55a72fe3</guid>
            <category><![CDATA[test-automation]]></category>
            <category><![CDATA[automated-testing]]></category>
            <dc:creator><![CDATA[Courtney Zhan]]></dc:creator>
            <pubDate>Sun, 08 Nov 2026 00:01:01 GMT</pubDate>
            <atom:updated>2026-11-08T00:01:01.878Z</atom:updated>
            <content:encoded><![CDATA[<h4>What’s the speed bottleneck for your E2E automated tests?</h4><p>In this article, I’ll cover what you should be looking at for improving/affecting the execution speed of your E2E automated tests.</p><p>By E2E test automation execution, I mean running an automated end-to-end test from an end-user perspective. In web testing, for example, this involves watching a browser interact with UI elements — clicking buttons, filling forms, navigating pages — just as a real user would.</p><p>Compared to unit tests, E2E tests are undeniably slower. However, they are still far faster than manual testing. Because of this, most software teams naturally want to optimize E2E execution speed — and many attempt to do so. Unfortunately, some approaches are misguided. In this article, I’ll clarify what actually affects execution speed in E2E test automation — and what doesn’t.</p><h4>1. Script Language Differences Are Negligible</h4><p>One common misconception is that the choice of programming language significantly impacts execution speed.</p><p>In application development, compiled languages like C++ often have a major performance advantage over scripting languages. But in the context of test automation, this difference is almost negligible.</p><p>Why? Because the majority of execution time is spent waiting on the application under test — not executing the test script itself. The script simply issues commands (e.g., click, type, wait), browser and network speeds are very fast right now, so the backend app is the most time spent on the application itself. Whether the script is written in Ruby, JavaScript, Java, or Python has minimal impact on overall execution time.</p><p>So, instead, choose a language that is flexible and easy to read, e.g. Ruby, a scripting language.</p><h4>2. Framework Differences Are Also Overstated</h4><p>Another frequent claim is that certain test frameworks are “much faster” than others. As stated before, it is the app costs the most time.</p><p>In reality, the test automation framework differences are often exaggerated. Some frameworks — such as Cypress — promote faster execution as part of their marketing. However, real-world benchmarks often show a different picture. Many framework demos use extremely simple applications (like a basic TODO app). These scenarios don’t reflect the complexity of real-world systems, where network latency, rendering time, and backend processing dominate execution time.</p><h4>3. Execution of Individual Test vs Test Suite Execution</h4><p>In E2E test automation, we usually run in one of two modes:</p><ul><li>Running a single test (for development, refine, stabilise, debugging)</li><li>Running a full test suite (for regression runs)</li></ul><p>Some test automation frameworks, e.g. Cypress, claim it has a much faster test execution speed, but various benchmark shows otherwise. Why? One reason is architectural: for example, frameworks relying on chatty communication protocols can introduce overhead that accumulates over time, especially in large test suites.</p><h4>4. Sum of Individual Test Time vs. Suite Execution Time</h4><p>If you have a suite of 200 automated E2E tests, and each test takes an average of one minute, the total time adds up to 200 minutes (over three hours). However, this does not have to be the actual suite execution time.</p><p>By utilizing parallel execution, tests can run concurrently across multiple machines or environments, significantly reducing the overall runtime. With an efficient parallel setup, what would take hours sequentially can often be completed in a fraction of the time.</p><p>For example, below is a test run of the WhenWise test suite, which consists of 626 user-story-level UI automated tests built with Selenium WebDriver and executed on the BuildWise Continuous Testing server</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*lHaU_ldoMwgBi3Wb.png" /><figcaption><a href="https://agileway.substack.com/p/2026-kickoff-first-successful-run">2026 Kickoff: A Successful Run of the 626 E2E UI (Selenium) Test Suite and a Milestone of 450K Total Test Case Executions</a></figcaption></figure><p>By utilizing five build agents, the total execution time was reduced to 47 minutes — down from nearly three hours when run on a single machine.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=70da55a72fe3" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Simple and Effective Waiting in Appium Ruby Automation Scripts]]></title>
            <link>https://courtneyzhan.medium.com/simple-and-effective-waiting-in-appium-ruby-automation-scripts-5bb31dd77371?source=rss-c55af017bb81------2</link>
            <guid isPermaLink="false">https://medium.com/p/5bb31dd77371</guid>
            <category><![CDATA[mobile-testing]]></category>
            <category><![CDATA[appium]]></category>
            <category><![CDATA[test-automation]]></category>
            <category><![CDATA[automated-testing]]></category>
            <dc:creator><![CDATA[Courtney Zhan]]></dc:creator>
            <pubDate>Sat, 31 Oct 2026 21:43:49 GMT</pubDate>
            <atom:updated>2026-10-31T21:43:49.431Z</atom:updated>
            <content:encoded><![CDATA[<h4>Tips for Waiting in your Automated Appium Scripts</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jYPshx-qBB1TEqxm0XBZbg.png" /><figcaption>Image generated by ChatGPT</figcaption></figure><blockquote>Non-Medium Members: You can read this article for free on “<a href="https://agileway.substack.com/p/simple-and-effective-waiting-in-appium">The Agile Way — Practical Automated E2E Testing</a>” Substack Newsletter.</blockquote><p>In mobile test automation, <strong>waiting is essential.</strong> Mobile applications frequently perform asynchronous operations such as network requests, UI animations, screen transitions, and background rendering. If a test script attempts to interact with an element before the UI is fully ready, the test may fail even though the application itself is functioning correctly, this is known as a ‘flaky’ failure.</p><p>Appium follows the WebDriver protocol and therefore inherits the same waiting mechanisms used by Selenium WebDriver. This means mobile tests can use implicit waits, explicit waits, and polling-based synchronization in exactly the same way as web tests.</p><h4>Waiting difference between Web and Mobile Test Automation</h4><p>In web automation, waiting is typically required for events such as AJAX requests, DOM updates, or JavaScript execution. Modern browsers expose a relatively stable DOM, and elements usually become interactable quickly once they appear. In contrast, mobile automation interacts with a <strong>native UI hierarchy provided by platform automation frameworks</strong>, such as UiAutomator2 on Android and XCUITest on iOS. These frameworks may report that an element exists even while the screen is still animating or transitioning, meaning the element may not yet be stable or ready for interaction.</p><p>Another difference is <strong>device performance variability</strong>. Web tests typically run on consistent browser environments or cloud grids, whereas mobile tests run on real devices or emulators with widely varying CPU, memory, and rendering speeds. Network conditions also affect mobile apps more strongly because many mobile apps rely heavily on backend APIs for data loading.</p><p>Because of these factors, mobile test automation often requires <strong>more careful synchronization strategies</strong> than web automation. Instead of waiting only for element presence, reliable Appium tests frequently wait for conditions such as element visibility, enabled state, absence of loading indicators, or completion of screen transitions. Designing proper waiting strategies is therefore a crucial part of building stable mobile automation suites.</p><p>For common alternative waiting (such as explicit fixed waits and implicit waits), see this other article:</p><ul><li><a href="https://zhiminzhan.medium.com/waiting-strategies-for-test-steps-in-web-test-automation-aaae828eb3b3">Waiting Strategies for Test Steps in Web Test Automation</a></li></ul><p>This article will focus on auto-waiting for Appium specifically.</p><h4>Catching Specific Errors</h4><p>My current preferred method to handle effective waiting is to use Selenium WebDriver’s wait but customize it to ignore the Appium ‘element not found” and “stale element reference” errors that are associated with item visibility/loading.</p><pre>wait = Selenium::WebDriver::Wait.new(<br>  timeout: 15,<br>  interval: 0.5,<br>  ignore: [Selenium::WebDriver::Error::NoSuchElementError, <br>           Selenium::WebDriver::Error::StaleElementReferenceError]<br>)<br><br>wait.until do<br>  el = driver.find_element(:id, &#39;com.example:id/submit&#39;)<br>  el.click if el.displayed?<br>end</pre><p>You can also use Appium’s wait helper method directly, which is a wrapper around the Selenium wait:</p><pre>wait { driver.find_element(:id, &#39;my_element&#39;).displayed? }</pre><p>To learn more about Auto Waiting, check out this other article:</p><p><a href="https://agileway.substack.com/p/auto-waiting-in-web-test-automation">Auto-Waiting in Web Test Automation Clarified</a></p><p>My father’s innovative try_for approach works well for Appium too, as long as the test scripts are in Ruby syntax.</p><ul><li><a href="https://agileway.substack.com/p/my-innovative-solution-to-test-automation-d3c">My Innovative Solution to Test Automation: Easy Wait in Web Automation Scripts</a></li></ul><p>Related reading:</p><ul><li>My books:<br>- <a href="https://courtneyzhan.gumroad.com/l/web-test-automation-in-action-volume-1">Web Test Automation in Action: Volume 1</a><br>- <a href="https://leanpub.com/effective-web-test-automation-selenium-junit/">Effective Web Test Automation with Selenium WebDriver and JUnit</a><br>- <a href="https://leanpub.com/practical-web-test-automation-with-playwright-pytest">Practical Web Test Automation with Playwright and Pytest</a></li><li>My “<a href="https://www.educative.io/courses/discover-ruby-programming-through-fun-examples">Discover Ruby Programming Through Fun Examples</a>” interactive course on Educative</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5bb31dd77371" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Why I Choose macOS as the platform for my book? Part-2]]></title>
            <link>https://courtneyzhan.medium.com/why-i-choose-macos-as-the-platform-for-my-book-part-2-6ec472b04c20?source=rss-c55af017bb81------2</link>
            <guid isPermaLink="false">https://medium.com/p/6ec472b04c20</guid>
            <category><![CDATA[software-development]]></category>
            <dc:creator><![CDATA[Courtney Zhan]]></dc:creator>
            <pubDate>Sun, 25 Oct 2026 08:55:51 GMT</pubDate>
            <atom:updated>2026-10-25T20:35:18.759Z</atom:updated>
            <content:encoded><![CDATA[<h3>Why I Chose macOS as the Platform for My Latest Book: Practical Web Test Automation with Playwright and Pytest. Part-2: Test Automation Aspects</h3><h4>Using macOS to develop automated E2E scripts for my latest book</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Mnrtfv4HH0qe_mAq.png" /><figcaption><a href="https://agileway.substack.com/p/announcing-my-new-book-practical">Announcing my new book, “Practical Web Test Automation with Playwright and Pytest”</a></figcaption></figure><p>This is a continuation from <a href="https://medium.com/p/f5cc220e0bc7/edit">Part 1</a>. In this article I’ll be looking outside of specific tech stacks, and more on the benefits of using macOS for testing.</p><p><a href="https://courtneyzhan.medium.com/why-i-choose-macos-as-the-platform-for-my-upcoming-book-part-1-f5cc220e0bc7">Why I Choose macOS as the platform for my upcoming book? Part-1</a></p><h4>1. E2E test automation foundation is scripting, which unix-based Mac is far superior</h4><p>Currently Windows does include Linux now with WSL2, but some older versions of Windows may not. macOS is Unix-based out of the box and natively supports popular scripting languages and package managers (like Homebrew). This makes environment set up and scripting a lot smoother.</p><h4>2. Mobile test automation with iOS</h4><p>Although my recent book focuses on web test automation, I am also interested in mobile test automation. iOS development and testing are locked to macOS devices. So if you plan to expand to mobile testing, having macOS ensures you are not blocked when running and developing iOS test suites.</p><h4>3. Continuous Testing lab</h4><p>The Mac mini (M4 and and upcoming M6) are the best choices for a dedicated testing lab as it ticks all of boxes:</p><ul><li><em>Low Price, from only US$599</em></li><li><em>Fast</em></li><li><em>Reliable</em></li><li><em>Small Form Factor</em></li><li><em>Quiet</em></li><li><em>Power Efficiency &amp; Environmental Friendly</em></li></ul><p>For detail, check out this article, <a href="https://agileway.substack.com/p/m4-mac-mini-a-perfect-build-machine">M4 Mac Mini: A Perfect Build Machine for E2E Test Automation Labs</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*9UJjhOJTda72_VIx.png" /></figure><h4>4. Easy to add macOS virtual machine</h4><p>On Apple hardware, it’s easy to set up native VMs, unlike Windows which involves licensing keys and activation. On macOS, with <a href="https://blogs.vmware.com/cloud-foundation/2024/11/11/vmware-fusion-and-workstation-are-now-free-for-all-users/">VMware Fusion</a> now available for free, setting up a Windows virtual machine on a Mac is easy, it’s easy to create new virtual machines, which is helpful to use for test build machines.</p><h4>5. Apple’s built-in Screen Sharing app is great for remote controlling build machines.</h4><p>macOS also comes with Apple’s “Screen Sharing” app, which lets you view and control another macOS machine remotely. This is really convenient if you have additional build machines, so you can remote in, update configurations and monitor builds from a single central machine.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6ec472b04c20" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Clarifying QA vs. Testing in Software Development in Simple Terms]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://courtneyzhan.medium.com/clarifying-qa-vs-testing-in-software-development-in-simple-terms-7ad8b58bc842?source=rss-c55af017bb81------2"><img src="https://cdn-images-1.medium.com/max/1200/0*oJBH7kYB6CRMHAz0" width="1200"></a></p><p class="medium-feed-snippet">What&#x2019;s the difference between QA and Testing?</p><p class="medium-feed-link"><a href="https://courtneyzhan.medium.com/clarifying-qa-vs-testing-in-software-development-in-simple-terms-7ad8b58bc842?source=rss-c55af017bb81------2">Continue reading on Medium »</a></p></div>]]></description>
            <link>https://courtneyzhan.medium.com/clarifying-qa-vs-testing-in-software-development-in-simple-terms-7ad8b58bc842?source=rss-c55af017bb81------2</link>
            <guid isPermaLink="false">https://medium.com/p/7ad8b58bc842</guid>
            <category><![CDATA[software-testing]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[test-automation]]></category>
            <dc:creator><![CDATA[Courtney Zhan]]></dc:creator>
            <pubDate>Sun, 18 Oct 2026 10:47:53 GMT</pubDate>
            <atom:updated>2026-10-18T23:06:44.807Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[API Testing Anti-Pattern: Not Running in CI/CD pipeline or CT]]></title>
            <link>https://courtneyzhan.medium.com/api-testing-anti-pattern-not-running-in-ci-cd-pipeline-or-ct-f84e49457ad5?source=rss-c55af017bb81------2</link>
            <guid isPermaLink="false">https://medium.com/p/f84e49457ad5</guid>
            <category><![CDATA[api-development]]></category>
            <category><![CDATA[test-automation]]></category>
            <dc:creator><![CDATA[Courtney Zhan]]></dc:creator>
            <pubDate>Sat, 10 Oct 2026 20:31:21 GMT</pubDate>
            <atom:updated>2026-10-10T20:33:02.836Z</atom:updated>
            <content:encoded><![CDATA[<h4>How (and often) should run the suite of API tests?</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9xXZkSuaA3sh_i_L7hGtWQ.png" /><figcaption>The image is generated by ChatGPT</figcaption></figure><p>API tests are generally faster and more reliable than UI-based end-to-end (E2E) tests. For this reason, many ‘agile teams’ focus heavily on API testing. The technical challenges are certainly lower, as software engineers are typically more comfortable writing and maintaining API tests.</p><p>However, for applications with a user interface <em>(which are most applications, such as Web and Mobile)</em>, API testing alone is not true end-to-end testing. Many defects related to the user experience — including rendering issues, browser compatibility problems, JavaScript errors within the UI layer — cannot be detected through API testing.</p><p>Teams often accumulate a large number of API tests because they are granular and straightforward to create. While API testing is significantly faster than UI automation, it is still black-box testing and considerably slower than white-box unit testing. As the test suite grows, it becomes impractical for developers to execute the entire API regression suite repeatedly during day-to-day development.</p><p>The logical solution is to execute the full API test suite automatically in a continuous testing environment whenever application changes are made. Some organizations achieve this through a CI/CD pipeline. My father prefers the term <a href="https://agileway.substack.com/p/software-development-trend-continuous"><strong>Continuous Testing</strong></a><strong> (CT)</strong> because many so-called CI/CD pipelines perform little or no meaningful automated regression testing, particularly at the end-to-end level.</p><p>The answer to the title question: <strong>We should run the whole suite of API tests on a CT server, multiple times a day.</strong></p><p>A Continuous Testing environment provides <strong>rapid feedback</strong> by automatically executing the complete API regression suite whenever code changes are introduced. This helps detect defects early, reduces the cost of maintaining both the application and the test suite, and prevents automated tests from becoming stale, outdated, and rarely executed! After all, an automated test that is not run regularly provides little real value.</p><p>Both API testing and functional UI testing are types of black-box testing, meaning they operate independently of the application’s internal implementation. Consequently, the same Continuous Testing (CT) environment can be used to execute both API and end-to-end (UI) test suites, improving infrastructure utilization and simplifying operations.</p><p>For example, my father’s web, mobile, and API test suites are all built on the same RSpec-based testing framework, allowing them to share a common syntax and execution model (within the same <a href="https://agileway.substack.com/p/a-well-setup-parallel-testing-lab">parallel testing lab</a>, consisting of a<a href="https://agileway.substack.com/p/set-up-buildwise-ct-server-step-by"> BuildWise CT server</a> and multiple build agents).</p><p>Related reading:</p><ul><li>My books:<br>- <a href="https://courtneyzhan.gumroad.com/l/web-test-automation-in-action-volume-1">Web Test Automation in Action: Volume 1</a><br>- <a href="https://leanpub.com/effective-web-test-automation-selenium-junit/">Effective Web Test Automation with Selenium WebDriver and JUnit</a><br>- <a href="https://agileway.substack.com/p/announcing-my-new-book-practical">Announcing my new book, “Practical Web Test Automation with Playwright and Pytest”</a></li><li>My “<a href="https://www.educative.io/courses/discover-ruby-programming-through-fun-examples">Discover Ruby Programming Through Fun Examples</a>” interactive course on Educative</li><li><a href="https://agileway.substack.com/p/a-story-of-100x-api-testing-i-implemented">A Story of 100X API Testing I Implemented in a Matter of Days</a></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*khQrXtQ6i95hoRA1.jpeg" /><figcaption><a href="https://agileway.substack.com/p/the-resources-zhimin-created-to-help">The Resources Zhimin Created to Help Achieve Real End-to-End Test Automation &amp; Continuous Testing</a></figcaption></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f84e49457ad5" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Why I Choose macOS as the platform for my upcoming book? Part-1]]></title>
            <link>https://courtneyzhan.medium.com/why-i-choose-macos-as-the-platform-for-my-upcoming-book-part-1-f5cc220e0bc7?source=rss-c55af017bb81------2</link>
            <guid isPermaLink="false">https://medium.com/p/f5cc220e0bc7</guid>
            <category><![CDATA[test-automation]]></category>
            <category><![CDATA[software-engineering]]></category>
            <dc:creator><![CDATA[Courtney Zhan]]></dc:creator>
            <pubDate>Sat, 03 Oct 2026 20:43:10 GMT</pubDate>
            <atom:updated>2026-10-03T20:43:10.986Z</atom:updated>
            <content:encoded><![CDATA[<h3>Why I Chose macOS as the Platform for My Latest Book: Practical Web Test Automation with Playwright and Pytest. Part-1: Hardware aspects</h3><h4>Using macOS to develop automated E2E scripts for my latest book</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*r5Z31eHK-Kh5J_AZ.png" /><figcaption><a href="https://agileway.substack.com/p/announcing-my-new-book-practical">Announcing my new book, “Practical Web Test Automation with Playwright and Pytest”</a></figcaption></figure><p>Except for one half-broken Dell laptop that I used during high school, my family has always been a Mac-only household.</p><p>The original <em>Practical Web Test Automation</em> book was written by my father in 2009. All of the test scripts were initially developed on his MacBook. They were then rerun in a Windows virtual machine solely to capture the screenshots shown in the book.</p><p>For my new book, <a href="https://leanpub.com/practical-web-test-automation-with-playwright-pytest"><em>Practical Web Test Automation with Playwright and Pytest</em></a>, I decided to eliminate that extra work and use macOS as the only platform presented throughout the book.</p><p>First, let me make one point clear. For end-to-end test automation — whether web or mobile — the <strong>entire technical stack is cross-platform</strong>. Frameworks such as Selenium WebDriver, Playwright, and Appium, along with tools such as VS Code, TestWise IDE and BuildWise CT Server, work the same way across operating systems.</p><p>As a result, anyone who learns test automation on macOS can easily apply the same knowledge on Windows or Linux, provided they are familiar with the basics of those operating systems.</p><p>My father agrees with this decision. For his future books — and when updating existing titles — he also plans to use macOS as the primary platform.</p><p>This reflects a broader recommendation for those who are starting their test automation journey: if you are open for suggestions, I recommend learning on macOS.</p><p>For the general public, there is now little reason to choose a Windows PC over a Mac, considering factors such as price, build quality, design, support, longevity, and overall user experience.</p><p>On LinkedIn, when software engineers announce that they have started a new job, they often share photos of their welcome packages. From what I’ve seen, the included computer is almost always a MacBook Pro (but maybe if it is not a MacBook, they just don’t post it… 😅)</p><p>At my current company, Amazon, software engineers are offered a choice between Windows and Apple laptops. Almost all choose a MacBook Pro.</p><p>For test automation engineers — also known as Software Development Engineers in Test (SDETs) — there is an additional reason to choose a Mac: a Mac can be used to test both macOS and Windows applications by running Windows in a virtual machine (such as VMware Fusion, which now is free). However, the reverse is not possible.</p><p>In the next article, I will share the specific reasons why macOS is better (than Windows) for E2E test automation. Stay tuned.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f5cc220e0bc7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Scripting Language Comparison in E2E Test Automation: Ruby vs Python. Part 3 — My Preference]]></title>
            <link>https://courtneyzhan.medium.com/scripting-language-comparison-in-e2e-test-automation-ruby-vs-python-part-3-my-preference-36aef163b5db?source=rss-c55af017bb81------2</link>
            <guid isPermaLink="false">https://medium.com/p/36aef163b5db</guid>
            <category><![CDATA[automated-testing]]></category>
            <category><![CDATA[test-automation]]></category>
            <dc:creator><![CDATA[Courtney Zhan]]></dc:creator>
            <pubDate>Sat, 26 Sep 2026 21:10:03 GMT</pubDate>
            <atom:updated>2026-09-26T21:10:58.413Z</atom:updated>
            <content:encoded><![CDATA[<h4>Which language is better for scripting automated E2E tests?</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dofMVeR_pOLJYerAbtMJrw.png" /></figure><p>In this series:</p><ul><li>Part-1: <a href="https://agileway.substack.com/p/scripting-language-comparison-in">Syntax</a></li><li>Part-2: <a href="https://agileway.substack.com/p/scripting-language-comparison-in-818">Language Features</a></li><li>Part-3: <a href="https://courtneyzhan.medium.com/scripting-language-comparison-in-e2e-test-automation-ruby-vs-python-part-3-my-preference-36aef163b5db"><strong>My Preference</strong></a></li></ul><p>I have written books on test automation using five different programming languages:</p><ul><li><a href="https://courtneyzhan.gumroad.com/l/web-test-automation-in-action-volume-1">Web Test Automation in Action: Volume 1</a>: Hands-On Exercises with Selenium WebDriver and Playwright (<strong>Ruby</strong> and <strong>TypeScript</strong>)</li><li><a href="https://leanpub.com/effective-web-test-automation-selenium-junit/">Effective Web Test Automation with Selenium WebDriver and JUnit</a> (<strong>Java</strong>)</li><li><a href="https://www.amazon.com.au/Selenium-WebDriver-Recipes-Practical-Solutions/dp/B0CJ2DBVNG">Selenium WebDriver Recipes in C#: Practical Testing Solutions for Selenium WebDriver</a> <strong>(C#)</strong></li><li><a href="https://agileway.substack.com/p/announcing-my-new-book-practical">Practical Web Test Automation with Playwright and pytest</a> (<strong>Python</strong>)</li><li><em>Practical Mobile Test Automation (Appium in </em><strong><em>Ruby</em></strong><em>) — upcoming</em></li></ul><p>Some readers might wonder:</p><blockquote>“Which programming language is the best for E2E test automation?”</blockquote><p>Programming language preference is one of the most sensitive topics in software engineering. Every language has its passionate supporters.</p><p>My answer is simple: for end-to-end test automation, I prefer Ruby. This doesn’t mean I can’t or won’t use other languages when needed.</p><p>A quick summary of the five objective comparisons covered in Parts 1 and 2:</p><ul><li>Ruby is easier to create more readable DSL. Ruby👍</li><li>Ruby keeps your project folder cleaner 👍 , it doesn’t generate an annoying __pycache__ folder 👎🏽</li><li>Calling methods without parentheses: Python 👎🏽; Ruby👍</li><li>Ruby modules are elegant. Ruby👍</li><li>Python’s indentation rules are strict. Python 👎🏽; Ruby👍</li></ul><p>Then, some maybe subjective ones.</p><h4>6. RSpec is more expressive than pytest.</h4><p>The language itself is only part of the story.</p><p>For test automation, the testing framework matters just as much.</p><p>Ruby’s RSpec produces extremely more readable test scripts than pytest (the de facto test syntax framework in Python). For differences, check my other article, “<a href="https://medium.com/p/74f2786480b9/edit">Test Syntax Framework Comparison in E2E Test Automation: RSpec vs. Pytest</a>”</p><h4>7. Ruby Has a Better History and Ecosystem for automation.</h4><p>There are also several other reasons to consider Ruby:</p><ul><li>RubyGems is a better package management ecosystem than pip.</li><li>Ruby has Rake, a task management and build automation tool. The configuration file (Rakefile) is actually a Ruby script. You can configure Rake targets, that are useful for executing tests in CI/CD.</li><li>Some important advances in web test automation originated in Ruby, such as Watir and Cucumber.</li><li>Ruby programmers tend to love Ruby, not merely like it. This is evidenced by creators intentionally putting Ruby in the framework name, such as Watir (Web application testing in Ruby) and Ruby on Rails. As such, there is a lot of support for Ruby online..</li></ul><h4>8. TestWise IDE supports Ruby Better</h4><p>Finally, a personal and subjective one: my favourite Testing IDE <a href="https://agileway.substack.com/p/my-innovative-solution-to-test-automation-f3c">TestWise</a> <em>(disclaimer: created by my father</em>) is really a huge productivity booster, and while it supports both Python and Ruby<em> (and JavaScript too)</em>, its Ruby support is better.</p><p>Related reading:</p><ul><li>My books:<br>- <a href="https://courtneyzhan.gumroad.com/l/web-test-automation-in-action-volume-1">Web Test Automation in Action: Volume 1</a><br>- <a href="https://leanpub.com/effective-web-test-automation-selenium-junit/">Effective Web Test Automation with Selenium WebDriver and JUnit</a><br>- <a href="https://agileway.substack.com/p/announcing-my-new-book-practical">Announcing my new book, “Practical Web Test Automation with Playwright and Pytest”</a></li><li>My “<a href="https://www.educative.io/courses/discover-ruby-programming-through-fun-examples">Discover Ruby Programming Through Fun Examples</a>” interactive course on Educative</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*FDASHPE1aTFZqdWC.jpeg" /><figcaption><a href="https://agileway.substack.com/p/the-resources-zhimin-created-to-help">The Resources Zhimin Created to Help Achieve Real End-to-End Test Automation &amp; Continuous Testing</a></figcaption></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=36aef163b5db" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Scripting Language Comparison in E2E Test Automation: Ruby vs Python. Part 2 — Language Features]]></title>
            <link>https://courtneyzhan.medium.com/scripting-language-comparison-in-e2e-test-automation-ruby-vs-python-part-2-language-features-652e29eb6cb9?source=rss-c55af017bb81------2</link>
            <guid isPermaLink="false">https://medium.com/p/652e29eb6cb9</guid>
            <category><![CDATA[automated-testing]]></category>
            <category><![CDATA[test-automation]]></category>
            <dc:creator><![CDATA[Courtney Zhan]]></dc:creator>
            <pubDate>Sun, 20 Sep 2026 00:01:02 GMT</pubDate>
            <atom:updated>2026-09-20T00:01:02.102Z</atom:updated>
            <content:encoded><![CDATA[<h4>Which language is better for scripting automated E2E tests?</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dofMVeR_pOLJYerAbtMJrw.png" /></figure><p>This is a continuation from <a href="https://medium.com/@courtneyzhan/scripting-language-comparison-in-e2e-test-automation-ruby-vs-python-part-1-syntax-8b2590af2762">Part 1</a> of this series, comparing Ruby and Python for E2E test scripting. In Part 1, we looked at the syntax differences, between Ruby and Python. In this article, we’ll compare some of the language features in the context of E2E test scripts.</p><h4>3. Ruby does not clutter the project with __pycache__</h4><p>Python commonly creates __pycache__ directories containing compiled bytecode files. These are harmless and normally excluded from source control, but they add some noise to a project.</p><p>Ruby does not create an equivalent __pycache__ directory when you run a test script. A Ruby test project therefore tends to remain relatively clean.</p><h4>4. Ruby has powerful language features such as blocks and mixins</h4><p>Ruby has several language features that are particularly useful for building maintainable test automation frameworks.</p><p><strong>Blocks</strong> allow you to pass a piece of behavior to a method. They are used extensively throughout Ruby and make it possible to create concise and expressive APIs. For example, my father’s <a href="https://agileway.substack.com/p/my-innovative-solution-to-test-automation-d3c">invention of </a><a href="https://agileway.substack.com/p/my-innovative-solution-to-test-automation-d3c">try_for </a>is using this feature.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*_qFUwUX02RN7nPUk.png" /><figcaption><a href="https://agileway.substack.com/p/my-innovative-solution-to-test-automation-d3c">https://agileway.substack.com/p/my-innovative-solution-to-test-automation-d3c</a></figcaption></figure><p><strong>Mixins</strong>, implemented through modules, provide a convenient way to share behaviours between classes without relying solely on traditional inheritance.</p><p>Below is an example Mixin usage in a test script to take screenshots:</p><pre>module ScreenshotMixin<br>  def take_screenshot<br>    puts &quot;Taking screenshot...&quot;<br>  end<br>end<br><br>class LoginTest<br>  include ScreenshotMixin<br>end<br>test = LoginTest.new<br>test.take_screenshot</pre><p>Adding reusable behaviour is as simple as: include ScreenshotMixin .</p><p>Python achieves similar functionality using multiple inheritance.</p><p>These features can be particularly useful when building Page Object Models and reusable test helpers. Instead of repeatedly copying code, common behaviour can be encapsulated and composed where it is needed.</p><p>The result can be test code that is both concise and expressive without sacrificing maintainability.</p><h4>5. Calling methods without parentheses: Python 👎; Ruby 👍</h4><p>Python requires parentheses when calling a method, even if it has no parameters.</p><pre>page.locator(&quot;#testwise&quot;).click()  # works</pre><p>If you accidentally omit them:</p><pre>page.locator(&quot;#testwise&quot;).click</pre><p>Python does <strong>not</strong> report a syntax error. Instead, it simply returns a method object, meaning the click is never performed.</p><p>For beginners to Python, this can be confusing because the script runs without an obvious indication that the intended action never happened.</p><p>Ruby is much more forgiving. Both of the following are equivalent:</p><pre>driver.find_element(:link_text, &quot;TestWise&quot;).click<br>driver.find_element(:link_text, &quot;TestWise&quot;).click()</pre><p>Related reading:</p><ul><li>My books:<br>- <a href="https://courtneyzhan.gumroad.com/l/web-test-automation-in-action-volume-1">Web Test Automation in Action: Volume 1</a><br>- <a href="https://leanpub.com/effective-web-test-automation-selenium-junit/">Effective Web Test Automation with Selenium WebDriver and JUnit</a></li><li>My “<a href="https://www.educative.io/courses/discover-ruby-programming-through-fun-examples">Discover Ruby Programming Through Fun Examples</a>” interactive course on Educative</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*iKMzxBNmlwAad9dw.jpeg" /><figcaption><a href="https://agileway.substack.com/p/the-resources-zhimin-created-to-help">The Resources Zhimin Created to Help Achieve Real End-to-End Test Automation &amp; Continuous Testing</a></figcaption></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=652e29eb6cb9" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Scripting Language Comparison in E2E Test Automation: Ruby vs.Python Part 1 — Syntax]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://courtneyzhan.medium.com/scripting-language-comparison-in-e2e-test-automation-ruby-vs-python-part-1-syntax-8b2590af2762?source=rss-c55af017bb81------2"><img src="https://cdn-images-1.medium.com/max/1286/1*dofMVeR_pOLJYerAbtMJrw.png" width="1286"></a></p><p class="medium-feed-snippet">Which language is better for scripting automated E2E tests</p><p class="medium-feed-link"><a href="https://courtneyzhan.medium.com/scripting-language-comparison-in-e2e-test-automation-ruby-vs-python-part-1-syntax-8b2590af2762?source=rss-c55af017bb81------2">Continue reading on Medium »</a></p></div>]]></description>
            <link>https://courtneyzhan.medium.com/scripting-language-comparison-in-e2e-test-automation-ruby-vs-python-part-1-syntax-8b2590af2762?source=rss-c55af017bb81------2</link>
            <guid isPermaLink="false">https://medium.com/p/8b2590af2762</guid>
            <category><![CDATA[test-automation]]></category>
            <category><![CDATA[automated-testing]]></category>
            <dc:creator><![CDATA[Courtney Zhan]]></dc:creator>
            <pubDate>Sun, 13 Sep 2026 00:01:02 GMT</pubDate>
            <atom:updated>2026-09-13T21:04:42.809Z</atom:updated>
        </item>
    </channel>
</rss>