NexJ Logo

Writing a UI unit test

Overview

The way a unit test runs is as follows, in order:

  1. Iterates through each value a variable in the "Loops" tab can take and
  2. Execute the .utest Initializer*
  3. Define variables that the UI test will need
  4. Login to the application and execute the testing script
  5. Run the .utest Finalizer

 *This is not necessarily applicable to dirty UI tests where the initializer is run only once.

1. The Initializer

  • The Initializer tab has code that is run for each test in the .utest file (in general). 
  • The Initializer should have code that
    1. Sets global variables (from the Overview tab of the .utest file)
    2. Creates a new login user to use for running the UI tests
    3. Creates additional data required by the test cases, if necessary


 Setting Global Variables

  • Recall that the UI tests have the following global variables at a minimum: sim, login and pwd

  • The below table describes what to set the global variables as, and what the return values are


    Value to set global variablesScheme console return value

    (set! sim (ui-test-player "portal" browser))

    ; #nexj.core.testing.ui.application.AFLApplication@7481b707

    (set! login (string-append "afl" browser)); "aflCH"
    (set! pwd "nexj"); "nexj"


  • Now, sim refers to the application instance, login will be the username of the account accessing that application instance and pwd will be the password of that account.



Creating the login user

  • Note that when we set our login and pwd variables above, we only set the string values of these variables. The above step will not actually make a new user with this login name and password! This is easy to deal with: we can leverage a helper function.
  • Below, is the code that demonstrates how to create a login

