Codementor Events

Walkthrough: Windows Notepad Test Automation with Node.js

Published Nov 01, 2018Last updated Apr 29, 2019
Walkthrough: Windows Notepad Test Automation with Node.js

This article demonstrates how to create an automation script for Windows 10 Notepad, using Node.js and Cucumber.js. You will also learn how to create object model for your Windows application,and how to use Windows automation APIs in CukeTest to write the script.

In this walkthrough, we will:

  • Create BDD scenarios that describe the automation steps
  • Spy Notepad controls and add test objects to object model
  • Implement the automation code
  • Debug and run the script to get report

We have created a video on how to do this, watch it on YouTube

To do it step-by-step yourself, please first install Node.js and CukeTest as the development tools.

1. Create project

  1. Open CukeTest, click "File" -> "New Project"

  2. Set "NotepadTesting" as the Project Name, and select "Windows" project template, also specify a Project Path, and then click "Create" to create the project.

newproject.png

2. Write scenarios

To write behavior driven automation script, one always start by writing the test cases you want to automate as feature files. Open feature1.feature file, on "Visual" view, input the content according to the following picture.

feature.png

In "Text" view, you will find the content of the feature file:

Feature: Notepad Application Automation
Automate Windows 10 Notepad application for testing

Scenario: Edit content and save
   Given Notepad application is opened
   When input text "hello world" in the Notepad
   And select [File] -> [Save] to show the file save dialog
   And enter the file name "helloworld.txt" and click [OK]
   Then the file should be saved successfully

Scenario: Change Notepad font
   Given Notepad application is opened
   When select [format] -> [font] to open font dialog
   And select [Arial] font from the Font dropdown box
   Then Click [OK] button to dismiss the Font dialog

With the scenarios created, it is now very clear what need to be implemented.

3. Spy controls

When automate a Windows Application, "test objects" are used to identify windows controls. each Test Object contains a set of properties and rules used to locate the control. Test object information is stored in an object model file (or in abbreviation, "model file"), which is end with ".tmodel". Model Manager in CukeTest is used to create and manager the model file. Here is the quick instruction on how to spy and add objects to the model:

Click "Add Object"addObj.png button to start the element spying, click the control you want to add, if the control is spied successfully, it shows the controls you want to add and its properties. Then you click "Add to Model" add.png button to add it to the object model.

Please now follow the below steps to create the model:

  1. Click step_definitions\model1.tmodel file to open it in Model Manager.

    tmodel.png

  2. Open Notepad, spy the following list of controls, and add them to the model, also give them names as the "Object Name" column below:

    Text Control Type Object Name
    "File" MenuItem File
    "Save" MenuItem Save1
    "Format" MenuItem Format
    "Font..." MenuItem Font...
    "" Document TextEditor

    One tip about spying, to spy the "Save" button, first press Ctrl key when click "File" menu, so that this click won't trigger spying dialog to show up, and then release Ctrl key when you click "Save".

  3. Open "Font" dialog by clicking "Format" -> "Font..." menu, spy and add the following list of controls, and add them to the model.

    Text Control Type Object Name
    "Arial" ListItem Arial
    "OK" Button OK
  4. Open the File Save dialog, spy and add the following list of the controls, and add them to the model

    Text Control Type Object Name
    "" Edit File name:1
    "OK" Button OK

    After adding all these elements, your model should look like the following:

    modelfile.png

4. Start implementing the scenarios

  1. Open step_definations\definitions1.js file, click the gray buttons on each step to generate the step definition code stub.

    autoscript.png

    notice that now the button next to step text are orange, which means the steps has matching step definition functions, but they are not implemented yet.

    You may also notice that, the model loading code has already been added to this file, so in the code when project is created, you can use this model variable directly to access these objects.

    Now you can open the model1.tmodel file, select an object from model tree,select "Actions/Properties" tab, and then copy the method from the list and add them to the script.

  2. To implement the step definitions, first to implement the step "Given Notepad application is opened", you can use the "Util.launchProcess" API to launch the Notepad process:

    Given(/^Notepad application is opened$/, async function () {
       if (!await model.getWindow("Notepad").exists(0)) {
          Util.launchProcess('c:\\Windows\\notepad.exe');
       }
    });
    
  3. After writing the code, you can test it by right-clicking the step, and click "Run This Step" button on the step toolbar:

    run_first_step.png

    this will just run the step for debugging purpose, and if succeed, your notepad should be launched.

  4. Before implementing the rest steps, we should add hook functions, to minimize the CukeTest window when the script starts, and restore the CukeTest window when the run is finished, we can achieve this in the BeforeAll and AfterAll hooks. For more information about hooks, you can read BDD Web Automation 04: Hooks and TimeOut. Add a file "support/hooks.js", and put the following content:

    const {BeforeAll, AfterAll, setDefaultTimeout} = require('cucumber')
    const cuketest = require('cuketest');
    
    setDefaultTimeout(20 * 1000);
    
    BeforeAll(async function() {
        await cuketest.minimize();
        await cuketest.delay(1000);
    })
    
    AfterAll(async function () {
        await cuketest.delay(1000);
        await cuketest.maximize();
    })
    

    In hooks.js, we set the step timeout to be 20 seconds instead of default 5 seconds, which is a bit short for windows automation script. Also, in BeforeAll, we minimize the CukeTest window before running any scenarios, wait for 1 second till the minimization actually take effect, so that it won't interfere with the UI of application under test when perform automatino operations.

