GUI ScriptingThe standard PicoLisp GUI (in "@lib/xhtml.l" and "@lib/form.l") can be completely driven under program control. A set of functions in "@lib/scrape.l" allows you to write scripts for automated
- database queries and updates
A Simple ExampleLet's use the demo application that comes with the PicoLisp distribution. You can start it locally, and access it as http://localhost:8080 (recommended), or - if this is not an option - try the online demo at http://app.7fach.de.
The demo application is a simplified ERP system, containing things like customers, articles and orders. For the following example, we want to find the price of an article with the name "Spare Part".
Using the Browser GUINormally, you would connect to the server with a browser,
log in on the first page (by typing user name and password, and pressing the "login" button),
then search for that article in the "Items" search dialog (after clicking on the "Items" link in the "Data" submenu),
and read the price on the page of that item (here: 12.50).
Using GUI ScriptingThe same result can be obtained without a browser, by interacting on the REPL with the remote application. We assume that the demo application is still running locally at http://localhost:8080.
Start PicoLisp, and load the necessary libraries:
$ pil + : (load "@lib/http.l" "@lib/scrape.l")Call scrape to connect to the server
: (scrape "localhost" 8080) -> "PicoLisp App"If you must use the online demo server, call (scrape "7fach.de" 80 "8080") instead, telling scrape to connect to port 80 of that server (where 'httpGate' is running), and then to dispatch to 8080 (the application's address).
Now log in:
: (expect "'admin' logged in" (enter 3 "admin") (enter 4 "admin") (press "login") ) -> NIL(Caveat: Keep in mind a fundamental feature of the PicoLisp server: Whenever a second log in of the same user from the same IP address is detected, the first session of that user is automatically terminated. This means that you cannot run a GUI and a scrape session with user "admin" at the same time. If you already had a gui session open, it will be dead now.)
expect takes a string argument - a pattern which is to be expected on the resulting page after the body (the remaining arguments) was executed. This body enters two values (the user name and the password) into the appropriate fields, and presses the "login" button.
enter takes a field specification and a value. The first call with 3 refers to the "Name" field, as this is the third field on the form (the first field is the "TimeOut" indicator, and the second one is the language selector). The next field, field number 4, is the password field.
Finally, press simulates a press of the corresponding button, and the message "'admin' logged in" appears on the page, satisfying expect.
Then, just as in the GUI, click on the "Items" link to open the dialog. We forgo the expect here, and assume that the dialog can't fail:
: (click "Items") -> "Item"We also assume that "Spare Part" readily appears in the result list of the search dialog (it was on the second line). A real script would interact with the dialog to find the desired item. So we just click on it:
: (click "Spare Part") -> "Item"Now the page of that article is open. Counting the fields, we find that the price is in the 8th one. We can read that field's value, and get the same result as in the GUI session above:
: (value 8) -> "12.50"Note that you can also get an overview of the current page with display:
: (display) ############### click "Home" "logout" "Data" "Orders" "Items" "Customers/Suppliers" "Salutations" "Report" "Inventory" "Sales" "System" "<<<" ">>>" "obj" press "Edit" "Delete" "Select" "+" "Install" "Edit" value "TimeOut 12:11" "2" "Spare Part" "Seven Oaks UnLtd." "Winterburg" "100" "98" "12.50" -> "Item"This helps you to find the positions of links, buttons and fields.
Finally, we should log out:
: (click "logout") -> "PicoLisp App"
The Scrape LibraryTo use the GUI scripting functionality, you need to load "@lib/http.l" and "@lib/scrape.l". It implements the following functions:
- (scrape 'host 'port 'how) -> sym | lst Sets up an environment for further operations on an application, which can be connected on a server at host and port, and an optional URL argument how. Returns the title of the page if no errors occurred, otherwise a list of error messages.
- (expect 'sym . prg) Executes a prg body (holding calls to the functions explained below), and checks for an expected pattern sym in the server output.
- (click 'label ['cnt]) -> sym | lst Simulates the click on a link. The first (or cnt'th) link found on the page which has label as a prefix is used. Returns the result of scrape.
- (press 'label ['cnt]) -> sym | lst Simulates the press of a button. The first (or cnt'th) button found on the page which has label as a prefix is used. Returns the result of scrape.
- (value 'field ['cnt]) -> sym Returns the current value of the GUI field. The field argument may be either a positive number (to specify the cnt'th field on the page), a negative number (to specify the -cnt'th last field on the page), or the field's name. If the name is given, then cnt may specify the form if more than one form is on the page.
- (enter 'field 'sym ['cnt]) -> sym Enters a value sym into the GUI field. The field argument may be either a positive number (to specify the cnt'th field on the page), a negative number (to specify the -cnt'th last field on the page), or the field's name. If the name is given, then cnt may specify the form if more than one form is on the page.
- (display) -> sym Display the state of the current page. First a line ############### is printed as a visual separator, then all available links and buttons, and the values of all GUI fields is printed.
Let your imagination fly!