(unittest-create-update-user
   login
   (: updatablePassword pwd)
   (: groups '("ManageContacts"))
)

  • Executing this code creates a new user with the username as the login variable ("aflCH") and the password as the pwd variable ("nexj"). Note that the groups given may need to be modified to allow other functionality to be tested.


2. Defining Variables for the UI test

  • This part of the test is done at the test level (Test Cases tab)
  • The UI tests will have objects, strings, dates, numbers, etc. that may be repeated throughout the test. If you plan on re-using an item many times, these should be variables.
  • Variables in UI tests can be declared with the define key word. Note that the type of variable is automatically determined. Below are examples:
VariableHow to set the variableScheme console return valueVariable Type

oppTemplate

(define oppTemplate "Opportunity Template 1")

; "Opportunity Template 1"String
expCloseDate(define expCloseDate (today)); #m2018-09-11T04:00:00.000000000Timestamp
actAmnt(define actAmnt 140000); 140000Number
person(define person (unittest-create-contact))
; #<Instance<Person, null, new>(
 createTime=#m2018-09-11T18:43:45.811000000,
 createUserAlias="nexjsa",
 createAuthorAlias="nexjsa",
 editTime=#m2018-09-11T18:43:45.811000000,
 editUserAlias="nexjsa",
 editAuthorAlias="nexjsa",
 importMode=#f,
 sysCreateUser=Instance<LocalUser, (oid #z00000000000010008000BEEF0000000C), clean>,
 sysCreateTime=#m2018-09-11T18:43:45.811000000,
 sysEditUser=Instance<LocalUser, (oid #z00000000000010008000BEEF0000000C), clean>,
 sysEditTime=#m2018-09-11T18:43:45.811000000,
 viewPrincipal=Instance<PublicPrincipal, (oid #z00000000000010008000BEEF0000000A), clean>,
 editPrincipal=Instance<PublicPrincipal, (oid #z00000000000010008000BEEF0000000A), clean>,
 viewSecurityType=0,
 editSecurityType=0,
 type=Instance<EntityType, (oid #z00000000000010008000CEEDED001000), clean>,
 firstName="firstName1",
 lastName="lastName1",
 telcoms=Collection(0),
 addrs=Collection(0),
 playedRoles=Collection(0),
 workPhone=(),
 faxPhone=(),
 workPhoneAddress=(),
 emailAddress=(),
 faxPhoneAddress=(),
 parents=Collection(4),
 children=Collection(4),
 company=(),
 department=(),
 household=(),
 isClient=#f,
 isProspect=#f,
 isFormerClient=#f,
 isOther=#t,
 isLead=#f,
 isStatus1=#f,
 isStatus2=#f,
 isStatus3=#f,
 entityStatus=Instance<EntityStatusEnum, (oid "Other" "en" "SENTITYSTATUS"), clean>,
 coverageParent=Instance<Person, null, new>,
 coverageChildren=Collection(1),
 tier=Instance<ClientTierEnum, (oid "UNASSIGNED" "en" "SCLIENTTIERENUM"), clean>,
 dates=Collection(1),
 dear="firstName1",
 workPhoneExtension=(),
 birthTime=(),
 rankedTiers=Collection(1),
 taxonomyCriteria=#f,
 taxonomy=(),
 primaryRepCode=(),
 rebuildACLTrigger=1,
 rebuildPrincipalSet=#f,
 serviceLevel=Instance<ServiceLevel, (oid #zEFD6BA2D681EB74D9B16D929EED70B46), clean>,
 touchTypeIntervals=Collection(0),
 nextBirthday=(),
 mobilePhoneAddress=(),
 executeRules=#t,
 workflowRuleTriggerType=CREATE,
 homePhoneAddress=(),
 homePhoneExtension=(),
 mobilePhoneExtension=()
)
Object

3. Login to the application and execute the testing script

    • This part of the test is done at the test level (Test Cases tab)
    • After the variable definition block (and don't worry, you can always add more variables into this block as you find necessary), we are now ready to login!
    • To login, we execute 

(sim'login login pwd)

    • Doing so will open a new browser. 
    • Note: Headless Mode must be turned off to see the browser. See the Troubleshooting UI automation page for help. 
    • You will know that this code has been executed successfully if you see something similar to: 

Starting ChromeDriver 2.38.552522 (437e6fbedfa8762dec75e2c5b3ddb86763dc9dcb) on port 19701
Only local connections are allowed.


    • The remainder of your test case after logging in is determined based on your recorder output and assert statements.


4. The Finalizer

    • Similar to the Initializer, the Finalizer has code that is executed at the end of every test. Note that in the case of the Finalizer, the test passing, failing or producing an error is not relevant; the code here will be executed regardless. 
    • This tab is used to close the browser that we had just tested. We can do so by adding

(sim'quit

to the Finalizer. This should be added to the Finalizer of every .utest file, although other .utest files might require additional code.


Example UI Test: CompaniesUI

Overview

Loops

Initializer

(set! app (ui-test-player "portal" browser))
(set! login (string-append "compUI" browser))
(set! pwd "nexj")
(unittest-create-privilege-group
   "CustomField"
   "WorkspaceCustomize"
   "AdminCustomFieldTypeManage"
   "AdminEditCustomFieldTypes"
   "PrivateCustomFieldTypeManage"
   "PublicCustomFieldTypeManage"
   "EnumDisplayManage"
   "EnumManage"
)
(pre-commit)
(unittest-create-update-user
   login
   (: updatablePassword pwd)
   (: groups '("ManageContacts" "CustomField"))
)
(commit)

Test Case

(define name1 "Company1")
(define tier1 "A")
(define status1 "Prospect")
(define name2 "Company2")
(define tier2 "B")
(define status2 "Client")
; login and navigate to contacts workspace
(app'login login pwd)
(app'use "navigator/1")
(app'click)
(app'use "workspaces/Contacts/refEntityNavigator/EntitySearch/fieldPicker/fieldPickerViewSelector#caption:Companies")
(app'click)
; launch add company window
(app'use "workspaces/Contacts/refEntityNavigator/EntityList/grdEntity/tools:0/0")
(app'click)
(app'use "workspaces/Contacts/refEntityNavigator/EntityList/grdEntity/tools:0/>#caption:Company...")
(app'click)
(app'use "OrganizationDetail/inpName")
(app'click)
(app'text name1)
(app'use "OrganizationDetail/cboStatus#popup")
(app'click)
(app'use "OrganizationDetail/cboStatus/#1")
(app'click)
(app'use "OrganizationDetail/cboTier")
(app'click)
(app'use "OrganizationDetail/cboTier/#1")
(app'click)
(app'use "FinishButton")
(app'click)
; search for company
(app'use "workspaces/Contacts/refEntityNavigator/EntitySearch/fieldPicker/fieldPickerFieldPicker/0")
(app'click)
(app'text (string-append name1 "\r"))
; assert companies details in grid
(app'use "workspaces/Contacts/refEntityNavigator/EntityList/grdEntity#cell.0.2")
(app'assertText name1)
(app'use "workspaces/Contacts/refEntityNavigator/EntityList/grdEntity#cell.0.4")
(app'assertText status1)
(app'use "workspaces/Contacts/refEntityNavigator/EntityList/grdEntity#cell.0.14")
(app'assertText tier1)
; edit company details
(app'use "workspaces/Contacts/refEntityNavigator/EntityList/grdEntity/__toolbar:0/0")
(app'click)
(app'use "grpDetailLayout/tabOrg/frmCompanyLayout/inpName")
(app'click)
(app'clear)
(app'text name2)
(app'use "grpDetailLayout/tabOrg/frmCompanyLayout/cboStatus")
(app'click)
(app'use "grpDetailLayout/tabOrg/frmCompanyLayout/cboStatus/#0")
(app'click)
(app'use "grpDetailLayout/tabOrg/frmCompanyLayout/cboTier")
(app'click)
(app'use "grpDetailLayout/tabOrg/frmCompanyLayout/cboTier/#2")
(app'click)
(app'use "FinishButton")
(app'click)
; search companies old name
(app'use "workspaces/Contacts/refEntityNavigator/EntitySearch/fieldPicker/fieldPickerFieldPicker/0")
(app'clear)
(app'text (string-append name1 "\r"))
(app'assertNotFound "workspaces/Contacts/refEntityNavigator/EntityList/grdEntity#cell.0.2")
; search companies new name
(app'use "workspaces/Contacts/refEntityNavigator/EntitySearch/fieldPicker/fieldPickerFieldPicker/0")
(app'clear)
(app'text (string-append name2 "\r"))
; assert companies details in grid
(app'use "workspaces/Contacts/refEntityNavigator/EntityList/grdEntity#cell.0.2")
(app'assertText name2)
(app'use "workspaces/Contacts/refEntityNavigator/EntityList/grdEntity#cell.0.4")
(app'assertText status2)
(app'use "workspaces/Contacts/refEntityNavigator/EntityList/grdEntity#cell.0.14")
(app'assertText tier2)
; delete company
(app'use "workspaces/Contacts/refEntityNavigator/EntityList/grdEntity/__toolbar:0/5")
(app'click)
(app'use "workspaces/Contacts/refEntityNavigator/EntityList/grdEntity/__toolbar:0/menu:#caption:Delete")
(app'click)
(app'use "actions:0")
(app'click)
; assert that the company is now deleted
(app'use "workspaces/Contacts/refEntityNavigator/EntitySearch/fieldPicker/fieldPickerFieldPicker/0")
(app'clear)
(app'text (string-append name2 "\r"))
(app'assertNotFound "workspaces/Contacts/refEntityNavigator/EntityList/grdEntity#cell.0.2")

Finalizer

(app'quit)