2020 November Release

Recording a TestPermanent link for this heading

To record a test, proceed as follows:

  1. Open the test file and enter the sample code below (either for Fabasoft Folio or Fabasoft Cloud).
  2. Add a breakpoint on the third line (double-click the left border of the source code editor).
  3. Run a run configuration.
    If everything works fine, a web browser will be opened and the Fabasoft Folio or Fabasoft Cloud user interface is shown. The test run stops at the breakpoint.
  4. In the ARIA tree you can record the actions that should be carried out. To do so, navigate to the desired node open the context menu command and click the wanted command (e.g. Click). The selected action will be inserted in the source code.
  5. To define where the statement should be inserted, move the cursor to the desired line and click the “Run to Line” command in the debug symbol bar. The statement will be inserted before the instruction pointer.

By inserting some statements, you record your test. When you are done you can stop the debug session.

Sample Code

// Fabasoft Folio example (basic authentication)
// replace <username> and <password> with the values of an existing user

test "Test" {
session Seq1("<username>", "<password>") {
    mystr = "string"
// add breakpoint here


// Fabasoft Cloud example
test "Test" {
session Seq1() {
    mystr = "string"
// add breakpoint here


The following chapters describe the recording process in detail.

NavigationPermanent link for this heading

When recording a test, you can navigate in the test file the following way:

  • Breakpoint
    The execution continues until a breakpoint is reached. The line with the breakpoint is not executed.
  • Resume (F8)
    A stopped execution will be resumed until a breakpoint is reached or the end of the test.
  • Step Into (F5)
    Executes the current statement. If the statement is a function definition the debugger enters the function.
  • Step Over (F6)
    Executes the current statement. If the statement is a function definition the debugger executes the function without entering it.
  • Step Return (F7)
    Returns to the line where the function definition was called.
  • Run to Line (Ctrl + R)
    Sets the instruction pointer to the line of the current caret position. The further execution will start on that line and recorded statements via the ARIA tree or click recorder are inserted one line before the instruction pointer.

ARIA TreePermanent link for this heading

The ARIA tree represents the user interface. You can navigate through the tree and record actions (like “Click”) on the elements.

To insert a statement in the source code, proceed as follows:

  1. Navigate to the desired element in the ARIA tree (e.g. a button).
  2. Open the context menu of the element and click an action (like “Click”).
    The corresponding statement is entered in the source code file one line before the instruction pointer and it is also executed in the web browser.


  • Some actions like SetValue need an additional input. In this case the action is not executed right away. You can enter the additional input in the source code editor and execute the statement by clicking “Step Into” (F5).
  • If you interact in the web browser manually via the user interface, click the “Refresh” button in the symbol bar of the “ARIA Tree” area to refresh the tree.

Click RecorderPermanent link for this heading

In the “ARIA Tree” area you can enable the click recorder by clicking the “Toggle Click Recording” button. The interaction with the user interface in the web browser will be recorded and entered in the source file. To stop recording click the button again.


  • Click recording can only be used with Google Chrome or Microsoft Edge.
  • The click recorder does not support every possible interaction. For these cases use the recording functionality of the ARIA tree.

Editing the Source CodePermanent link for this heading

The easiest way to add statements is the recording functionality but you can also write statements directly in the source code. In addition, control structures (like if, while etc.) and annotations can be easily added to enhance the test.

For more information have a look at chapter “Fabasoft app.test DSL”.

Advanced PossibilitiesPermanent link for this heading

Fabasoft app.test provides the following advanced functionality.


Provides mainly operating system functionality like renaming a file. When entering the external session or a special command, the possibilities are displayed in the “ARIA Tree” area. In general, a command is selected (Select), some parameters are set (SetValue), the command is executed (Execute) and closed (Close).


session (applicationtype="JAVA", clienttype="External",
    jarfile="apptest-commander.jar", classname="Commander") {

  // rename a file  
  Select 'Commands.Rename'
  SetValue("{~path~}/{~tc~}/{~textdoc1~}.txt") 'Commands.Rename.Path'
  SetValue("renamed3.txt") 'Commands.Rename.RenameTo'
  Execute 'Commands.Rename'
  Close 'Commands.Rename'

  // execute JavaScript
  val = ExecuteScript("return document.querySelectorAll('.FscH').length")

  // run a unit test
  Select 'Commands.RunTest'
  // provided URL parameters are available in the unit test
  // e.g.: group={~bx~}&sendmail=false

  SetValue("{~querystring~}") 'Commands.RunTest.QueryString'
  // reference of the unit test
  // e.g.: FSCFOLIOCLOUDUTPREPARATIONS@1.1001:PrepareCheckDeadlines

  SetValue("{~unittest~}") 'Commands.RunTest.UnitTest'
  // the web service URL
  SetValue("{~uturl~}") 'Commands.RunTest.Address'
  // the user who executes the unit test
  SetValue("Administrator") 'Commands.RunTest.Username'
  SetValue("{~testuser_pwd~}") 'Commands.RunTest.Password'
  SetValue(false) 'Commands.RunTest.SSLVerify'

  Execute 'Commands.RunTest'
  uterror = GetValue 'Commands.RunTest.ErrorMessage'
  Close 'Commands.RunTest'

  // run an app.ducx expression

  Select 'Commands.Expression'
  // the app.dux expression
  // e.g.:
  SetValue("{~expr~}") 'Commands.Expression.Expression'
SetValue("GET") 'Commands.Expression.Method'
  // the web service URL
  SetValue("{~uturl~}") 'Commands.Expression.Address'
  // the user who starts the command
  SetValue("Administrator") 'Commands.Expression.Username'
  SetValue("{~testuser_pwd~}") 'Commands.Expression.Password'
  // the expression is executed as the defined user (impersonated)
  SetValue("{~expruser~}") 'Commands.Expression.ExecuteAsUsername'
  SetValue(false) 'Commands.Expression.SSLVerify'
  SetValue(120000) 'Commands.Expression.Timeout'

  Execute 'Commands.Expression'
  zexprresult = GetValue 'Commands.Expression.ResponseStatusCode'
  zexprbody = GetValue 'Commands.Expression.Body'
  Close 'Commands.Expression'

  // start a scenario (can be used to prepare a test environment)
  // scenarios can be definined in Fabasoft app.ducx

  Select @Commands.StartScenario
  SetValue("{~scenario~}") 'Commands.StartScenario.Scenario'
  SetValue("{~baseurl~}") 'Commands.StartScenario.Address'
  SetValue("Administrator") 'Commands.StartScenario.Username'
  SetValue("{~testuser_pwd~}") 'Commands.StartScenario.Password'
  SetValue("{~testid~}") 'Commands.StartScenario.SessionId'
  SetValue("{~scope~}") 'Commands.StartScenario.Scope'
  SetValue(false) 'Commands.StartScenario.SSLVerify'

  Execute 'Commands.StartScenario'
  scid = GetValue 'Commands.StartScenario.CreatedSessionId'
  scerror = GetValue 'Commands.StartScenario.ErrorMessage'
  // contains the scenario return values, available as variables
  scbody = GetValue 'Commands.StartScenario.Body'
  Close 'Commands.StartScenario'

  // stop a scenario (cleanup after a test run)
  Select 'Commands.StopScenario'
  SetValue("{~scid~}") 'Commands.StopScenario.SessionId'
  SetValue("{~baseurl~}") 'Commands.StopScenario.Address'
  SetValue("Administrator") 'Commands.StopScenario.Username'
  SetValue("{~testuser_pwd~}") 'Commands.StopScenario.Password'
  SetValue(false) 'Commands.StopScenario.SSLVerify'
  Execute 'Commands.StopScenario'
  sessionerror = GetValue 'Commands.StopScenario.ErrorMessage'
  Close 'Commands.StopScenario'

  // execute an abitrary shell command
  Select 'Commands.Execute'
  SetValue(true) 'Commands.Execute.Asynchronous'
  SetValue("someStdOutFile.txt") 'Commands.Execute.StdOutFile'
  SetValue("someStdErrFile.txt ") 'Commands.Execute.StdErrFile'
  SetValue("dir") 'Commands.Execute.Command'
  SetValue(false) 'Commands.Execute.Elevate'
  Execute 'Commands.Execute'
  cierror = GetValue 'Commands.Execute.Error Stream'
  ciresult = GetValue 'Commands.Execute.Output Stream'
  exitCode = GetValue 'Commands.Execute.Exit Code'
  Close 'Commands.Execute'



Provides the possibility to retrieve e-mails from a mailbox.


session (applicationtype="JAVA", clienttype="EXTERNAL",
    jarfile="apptest-mail.jar", classname="Mail") {

  // retrieve an e-mail from a mailbox
  SetValue("{~mailserver~}", "server")
  SetValue("{~zmailusername~}", "username")
  SetValue("{~zmailpassword~}", "password")
  Connect 'Mailbox'

  Assert(Exists) '{~zmailusername~}'
  Assert(Exists) '{~zmailusername~}.{~subject~}'
  [E] mailfrom = GetValue '{~zmailusername~}.{~subject~}[1]'
  // e-mail is selected based on the subject
  mailcontent = GetValue '{~zmailusername~}.{~subject~}.Text Content'
  // e.g. if there are links in the e-mail they can be retrieved seperately
  [E] mailadd1 = GetValue '{~zmailusername~}.{~subject~}.Content.[1]'
  [E] mailadd2 = GetValue '{~zmailusername~}.{~subject~}.Content.[2]'
  [E] mailadd3 = GetValue '{~zmailusername~}.{~subject~}.Content.[3]'
  [E] mailadd4 = GetValue '{~zmailusername~}.{~subject~}.Content.[4]'
  [E] mailadd5 = GetValue '{~zmailusername~}.{~subject~}.Content.[5]'

  // delete all e-mails in a mailbox    
  SetValue("{~mailserver~}", "server")
  SetValue("{~zmailusername~}", "username")
  SetValue("{~zmailpassword~}", "password")
  Connect 'Mailbox'

  Assert(Exists) '{~zmailusername~}'
  DeleteAll '{~zmailusername~}'


Best PracticesPermanent link for this heading

To create the best possible tests, here are some hints:

  • When using a CI and running tests in parallel, you can use the system variable scope to ensure that each scoped user (e.g. jones0001 to jones0016) is not used at the same time.
  • You can create a token at the beginning of a test (if you want to name the objects in a unique way). You can for example create a token out of the time stamp and the scope.
  • Statement blocks that are used by many tests can be put in function definition files and reused in tests. This way you must maintain common functions only in one place.
  • The size of tests should be limited to avoid long waiting time until the line is reached where changes are needed. Maximal 800 lines is a reasonable size.
  • Separate logical statement blocks by an empty line and comment the block to ease maintenance.
  • Use the annotation [WaitUntilExists] if asynchronous calls take place (e.g. when importing files).
  • Define variables for names and annotate them with [AutoReplace] or [A]. This way when recording tests, strings matching the variable value will be automatically replaced by the variable.
  • Determining the language of a web page
    In some cases it might be useful to know the language of the web page or even of a specific control as defined in the lang or xml:lang attribute. This can be achieved with the GetLanguage function.
    Fabasoft app.test:
    lang1 = GetLanguage @document(0)
    lang2 =
    GetLanguage @document(0).alert[text "Cloud"]
    <html lang="de">
    <div id="
    pluginalertheader" role="alert">
      Fabasoft <span

    lang1 = de
    lang2 =