5. Implement all automation steps

  1. Now we can implement the second step:

       When input text "hello world" in the Notepad
    

    In this step definition function sub, change the parameter name to be "text", and drag the "Text Editor" object from Model Manager to the function, select the set method, and fill the parameter "text" in it, the code is as the following:

    When(/^input text "([^"]*)" in the Notepad$/, async function (text) {
       await model.getDocument("Text Editor").set(text);
    });
    

    Assume you have opened a Notepad, you can now right click the step text, and select "Run This Step" as you did for the first step, it will minimize the CukeTest, set the Notepad content to be "hello world", and then restore CukeTest window. If this step runs successfully, you can add the rest steps similarly.

  2. To save the paragraph, I paste all the definitions1.js code below:

    const { Given, When, Then } = require('cucumber');
    const { TestModel } = require('leanpro.win');
    const { Util } = require('leanpro.common');
    const fs = require('fs');
    const cuketest = require('cuketest')
    const assert = require('assert')
    
    let model = TestModel.loadModel(__dirname + "/model1.tmodel");
    
    Given(/^Notepad application is opened$/, async function () {
        if (!await model.getWindow("Notepad").exists(0)) {
            Util.launchProcess('c:\\Windows\\notepad.exe');
        }
    });
    
    When(/^input text "([^"]*)" in the Notepad$/, async function (text) {
        await model.getDocument("Text Editor").set(text);
    });
    
    When(/^select \[File\] \-> \[Save\] to show the file save dialog$/, async function () {
        await model.getMenuItem("File").click();
        await model.getMenuItem("Save1").click();
    });
    
    When(/^enter the file name "([^"]*)" and click \[OK\]$/, async function (fileName) {
        this.fileName = __dirname + '\\' + fileName;
        if (fs.existsSync(this.fileName)) {
            fs.unlinkSync(this.fileName); //remove the file if it exists
        }
    
        await cuketest.delay(1000)
    
        await model.getEdit("File name:1").set(this.fileName);
        await model.getButton("Save").click();
    });
    
    Then(/^the file should be saved successfully$/, async function () {
        await cuketest.delay(1000)
        assert.ok(fs.existsSync(this.fileName), `${this.fileName} should exists`);
    });
    
    When(/^select \[format\] \-> \[font\] to open font dialog$/, async function () {
        await model.getMenuItem("Format").click();
        await model.getMenuItem("Font...").click();
        await cuketest.delay(1000);
    });
    
    When(/^select \[Arial\] font from the Font dropdown box$/, async function () {
        await model.getList("Font:1").select('Arial');
        await cuketest.delay(1000);
    });
    
    Then(/^Click \[OK\] button to dismiss the Font dialog$/, async function () {
        await model.getButton("OK").click();
    });
    

    to make sure it runs successfully in repeated run, it will delete the existing file before saving.

6. Run

Click run button, it will run these two scenarios, and then open the test report, like the following:

report.png
report1.png

Summary

In this article, we have successfully created a BDD script that can automate Notepad, and generate test report. With the test model that manage the test objects, the code is simplified and easier to maintain. CukeTest provides debugging capability that can run a scenario step-by-step.

In the next article, we will talk about how to organize object models in Model manager to make them more organized. Also, we will talk about how to update the properties in the test object so that it can work across Windows with different displaying language.

Some other readings about Windows Automation using Node.js:

Discover and read more posts from CukeTest
get started
post comments1Reply
Beyonslay
6 years ago

Very good article. The steps are well detailed and explained. Even if you are a beginner but you can easily learn from it. Thank you