In this recipe, we will see how to implement a generic Login
class. The class captures both, the GUI structure and the processes that are common to all applications with regard to their user access module. It is agnostic to the particular object classes, their technologies, and other identification properties. The class shown here implements the command wrapper design pattern, as it encapsulates a process (Login
) with the main default method (Run
).
You can use the same function library cls.Google.vbs
as in the previous recipe Implementing a simple search class, or create a new one (for instance, cls.Login.vbs
) and associate it with your test.
Login
:Class Login Private m_wndContainer 'Such as a Browser, Window, SwfWindow Private m_wndLoginForm 'Such as a Page, Dialog, SwfWindow Private m_txtUsername 'Such as a WebEdit, WinEdit, SwfEdit Private m_txtIdField 'Such as a WebEdit, WinEdit, SwfEdit Private m_txtPassword 'Such as a WebEdit, WinEdit, SwfEdit Private m_chkRemember 'Such as a WebCheckbox, WinCheckbox, SwfCheckbox Private m_btnLogin 'Such as a WebEdit, WinEdit, SwfEdit End Class
These fields define the test objects, which are required for any Login
class, and the following fields are used to keep runtime data for the report:
Public Status 'As Integer Public Info 'As String
The Run
function is defined as a Default
method that accepts a Dictionary
as argument. This way, we can pass a set of named arguments, some of which are optional, such as timeout
.
Public Default Function Run(ByVal ArgsDic) 'Check if the timeout parameter was passed, if not assign it 10 seconds If Not ArgsDic.Exists("timeout") Then ArgsDic.Add "timeout", 10 'Check if the client window exists If Not me.Container.Exist(ArgsDic("timeout")) Then me.Status = micFail me.Info = "Failed to detect login browser/dialog/window." Exit Function End If 'Set the Username me.Username.Set ArgsDic("Username") 'If the login form has an additional mandatory field If me.IdField.Exist(ArgsDic("timeout")) And ArgsDic.Exists("IdField") Then me.IdField.Set ArgsDic("IdField") End If 'Set the password me.Password.SetSecure ArgsDic("Password") 'It is a common practice that Login forms have a checkbox to keep the user logged-in if set ON If me.Remember.Exist(ArgsDic("timeout")) And ArgsDic.Exists("Remember") Then me.Remember.Set ArgsDic("Remember") End If me.LoginButton.Click End Function
The Run
method actually performs the login procedure, setting the username and password, as well as checking or unchecking the Remember Me or Keep me Logged In checkbox according to the argument passed with the ArgsDic
dictionary.
The Initialize
method accepts Dictionary
just like the Run
method. However, in this case, we pass the actual TOs with which we wish to perform the login procedure. This way, we can actually utilize the class for any Login
form, whatever the technology used to develop it. We can say that the class is technology agnostic. The parent client dialog/browser/window of the objects is retrieved using the GetTOProperty("parent")
statement:
Function Initialize(ByVal ArgsDic) Set m_txtUsername = ArgsDic("Username") Set m_txtIdField = ArgsDic("IdField") Set m_txtPassword = ArgsDic("Password") Set m_btnLogin = ArgsDic("LoginButton") Set m_chkRemember = ArgsDic("Remember") 'Get Parents Set m_wndLoginForm = me.Username.GetTOProperty("parent") Set m_wndContainer = me.LoginForm.GetTOProperty("parent") End Function
In addition, here you can see the following properties used in the class for better readability:
Property Get Container() Set Container = m_wndContainer End Property Property Get LoginForm() Set LoginForm = m_wndLoginForm End Property Property Get Username() Set Username = m_txtUsername End Property Property Get IdField() Set IdField = m_txtIdField End Property Property Get Password() Set Password = m_txtPassword End Property Property Get Remember() Set Remember = m_chkRemember End Property Property Get LoginButton() Set LoginButton = m_btnLogin End Property Private Sub Class_Initialize() 'TODO: Additional initialization code here End Sub Private Sub Class_Terminate() 'TODO: Additional finalization code here End Sub
We will also add a custom function to override the WinEdit
and WinEditor Type
methods:
Function WinEditSet(ByRef obj, ByVal str) obj.Type str End Function
This way, no matter which technology the textbox belongs to, the Set
method will work seamlessly.
Login
class, write the following code in the Test Action (this time we assume that the Login
form was already opened by another procedure):Dim ArgsDic, oLogin 'Register the set method for the WinEdit and WinEditor RegisterUserFunc "WinEdit", "WinEditSet", "Set" RegisterUserFunc "WinEditor", "WinEditSet", "Set" 'Create a Dictionary object Set ArgsDic = CreateObject("Scripting.Dictionary") 'Create a Login object Set oLogin = New Login 'Add the test objects to the Dictionary With ArgsDic .Add "Username", Browser("Gmail").Page("Gmail").WebEdit("txtUsername") .Add "Password", Browser("Gmail").Page("Gmail").WebEdit("txtPassword") .Add "Remember", Browser("Gmail").Page("Gmail").WebCheckbox("chkRemember") .Add "LoginButton", Browser("Gmail").Page("Gmail").WebButton("btnLogin") End With 'Initialize the Login class oLogin.Initialize(ArgsDic) 'Initialize the dictionary to pass the arguments to the login ArgsDic.RemoveAll With ArgsDic .Add "Username", "myuser" .Add "Password", "myencriptedpassword" .Add "Remember", "OFF" End With 'Login oLogin.Run(ArgsDic) 'or: oLogin(ArgsDic) 'Report result Reporter.ReportEvent oLogin.Status, "Login", "Ended with " & GetStatusText(oLogin.Status) & "." & vbNewLine & oStatus.Info 'Dispose of the objects Set oLogin = Nothing Set ArgsDic = Nothing
Here, we will not delve into the parts of the code already explained in the Implementing a simple search class recipe. Let's see what we did in this recipe:
WinEditSet
to the WinEdit
and WinEditor
TO classes using RegisterUserFunc
. As discussed previously, this will make every call to the method set to be rerouted to our custom function, resulting in applying the correct method to the Standard Windows text fields.Dictionary
object and a Login
object.Dictionary
, and then invoked its Initialize
method, passing the Dictionary
as the argument.Dictionary
and then added to it the values needed for actually executing the login (Username
, Password
, and the whether to remember the user or keep logged in checkboxes usually used in Login
forms).Run
method for the Login
class with the newly populated Dictionary
.Status
and Info
public fields from the oLogin
object.StdWin
in this case).