├── Server.res
├── DelphiWebDriver.res
├── TestHost
├── TestHost.res
├── TestHost.dpr
└── HostMain.pas
├── TestClient
├── TestClient.res
├── TestClient.dpr
├── Unit3.dfm
├── Unit3.pas
└── TestClient.dproj
├── Utils.pas
├── JsonAttributeSource.pas
├── Unit1.dfm
├── Server.dpr
├── Unit1.pas
├── .gitignore
├── ResourceProcessing.pas
├── DelphiWebDriver.dpk
├── Commands
├── Commands.GetWindowHandle.pas
├── Commands.DeleteSession.pas
├── Commands.CreateSession.pas
├── Commands.PostClear.pas
├── Commands.GetRect.pas
├── Commands.PostValue.pas
├── Commands.GetEnabled.pas
├── Commands.PostElementElements.pas
├── Commands.ClickElement.pas
├── Commands.GetElementValue.pas
├── Commands.GetText.pas
├── Commands.PostElements.pas
├── Commands.PostExecute.pas
├── Commands.PostElement.pas
└── Commands.pas
├── ServerAndClient.groupproj
├── HttpServerCommand.pas
├── Session.pas
├── RestServer.pas
├── README.md
├── CommandRegistry.pas
├── Sessions.pas
├── DelphiWebDriver.dproj
└── LICENSE
/Server.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mmarquee/DelphiWebDriver/HEAD/Server.res
--------------------------------------------------------------------------------
/DelphiWebDriver.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mmarquee/DelphiWebDriver/HEAD/DelphiWebDriver.res
--------------------------------------------------------------------------------
/TestHost/TestHost.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mmarquee/DelphiWebDriver/HEAD/TestHost/TestHost.res
--------------------------------------------------------------------------------
/TestClient/TestClient.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mmarquee/DelphiWebDriver/HEAD/TestClient/TestClient.res
--------------------------------------------------------------------------------
/TestClient/TestClient.dpr:
--------------------------------------------------------------------------------
1 | program TestClient;
2 |
3 | uses
4 | Vcl.Forms,
5 | Unit3 in 'Unit3.pas' {Form3};
6 |
7 | {$R *.res}
8 |
9 | begin
10 | Application.Initialize;
11 | Application.MainFormOnTaskbar := True;
12 | Application.CreateForm(TForm3, Form3);
13 | Application.Run;
14 | end.
15 |
--------------------------------------------------------------------------------
/Utils.pas:
--------------------------------------------------------------------------------
1 | unit Utils;
2 |
3 | interface
4 |
5 | function isNumber(const s: String): boolean;
6 |
7 | implementation
8 |
9 | function isNumber(const s: String): boolean;
10 | var
11 | iValue, iCode: Integer;
12 | begin
13 | val(s, iValue, iCode);
14 | result := (iCode = 0)
15 | end;
16 |
17 | end.
18 |
--------------------------------------------------------------------------------
/JsonAttributeSource.pas:
--------------------------------------------------------------------------------
1 | unit JsonAttributeSource;
2 |
3 | interface
4 |
5 | type
6 | JsonAttribute = class(TCustomAttribute)
7 | private
8 | FName: String;
9 | public
10 | constructor Create(const AName: String);
11 | property Name: String read FName;
12 | end;
13 |
14 | implementation
15 |
16 |
17 | constructor JsonAttribute.Create(const AName: String);
18 | begin
19 | FName := AName;
20 | end;
21 |
22 | end.
23 |
--------------------------------------------------------------------------------
/Unit1.dfm:
--------------------------------------------------------------------------------
1 | object Form1: TForm1
2 | Left = 0
3 | Top = 0
4 | Caption = 'Form1'
5 | ClientHeight = 299
6 | ClientWidth = 635
7 | Color = clBtnFace
8 | Font.Charset = DEFAULT_CHARSET
9 | Font.Color = clWindowText
10 | Font.Height = -11
11 | Font.Name = 'Tahoma'
12 | Font.Style = []
13 | OldCreateOrder = False
14 | PixelsPerInch = 96
15 | TextHeight = 13
16 | object Button1: TButton
17 | Left = 8
18 | Top = 266
19 | Width = 75
20 | Height = 25
21 | Caption = 'Start'
22 | TabOrder = 0
23 | OnClick = Button1Click
24 | end
25 | object ListBox1: TListBox
26 | Left = 8
27 | Top = 8
28 | Width = 619
29 | Height = 252
30 | ItemHeight = 13
31 | TabOrder = 1
32 | end
33 | object Button2: TButton
34 | Left = 89
35 | Top = 266
36 | Width = 75
37 | Height = 25
38 | Caption = 'Stop'
39 | Enabled = False
40 | TabOrder = 2
41 | OnClick = Button2Click
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/Server.dpr:
--------------------------------------------------------------------------------
1 | program Server;
2 |
3 | uses
4 | Vcl.Forms,
5 | Unit1 in 'Unit1.pas' {Form1},
6 | RestServer in 'RestServer.pas',
7 | CommandRegistry in 'CommandRegistry.pas',
8 | Commands in 'Commands.pas',
9 | Session in 'Session.pas',
10 | HttpServerCommand in 'HttpServerCommand.pas',
11 | ResourceProcessing in 'ResourceProcessing.pas',
12 | Sessions in 'Sessions.pas',
13 | JsonAttributeSource in 'JsonAttributeSource.pas',
14 | Commands.PostElement in 'Commands.PostElement.pas',
15 | Commands.PostElements in 'Commands.PostElements.pas',
16 | Commands.ClickElement in 'Commands.ClickElement.pas',
17 | Utils in 'Utils.pas',
18 | Commands.PostElementElementsCommand in 'Commands.PostElementElementsCommand.pas',
19 | Commands.GetText in 'Commands.GetText.pas',
20 | Commands.GetRect in 'Commands.GetRect.pas';
21 |
22 | {$R *.res}
23 |
24 | begin
25 | Application.Initialize;
26 | Application.MainFormOnTaskbar := True;
27 | Application.CreateForm(TForm1, Form1);
28 | Application.Run;
29 | end.
30 |
--------------------------------------------------------------------------------
/Unit1.pas:
--------------------------------------------------------------------------------
1 | unit Unit1;
2 |
3 | interface
4 |
5 | uses
6 | RestServer,
7 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
8 | Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
9 |
10 | type
11 | TForm1 = class(TForm)
12 | Button1: TButton;
13 | ListBox1: TListBox;
14 | Button2: TButton;
15 | procedure Button1Click(Sender: TObject);
16 | procedure Button2Click(Sender: TObject);
17 | private
18 | { Private declarations }
19 | FRestServer : TRestServer;
20 | procedure createServer(port: word);
21 | procedure destroyServer;
22 | procedure LogMessage(const msg: String);
23 | public
24 | { Public declarations }
25 | end;
26 |
27 | var
28 | Form1: TForm1;
29 |
30 | implementation
31 |
32 | {$R *.dfm}
33 |
34 | procedure TForm1.LogMessage(const msg: String);
35 | begin
36 | listbox1.Items.Add(msg);
37 | end;
38 |
39 | procedure TForm1.Button1Click(Sender: TObject);
40 | begin
41 | createServer(4723);
42 |
43 | Button1.enabled := false;
44 | Button2.enabled := true;
45 |
46 | end;
47 |
48 | procedure TForm1.Button2Click(Sender: TObject);
49 | begin
50 | destroyServer;
51 |
52 | listbox1.Items.Add('Stopping server');
53 |
54 | Button1.enabled := true;
55 | Button2.enabled := false;
56 | end;
57 |
58 | procedure TForm1.createServer(port: word);
59 | begin
60 | listbox1.Items.Add('Starting server on port ' + IntToStr(port));
61 | FRestServer := TRestServer.Create(self);
62 | FRestServer.OnLogMessage := LogMessage;
63 | FRestServer.Start(port);
64 | end;
65 |
66 | procedure TForm1.destroyServer;
67 | begin
68 | FRestServer.Free;
69 | end;
70 |
71 | end.
72 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Uncomment these types if you want even more clean repository. But be careful.
2 | # It can make harm to an existing project source. Read explanations below.
3 | #
4 | # Resource files are binaries containing manifest, project icon and version info.
5 | # They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files.
6 | #*.res
7 | #
8 | # Type library file (binary). In old Delphi versions it should be stored.
9 | # Since Delphi 2009 it is produced from .ridl file and can safely be ignored.
10 | #*.tlb
11 | #
12 | # Diagram Portfolio file. Used by the diagram editor up to Delphi 7.
13 | # Uncomment this if you are not using diagrams or use newer Delphi version.
14 | #*.ddp
15 | #
16 | # Visual LiveBindings file. Added in Delphi XE2.
17 | # Uncomment this if you are not using LiveBindings Designer.
18 | #*.vlb
19 | #
20 | # Deployment Manager configuration file for your project. Added in Delphi XE2.
21 | # Uncomment this if it is not mobile development and you do not use remote debug feature.
22 | #*.deployproj
23 | #
24 | # C++ object files produced when C/C++ Output file generation is configured.
25 | # Uncomment this if you are not using external objects (zlib library for example).
26 | #*.obj
27 | #
28 |
29 | # Delphi compiler-generated binaries (safe to delete)
30 | *.exe
31 | *.dll
32 | *.bpl
33 | *.bpi
34 | *.dcp
35 | *.so
36 | *.apk
37 | *.drc
38 | *.map
39 | *.dres
40 | *.rsm
41 | *.tds
42 | *.dcu
43 | *.lib
44 | *.a
45 | *.o
46 | *.ocx
47 |
48 | # Delphi autogenerated files (duplicated info)
49 | *.cfg
50 | *.hpp
51 | *Resource.rc
52 |
53 | # Delphi local files (user-specific info)
54 | *.local
55 | *.identcache
56 | *.projdata
57 | *.tvsconfig
58 | *.dsk
59 |
60 | # Delphi history and backups
61 | __history/
62 | __recovery/
63 | *.~*
64 |
65 | # Castalia statistics file (since XE7 Castalia is distributed with Delphi)
66 | *.stat
67 |
--------------------------------------------------------------------------------
/ResourceProcessing.pas:
--------------------------------------------------------------------------------
1 | unit ResourceProcessing;
2 |
3 | interface
4 |
5 | function GetModuleVersion: String;
6 | function GetAppRevision: String;
7 |
8 | implementation
9 |
10 | uses
11 | System.Types,
12 | System.SysUtils,
13 | System.StrUtils,
14 | System.Classes,
15 | Winapi.Windows;
16 |
17 | // via http://stackoverflow.com/questions/10854958/how-to-get-version-of-running-executable
18 | function GetFullModuleVersion(Instance: THandle; out iMajor, iMinor, iRelease, iBuild: Integer): Boolean;
19 | var
20 | fileInformation: PVSFIXEDFILEINFO;
21 | verlen: Cardinal;
22 | rs: TResourceStream;
23 | m: TMemoryStream;
24 | begin
25 | if Instance = 0 then
26 | Instance := HInstance;
27 |
28 | FindResource(Instance, MAKEINTRESOURCE(100), RT_VERSION);
29 |
30 | m := TMemoryStream.Create;
31 | try
32 | rs := TResourceStream.CreateFromID(Instance, 1, RT_VERSION);
33 | try
34 | m.CopyFrom(rs, rs.Size);
35 | finally
36 | rs.Free;
37 | end;
38 |
39 | m.Position:=0;
40 | if not VerQueryValue(m.Memory, '\', (*var*)Pointer(fileInformation), (*var*)verlen) then
41 | begin
42 | iMajor := 0;
43 | iMinor := 0;
44 | iRelease := 0;
45 | iBuild := 0;
46 | Exit(false);
47 | end;
48 |
49 | iMajor := fileInformation.dwFileVersionMS shr 16;
50 | iMinor := fileInformation.dwFileVersionMS and $FFFF;
51 | iRelease := fileInformation.dwFileVersionLS shr 16;
52 | iBuild := fileInformation.dwFileVersionLS and $FFFF;
53 | finally
54 | m.Free;
55 | end;
56 |
57 | Result := True;
58 | end;
59 |
60 | function GetModuleVersion: String;
61 | var
62 | minor, major, release, build : integer;
63 | begin
64 | GetFullModuleVersion (0, major, minor, release, build);
65 |
66 | result := Format('%d.%d', [major, minor]);
67 | end;
68 |
69 | function GetAppRevision: String;
70 | var
71 | minor, major, release, build : integer;
72 | begin
73 | GetFullModuleVersion (0, major, minor, release, build);
74 |
75 | result := Format('%d.%d', [release, build]);
76 | end;
77 |
78 | end.
79 |
--------------------------------------------------------------------------------
/DelphiWebDriver.dpk:
--------------------------------------------------------------------------------
1 | package DelphiWebDriver;
2 |
3 | {$R *.res}
4 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users}
5 | {$ALIGN 8}
6 | {$ASSERTIONS ON}
7 | {$BOOLEVAL OFF}
8 | {$DEBUGINFO OFF}
9 | {$EXTENDEDSYNTAX ON}
10 | {$IMPORTEDDATA ON}
11 | {$IOCHECKS ON}
12 | {$LOCALSYMBOLS ON}
13 | {$LONGSTRINGS ON}
14 | {$OPENSTRINGS ON}
15 | {$OPTIMIZATION OFF}
16 | {$OVERFLOWCHECKS OFF}
17 | {$RANGECHECKS OFF}
18 | {$REFERENCEINFO ON}
19 | {$SAFEDIVIDE OFF}
20 | {$STACKFRAMES ON}
21 | {$TYPEDADDRESS OFF}
22 | {$VARSTRINGCHECKS ON}
23 | {$WRITEABLECONST OFF}
24 | {$MINENUMSIZE 1}
25 | {$IMAGEBASE $400000}
26 | {$DEFINE DEBUG}
27 | {$ENDIF IMPLICITBUILDING}
28 | {$RUNONLY}
29 | {$IMPLICITBUILD ON}
30 |
31 | requires
32 | IndyCore,
33 | IndyProtocols,
34 | rtl,
35 | vcl;
36 |
37 | contains
38 | CommandRegistry in 'CommandRegistry.pas',
39 | Commands.ClickElement in 'Commands\Commands.ClickElement.pas',
40 | Commands.GetRect in 'Commands\Commands.GetRect.pas',
41 | Commands.GetText in 'Commands\Commands.GetText.pas',
42 | Commands in 'Commands\Commands.pas',
43 | Commands.PostElement in 'Commands\Commands.PostElement.pas',
44 | Commands.PostElementElements in 'Commands\Commands.PostElementElements.pas',
45 | Commands.PostElements in 'Commands\Commands.PostElements.pas',
46 | HttpServerCommand in 'HttpServerCommand.pas',
47 | JsonAttributeSource in 'JsonAttributeSource.pas',
48 | ResourceProcessing in 'ResourceProcessing.pas',
49 | RestServer in 'RestServer.pas',
50 | Session in 'Session.pas',
51 | Sessions in 'Sessions.pas',
52 | Utils in 'Utils.pas',
53 | Commands.CreateSession in 'Commands\Commands.CreateSession.pas',
54 | Commands.PostExecute in 'Commands\Commands.PostExecute.pas',
55 | Commands.GetEnabled in 'Commands\Commands.GetEnabled.pas',
56 | Commands.PostValue in 'Commands\Commands.PostValue.pas',
57 | Commands.DeleteSession in 'Commands\Commands.DeleteSession.pas',
58 | Commands.GetWindowHandle in 'Commands\Commands.GetWindowHandle.pas',
59 | Commands.PostClear in 'Commands\Commands.PostClear.pas',
60 | Commands.GetElementValue in 'Commands\Commands.GetElementValue.pas';
61 |
62 | end.
63 |
--------------------------------------------------------------------------------
/Commands/Commands.GetWindowHandle.pas:
--------------------------------------------------------------------------------
1 | {***************************************************************************}
2 | { }
3 | { DelphiWebDriver }
4 | { }
5 | { Copyright 2017 inpwtepydjuf@gmail.com }
6 | { }
7 | {***************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the "License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {***************************************************************************}
22 | unit Commands.GetWindowHandle;
23 |
24 | interface
25 |
26 | uses
27 | Commands;
28 |
29 | type
30 | TGetWindowHandleCommand = class(TUnimplementedCommand)
31 | public
32 | class function GetCommand: String; override;
33 | class function GetRoute: String; override;
34 | end;
35 |
36 | implementation
37 |
38 | class function TGetWindowHandleCommand.GetCommand: String;
39 | begin
40 | result := 'GET';
41 | end;
42 |
43 | class function TGetWindowHandleCommand.GetRoute: String;
44 | begin
45 | result := '/session/(.*)/window_handle';
46 | end;
47 |
48 | end.
49 |
--------------------------------------------------------------------------------
/ServerAndClient.groupproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {F0632DB7-C065-419A-AD41-FF66399F1522}
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | Default.Personality.12
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/Commands/Commands.DeleteSession.pas:
--------------------------------------------------------------------------------
1 | {***************************************************************************}
2 | { }
3 | { DelphiWebDriver }
4 | { }
5 | { Copyright 2017 inpwtepydjuf@gmail.com }
6 | { }
7 | {***************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the "License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {***************************************************************************}
22 | unit Commands.DeleteSession;
23 |
24 | interface
25 |
26 | uses
27 | Sessions,
28 | Vcl.Forms,
29 | CommandRegistry,
30 | HttpServerCommand;
31 |
32 | type
33 | ///
34 | /// Handles 'DELETE' '/session/(.*)'
35 | ///
36 | TDeleteSessionCommand = class(TRestCommand)
37 | public
38 | class function GetCommand: String; override;
39 | class function GetRoute: String; override;
40 |
41 | procedure Execute(AOwner: TForm); override;
42 | end;
43 |
44 | implementation
45 |
46 | uses
47 | System.SysUtils,
48 | Commands;
49 |
50 | procedure TDeleteSessionCommand.Execute(AOwner: TForm);
51 | begin
52 | try
53 | // Need to delete it!
54 | Commands.Sessions.DeleteSession(self.Params[1]);
55 |
56 | except on e: Exception do
57 | Error(404);
58 | end;
59 | end;
60 |
61 | class function TDeleteSessionCommand.GetCommand: String;
62 | begin
63 | result := 'DELETE';
64 | end;
65 |
66 | class function TDeleteSessionCommand.GetRoute: String;
67 | begin
68 | result := '/session/(.*)';
69 | end;
70 |
71 | end.
72 |
--------------------------------------------------------------------------------
/Commands/Commands.CreateSession.pas:
--------------------------------------------------------------------------------
1 | {***************************************************************************}
2 | { }
3 | { DelphiWebDriver }
4 | { }
5 | { Copyright 2017 inpwtepydjuf@gmail.com }
6 | { }
7 | {***************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the "License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {***************************************************************************}
22 | unit Commands.CreateSession;
23 |
24 | interface
25 |
26 | uses
27 | CommandRegistry,
28 | Vcl.Forms,
29 | HttpServerCommand;
30 |
31 | type
32 | ///
33 | /// Handles 'POST' '/session'
34 | ///
35 | TCreateSessionCommand = class(TRESTCommand)
36 | public
37 | class function GetCommand: String; override;
38 | class function GetRoute: String; override;
39 |
40 | procedure Execute(AOwner: TForm); override;
41 | end;
42 |
43 | implementation
44 |
45 | uses
46 | Commands,
47 | Session;
48 |
49 | class function TCreateSessionCommand.GetCommand: String;
50 | begin
51 | result := 'POST';
52 | end;
53 |
54 | class function TCreateSessionCommand.GetRoute: String;
55 | begin
56 | result := '/session';
57 | end;
58 |
59 | procedure TCreateSessionCommand.Execute(AOwner: TForm);
60 | var
61 | request : String;
62 | session : TSession;
63 | begin
64 | request := self.StreamContents;
65 |
66 | session := TSession.Create(request);
67 |
68 | Commands.Sessions.Add(session);
69 |
70 | ResponseJSON(session.GetSessionDetails);
71 | end;
72 |
73 | end.
74 |
--------------------------------------------------------------------------------
/HttpServerCommand.pas:
--------------------------------------------------------------------------------
1 | unit HttpServerCommand;
2 |
3 | interface
4 |
5 | uses
6 | vcl.forms,
7 | IdContext, IdCustomHTTPServer,
8 | CommandRegistry,
9 | System.SysUtils, classes;
10 |
11 | type
12 | TOnLogMessage = procedure (const msg: String) of Object;
13 |
14 | type
15 | THttpServerCommand = class(TComponent)
16 | strict private
17 | FOnLogMessage: TOnLogMessage;
18 | FCommands: THttpServerCommandRegister;
19 | private
20 | function FindCommand(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo): boolean;
21 | procedure SendError(ACmd: TRESTCommandREG;AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo; E: Exception);
22 | procedure LogMessage(const msg: String);
23 | public
24 | constructor Create(AOwner: TComponent); override;
25 | destructor Destroy; override;
26 | procedure CommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
27 | property Commands: THttpServerCommandRegister read FCommands;
28 | property OnLogMessage: TOnLogMessage read FOnLogMessage write FOnLogMessage;
29 | end;
30 |
31 | implementation
32 |
33 | { THttpServerCommand }
34 |
35 | procedure THttpServerCommand.LogMessage(const msg: String);
36 | begin
37 | if assigned(FOnLogMessage) then
38 | OnLogMessage(msg);
39 | end;
40 |
41 | function THttpServerCommand.FindCommand(AContext: TIdContext;
42 | ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo): boolean;
43 | var
44 | cmdReg: TRESTCommandREG;
45 | cmd: TRESTCommand;
46 | Params: TStringList;
47 | begin
48 | Params:= TStringList.Create;
49 | try
50 | cmdReg:= FCommands.FindCommand(ARequestInfo.Command,ARequestInfo.URI, Params);
51 | if cmdReg=nil then exit(false);
52 |
53 | try
54 | cmd := cmdReg.FCommand.create;
55 | try
56 | cmd.Start(cmdReg, AContext, ARequestInfo, AResponseInfo, Params);
57 | LogMessage(cmd.StreamContents);
58 | cmd.Execute(self.Owner as TForm); // Again with the TForm
59 | finally
60 | cmd.Free;
61 | end;
62 | except
63 | on e:Exception do
64 | begin
65 | SendError(cmdReg, AContext, ARequestInfo, AResponseInfo, e);
66 | end;
67 | end;
68 | result:= true;
69 | finally
70 | params.Free;
71 | end;
72 | end;
73 |
74 | procedure THttpServerCommand.SendError(ACmd: TRESTCommandREG;
75 | AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo;
76 | AResponseInfo: TIdHTTPResponseInfo; E: Exception);
77 | begin
78 | AResponseInfo.ResponseNo := 404;
79 | end;
80 |
81 | procedure THttpServerCommand.CommandGet(AContext: TIdContext;
82 | ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
83 | begin
84 | if not FindCommand(AContext,ARequestInfo,AResponseInfo) then
85 | AResponseInfo.ResponseNo := 404;
86 | end;
87 |
88 | constructor THttpServerCommand.Create(AOwner: TComponent);
89 | begin
90 | inherited Create(AOwner);
91 | FCommands:= THttpServerCommandRegister.Create(self);
92 | end;
93 |
94 | destructor THttpServerCommand.Destroy;
95 | begin
96 | FCommands.Free;
97 | inherited;
98 | end;
99 |
100 | end.
101 |
--------------------------------------------------------------------------------
/TestHost/TestHost.dpr:
--------------------------------------------------------------------------------
1 | {***************************************************************************}
2 | { }
3 | { DelphiUIAutomation }
4 | { }
5 | { Copyright 2015-16 JHC Systems Limited }
6 | { }
7 | {***************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the "License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {***************************************************************************}
22 | program TestHost;
23 |
24 | uses
25 | Vcl.Forms,
26 | HostMain in 'HostMain.pas' {Form1},
27 | CommandRegistry in '..\CommandRegistry.pas',
28 | HttpServerCommand in '..\HttpServerCommand.pas',
29 | JsonAttributeSource in '..\JsonAttributeSource.pas',
30 | ResourceProcessing in '..\ResourceProcessing.pas',
31 | RestServer in '..\RestServer.pas',
32 | Session in '..\Session.pas',
33 | Sessions in '..\Sessions.pas',
34 | Utils in '..\Utils.pas',
35 | Commands.ClickElement in '..\Commands\Commands.ClickElement.pas',
36 | Commands.CreateSession in '..\Commands\Commands.CreateSession.pas',
37 | Commands.GetRect in '..\Commands\Commands.GetRect.pas',
38 | Commands.GetText in '..\Commands\Commands.GetText.pas',
39 | Commands in '..\Commands\Commands.pas',
40 | Commands.PostElement in '..\Commands\Commands.PostElement.pas',
41 | Commands.PostElementElements in '..\Commands\Commands.PostElementElements.pas',
42 | Commands.PostElements in '..\Commands\Commands.PostElements.pas',
43 | Commands.PostExecute in '..\Commands\Commands.PostExecute.pas',
44 | Commands.GetEnabled in '..\Commands\Commands.GetEnabled.pas',
45 | Commands.PostValue in '..\Commands\Commands.PostValue.pas',
46 | Commands.DeleteSession in '..\Commands\Commands.DeleteSession.pas',
47 | Commands.GetWindowHandle in '..\Commands\Commands.GetWindowHandle.pas',
48 | Commands.PostClear in '..\Commands\Commands.PostClear.pas',
49 | Commands.GetElementValue in '..\Commands\Commands.GetElementValue.pas';
50 |
51 | {$R *.res}
52 |
53 | begin
54 | Application.Initialize;
55 | Application.MainFormOnTaskbar := True;
56 | Application.CreateForm(TForm1, Form1);
57 | Application.Run;
58 | end.
59 |
--------------------------------------------------------------------------------
/Session.pas:
--------------------------------------------------------------------------------
1 | unit Session;
2 |
3 | interface
4 |
5 | uses
6 | JsonAttributeSource,
7 | System.Classes;
8 |
9 | type
10 | { Will use attributes later, maybe }
11 | TStatus = class
12 | public
13 | [JsonAttribute('sessionId')]
14 | Guid: String;
15 | [JsonAttribute('args')]
16 | Args: String;
17 | [JsonAttribute('app')]
18 | App: String;
19 | [JsonAttribute('platform')]
20 | Platform: String;
21 |
22 | function ToJsonString: String;
23 | end;
24 |
25 | type
26 | TSession = class
27 | private
28 | FStatus: TStatus;
29 | FTimeouts: Integer;
30 |
31 | function GetUid: String;
32 | procedure SetUid(val: String);
33 |
34 | public
35 | function GetSessionDetails: String;
36 | function GetSession: String;
37 |
38 | property Uid: String read GetUid write SetUid;
39 | property Timeouts: Integer write FTimeouts;
40 |
41 | constructor Create(const request: String);
42 | end;
43 |
44 | implementation
45 |
46 | uses
47 | ResourceProcessing,
48 | System.JSON,
49 | System.Types,
50 | System.SysUtils,
51 | System.StrUtils,
52 | System.JSON.Types,
53 | System.JSON.Writers,
54 | System.JSON.Builders;
55 |
56 | { TSession }
57 |
58 | constructor TSession.Create;
59 | var
60 | jsonObj : TJSONObject;
61 | requestObj : TJSONValue;
62 | guid: TGuid;
63 | value: String;
64 |
65 | begin
66 | FStatus:= TStatus.Create;
67 |
68 | if CreateGUID(Guid) <> 0 then
69 | raise Exception.Create('Unable to generate GUID')
70 | else
71 | begin
72 | // Decode the incoming JSON and see what we have
73 | jsonObj := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(request),0) as TJSONObject;
74 | try
75 | requestObj := jsonObj.Get('desiredCapabilities').JsonValue;
76 |
77 | (requestObj as TJsonObject).TryGetValue('args', FStatus.Args);
78 | (requestObj as TJsonObject).TryGetValue('app', FStatus.App);
79 | (requestObj as TJsonObject).TryGetValue('platformName', FStatus.Platform);
80 |
81 | value := Guid.ToString;
82 | delete(value,length(value),1);
83 | delete(value,1,1);
84 |
85 | FStatus.Guid := value;
86 |
87 | finally
88 | jsonObj.Free;
89 | end;
90 | end;
91 | end;
92 |
93 | function TSession.GetSession: String;
94 | begin
95 | result := GetSessionDetails;
96 | end;
97 |
98 | function TSession.GetSessionDetails: String;
99 | begin
100 | result := FStatus.ToJsonString;
101 | end;
102 |
103 | function TSession.GetUid: String;
104 | begin
105 | result := FStatus.Guid;
106 | end;
107 |
108 | procedure TSession.SetUid(val: String);
109 | begin
110 | FStatus.Guid := val;
111 | end;
112 |
113 | function TStatus.ToJsonString: String;
114 | var
115 | Builder: TJSONObjectBuilder;
116 | Writer: TJsonTextWriter;
117 | StringWriter: TStringWriter;
118 | StringBuilder: TStringBuilder;
119 |
120 | begin
121 | StringBuilder := TStringBuilder.Create;
122 | StringWriter := TStringWriter.Create(StringBuilder);
123 | Writer := TJsonTextWriter.Create(StringWriter);
124 | Writer.Formatting := TJsonFormatting.Indented;
125 | Builder := TJSONObjectBuilder.Create(Writer);
126 |
127 | Builder
128 | .BeginObject()
129 | .Add('sessionId', self.Guid)
130 | .Add('status', 0)
131 | .BeginObject('value')
132 | .Add('app', self.App)
133 | .Add('args', self.Args)
134 | .Add('platformName', self.Platform)
135 | .EndObject
136 | .EndObject;
137 |
138 | result := StringBuilder.ToString;
139 | end;
140 |
141 | end.
142 |
--------------------------------------------------------------------------------
/Commands/Commands.PostClear.pas:
--------------------------------------------------------------------------------
1 | {***************************************************************************}
2 | { }
3 | { DelphiWebDriver }
4 | { }
5 | { Copyright 2017 inpwtepydjuf@gmail.com }
6 | { }
7 | {***************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the "License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {***************************************************************************}
22 | unit Commands.PostClear;
23 |
24 | interface
25 |
26 | uses
27 | Sessions,
28 | Vcl.Forms,
29 | CommandRegistry,
30 | HttpServerCommand;
31 |
32 | type
33 | TPostClearCommand = class(TRestCommand)
34 | private
35 | function OKResponse(const sessionId, value: String): String;
36 | public
37 | class function GetCommand: String; override;
38 | class function GetRoute: String; override;
39 |
40 | procedure Execute(AOwner: TForm); override;
41 | end;
42 |
43 | implementation
44 |
45 | uses
46 | Vcl.StdCtrls,
47 | Vcl.Controls,
48 | System.StrUtils,
49 | System.SysUtils,
50 | Utils,
51 | System.Classes,
52 | System.JSON;
53 |
54 | procedure TPostClearCommand.Execute(AOwner: TForm);
55 | var
56 | value: String;
57 | handle: integer;
58 | ctrl: TComponent;
59 |
60 | begin
61 | try
62 | if (isNumber(self.Params[2])) then
63 | begin
64 | handle := StrToInt(self.Params[2]);
65 | ctrl := FindControl(handle);
66 |
67 | if (ctrl <> nil) then
68 | begin
69 | if (ctrl is TEdit) then
70 | (ctrl as TEdit).Text := '';
71 | // else if (ctrl is TStaticText) then
72 | // (ctrl as TStaticText).Caption := value
73 | // else if (ctrl is TCheckBox) then
74 | // (ctrl as TCheckBox).Caption := value
75 | // else if (ctrl is TLinkLabel) then
76 | // (ctrl as TLinkLabel).Caption := value
77 | // else if (ctrl is TRadioButton) then
78 | // (ctrl as TRadioButton).Caption := value;
79 |
80 | ResponseJSON(OKResponse(self.Params[2], value));
81 | end
82 | else
83 | Error(404);
84 | end
85 | else
86 | begin
87 | // simple controls?
88 | Error(404);
89 | end;
90 | except on e: Exception do
91 | Error(404);
92 | end;
93 |
94 | end;
95 |
96 | function TPostClearCommand.OKResponse(const sessionId, value: String): String;
97 | var
98 | jsonObject: TJSONObject;
99 |
100 | begin
101 | jsonObject := TJSONObject.Create;
102 |
103 | jsonObject.AddPair(TJSONPair.Create('sessionId', sessionId));
104 | // jsonObject.AddPair(TJSONPair.Create('status', '0'));
105 |
106 | result := jsonObject.ToString;
107 | end;
108 |
109 | class function TPostClearCommand.GetCommand: String;
110 | begin
111 | result := 'POST';
112 | end;
113 |
114 | class function TPostClearCommand.GetRoute: String;
115 | begin
116 | result := '/session/(.*)/element/(.*)/clear';
117 | end;
118 |
119 | end.
120 |
--------------------------------------------------------------------------------
/Commands/Commands.GetRect.pas:
--------------------------------------------------------------------------------
1 | {***************************************************************************}
2 | { }
3 | { DelphiWebDriver }
4 | { }
5 | { Copyright 2017 inpwtepydjuf@gmail.com }
6 | { }
7 | {***************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the "License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {***************************************************************************}
22 | unit Commands.GetRect;
23 |
24 | interface
25 |
26 | uses
27 | CommandRegistry,
28 | Vcl.Forms,
29 | HttpServerCommand;
30 |
31 | type
32 | ///
33 | /// Handles 'GET' '/session/(.*)/element/(.*)/rect'
34 | ///
35 | TGetRectCommand = class(TRESTCommand)
36 | private
37 | function OKResponse(const sessionId: String; x, y, width, height: Integer): String;
38 | public
39 | class function GetCommand: String; override;
40 | class function GetRoute: String; override;
41 |
42 | procedure Execute(AOwner: TForm); override;
43 | end;
44 |
45 | implementation
46 |
47 | uses
48 | Vcl.Controls,
49 | System.SysUtils,
50 | System.Classes,
51 | System.StrUtils,
52 | System.JSON,
53 | System.JSON.Types,
54 | System.JSON.Writers,
55 | System.JSON.Builders,
56 | Vcl.Buttons,
57 | Vcl.StdCtrls,
58 | utils;
59 |
60 | procedure TGetRectCommand.Execute(AOwner: TForm);
61 | var
62 | comp: TComponent;
63 | ctrl: TWinControl;
64 | handle: Integer;
65 |
66 | begin
67 | ctrl := nil;
68 | comp := nil;
69 |
70 | if (isNumber(self.Params[2])) then
71 | begin
72 | handle := StrToInt(self.Params[2]);
73 | ctrl := FindControl(handle);
74 | end
75 | else
76 | comp := AOwner.FindComponent(self.Params[2]);
77 |
78 | // Needs to actually be proper rect
79 | if (ctrl <> nil) then
80 | begin
81 | ResponseJSON(OKResponse(self.Params[1], ctrl.top, ctrl.left, ctrl.width, ctrl.height))
82 | end
83 | // Not possible for components?
84 | // else if (comp <> nil) then
85 | // begin
86 | // ResponseJSON(OKResponse(self.Params[1], comp.top, comp.left, comp.width, comp.height))
87 | // end
88 | else
89 | begin
90 | Error(404);
91 | end;
92 | end;
93 |
94 | class function TGetRectCommand.GetCommand: String;
95 | begin
96 | result := 'GET';
97 | end;
98 |
99 | class function TGetRectCommand.GetRoute: String;
100 | begin
101 | result := '/session/(.*)/element/(.*)/rect';
102 | end;
103 |
104 | function TGetRectCommand.OKResponse(const sessionId: String; x, y, width, height: Integer): String;
105 | var
106 | Builder: TJSONObjectBuilder;
107 | Writer: TJsonTextWriter;
108 | StringWriter: TStringWriter;
109 | StringBuilder: TStringBuilder;
110 |
111 | begin
112 | StringBuilder := TStringBuilder.Create;
113 | StringWriter := TStringWriter.Create(StringBuilder);
114 | Writer := TJsonTextWriter.Create(StringWriter);
115 | Writer.Formatting := TJsonFormatting.Indented;
116 | Builder := TJSONObjectBuilder.Create(Writer);
117 |
118 | Builder
119 | .BeginObject()
120 | .Add('sessionId', sessionId)
121 | .Add('status', 0)
122 | .Add('x', x)
123 | .Add('y', y)
124 | .Add('width', width)
125 | .Add('height', height)
126 | .EndObject;
127 |
128 | result := StringBuilder.ToString;
129 | end;
130 |
131 | end.
132 |
--------------------------------------------------------------------------------
/Commands/Commands.PostValue.pas:
--------------------------------------------------------------------------------
1 | {***************************************************************************}
2 | { }
3 | { DelphiWebDriver }
4 | { }
5 | { Copyright 2017 inpwtepydjuf@gmail.com }
6 | { }
7 | {***************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the "License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {***************************************************************************}
22 | unit Commands.PostValue;
23 |
24 | interface
25 |
26 | uses
27 | Sessions,
28 | Vcl.Forms,
29 | CommandRegistry,
30 | HttpServerCommand;
31 |
32 | type
33 | TPostValueCommand = class(TRestCommand)
34 | private
35 | function OKResponse(const sessionId, value: String): String;
36 | public
37 | class function GetCommand: String; override;
38 | class function GetRoute: String; override;
39 |
40 | procedure Execute(AOwner: TForm); override;
41 | end;
42 |
43 | implementation
44 |
45 | uses
46 | Vcl.StdCtrls,
47 | Vcl.Controls,
48 | System.StrUtils,
49 | System.SysUtils,
50 | Utils,
51 | System.Classes,
52 | System.JSON;
53 |
54 | procedure TPostValueCommand.Execute(AOwner: TForm);
55 | var
56 | jsonObj : TJSONObject;
57 | value: String;
58 | handle: integer;
59 | ctrl: TComponent;
60 |
61 | begin
62 | // Decode the incoming JSON and see what we have
63 | jsonObj := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(self.StreamContents),0) as TJSONObject;
64 | try
65 | (jsonObj as TJsonObject).TryGetValue('value', value);
66 | finally
67 | jsonObj.Free;
68 | end;
69 |
70 | try
71 | if (isNumber(self.Params[2])) then
72 | begin
73 | handle := StrToInt(self.Params[2]);
74 | ctrl := FindControl(handle);
75 |
76 | if (ctrl <> nil) then
77 | begin
78 | if (ctrl is TEdit) then
79 | (ctrl as TEdit).Text := value
80 | else if (ctrl is TCombobox) then
81 | (ctrl as TCombobox).Text := value;
82 |
83 | // else if (ctrl is TStaticText) then
84 | // (ctrl as TStaticText).Caption := value
85 | // else if (ctrl is TCheckBox) then
86 | // (ctrl as TCheckBox).Caption := value
87 | // else if (ctrl is TLinkLabel) then
88 | // (ctrl as TLinkLabel).Caption := value
89 | // else if (ctrl is TRadioButton) then
90 | // (ctrl as TRadioButton).Caption := value;
91 |
92 | ResponseJSON(OKResponse(self.Params[2], value));
93 | end
94 | else
95 | Error(404);
96 | end
97 | else
98 | begin
99 | // simple controls?
100 | Error(404);
101 | end;
102 | except on e: Exception do
103 | Error(404);
104 | end;
105 |
106 | end;
107 |
108 | function TPostValueCommand.OKResponse(const sessionId, value: String): String;
109 | var
110 | jsonObject: TJSONObject;
111 |
112 | begin
113 | jsonObject := TJSONObject.Create;
114 |
115 | jsonObject.AddPair(TJSONPair.Create('sessionId', sessionId));
116 | // jsonObject.AddPair(TJSONPair.Create('status', '0'));
117 | jsonObject.AddPair(TJSONPair.Create('value', value));
118 |
119 | result := jsonObject.ToString;
120 | end;
121 |
122 | class function TPostValueCommand.GetCommand: String;
123 | begin
124 | result := 'POST';
125 | end;
126 |
127 | class function TPostValueCommand.GetRoute: String;
128 | begin
129 | result := '/session/(.*)/element/(.*)/value';
130 | end;
131 |
132 | end.
133 |
--------------------------------------------------------------------------------
/RestServer.pas:
--------------------------------------------------------------------------------
1 | unit RestServer;
2 |
3 | interface
4 |
5 | uses
6 | Vcl.Forms,
7 | HttpServerCommand,
8 | IdHTTPServer, IdContext, IdHeaderList, IdCustomHTTPServer,
9 | classes,
10 | IdUri,
11 | System.SysUtils;
12 |
13 | type
14 | TRestServer = Class
15 | strict private
16 | FOwner: TComponent;
17 | FCommand: THttpServerCommand;
18 | FHttpServer : TIdHTTPServer;
19 | FOnLogMessage: TOnLogMessage;
20 | private
21 | procedure OnCommandGet(AContext: TIdContext;
22 | ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
23 |
24 | //procedure OnCommandOther(ACommand, AData, AVersion, Thread);
25 |
26 | procedure CreatePostStream(AContext: TIdContext; AHeaders: TIdHeaderList;
27 | var VPostStream: TStream);
28 | procedure LogMessage(const msg: String);
29 | public
30 | constructor Create(AOwner: TComponent);
31 | procedure Start(port: word);
32 | property OnLogMessage: TOnLogMessage read FOnLogMessage write FOnLogMessage;
33 | end;
34 |
35 | implementation
36 |
37 | uses
38 | Commands.GetWindowHandle,
39 | Commands.DeleteSession,
40 | Commands.PostElementElements,
41 | Commands.PostExecute,
42 | Commands.GetElementValue,
43 | Commands.PostClear,
44 | Commands.GetText,
45 | Commands.ClickElement,
46 | Commands.GetRect,
47 | Commands.PostElements,
48 | Commands.PostElement,
49 | Commands.CreateSession,
50 | Commands.GetEnabled,
51 | Commands.PostValue,
52 | System.JSON.Types,
53 | System.JSON.Writers,
54 | System.JSON.Builders,
55 | Commands;
56 |
57 | { TRestServer }
58 |
59 | constructor TRestServer.Create(AOwner: TComponent);
60 | begin
61 | inherited Create;
62 |
63 | FOwner := AOwner;
64 |
65 | FCommand:= THttpServerCommand.Create(AOwner);
66 |
67 | FCommand.Commands.Register(TGetElementValueCommand);
68 |
69 | FCommand.Commands.Register(TGetEnabledCommand);
70 | FCommand.Commands.Register(TGetRectCommand);
71 | FCommand.Commands.Register(TGetTextCommand);
72 | // FCommand.Commands.Register(TGetElementCommand);
73 | //FCommand.Commands.Register(TGetScreenshotCommand);
74 | FCommand.Commands.Register(TGetWindowhandleCommand);
75 | FCommand.Commands.Register(TGetWindowCommand);
76 | FCommand.Commands.Register(TGetTitleCommand);
77 | FCommand.Commands.Register(TGetSessionCommand);
78 | FCommand.Commands.Register(TGetSessionsCommand);
79 | FCommand.Commands.Register(TStatusCommand);
80 | FCommand.Commands.Register(TPostValueCommand);
81 | FCommand.Commands.Register(TPostClearCommand);
82 | FCommand.Commands.Register(TClickElementCommand);
83 | FCommand.Commands.Register(TPostElementElementsCommand);
84 |
85 | // Avoiding mismatch with pattern above
86 | FCommand.Commands.Register(TPostElementsCommand);
87 | FCommand.Commands.Register(TPostElementCommand);
88 | FCommand.Commands.Register(TPostExecuteCommand);
89 | FCommand.Commands.Register(TPostImplicitWaitCommand);
90 | FCommand.Commands.Register(TSessionTimeoutsCommand);
91 | FCommand.Commands.Register(TCreateSessionCommand);
92 | FCommand.Commands.Register(TDeleteSessionCommand);
93 |
94 | FCommand.OnLogMessage := FOnLogMessage;
95 |
96 | FHttpServer := TIdHTTPServer.Create(AOwner);
97 | end;
98 |
99 |
100 | procedure TRestServer.CreatePostStream(AContext: TIdContext;
101 | AHeaders: TIdHeaderList; var VPostStream: TStream);
102 | begin
103 | VPostStream := TStringStream.Create;
104 | end;
105 |
106 | procedure TRestServer.LogMessage(const msg: String);
107 | begin
108 | if assigned(FOnLogMessage) then
109 | OnLogMessage(msg);
110 | end;
111 |
112 | procedure TRestServer.OnCommandGet(AContext: TIdContext;
113 | ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
114 | var
115 | cmd: String;
116 |
117 | begin
118 | cmd := ARequestInfo.Command;
119 |
120 | LogMessage('===================================================');
121 | LogMessage(ARequestInfo.Command + ' ' + ARequestInfo.uri + ' ' + ARequestInfo.Version);
122 | LogMessage('Accept-Encoding: ' + ARequestInfo.AcceptEncoding);
123 | LogMessage('Connection: ' + ARequestInfo.Connection);
124 | LogMessage('Content-Length: ' + Inttostr(ARequestInfo.ContentLength));
125 | LogMessage('Content-Type: ' + ARequestInfo.ContentType);
126 | LogMessage('Host: ' + ARequestInfo.Host);
127 | LogMessage(ARequestInfo.UserAgent);
128 |
129 | LogMessage(ARequestInfo.Params.CommaText);
130 |
131 | FCommand.CommandGet(AContext, ARequestInfo, AResponseInfo);
132 |
133 | LogMessage('');
134 | LogMessage('Response: ' + IntToStr(AResponseInfo.ResponseNo));
135 | // LogMessage('Content-Length:' + Inttostr(AResponseInfo.ContentLength));
136 | LogMessage('Content-Type: ' + AResponseInfo.ContentType);
137 | LogMessage(AResponseInfo.ContentText);
138 | end;
139 |
140 | procedure TRestServer.Start(port: word);
141 | begin
142 | FHttpServer.DefaultPort := port;
143 | FHttpServer.OnCommandGet := OnCommandGet;
144 | FHttpServer.OnCommandOther := OnCommandGet;
145 | FHttpServer.OnCreatePostStream := CreatePostStream;
146 | FHttpServer.Active := True;
147 | end;
148 |
149 | end.
150 |
--------------------------------------------------------------------------------
/Commands/Commands.GetEnabled.pas:
--------------------------------------------------------------------------------
1 | {***************************************************************************}
2 | { }
3 | { DelphiWebDriver }
4 | { }
5 | { Copyright 2017 inpwtepydjuf@gmail.com }
6 | { }
7 | {***************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the "License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {***************************************************************************}
22 | unit Commands.GetEnabled;
23 |
24 | interface
25 |
26 | uses
27 | CommandRegistry,
28 | Vcl.Forms,
29 | HttpServerCommand;
30 |
31 | type
32 | ///
33 | /// Handles 'GET' '/session/(.*)/element/(.*)/enabled'
34 | ///
35 | TGetEnabledCommand = class(TRESTCommand)
36 | private
37 | function OKResponse(const SessionID: String; enabled: boolean): String;
38 | public
39 | class function GetCommand: String; override;
40 | class function GetRoute: String; override;
41 |
42 | procedure Execute(AOwner: TForm); override;
43 | end;
44 |
45 | implementation
46 |
47 | uses
48 | Vcl.Controls,
49 | System.SysUtils,
50 | System.Classes,
51 | Vcl.ComCtrls,
52 | Vcl.ExtCtrls,
53 | Vcl.Buttons,
54 | Vcl.StdCtrls,
55 | System.StrUtils,
56 | System.JSON,
57 | System.JSON.Types,
58 | System.JSON.Writers,
59 | System.JSON.Builders,
60 | utils;
61 |
62 | procedure TGetEnabledCommand.Execute(AOwner: TForm);
63 | var
64 | comp: TComponent;
65 | ctrl: TWinControl;
66 | handle: Integer;
67 | values : TStringList;
68 | value: boolean;
69 | parent: TComponent;
70 |
71 | const
72 | Delimiter = '.';
73 |
74 | begin
75 | ctrl := nil;
76 | comp := nil;
77 |
78 | if (isNumber(self.Params[2])) then
79 | begin
80 | handle := StrToInt(self.Params[2]);
81 | ctrl := FindControl(handle);
82 |
83 | ResponseJSON(OKResponse(self.Params[1], ctrl.Enabled))
84 | end
85 | else
86 | if (ContainsText(self.Params[2], Delimiter)) then
87 | begin
88 | values := TStringList.Create;
89 | try
90 | values.Delimiter := Delimiter;
91 | values.StrictDelimiter := True;
92 | values.DelimitedText := self.Params[2];
93 |
94 | // Get parent
95 | parent := AOwner.FindComponent(values[0]);
96 |
97 | if (parent is TToolBar) then
98 | begin
99 | value := (parent as TToolBar).Buttons[StrToInt(values[1])].enabled;
100 | end;
101 |
102 | // Now send it back please
103 | ResponseJSON(OKResponse(self.Params[2], value));
104 | finally
105 | values.free;
106 | end;
107 | end
108 | else
109 | begin
110 | comp := AOwner.FindComponent(self.Params[2]);
111 |
112 | if (comp <> nil) then
113 | begin
114 | if (comp is TSpeedButton) then
115 | OKResponse(self.Params[1], (comp as TSpeedButton).enabled)
116 | else if (comp is TLabel) then
117 | OKResponse(self.Params[1], (comp as TLabel).enabled);
118 |
119 | ResponseJSON(OKResponse(self.Params[2], value));
120 | end
121 | else
122 | Error(404);
123 | end;
124 | end;
125 |
126 | class function TGetEnabledCommand.GetCommand: String;
127 | begin
128 | result := 'GET';
129 | end;
130 |
131 | class function TGetEnabledCommand.GetRoute: String;
132 | begin
133 | result := '/session/(.*)/element/(.*)/enabled';
134 | end;
135 |
136 | function TGetEnabledCommand.OKResponse(const SessionID: String; enabled: boolean): String;
137 | var
138 | Builder: TJSONObjectBuilder;
139 | Writer: TJsonTextWriter;
140 | StringWriter: TStringWriter;
141 | StringBuilder: TStringBuilder;
142 | value: Variant;
143 |
144 | begin
145 | StringBuilder := TStringBuilder.Create;
146 | StringWriter := TStringWriter.Create(StringBuilder);
147 | Writer := TJsonTextWriter.Create(StringWriter);
148 | Writer.Formatting := TJsonFormatting.Indented;
149 | Builder := TJSONObjectBuilder.Create(Writer);
150 |
151 | value := enabled;
152 |
153 | Builder
154 | .BeginObject()
155 | .Add('sessionId', sessionId)
156 | .Add('status', 0)
157 | .Add('value', value)
158 | .EndObject;
159 |
160 | result := StringBuilder.ToString;
161 | end;
162 |
163 | end.
164 |
--------------------------------------------------------------------------------
/Commands/Commands.PostElementElements.pas:
--------------------------------------------------------------------------------
1 | {***************************************************************************}
2 | { }
3 | { DelphiWebDriver }
4 | { }
5 | { Copyright 2017 inpwtepydjuf@gmail.com }
6 | { }
7 | {***************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the "License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {***************************************************************************}
22 | unit Commands.PostElementElements;
23 |
24 | interface
25 |
26 | uses
27 | Vcl.Forms,
28 | System.Classes,
29 | generics.collections,
30 | CommandRegistry,
31 | HttpServerCommand;
32 |
33 | Type
34 | ///
35 | /// Handles 'POST' '/session/(.*)/element(.*)/elements'
36 | ///
37 | TPostElementElementsCommand = class(TRestCommand)
38 | private
39 | function OKResponse(const sessionId: String; elements: TStringList): String;
40 | public
41 | class function GetCommand: String; override;
42 | class function GetRoute: String; override;
43 |
44 | procedure Execute(AOwner: TForm); override;
45 | end;
46 |
47 | implementation
48 |
49 | uses
50 | System.JSON,
51 | Vcl.Grids,
52 | Vcl.controls,
53 | Vcl.StdCtrls,
54 | Vcl.ExtCtrls,
55 | System.Types,
56 | Vcl.ComCtrls,
57 | System.SysUtils,
58 | System.StrUtils,
59 | System.JSON.Types,
60 | System.JSON.Writers,
61 | System.JSON.Builders,
62 | utils;
63 |
64 | procedure TPostElementElementsCommand.Execute(AOwner: TForm);
65 | var
66 | ctrl: TWinControl;
67 | comp: TComponent;
68 | handle: Integer;
69 | i: integer;
70 | comps: TStringList;
71 |
72 | begin
73 | ctrl := nil;
74 | comp := nil;
75 |
76 | comps := TStringList.Create;
77 |
78 | if (isNumber(self.Params[2])) then
79 | begin
80 | handle := StrToInt(self.Params[2]);
81 | ctrl := FindControl(handle);
82 | end
83 | else
84 | comp := (AOwner.FindComponent(self.Params[2]));
85 |
86 | if (ctrl <> nil) then
87 | begin
88 | if (ctrl is TStringGrid) then
89 | begin
90 | for i := 0 to (ctrl as TStringGrid).RowCount -1 do
91 | begin
92 | comps.Add(ctrl.name + '.' + IntToStr(i));
93 | end;
94 | end
95 | else if (ctrl is TListBox) then
96 | begin
97 | for i := 0 to (ctrl as TListBox).Count -1 do
98 | begin
99 | comps.Add(ctrl.name + '.' + IntToStr(i));
100 | end;
101 | end
102 | else if (ctrl is TPageControl) then
103 | begin
104 | for i := 0 to (ctrl as TPageControl).PageCount -1 do
105 | begin
106 | comps.Add(ctrl.name + '.' + IntToStr(i));
107 | end;
108 | end
109 | else if (ctrl is TToolBar) then
110 | begin
111 | for i := 0 to (ctrl as TToolBar).ButtonCount -1 do
112 | begin
113 | comps.Add(ctrl.name + '.' + IntToStr(i));
114 | end;
115 | end;
116 |
117 | if comps = nil then
118 | raise Exception.Create('Control(s) not found');
119 |
120 | ResponseJSON(self.OKResponse(self.Params[1], comps));
121 | end
122 | else
123 | Error(404);
124 | end;
125 |
126 | function TPostElementElementsCommand.OKResponse(const sessionId: String; elements: TStringList): String;
127 | var
128 | i: Integer;
129 | jsonPair: TJSONPair;
130 | jsonObject, arrayObject: TJSONObject;
131 | jsonArray: TJSONArray;
132 |
133 | begin
134 | jsonArray := TJSONArray.Create;
135 | jsonObject := TJSONObject.Create;
136 | jsonPair := TJSONPair.Create('value', jsonArray);
137 |
138 | jsonObject.AddPair(TJSONPair.Create('sessionId', sessionId));
139 | // jsonObject.AddPair(TJSONPair.Create('status', '0'));
140 |
141 | for i := 0 to elements.count -1 do
142 | begin
143 | arrayObject := TJSONObject.Create;
144 |
145 | arrayObject.AddPair(TJSONPair.Create('ELEMENT', elements[i]));
146 |
147 | jsonArray.AddElement(arrayObject);
148 | end;
149 |
150 | jsonObject.AddPair(jsonPair);
151 |
152 | result := jsonObject.ToString;
153 | end;
154 |
155 | class function TPostElementElementsCommand.GetCommand: String;
156 | begin
157 | result := 'POST';
158 | end;
159 |
160 | class function TPostElementElementsCommand.GetRoute: String;
161 | begin
162 | result := '/session/(.*)/element/(.*)/elements';
163 | end;
164 |
165 | end.
166 |
--------------------------------------------------------------------------------
/Commands/Commands.ClickElement.pas:
--------------------------------------------------------------------------------
1 | {***************************************************************************}
2 | { }
3 | { DelphiWebDriver }
4 | { }
5 | { Copyright 2017 inpwtepydjuf@gmail.com }
6 | { }
7 | {***************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the "License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {***************************************************************************}
22 | unit Commands.ClickElement;
23 |
24 | interface
25 |
26 | uses
27 | CommandRegistry,
28 | Vcl.Forms,
29 | HttpServerCommand;
30 |
31 | type
32 | ///
33 | /// Handles 'POST', '/session/(.*)/element/(.*)/click'
34 | ///
35 | TClickElementCommand = class(TRESTCommand)
36 | private
37 | procedure ProcessHandle(AOwner: TForm);
38 | procedure ProcessControlName(AOwner: TForm);
39 | function OKResponse(const handle: String): String;
40 | public
41 | class function GetCommand: String; override;
42 | class function GetRoute: String; override;
43 |
44 | procedure Execute(AOwner: TForm); override;
45 | end;
46 |
47 | implementation
48 |
49 | uses
50 | Utils,
51 | System.StrUtils,
52 | Vcl.StdCtrls,
53 | Vcl.ComCtrls,
54 | Vcl.Buttons,
55 | Vcl.Controls,
56 | Vcl.Menus,
57 | System.SysUtils,
58 | System.JSON,
59 | System.Classes;
60 |
61 | procedure TClickElementCommand.ProcessHandle(AOwner: TForm);
62 | var
63 | ctrl: TWinControl;
64 | handle: Integer;
65 | checked: boolean;
66 |
67 | begin
68 | handle := StrToInt(self.Params[2]);
69 | ctrl := FindControl(handle);
70 |
71 | if (ctrl <> nil) then
72 | begin
73 | if (ctrl is TButton) then
74 | begin
75 | (ctrl as TButton).click;
76 | end
77 | else if (ctrl is TCheckBox) then
78 | begin
79 | checked := (ctrl as TCheckBox).Checked;
80 | (ctrl as TCheckBox).Checked := not checked;
81 | end
82 | else if (ctrl is TRadioButton) then
83 | begin
84 | (ctrl as TRadioButton).Checked := true;
85 | end;
86 |
87 | ResponseJSON(self.OKResponse(self.Params[2]));
88 | end
89 | else
90 | Error(404);
91 | end;
92 |
93 | procedure TClickElementCommand.ProcessControlName(AOwner: TForm);
94 | var
95 | comp: TComponent;
96 | values : TStringList;
97 |
98 | const
99 | Delimiter = '.';
100 |
101 | begin
102 | if (ContainsText(self.Params[2], Delimiter)) then
103 | begin
104 | values := TStringList.Create;
105 | try
106 | values.Delimiter := Delimiter;
107 | values.StrictDelimiter := True;
108 | values.DelimitedText := self.Params[2];
109 |
110 | // Find parent
111 | comp := (AOwner.FindComponent(values[0]));
112 |
113 | if comp <> nil then
114 | begin
115 | if comp is TPageControl then
116 | begin
117 | (comp as TPageControl).ActivePage :=
118 | (comp as TPageControl).Pages[StrToInt(values[1])];
119 | end;
120 | end
121 | else
122 | Error(404);
123 | finally
124 | values.Free;
125 | end
126 | end
127 | else
128 | begin
129 | comp := (AOwner.FindComponent(self.Params[2]));
130 |
131 | if (comp <> nil) then
132 | begin
133 | if (comp is TSpeedButton) then
134 | (comp as TSpeedButton).click
135 | else if (comp is TMenuItem) then
136 | (comp as TMenuItem).click
137 | else if (comp is TToolButton) then
138 | (comp as TToolButton).click;
139 | ResponseJSON(self.OKResponse(self.Params[2]));
140 | end
141 | else
142 | Error(404);
143 | end;
144 | end;
145 |
146 | procedure TClickElementCommand.Execute(AOwner: TForm);
147 | begin
148 | if (isNumber(self.Params[2])) then
149 | ProcessHandle(AOwner)
150 | else
151 | ProcessControlName(AOwner);
152 | end;
153 |
154 | class function TClickElementCommand.GetCommand: String;
155 | begin
156 | result := 'POST';
157 | end;
158 |
159 | class function TClickElementCommand.GetRoute: String;
160 | begin
161 | result := '/session/(.*)/element/(.*)/click';
162 | end;
163 |
164 | function TClickElementCommand.OKResponse(const handle: String): String;
165 | var
166 | jsonObject: TJSONObject;
167 |
168 | begin
169 | jsonObject := TJSONObject.Create;
170 |
171 | jsonObject.AddPair(TJSONPair.Create('id', handle));
172 |
173 | result := jsonObject.ToString;
174 | end;
175 |
176 | end.
177 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DelphiWebDriver
2 | An attempt at building a Delphi implementation of the [W3C WebDriver](https://www.w3.org/TR/webdriver), so it can be embedded in a Delphi project
3 |
4 | Essentially a proof of concept / futile excerise.
5 |
6 | ## Currently Supported APIs
7 |
8 | | HTTP | Path | Status |
9 | | --- | --- | --- |
10 | | GET | /status | Functional |
11 | | POST | /session | Functional |
12 | | GET | /session/:sessionId | Functional |
13 | | GET | /session/:sessionId/title | In Progress |
14 | | GET | /session/:sessionId/element/:id | In Progress |
15 | | POST | /session/:sessionId/elements | Initial |
16 | | POST | /session/:sessionId/element | Initial |
17 | | GET | /session/:sessionId/screenshot | Initial |
18 | | POST | /session/:sessionId/element/:id/click | In Progress |
19 | | POST | /session/:sessionId/timeouts/implicit_wait | In Progress |
20 | | POST | /session/:sessionId/timeouts | In Progress |
21 | | GET | /sessions | In Progress |
22 | | DELETE | /session/:sessionId | Functional |
23 | | POST | /session/:sessionId/back | Not implemented |
24 | | POST | /session/:sessionId/forward | Not implemented |
25 | | GET | /session/:sessionId/source | Not implemented |
26 | | POST | /session/:sessionId/url | Not implemented |
27 | | POST | /session/:sessionId/appium/app/launch | Not implemented? |
28 | | POST | /session/:sessionId/appium/app/close | Not implemented? |
29 | | GET | /session/:sessionId/window | In Progress |
30 | | POST | /session/:sessionId/element/:id/value | In Progress |
31 | | GET | /session/:sessionId/element/:id/enabled | In Progress |
32 | | GET | /session/:sessionId/element/:id/rect | In Progress |
33 |
34 | NOTES:
35 | * Functional here means it has been at least partially implemented in both a host and a test client
36 | * Not Implemented commands are those that are usually to do with navigation, etc. in a browser
37 |
38 | ## To been implemented - not an exhaustive list yet
39 |
40 | | HTTP | Path |
41 | | --- | --- |
42 | | GET | /sessions |
43 | | POST | /session/:sessionId/buttondown |
44 | | POST | /session/:sessionId/buttonup |
45 | | POST | /session/:sessionId/click |
46 | | POST | /session/:sessionId/doubleclick |
47 | | POST | /session/:sessionId/element/active |
48 | | GET | /session/:sessionId/element/:id/attribute/:name |
49 | | POST | /session/:sessionId/element/:id/clear |
50 | | POST | /session/:sessionId/element/:id/click |
51 | | GET | /session/:sessionId/element/:id/displayed |
52 | | GET | /session/:sessionId/element/:id/element |
53 | | GET | /session/:sessionId/element/:id/elements |
54 | | GET | /session/:sessionId/element/:id/enabled |
55 | | GET | /session/:sessionId/element/:id/equals |
56 | | GET | /session/:sessionId/element/:id/location |
57 | | GET | /session/:sessionId/element/:id/location_in_view |
58 | | GET | /session/:sessionId/element/:id/name |
59 | | GET | /session/:sessionId/element/:id/screenshot |
60 | | GET | /session/:sessionId/element/:id/selected |
61 | | GET | /session/:sessionId/element/:id/size |
62 | | GET | /session/:sessionId/element/:id/text |
63 | | GET | /session/:sessionId/element/:id/rect |
64 | | POST | /session/:sessionId/element/:id/value |
65 | | POST | /session/:sessionId/keys |
66 | | GET | /session/:sessionId/location |
67 | | POST | /session/:sessionId/moveto |
68 | | GET | /session/:sessionId/orientation |
69 | | GET | /session/:sessionId/screenshot |
70 | | GET | /session/:sessionId/title |
71 | | POST | /session/:sessionId/touch/click |
72 | | POST | /session/:sessionId/touch/doubleclick |
73 | | POST | /session/:sessionId/touch/longclick |
74 | | POST | /session/:sessionId/touch/flick |
75 | | POST | /session/:sessionId/touch/scroll |
76 | | DELETE | /session/:sessionId/window |
77 | | POST | /session/:sessionId/window |
78 | | GET | /session/:sessionId/window/handles |
79 | | POST | /session/:sessionId/window/maximize |
80 | | POST | /session/:sessionId/window/size |
81 | | GET | /session/:sessionId/window/size |
82 | | POST | /session/:sessionId/window/:windowHandle/size |
83 | | GET | /session/:sessionId/window/:windowHandle/size |
84 | | POST | /session/:sessionId/window/:windowHandle/position |
85 | | GET | /session/:sessionId/window/:windowHandle/position |
86 | | POST | /session/:sessionId/window/:windowHandle/maximize |
87 | | GET | /session/:sessionId/window_handle |
88 | | GET | /session/:sessionId/window_handles |
89 |
90 |
--------------------------------------------------------------------------------
/Commands/Commands.GetElementValue.pas:
--------------------------------------------------------------------------------
1 | {***************************************************************************}
2 | { }
3 | { DelphiWebDriver }
4 | { }
5 | { Copyright 2017 inpwtepydjuf@gmail.com }
6 | { }
7 | {***************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the "License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {***************************************************************************}
22 | unit Commands.GetElementValue;
23 |
24 | interface
25 |
26 | uses
27 | Vcl.Forms,
28 | CommandRegistry,
29 | HttpServerCommand;
30 |
31 | type
32 | TGetElementValueCommand = class(TRestCommand)
33 | private
34 | procedure ProcessHandle(AOwner: TForm);
35 | procedure ProcessControlName(AOwner: TForm);
36 | function OKResponse(const session, value: String): String;
37 | public
38 | procedure Execute(AOwner: TForm); override;
39 |
40 | class function GetCommand: String; override;
41 | class function GetRoute: String; override;
42 | end;
43 |
44 | implementation
45 |
46 | uses
47 | System.JSON,
48 | System.JSON.Types,
49 | Vcl.Controls,
50 | Vcl.Grids,
51 | System.SysUtils,
52 | System.Classes,
53 | System.StrUtils,
54 | Vcl.ComCtrls,
55 | Vcl.ExtCtrls,
56 | Vcl.Buttons,
57 | Vcl.StdCtrls,
58 | System.JSON.Writers,
59 | System.JSON.Builders,
60 | utils;
61 |
62 | class function TGetElementValueCommand.GetCommand: String;
63 | begin
64 | result := 'GET';
65 | end;
66 |
67 | class function TGetElementValueCommand.GetRoute: String;
68 | begin
69 | result := '/session/(.*)/element/(.*)/attribute/(.*)';
70 | end;
71 |
72 | procedure TGetElementValueCommand.ProcessHandle(AOwner: TForm);
73 | var
74 | ctrl: TWinControl;
75 | handle: Integer;
76 | value: String;
77 |
78 | begin
79 | handle := StrToInt(self.Params[2]);
80 | ctrl := FindControl(handle);
81 |
82 | if (ctrl <> nil) then
83 | begin
84 | if (ctrl is TCheckBox) then
85 | begin
86 | if (self.Params[3] = 'Checked') then
87 | if (ctrl as TCheckBox).Checked then value := 'True' else value := 'False'
88 | else
89 | value := 'Unknown';
90 | end;
91 |
92 | ResponseJSON(self.OKResponse(self.Params[2], value));
93 | end
94 | else
95 | Error(404);
96 | end;
97 |
98 | procedure TGetElementValueCommand.ProcessControlName(AOwner: TForm);
99 | var
100 | comp: TComponent;
101 | values : TStringList;
102 |
103 | const
104 | Delimiter = '.';
105 |
106 | begin
107 | Error(404);
108 | (*
109 | if (ContainsText(self.Params[2], Delimiter)) then
110 | begin
111 | values := TStringList.Create;
112 | try
113 | values.Delimiter := Delimiter;
114 | values.StrictDelimiter := True;
115 | values.DelimitedText := self.Params[2];
116 |
117 | // Find parent
118 | comp := (AOwner.FindComponent(values[0]));
119 |
120 | if comp <> nil then
121 | begin
122 | if comp is TPageControl then
123 | begin
124 | (comp as TPageControl).ActivePage :=
125 | (comp as TPageControl).Pages[StrToInt(values[1])];
126 | end;
127 | end
128 | else
129 | Error(404);
130 | finally
131 | values.Free;
132 | end
133 | end
134 | else
135 | begin
136 | comp := (AOwner.FindComponent(self.Params[2]));
137 |
138 | if (comp <> nil) then
139 | begin
140 | if (comp is TSpeedButton) then
141 | (comp as TSpeedButton).click
142 | else if (comp is TToolButton) then
143 | (comp as TToolButton).click;
144 | ResponseJSON(self.OKResponse(self.Params[2]));
145 | end
146 | else
147 | Error(404);
148 | end;
149 | *)
150 | end;
151 |
152 | procedure TGetElementValueCommand.Execute(AOwner: TForm);
153 | begin
154 | if (isNumber(self.Params[2])) then
155 | ProcessHandle(AOwner)
156 | else
157 | ProcessControlName(AOwner);
158 | end;
159 |
160 | function TGetElementValueCommand.OKResponse(const session, value: String): String;
161 | var
162 | Builder: TJSONObjectBuilder;
163 | Writer: TJsonTextWriter;
164 | StringWriter: TStringWriter;
165 | StringBuilder: TStringBuilder;
166 |
167 | begin
168 | StringBuilder := TStringBuilder.Create;
169 | StringWriter := TStringWriter.Create(StringBuilder);
170 | Writer := TJsonTextWriter.Create(StringWriter);
171 | Writer.Formatting := TJsonFormatting.Indented;
172 | Builder := TJSONObjectBuilder.Create(Writer);
173 |
174 | Builder
175 | .BeginObject()
176 | .Add('sessionId', session)
177 | .Add('status', 0)
178 | .Add('value', value)
179 | .EndObject;
180 |
181 | result := StringBuilder.ToString;
182 | end;
183 |
184 | end.
185 |
--------------------------------------------------------------------------------
/Commands/Commands.GetText.pas:
--------------------------------------------------------------------------------
1 | {***************************************************************************}
2 | { }
3 | { DelphiWebDriver }
4 | { }
5 | { Copyright 2017 inpwtepydjuf@gmail.com }
6 | { }
7 | {***************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the "License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {***************************************************************************}
22 | unit Commands.GetText;
23 |
24 | interface
25 |
26 | uses
27 | Vcl.Forms,
28 | CommandRegistry,
29 | HttpServerCommand;
30 |
31 | type
32 | ///
33 | /// Handles 'GET' '/session/(.*)/element/(.*)/text'
34 | ///
35 | TGetTextCommand = class(TRESTCommand)
36 | private
37 | function OKResponse(const handle, value: String): String;
38 | public
39 | class function GetCommand: String; override;
40 | class function GetRoute: String; override;
41 |
42 | procedure Execute(AOwner: TForm); override;
43 | end;
44 |
45 | implementation
46 |
47 | uses
48 | System.JSON,
49 | System.JSON.Types,
50 | Vcl.Controls,
51 | Vcl.Grids,
52 | System.SysUtils,
53 | System.Classes,
54 | System.StrUtils,
55 | Vcl.ComCtrls,
56 | Vcl.Menus,
57 | Vcl.ExtCtrls,
58 | Vcl.Buttons,
59 | Vcl.StdCtrls,
60 | utils;
61 |
62 | procedure TGetTextCommand.Execute(AOwner: TForm);
63 | var
64 | comp: TComponent;
65 | ctrl: TWinControl;
66 | handle: Integer;
67 | parent: TComponent;
68 | values : TStringList;
69 | value: String;
70 |
71 | const
72 | Delimiter = '.';
73 |
74 | begin
75 | if (isNumber(self.Params[2])) then
76 | begin
77 | handle := StrToInt(self.Params[2]);
78 | ctrl := FindControl(handle);
79 |
80 | if (ctrl <> nil) then
81 | begin
82 | if (ctrl is TEdit) then
83 | value := (ctrl as TEdit).Text
84 | else if (ctrl is TStaticText) then
85 | value := (ctrl as TStaticText).Caption
86 | else if (ctrl is TCheckBox) then
87 | value := (ctrl as TCheckBox).Caption
88 | else if (ctrl is TLinkLabel) then
89 | value := (ctrl as TLinkLabel).Caption
90 | else if (ctrl is TRadioButton) then
91 | value := (ctrl as TRadioButton).Caption;
92 |
93 | ResponseJSON(OKResponse(self.Params[2], value));
94 | end
95 | else
96 | Error(404);
97 | end
98 | else
99 | begin
100 | // This might be a non-WinControl OR a DataItem for a container
101 | if (ContainsText(self.Params[2], Delimiter)) then
102 | begin
103 | values := TStringList.Create;
104 | try
105 | values.Delimiter := Delimiter;
106 | values.StrictDelimiter := True;
107 | values.DelimitedText := self.Params[2];
108 |
109 | // Get parent
110 | parent := AOwner.FindComponent(values[0]);
111 |
112 | if (parent is TListBox) then
113 | begin
114 | value := (parent as TListBox).items[StrToInt(values[1])];
115 | end
116 | else if (parent is TStringGrid) then
117 | begin
118 | value := (parent as TStringGrid).Cells[StrToInt(values[1]),StrToInt(values[2])];
119 | end
120 | else if (parent is TPageControl) then
121 | begin
122 | value := (parent as TPageControl).Pages[StrToInt(values[1])].Caption;
123 | end
124 | else if (parent is TCombobox) then
125 | begin
126 | value := (parent as TCombobox).items[StrToInt(values[1])];
127 | end;
128 |
129 | // Now send it back please
130 | ResponseJSON(OKResponse(self.Params[2], value));
131 | finally
132 | values.free;
133 | end;
134 | end
135 | else
136 | begin
137 | comp := AOwner.FindComponent(self.Params[2]);
138 |
139 | if (comp <> nil) then
140 | begin
141 | if (comp is TSpeedButton) then
142 | Value := (comp as TSpeedButton).Caption
143 | else if (comp is TMenuItem) then
144 | Value := (comp as TMenuItem).Caption
145 | else if (comp is TLabel) then
146 | Value := (comp as TLabel).Caption;
147 |
148 | ResponseJSON(OKResponse(self.Params[2], value));
149 | end
150 | else
151 | Error(404);
152 | end;
153 | end;
154 | end;
155 |
156 | function TGetTextCommand.OKResponse(const handle, value: String): String;
157 | var
158 | jsonObject: TJSONObject;
159 |
160 | begin
161 | jsonObject := TJSONObject.Create;
162 |
163 | jsonObject.AddPair(TJSONPair.Create('id', handle));
164 | jsonObject.AddPair(TJSONPair.Create('value', value));
165 |
166 | result := jsonObject.ToString;
167 | end;
168 |
169 | class function TGetTextCommand.GetCommand: String;
170 | begin
171 | result := 'GET';
172 | end;
173 |
174 | class function TGetTextCommand.GetRoute: String;
175 | begin
176 | result := '/session/(.*)/element/(.*)/text';
177 | end;
178 |
179 | end.
180 |
--------------------------------------------------------------------------------
/CommandRegistry.pas:
--------------------------------------------------------------------------------
1 | unit CommandRegistry;
2 |
3 | interface
4 |
5 | uses
6 | Vcl.forms,
7 | classes, IdContext, IdCustomHTTPServer, generics.collections,
8 | System.SysUtils;
9 |
10 | type
11 | TRESTCommandClass = class of TRESTCommand;
12 | TRESTCommandREG = class;
13 |
14 | TRESTCommand = class
15 | private
16 | FParams: TStringList;
17 | FContext: TIdContext;
18 | FRequestInfo: TIdHTTPRequestInfo;
19 | FResponseInfo: TIdHTTPResponseInfo;
20 | FReg: TRESTCommandREG;
21 | FStreamContents: String;
22 | procedure ParseParams(const AURI, AMask:String);
23 | procedure ReadStream(ARequestInfo: TIdHTTPRequestInfo);
24 | public
25 | class function GetCommand: String; virtual;
26 | class function GetRoute: String; virtual;
27 |
28 | constructor Create;
29 |
30 | procedure Start(AReg: TRESTCommandREG; AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo; AParams: TStringList);
31 | procedure Execute(AOwner: TForm); virtual;
32 |
33 | procedure ResponseJSON(Json: String);
34 | procedure Error(code: integer);
35 |
36 | destructor Destroy; override;
37 | property Context: TIdContext read FContext;
38 | property RequestInfo: TIdHTTPRequestInfo read FRequestInfo;
39 | property ResponseInfo: TIdHTTPResponseInfo read FResponseInfo;
40 | property Params: TStringList read FParams;
41 | property StreamContents : String read FStreamContents;
42 | property Reg: TRESTCommandREG read FReg;
43 | end;
44 |
45 | TRESTCommandREG = class
46 | public
47 | FTYPE: String;
48 | FPATH: String;
49 | FCommand: TRESTCommandClass;
50 | FHost: TForm; // TComponent;
51 | constructor Create(ATYPE:String; APATH: String; ACommand: TRESTCommandClass);
52 | end;
53 |
54 | THttpServerCommandRegister=class(TComponent)
55 | private
56 | FList: TObjectList;
57 | public
58 | procedure Register(ATYPE:String; APATH: String; ACommand: TRESTCommandClass); overload;
59 | procedure Register(ACommand: TRESTCommandClass); overload;
60 |
61 | constructor Create(AOwner: TComponent); override;
62 | function isUri(AURI: String; AMask: String; AParams: TStringList): boolean;
63 | function FindCommand(ACommand: String; AURI: String; Params: TStringList): TRESTCommandREG;
64 | destructor Destroy; override;
65 | end;
66 |
67 | implementation
68 |
69 | uses
70 | RegularExpressions;
71 |
72 | { THttpServerCommandRegister }
73 |
74 | constructor THttpServerCommandRegister.Create(AOwner: TComponent);
75 | begin
76 | inherited;
77 | FList:= TObjectList.Create(True);
78 | end;
79 |
80 | destructor THttpServerCommandRegister.Destroy;
81 | begin
82 | FList.Free;
83 | inherited;
84 | end;
85 |
86 | function THttpServerCommandRegister.FindCommand(ACommand, AURI: String; Params: TStringList): TRESTCommandREG;
87 | var
88 | I: Integer;
89 | begin
90 | for I := 0 to FList.Count-1 do
91 | begin
92 | if SameText(ACommand,FList[i].FTYPE) then
93 | begin
94 | if isURI(AURI,FList[i].FPATH, Params) then
95 | begin
96 | exit(FList[i]);
97 | end;
98 | end;
99 | end;
100 | result:= nil;
101 | end;
102 |
103 | function THttpServerCommandRegister.isUri(AURI, AMask: String; AParams: TStringList): boolean;
104 | var
105 | x: Integer;
106 | M : TMatch;
107 |
108 | begin
109 | result := TRegEx.IsMatch(AURI, AMask);
110 |
111 | M := TRegEx.Match(AURI, AMask);
112 |
113 | for x := 0 to M.Groups.Count-1 do
114 | begin
115 | AParams.Add(M.Groups[x].Value);
116 | end;
117 | end;
118 |
119 | procedure THttpServerCommandRegister.Register(ATYPE, APATH: String; ACommand: TRESTCommandClass);
120 | begin
121 | FList.Add(TRESTCommandREG.Create(ATYPE, APATH, ACommand));
122 | end;
123 |
124 | procedure THttpServerCommandRegister.Register(ACommand: TRESTCommandClass);
125 | begin
126 | FList.Add(TRESTCommandREG.Create(ACommand.GetCommand, ACommand.GetRoute, ACommand));
127 | end;
128 |
129 | { TRESTCommandREG }
130 |
131 | constructor TRESTCommandREG.Create(ATYPE, APATH: String; ACommand: TRESTCommandClass);
132 | begin
133 | FTYPE := AType;
134 | FPATH := APATH;
135 | FCommand := ACommand;
136 | end;
137 |
138 | { TRESTCommand }
139 |
140 | class function TRESTCommand.GetCommand: String;
141 | begin
142 | result := '';
143 | end;
144 |
145 | class function TRESTCommand.GetRoute: String;
146 | begin
147 | result := '';
148 | end;
149 |
150 | constructor TRESTCommand.create;
151 | begin
152 | FParams:= TStringList.Create;
153 | end;
154 |
155 | procedure TRESTCommand.ReadStream(ARequestInfo: TIdHTTPRequestInfo);
156 | var
157 | oStream : TStringStream;
158 |
159 | begin
160 | // Decode stream
161 | if ArequestInfo.PostStream <> nil then
162 | begin
163 | oStream := TStringStream.create;
164 | try
165 | oStream.CopyFrom(ArequestInfo.PostStream, ArequestInfo.PostStream.Size);
166 | oStream.Position := 0;
167 |
168 | FStreamContents := oStream.readString(oStream.Size);
169 | finally
170 | oStream.free;
171 | end;
172 | end;
173 | end;
174 |
175 | procedure TRESTCommand.Start(AReg: TRESTCommandREG; AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo; AParams: TStringList);
176 | begin
177 | FContext:= AContext;
178 | FRequestInfo:= ARequestInfo;
179 | FResponseInfo:= AResponseInfo;
180 | FReg:= AReg;
181 | FParams.Assign(AParams);
182 | ParseParams(ARequestInfo.URI, AReg.FPATH);
183 | ReadStream(ARequestInfo);
184 | end;
185 |
186 | destructor TRESTCommand.Destroy;
187 | begin
188 | FParams.free;
189 | inherited;
190 | end;
191 |
192 | procedure TRESTCommand.Execute(AOwner: TForm);
193 | begin
194 |
195 | end;
196 |
197 | procedure TRESTCommand.ParseParams(const AURI, AMask: String);
198 | var
199 | x: Integer;
200 | M : TMatch;
201 |
202 | begin
203 | M := TRegEx.Match(AURI, AMask);
204 |
205 | for x := 0 to M.Groups.Count-1 do
206 | begin
207 | FParams.Add(M.Groups[x].Value);
208 | end;
209 | end;
210 |
211 | procedure TRESTCommand.ResponseJSON(Json: String);
212 | begin
213 | ResponseInfo.ContentText := Json;
214 | ResponseInfo.ContentType := 'Application/JSON';
215 | end;
216 |
217 | procedure TRESTCommand.Error(code: integer);
218 | begin
219 | ResponseInfo.ResponseNo := code;
220 | end;
221 |
222 | end.
223 |
--------------------------------------------------------------------------------
/Sessions.pas:
--------------------------------------------------------------------------------
1 | unit Sessions;
2 |
3 | interface
4 |
5 | uses
6 | generics.collections,
7 | Session;
8 |
9 | Type
10 | TSessions = class
11 | strict private
12 | FSessions: TObjectList;
13 | public
14 | constructor Create;
15 | destructor Destroy; override;
16 |
17 | function GetSession(const sessionId: String): TSession;
18 | function GetSessionStatus(const sessionId: String): String;
19 | procedure DeleteSession(const sessionId: String);
20 | procedure Add(session: TSession);
21 | function SetSessionTimeouts(const sessionId: String; ms: integer): String;
22 | function SetSessionImplicitTimeouts(const sessionId: String; ms: integer): String;
23 | function Count: Integer;
24 | function GetStatus: String;
25 |
26 | function OKResponse(const sessionId: String): String;
27 | function ErrorResponse(const sessionId, code, msg: String): String;
28 |
29 | function FindElement(const sessionId: String): String;
30 | end;
31 |
32 | implementation
33 |
34 | uses
35 | System.StrUtils,
36 | System.JSON.Types,
37 | System.Classes,
38 | System.JSON.Writers,
39 | System.JSON.Builders,
40 | System.SysUtils,
41 | ResourceProcessing;
42 |
43 | { TSessions }
44 |
45 | constructor TSessions.Create;
46 | begin
47 | inherited;
48 | FSessions:= TObjectList.create;
49 | end;
50 |
51 | destructor TSessions.Destroy;
52 | begin
53 | FSessions.Free;
54 | inherited;
55 | end;
56 |
57 | function TSessions.GetSession(const sessionId: String): TSession;
58 | var
59 | i : integer;
60 |
61 | begin
62 | // Probably a better way of doing this!
63 | result := nil;
64 |
65 | for i := 0 to FSessions.Count -1 do
66 | begin
67 | if FSessions[i].Uid = sessionId then
68 | begin
69 | result := FSessions[i];
70 | break;
71 | end;
72 | end;
73 |
74 | if result = nil then
75 | raise Exception.create('Cannot find session');
76 | end;
77 |
78 | function TSessions.SetSessionImplicitTimeouts(const sessionId: String; ms: integer): String;
79 | var
80 | i : integer;
81 | found : boolean;
82 |
83 | begin
84 | found := false;
85 |
86 | // Probably a better way of doing this!
87 | for i := 0 to FSessions.Count -1 do
88 | begin
89 | if FSessions[i].Uid = sessionId then
90 | begin
91 | // Dodgy
92 | found := true;
93 | FSessions[i].Timeouts := ms;
94 | break;
95 | end;
96 | end;
97 |
98 | if not found then
99 | raise Exception.create('Cannot find session');
100 |
101 | result := self.OKResponse(sessionId);
102 | end;
103 |
104 | function TSessions.SetSessionTimeouts(const sessionId: String; ms: integer): String;
105 | var
106 | i : integer;
107 | found : boolean;
108 |
109 | begin
110 | found := false;
111 |
112 | // Probably a better way of doing this!
113 | for i := 0 to FSessions.Count -1 do
114 | begin
115 | if FSessions[i].Uid = sessionId then
116 | begin
117 | // Dodgy
118 | found := true;
119 | FSessions[i].Timeouts := ms;
120 | break;
121 | end;
122 | end;
123 |
124 | if not found then
125 | raise Exception.create('Cannot find session');
126 |
127 | result := self.OKResponse(sessionId);
128 | end;
129 |
130 | function TSessions.ErrorResponse(const sessionId, code, msg: String): String;
131 | var
132 | Builder: TJSONObjectBuilder;
133 | Writer: TJsonTextWriter;
134 | StringWriter: TStringWriter;
135 | StringBuilder: TStringBuilder;
136 |
137 | begin
138 | // Construct reply
139 | StringBuilder := TStringBuilder.Create;
140 | StringWriter := TStringWriter.Create(StringBuilder);
141 | Writer := TJsonTextWriter.Create(StringWriter);
142 | Writer.Formatting := TJsonFormatting.Indented;
143 | Builder := TJSONObjectBuilder.Create(Writer);
144 |
145 | Builder
146 | .BeginObject()
147 | .Add('sessionId', sessionId)
148 | .Add('status', code)
149 | .BeginObject('value')
150 | .Add('error', code)
151 | .Add('message', code)
152 | .EndObject
153 | .EndObject;
154 |
155 | result := StringBuilder.ToString;
156 | end;
157 |
158 | function TSessions.OKResponse(const sessionId: String): String;
159 | var
160 | Builder: TJSONObjectBuilder;
161 | Writer: TJsonTextWriter;
162 | StringWriter: TStringWriter;
163 | StringBuilder: TStringBuilder;
164 |
165 | begin
166 | // Construct reply
167 | StringBuilder := TStringBuilder.Create;
168 | StringWriter := TStringWriter.Create(StringBuilder);
169 | Writer := TJsonTextWriter.Create(StringWriter);
170 | Writer.Formatting := TJsonFormatting.Indented;
171 | Builder := TJSONObjectBuilder.Create(Writer);
172 |
173 | Builder
174 | .BeginObject()
175 | .Add('sessionId', sessionId)
176 | .Add('status', 0)
177 | .EndObject;
178 |
179 | result := StringBuilder.ToString;
180 | end;
181 |
182 | function TSessions.GetSessionStatus(const sessionId: String) : String;
183 | begin
184 | result := self.GetStatus;
185 | end;
186 |
187 | function TSessions.Count: Integer;
188 | begin
189 | result := FSessions.Count;
190 | end;
191 |
192 | procedure TSessions.Add(session: TSession);
193 | begin
194 | FSessions.Add(session);
195 | end;
196 |
197 | procedure TSessions.DeleteSession(const sessionId: String);
198 | var
199 | i : integer;
200 | found : boolean;
201 | begin
202 | found := false;
203 |
204 | // Probably a better way of doing this!
205 | for i := 0 to FSessions.Count -1 do
206 | begin
207 | if FSessions[i].Uid = sessionId then
208 | begin
209 | // Dodgy
210 | found := true;
211 | FSessions.Delete(i);
212 | break;
213 | end;
214 | end;
215 |
216 | if not found then
217 | raise Exception.create('Cannot find session');
218 | end;
219 |
220 | function OSArchitectureToString(arch: TOSVersion.TArchitecture): String;
221 | begin
222 | case arch of
223 | arIntelX86: result := 'Intel X86';
224 | arIntelX64: result := 'Intel X64';
225 | arArm64: result := 'ARM 64';
226 | arArm32: result := 'ARM 32';
227 | else
228 | result := 'Unknown';
229 | end;
230 | end;
231 |
232 | function TSessions.FindElement(const sessionId: String): String;
233 | begin
234 | result := 'N/A';
235 | //comp := (self.Reg.FHost.FindComponent(self.Params[2]));
236 | end;
237 |
238 | function TSessions.GetStatus: String;
239 | var
240 | Builder: TJSONObjectBuilder;
241 | Writer: TJsonTextWriter;
242 | StringWriter: TStringWriter;
243 | StringBuilder: TStringBuilder;
244 |
245 | begin
246 | StringBuilder := TStringBuilder.Create;
247 | StringWriter := TStringWriter.Create(StringBuilder);
248 | Writer := TJsonTextWriter.Create(StringWriter);
249 | Writer.Formatting := TJsonFormatting.Indented;
250 | Builder := TJSONObjectBuilder.Create(Writer);
251 |
252 | Builder
253 | .BeginObject
254 | .BeginObject('build')
255 | .Add('version', GetModuleVersion)
256 | .Add('revision', GetAppRevision)
257 | .Add('time', 2.1)
258 | .EndObject
259 | .BeginObject('os')
260 | .Add('arch', OSArchitectureToString(TOSVersion.Architecture))
261 | .Add('name', TOSVersion.Name)
262 | .Add('version', IntToStr(TOSVersion.Major) + '.' + IntToStr(TOSVersion.Minor))
263 | .EndObject
264 | .EndObject;
265 |
266 | result := StringBuilder.ToString;
267 | end;
268 |
269 | end.
270 |
--------------------------------------------------------------------------------
/Commands/Commands.PostElements.pas:
--------------------------------------------------------------------------------
1 | {***************************************************************************}
2 | { }
3 | { DelphiWebDriver }
4 | { }
5 | { Copyright 2017 inpwtepydjuf@gmail.com }
6 | { }
7 | {***************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the "License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {***************************************************************************}
22 | unit Commands.PostElements;
23 |
24 | interface
25 |
26 | uses
27 | generics.collections,
28 | Vcl.Forms,
29 | Vcl.controls,
30 | System.Classes,
31 | CommandRegistry,
32 | HttpServerCommand;
33 |
34 | type
35 | ///
36 | /// Handles 'POST' '/session/(.*)/elements'
37 | ///
38 | TPostElementsCommand = class(TRestCommand)
39 | private
40 | procedure GetElementsByName(const value:String; AOwner: TForm);
41 | procedure GetElementsByCaption(const value:String; AOwner: TForm);
42 | procedure GetElementsByPartialCaption(const value:String; AOwner: TForm);
43 | procedure GetElementsByClassName(const value:String; AOwner: TForm);
44 |
45 | function OKResponse(const sessionId: String; elements: TObjectList): String;
46 | public
47 | class function GetCommand: String; override;
48 | class function GetRoute: String; override;
49 |
50 | procedure Execute(AOwner: TForm); override;
51 | end;
52 |
53 | implementation
54 |
55 | uses
56 | System.JSON,
57 | Vcl.stdctrls,
58 | System.Types,
59 | System.SysUtils,
60 | System.StrUtils,
61 | System.JSON.Types,
62 | System.JSON.Writers,
63 | System.JSON.Builders;
64 |
65 | procedure TPostElementsCommand.GetElementsByName(const value:String; AOwner: TForm);
66 | var
67 | comps: TObjectList;
68 | i: Integer;
69 |
70 | begin
71 | comps:= TObjectList.create;
72 |
73 | try
74 | try
75 | if (AOwner.Name = value) then
76 | comps.Add(AOwner)
77 | else
78 | begin
79 | for i := 0 to tForm(AOwner).ControlCount -1 do
80 | begin
81 | if tForm(AOwner).Controls[i].Name = value then
82 | begin
83 | comps.Add(AOwner.Controls[i]);
84 | end;
85 | end;
86 | end;
87 |
88 | if comps.count = 0 then
89 | raise Exception.Create('Control(s) not found');
90 |
91 | ResponseJSON(self.OKResponse(self.Params[1], comps));
92 |
93 | except on e: Exception do
94 | // Probably should give a different reply
95 |
96 | Error(401);
97 | end;
98 | finally
99 | // comps.free;
100 | end;
101 | end;
102 |
103 | procedure TPostElementsCommand.GetElementsByPartialCaption(const value:String; AOwner: TForm);
104 | begin
105 |
106 | end;
107 |
108 | procedure TPostElementsCommand.GetElementsByCaption(const value:String; AOwner: TForm);
109 | begin
110 |
111 | end;
112 |
113 | procedure TPostElementsCommand.GetElementsByClassName(const value:String; AOwner: TForm);
114 | var
115 | comps: TObjectList;
116 | i: Integer;
117 |
118 | begin
119 | comps:= TObjectList.create;
120 |
121 | try
122 | try
123 | if (AOwner.ClassName = value) then
124 | comps.Add(AOwner)
125 | else
126 | begin
127 | for i := 0 to tForm(AOwner).ComponentCount -1 do
128 | begin
129 | if tForm(AOwner).Components[i].ClassName = value then
130 | begin
131 | comps.Add(AOwner.Components[i]);
132 | end;
133 | end;
134 | end;
135 |
136 | if comps.count = 0 then
137 | raise Exception.Create('Control(s) not found');
138 |
139 | ResponseJSON(self.OKResponse(self.Params[1], comps));
140 |
141 | except on e: Exception do
142 | // Probably should give a different reply
143 | Error(404);
144 | end;
145 | finally
146 | // comps.free;
147 | end;
148 | end;
149 |
150 | procedure TPostElementsCommand.Execute(AOwner: TForm);
151 | var
152 | jsonObj : TJSONObject;
153 | using: String;
154 | value: String;
155 |
156 | begin
157 | // Decode request
158 | jsonObj := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(self.StreamContents),0) as TJSONObject;
159 | try
160 | (jsonObj as TJsonObject).TryGetValue('using', using);
161 | (jsonObj as TJsonObject).TryGetValue('value', value);
162 | finally
163 | jsonObj.Free;
164 | end;
165 |
166 | if (using = 'link text') then
167 | GetElementsByCaption(value, AOwner)
168 | else if (using = 'name') then
169 | GetElementsByName(value, AOwner)
170 | else if (using = 'class name') then
171 | GetElementsByClassName(value, AOwner)
172 | else if (using = 'partial link text') then
173 | GetElementsByPartialCaption(value, AOwner)
174 | end;
175 |
176 | function TPostElementsCommand.OKResponse(const sessionId: String; elements: TObjectList): String;
177 | var
178 | i: Integer;
179 | jsonPair: TJSONPair;
180 | jsonObject, arrayObject: TJSONObject;
181 | jsonArray: TJSONArray;
182 |
183 | begin
184 | jsonArray := TJSONArray.Create;
185 | jsonObject := TJSONObject.Create;
186 | jsonPair := TJSONPair.Create('value', jsonArray);
187 |
188 | jsonObject.AddPair(TJSONPair.Create('sessionId', sessionId));
189 | // jsonObject.AddPair(TJSONPair.Create('status', '0'));
190 |
191 | for i := 0 to elements.count -1 do
192 | begin
193 | arrayObject := TJSONObject.Create;
194 |
195 | if (elements[i] is TWinControl) then
196 | // Great we can use the actual window handle
197 | arrayObject.AddPair(TJSONPair.Create('ELEMENT', IntToStr((elements[i] as TWinControl).Handle)))
198 | else
199 | // Use the name, as it won't have a true handle
200 | arrayObject.AddPair(TJSONPair.Create('ELEMENT', elements[i].name));
201 |
202 | jsonArray.AddElement(arrayObject);
203 | end;
204 |
205 | jsonObject.AddPair(jsonPair);
206 |
207 | result := jsonObject.ToString;
208 | end;
209 |
210 | class function TPostElementsCommand.GetCommand: String;
211 | begin
212 | result := 'POST';
213 | end;
214 |
215 | class function TPostElementsCommand.GetRoute: String;
216 | begin
217 | result := '/session/(.*)/elements';
218 | end;
219 |
220 | end.
221 |
--------------------------------------------------------------------------------
/DelphiWebDriver.dproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {F1C536C2-DA14-4E2A-BDD0-697C5D1D1DEA}
4 | DelphiWebDriver.dpk
5 | 18.2
6 | VCL
7 | True
8 | Debug
9 | Win32
10 | 1
11 | Package
12 |
13 |
14 | true
15 |
16 |
17 | true
18 | Base
19 | true
20 |
21 |
22 | true
23 | Base
24 | true
25 |
26 |
27 | true
28 | Cfg_1
29 | true
30 | true
31 |
32 |
33 | true
34 | Base
35 | true
36 |
37 |
38 | System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)
39 | true
40 | All
41 | DelphiWebDriver
42 | true
43 | true
44 | .\$(Platform)\$(Config)
45 | .\$(Platform)\$(Config)
46 | false
47 | false
48 | false
49 | false
50 | false
51 |
52 |
53 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
54 | 1033
55 | true
56 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
57 |
58 |
59 | DEBUG;$(DCC_Define)
60 | true
61 | false
62 | true
63 | true
64 | true
65 |
66 |
67 | e:\Users\Mark\Documents\GitHub\DelphiWebDriver\TestHost\Win32\Debug\TestHost.exe
68 | 1033
69 | true
70 | false
71 |
72 |
73 | false
74 | RELEASE;$(DCC_Define)
75 | 0
76 | 0
77 |
78 |
79 |
80 | MainSource
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 | Cfg_2
111 | Base
112 |
113 |
114 | Base
115 |
116 |
117 | Cfg_1
118 | Base
119 |
120 |
121 |
122 | Delphi.Personality.12
123 | Package
124 |
125 |
126 |
127 | DelphiWebDriver.dpk
128 |
129 |
130 |
131 | True
132 |
133 |
134 | 12
135 |
136 |
137 |
138 |
139 |
--------------------------------------------------------------------------------
/Commands/Commands.PostExecute.pas:
--------------------------------------------------------------------------------
1 | {***************************************************************************}
2 | { }
3 | { DelphiWebDriver }
4 | { }
5 | { Copyright 2017 inpwtepydjuf@gmail.com }
6 | { }
7 | {***************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the "License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {***************************************************************************}
22 | unit Commands.PostExecute;
23 |
24 | interface
25 |
26 | uses
27 | Sessions,
28 | Vcl.Forms,
29 | CommandRegistry,
30 | HttpServerCommand;
31 |
32 | type
33 | ///
34 | /// Handles POST /session/{sessionId}/execute
35 | ///
36 | ///
37 | /// Only for certain specific controls - StringGrids and ToolButtons
38 | ///
39 | TPostExecuteCommand = class(TRestCommand)
40 | private
41 | ///
42 | /// Right click on the control
43 | ///
44 | ///
45 | /// Currently only implemented for some controls
46 | ///
47 | procedure RightClick (AOwner: TForm; Const control: String);
48 |
49 | ///
50 | /// Right click on the control
51 | ///
52 | ///
53 | /// Currently only implemented for some controls
54 | ///
55 | procedure LeftClick (AOwner: TForm; Const control: String);
56 |
57 | ///
58 | /// Right click on the control
59 | ///
60 | ///
61 | /// Currently only implemented for some controls
62 | ///
63 | procedure DoubleClick (AOwner: TForm; Const control: String);
64 |
65 | function OKResponse(const sessionId, control: String): String;
66 | public
67 | class function GetCommand: String; override;
68 | class function GetRoute: String; override;
69 |
70 | ///
71 | /// Highjacked for left and right clicks on controls
72 | ///
73 | procedure Execute(AOwner: TForm); override;
74 | end;
75 |
76 | implementation
77 |
78 | uses
79 | Vcl.ComCtrls,
80 | System.StrUtils,
81 | System.SysUtils,
82 | Vcl.Grids,
83 | System.Classes,
84 | System.JSON;
85 |
86 | procedure TPostExecuteCommand.Execute(AOwner: TForm);
87 | var
88 | jsonObj : TJSONObject;
89 | argsObj : TJsonValue;
90 | script: String;
91 | control: String;
92 |
93 | begin
94 | // Decode the incoming JSON and see what we have
95 | jsonObj := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(self.StreamContents),0) as TJSONObject;
96 | try
97 | (jsonObj as TJsonObject).TryGetValue('script', script);
98 | //(jsonObj as TJsonObject).TryGetValue('args', value);
99 | argsObj := jsonObj.Get('args').JsonValue;
100 |
101 | (argsObj as TJsonObject).TryGetValue('first', control);
102 |
103 | finally
104 | jsonObj.Free;
105 | end;
106 |
107 | try
108 | if (script = 'right click') then
109 | RightClick(AOwner, control)
110 | else if (script = 'left click') then
111 | LeftClick(AOwner, control)
112 | else if (script = 'double click') then
113 | DoubleClick(AOwner, control)
114 | else
115 | Error(404);
116 |
117 | except on e: Exception do
118 | Error(404);
119 | end;
120 | end;
121 |
122 | procedure TPostExecuteCommand.DoubleClick (AOwner: TForm; Const control: String);
123 | begin
124 |
125 | end;
126 |
127 | procedure TPostExecuteCommand.LeftClick (AOwner: TForm; Const control: String);
128 | begin
129 |
130 | end;
131 |
132 | procedure TPostExecuteCommand.RightClick (AOwner: TForm; Const control: String);
133 | var
134 | gridTop, top: Integer;
135 | gridLeft, left: Integer;
136 | parent, comp: TComponent;
137 | values : TStringList;
138 | parentGrid: TStringGrid;
139 |
140 | const
141 | Delimiter = '.';
142 |
143 | begin
144 | // find the control / component - currently only implemented for stringgrids
145 |
146 | if (ContainsText(control, Delimiter)) then
147 | begin
148 | values := TStringList.Create;
149 | try
150 | values.Delimiter := Delimiter;
151 | values.StrictDelimiter := True;
152 | values.DelimitedText := control;
153 |
154 | // Get parent
155 | parent := AOwner.FindComponent(values[0]);
156 |
157 | if (parent is TStringGrid) then
158 | begin
159 | parentGrid := (parent as TStringGrid);
160 | gridTop := parentGrid.top;
161 | gridLeft := parentGrid.left;
162 |
163 | left := parentGrid.CellRect(StrToInt(values[1]),StrToInt(values[2])).left -gridLeft +1;
164 | top := parentGrid.CellRect(StrToInt(values[1]),StrToInt(values[2])).top -gridTop +1;
165 |
166 | // Cell 2,2 : left = 179, top = 85 ???
167 | // Here we have to call into the grid itself somehow
168 |
169 | ResponseJSON(OKResponse(self.Params[2], control));
170 | end
171 | else
172 | Error(404);
173 | finally
174 | values.free;
175 | end;
176 | end
177 | else
178 | begin
179 | comp := AOwner.FindComponent(control);
180 |
181 | if comp <> nil then
182 | begin
183 | if (comp is TToolButton) then
184 | begin
185 | if (comp as TToolButton).PopupMenu <> nil then
186 | begin
187 | // Popup a menu item here
188 | (comp as TToolButton).PopupMenu.Popup(100, 100);
189 | ResponseJSON(OKResponse(self.Params[2], control));
190 | end
191 | else
192 | begin
193 | Error(404);
194 | end;
195 | end;
196 | end
197 | else
198 | Error(404);
199 | end;
200 | end;
201 |
202 | function TPostExecuteCommand.OKResponse(const sessionId, control: String): String;
203 | var
204 | jsonObject: TJSONObject;
205 |
206 | begin
207 | jsonObject := TJSONObject.Create;
208 |
209 | jsonObject.AddPair(TJSONPair.Create('sessionId', sessionId));
210 | // jsonObject.AddPair(TJSONPair.Create('status', '0'));
211 | jsonObject.AddPair(TJSONPair.Create('value', control));
212 |
213 | result := jsonObject.ToString;
214 | end;
215 |
216 | class function TPostExecuteCommand.GetCommand: String;
217 | begin
218 | result := 'POST';
219 | end;
220 |
221 | class function TPostExecuteCommand.GetRoute: String;
222 | begin
223 | result := '/session/(.*)/execute';
224 | end;
225 |
226 | end.
227 |
--------------------------------------------------------------------------------
/TestHost/HostMain.pas:
--------------------------------------------------------------------------------
1 | {***************************************************************************}
2 | { }
3 | { DelphiUIAutomation }
4 | { }
5 | { Copyright 2015 JHC Systems Limited }
6 | { }
7 | {***************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the "License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {***************************************************************************}
22 | unit HostMain;
23 |
24 | interface
25 |
26 | uses
27 | RestServer,
28 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
29 | Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls, Vcl.Menus,
30 | Vcl.Grids, Vcl.Mask,
31 | Vcl.ToolWin, Vcl.ExtCtrls, Vcl.ImgList, System.ImageList,
32 | Vcl.Buttons;
33 |
34 | type
35 | TForm1 = class(TForm)
36 | Edit2: TEdit;
37 | Button1: TButton;
38 | Button2: TButton;
39 | PageControl1: TPageControl;
40 | TabSheet1: TTabSheet;
41 | TabSheet2: TTabSheet;
42 | TabSheet3: TTabSheet;
43 | Edit3: TEdit;
44 | Edit4: TEdit;
45 | Edit5: TEdit;
46 | CheckBox1: TCheckBox;
47 | CheckBox2: TCheckBox;
48 | RadioButton1: TRadioButton;
49 | RadioButton2: TRadioButton;
50 | RadioButton3: TRadioButton;
51 | StatusBar1: TStatusBar;
52 | ComboBox1: TComboBox;
53 | MainMenu1: TMainMenu;
54 | File1: TMenuItem;
55 | Hel1: TMenuItem;
56 | Exit1: TMenuItem;
57 | About1: TMenuItem;
58 | PopupMenu1: TPopupMenu;
59 | PopupMenu2: TMenuItem;
60 | AutomatedEdit1: TEdit;
61 | AutomatedCombobox1: TCombobox;
62 | AutomatedCombobox2: TCombobox;
63 | AutomationStringGrid1: TStringGrid;
64 | AutomatedMaskEdit1: TMaskEdit;
65 | RichEdit1: TRichEdit;
66 | TreeView1: TTreeView;
67 | PopupMenu3: TPopupMenu;
68 | Popup11: TMenuItem;
69 | Popup21: TMenuItem;
70 | Edit1: TEdit;
71 | ListBox1: TListBox;
72 | LinkLabel1: TLinkLabel;
73 | Panel6: TPanel;
74 | Panel7: TPanel;
75 | ToolBar1: TToolBar;
76 | ToolButton3: TToolButton;
77 | ToolButton1: TToolButton;
78 | ToolButton2: TToolButton;
79 | ToolButton4: TToolButton;
80 | Panel8: TPanel;
81 | ToolBar2: TToolBar;
82 | ToolButton5: TToolButton;
83 | ToolButton6: TToolButton;
84 | ToolButton7: TToolButton;
85 | ToolButton8: TToolButton;
86 | ImageList1: TImageList;
87 | AutomatedStaticText1: TStaticText;
88 | ListBox2: TListBox;
89 | SpeedButton1: TSpeedButton;
90 | SpeedButton2: TSpeedButton;
91 | SpeedButton3: TSpeedButton;
92 | Button3: TButton;
93 | PopupMenu4: TPopupMenu;
94 | Menu11: TMenuItem;
95 | Menu21: TMenuItem;
96 | Menu31: TMenuItem;
97 | procedure Button2Click(Sender: TObject);
98 | procedure Button1Click(Sender: TObject);
99 | procedure Exit1Click(Sender: TObject);
100 | procedure PopupMenu2Click(Sender: TObject);
101 | procedure FormCreate(Sender: TObject);
102 | procedure ToolButton1Click(Sender: TObject);
103 | procedure ToolButton5Click(Sender: TObject);
104 | procedure ToolButton7Click(Sender: TObject);
105 | procedure LinkLabel1Click(Sender: TObject);
106 | procedure FormDestroy(Sender: TObject);
107 | procedure Button3Click(Sender: TObject);
108 | procedure SpeedButton1Click(Sender: TObject);
109 | procedure SpeedButton2Click(Sender: TObject);
110 | procedure SpeedButton3Click(Sender: TObject);
111 | procedure ToolButton2Click(Sender: TObject);
112 | procedure ToolButton4Click(Sender: TObject);
113 | private
114 | { Private declarations }
115 | FRestServer : TRestServer;
116 | procedure CreateServer(port: word);
117 | procedure DestroyServer;
118 | procedure LogMessage(const msg: String);
119 | public
120 | { Public declarations }
121 | end;
122 |
123 | var
124 | Form1: TForm1;
125 |
126 | implementation
127 |
128 | {$R *.dfm}
129 |
130 | procedure TForm1.Button1Click(Sender: TObject);
131 | begin
132 | ShowMessage (edit1.Text + ' | ' + edit2.Text);
133 | end;
134 |
135 | procedure TForm1.Button2Click(Sender: TObject);
136 | begin
137 | ShowMessage ('Cancelled');
138 | end;
139 |
140 | procedure TForm1.Button3Click(Sender: TObject);
141 | begin
142 | ShowMessage(self.caption);
143 | end;
144 |
145 | procedure TForm1.Exit1Click(Sender: TObject);
146 | begin
147 | ShowMessage('Oh well done');
148 | end;
149 |
150 | procedure TForm1.FormCreate(Sender: TObject);
151 | begin
152 | createServer(4723);
153 |
154 | AutomationStringGrid1.Cells[0,0] := 'Title 1';
155 | AutomationStringGrid1.Cells[1,0] := 'Title 2';
156 | AutomationStringGrid1.Cells[2,0] := 'Title 3';
157 | AutomationStringGrid1.Cells[3,0] := 'Title 4';
158 | AutomationStringGrid1.Cells[4,0] := 'Title 5';
159 |
160 | AutomationStringGrid1.Cells[0,1] := 'Row 1, Col 0';
161 | AutomationStringGrid1.Cells[1,1] := 'Row 1, Col 1';
162 | AutomationStringGrid1.Cells[2,1] := 'Row 1, Col 2';
163 | AutomationStringGrid1.Cells[3,1] := 'Row 1, Col 3';
164 | AutomationStringGrid1.Cells[4,1] := 'Row 1, Col 4';
165 |
166 | AutomationStringGrid1.Cells[0,3] := 'Row 3, Col 0';
167 | AutomationStringGrid1.Cells[1,3] := 'Row 3, Col 1';
168 | AutomationStringGrid1.Cells[2,3] := 'Row 3, Col 2';
169 | AutomationStringGrid1.Cells[3,3] := 'Row 3, Col 3';
170 | AutomationStringGrid1.Cells[4,3] := 'Row 3, Col 4';
171 |
172 | end;
173 |
174 | procedure TForm1.FormDestroy(Sender: TObject);
175 | begin
176 | FRestServer.Free;
177 | end;
178 |
179 | procedure TForm1.LinkLabel1Click(Sender: TObject);
180 | begin
181 | ShowMessage ('LinkLabel1Click');
182 | end;
183 |
184 | procedure TForm1.PopupMenu2Click(Sender: TObject);
185 | begin
186 | ShowMessage ('Popup menu clicked');
187 | end;
188 |
189 | procedure TForm1.SpeedButton1Click(Sender: TObject);
190 | begin
191 | ShowMessage('SpeedButton1Click');
192 | end;
193 |
194 | procedure TForm1.SpeedButton2Click(Sender: TObject);
195 | begin
196 | ShowMessage('SpeedButton2Click');
197 | end;
198 |
199 | procedure TForm1.SpeedButton3Click(Sender: TObject);
200 | begin
201 | ShowMessage('SpeedButton3Click');
202 | end;
203 |
204 | procedure TForm1.ToolButton1Click(Sender: TObject);
205 | begin
206 | ShowMessage ('ToolButton1Click');
207 | end;
208 |
209 | procedure TForm1.ToolButton2Click(Sender: TObject);
210 | begin
211 | ShowMessage ('ToolButton2Click');
212 | end;
213 |
214 | procedure TForm1.ToolButton4Click(Sender: TObject);
215 | begin
216 | ShowMessage ('ToolButton4Click');
217 | end;
218 |
219 | procedure TForm1.ToolButton5Click(Sender: TObject);
220 | begin
221 | ShowMessage ('ToolButton5Click');
222 | end;
223 |
224 | procedure TForm1.ToolButton7Click(Sender: TObject);
225 | begin
226 | ShowMessage ('ToolButton7Click');
227 | end;
228 |
229 | procedure TForm1.CreateServer(port: word);
230 | begin
231 | FRestServer := TRestServer.Create(self);
232 | FRestServer.OnLogMessage := LogMessage;
233 |
234 | FRestServer.Start(port);
235 | end;
236 |
237 | procedure TForm1.DestroyServer;
238 | begin
239 | FRestServer.Free;
240 | end;
241 |
242 | procedure TForm1.LogMessage(const msg: String);
243 | begin
244 | ListBox2.Items.Add(msg);
245 | end;
246 |
247 | end.
248 |
--------------------------------------------------------------------------------
/Commands/Commands.PostElement.pas:
--------------------------------------------------------------------------------
1 | {***************************************************************************}
2 | { }
3 | { DelphiWebDriver }
4 | { }
5 | { Copyright 2017 inpwtepydjuf@gmail.com }
6 | { }
7 | {***************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the "License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {***************************************************************************}
22 | unit Commands.PostElement;
23 |
24 | interface
25 |
26 | uses
27 | Vcl.Forms,
28 | CommandRegistry,
29 | HttpServerCommand;
30 |
31 | type
32 | ///
33 | /// Handles 'POST' '/session/(.*)/element'
34 | ///
35 | TPostElementCommand = class(TRestCommand)
36 | private
37 | procedure GetElementByName(const value:String; AOwner: TForm);
38 | procedure GetElementByCaption(const value:String; AOwner: TForm);
39 | procedure GetElementByClassName(const value:String; AOwner: TForm);
40 | procedure GetElementByPartialCaption(const value:String; AOwner: TForm);
41 |
42 | function OKResponse(const sessionId, handle: String): String;
43 | public
44 | class function GetCommand: String; override;
45 | class function GetRoute: String; override;
46 |
47 | procedure Execute(AOwner: TForm); override;
48 | end;
49 |
50 | implementation
51 |
52 | uses
53 | System.JSON,
54 | Vcl.controls,
55 | Vcl.StdCtrls,
56 | Vcl.ExtCtrls,
57 | System.Types,
58 | System.SysUtils,
59 | System.Classes,
60 | System.StrUtils,
61 | System.JSON.Types,
62 | System.JSON.Writers,
63 | System.JSON.Builders;
64 |
65 | procedure TPostElementCommand.GetElementByName(const value:String; AOwner: TForm);
66 | var
67 | comp: TComponent;
68 |
69 | begin
70 | try
71 | if (AOwner.Caption = value) then
72 | comp := AOwner
73 | else
74 | comp := AOwner.FindComponent(value);
75 |
76 | if comp = nil then
77 | raise Exception.Create('Control not found');
78 |
79 | if (comp is TWinControl) then
80 | ResponseJSON(self.OKResponse(self.Params[1], IntToStr((comp as TWinControl).Handle)))
81 | else
82 | ResponseJSON(self.OKResponse(self.Params[1], comp.name));
83 |
84 | except on e: Exception do
85 | // Probably should give a different reply
86 | Error(404);
87 | end;
88 | end;
89 |
90 | procedure TPostElementCommand.GetElementByClassName(const value:String; AOwner: TForm);
91 | var
92 | comp: TComponent;
93 | i: Integer;
94 |
95 | begin
96 | comp := nil;
97 |
98 | try
99 | if (AOwner.ClassName = value) then
100 | comp := AOwner
101 | else
102 | begin
103 | for i := 0 to tForm(AOwner).ControlCount -1 do
104 | if tForm(AOwner).Controls[i].ClassName = value then
105 | begin
106 | comp := tForm(AOwner).Controls[i];
107 | break;
108 | end;
109 | end;
110 |
111 | if comp = nil then
112 | raise Exception.Create('Control not found');
113 |
114 | ResponseJSON(self.OKResponse(self.Params[1], IntToStr((comp as TWinControl).Handle)));
115 |
116 | except on e: Exception do
117 | // Probably should give a different reply
118 | Error(404);
119 | end;
120 | end;
121 |
122 | procedure TPostElementCommand.GetElementByPartialCaption(const value:String; AOwner: TForm);
123 | begin
124 | Error(404);
125 | end;
126 |
127 | procedure TPostElementCommand.GetElementByCaption(const value:String; AOwner: TForm);
128 | var
129 | comp: TComponent;
130 | i: Integer;
131 |
132 | begin
133 | comp := nil;
134 |
135 | try
136 | if (AOwner.Caption = value) then
137 | comp := AOwner
138 | else
139 | begin
140 | for i := 0 to tForm(AOwner).ControlCount -1 do
141 |
142 | // Vcl.ExtCtrls ..
143 | // TButtonedEdit
144 | // THeader
145 | // TPanel
146 |
147 | // Vcl.StdCtrls ..
148 | // TButton - done
149 | // TCheckBox
150 | // TComboBox
151 | // TEdit
152 | // TLabel
153 | // TListBox
154 | // TRadioButton
155 | // TStaticText
156 | // TMemo
157 |
158 | // Specifically from the test host
159 | // TTreeView
160 | // TRichEdit
161 | // TToolbar
162 | // TToolbarButton
163 | // TPageControl
164 | // TTabSheet
165 | // TStatusBar
166 | // TMainMenu
167 | // TMenuItem
168 | // TPopupMenu
169 | // TStringGrid
170 | // TMaskedEdit
171 | // TLinkLabel
172 |
173 | // TSpeedButton - no window here, need to 'fake' one
174 |
175 | // Need to get each type of control and check the caption / text
176 | if (tForm(AOwner).Controls[i] is TButton) then
177 | begin
178 | if (tForm(AOwner).Controls[i] as TButton).caption = value then
179 | begin
180 | comp := tForm(AOwner).Controls[i];
181 | break;
182 | end;
183 | end
184 | else if (tForm(AOwner).Controls[i] is TPanel) then
185 | begin
186 | if (tForm(AOwner).Controls[i] as TPanel).caption = value then
187 | begin
188 | comp := tForm(AOwner).Controls[i];
189 | break;
190 | end;
191 | end
192 | else if (tForm(AOwner).Controls[i] is TEdit) then
193 | begin
194 | if (tForm(AOwner).Controls[i] as TEdit).Text = value then
195 | begin
196 | comp := tForm(AOwner).Controls[i];
197 | break;
198 | end;
199 | end;
200 | end;
201 |
202 | if comp = nil then
203 | raise Exception.Create('Control not found');
204 |
205 | ResponseJSON(self.OKResponse(self.Params[1], IntToStr((comp as TWinControl).Handle)));
206 |
207 | except on e: Exception do
208 | // Probably should give a different reply
209 | Error(404);
210 | end;
211 | end;
212 |
213 | procedure TPostElementCommand.Execute(AOwner: TForm);
214 | var
215 | jsonObj : TJSONObject;
216 | using: String;
217 | value: String;
218 |
219 | begin
220 | jsonObj := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(self.StreamContents),0) as TJSONObject;
221 | try
222 | (jsonObj as TJsonObject).TryGetValue('using', using);
223 | (jsonObj as TJsonObject).TryGetValue('value', value);
224 | finally
225 | jsonObj.Free;
226 | end;
227 |
228 | if (using = 'link text') then
229 | GetElementByCaption(value, AOwner)
230 | else if (using = 'name') then
231 | GetElementByName(value, AOwner)
232 | else if (using = 'class name') then
233 | GetElementByClassName(value, AOwner)
234 | else if (using = 'partial link text') then
235 | GetElementByPartialCaption(value, AOwner)
236 | else
237 | Error(404);
238 | // 'id' (automation id)
239 | end;
240 |
241 | function TPostElementCommand.OKResponse(const sessionId, handle: String): String;
242 | var
243 | Builder: TJSONObjectBuilder;
244 | Writer: TJsonTextWriter;
245 | StringWriter: TStringWriter;
246 | StringBuilder: TStringBuilder;
247 |
248 | begin
249 | StringBuilder := TStringBuilder.Create;
250 | StringWriter := TStringWriter.Create(StringBuilder);
251 | Writer := TJsonTextWriter.Create(StringWriter);
252 | Writer.Formatting := TJsonFormatting.Indented;
253 | Builder := TJSONObjectBuilder.Create(Writer);
254 |
255 | Builder
256 | .BeginObject()
257 | .Add('sessionId', sessionId)
258 | .Add('status', 0)
259 | .BeginObject('value')
260 | .Add('ELEMENT', Handle)
261 | .EndObject
262 | .EndObject;
263 |
264 | result := StringBuilder.ToString;
265 |
266 | end;
267 |
268 | class function TPostElementCommand.GetCommand: String;
269 | begin
270 | result := 'POST';
271 | end;
272 |
273 | class function TPostElementCommand.GetRoute: String;
274 | begin
275 | result := '/session/(.*)/element';
276 | end;
277 |
278 | end.
279 |
--------------------------------------------------------------------------------
/TestClient/Unit3.dfm:
--------------------------------------------------------------------------------
1 | object Form3: TForm3
2 | Left = 0
3 | Top = 0
4 | Caption = 'Form3'
5 | ClientHeight = 639
6 | ClientWidth = 909
7 | Color = clBtnFace
8 | Font.Charset = DEFAULT_CHARSET
9 | Font.Color = clWindowText
10 | Font.Height = -11
11 | Font.Name = 'Tahoma'
12 | Font.Style = []
13 | OldCreateOrder = False
14 | DesignSize = (
15 | 909
16 | 639)
17 | PixelsPerInch = 96
18 | TextHeight = 13
19 | object ListBox1: TListBox
20 | Left = 8
21 | Top = 8
22 | Width = 893
23 | Height = 341
24 | Anchors = [akLeft, akTop, akRight]
25 | ItemHeight = 13
26 | TabOrder = 0
27 | end
28 | object btnStartSession: TButton
29 | Left = 8
30 | Top = 355
31 | Width = 75
32 | Height = 25
33 | Caption = 'Start Session'
34 | TabOrder = 1
35 | OnClick = btnStartSessionClick
36 | end
37 | object Button1: TButton
38 | Left = 8
39 | Top = 386
40 | Width = 75
41 | Height = 25
42 | Caption = 'Status'
43 | TabOrder = 2
44 | OnClick = Button1Click
45 | end
46 | object Button2: TButton
47 | Left = 89
48 | Top = 355
49 | Width = 75
50 | Height = 25
51 | Caption = 'Timeout'
52 | TabOrder = 3
53 | OnClick = Button2Click
54 | end
55 | object StaticText1: TStaticText
56 | Left = 176
57 | Top = 355
58 | Width = 616
59 | Height = 25
60 | Anchors = [akLeft, akTop, akRight]
61 | AutoSize = False
62 | TabOrder = 4
63 | end
64 | object Button3: TButton
65 | Left = 89
66 | Top = 386
67 | Width = 75
68 | Height = 25
69 | Caption = 'Async'
70 | TabOrder = 5
71 | OnClick = Button3Click
72 | end
73 | object Button4: TButton
74 | Left = 170
75 | Top = 386
76 | Width = 75
77 | Height = 25
78 | Caption = 'Get Element'
79 | TabOrder = 6
80 | OnClick = Button4Click
81 | end
82 | object Button5: TButton
83 | Left = 251
84 | Top = 386
85 | Width = 75
86 | Height = 25
87 | Caption = 'Get Session'
88 | TabOrder = 7
89 | OnClick = Button5Click
90 | end
91 | object Button6: TButton
92 | Left = 332
93 | Top = 386
94 | Width = 75
95 | Height = 25
96 | Caption = 'Get Sessions'
97 | TabOrder = 8
98 | OnClick = Button6Click
99 | end
100 | object Button7: TButton
101 | Left = 413
102 | Top = 386
103 | Width = 75
104 | Height = 25
105 | Caption = 'Delete Session'
106 | TabOrder = 9
107 | OnClick = DeleteClick
108 | end
109 | object Button8: TButton
110 | Left = 544
111 | Top = 384
112 | Width = 75
113 | Height = 25
114 | Caption = 'Error'
115 | TabOrder = 10
116 | OnClick = Button8Click
117 | end
118 | object Button9: TButton
119 | Left = 8
120 | Top = 456
121 | Width = 75
122 | Height = 25
123 | Caption = 'Click OK'
124 | TabOrder = 11
125 | OnClick = Button9Click
126 | end
127 | object Button10: TButton
128 | Left = 8
129 | Top = 487
130 | Width = 75
131 | Height = 25
132 | Caption = 'Click Cancel'
133 | TabOrder = 12
134 | OnClick = Button10Click
135 | end
136 | object Button11: TButton
137 | Left = 89
138 | Top = 456
139 | Width = 75
140 | Height = 25
141 | Caption = 'Click Error'
142 | TabOrder = 13
143 | OnClick = Button11Click
144 | end
145 | object Button12: TButton
146 | Left = 170
147 | Top = 456
148 | Width = 75
149 | Height = 25
150 | Caption = 'Title'
151 | TabOrder = 14
152 | OnClick = Button12Click
153 | end
154 | object Button13: TButton
155 | Left = 170
156 | Top = 487
157 | Width = 75
158 | Height = 25
159 | Caption = 'Text'
160 | TabOrder = 15
161 | OnClick = Button13Click
162 | end
163 | object Button14: TButton
164 | Left = 413
165 | Top = 417
166 | Width = 75
167 | Height = 25
168 | Caption = 'Delete Invalid'
169 | TabOrder = 16
170 | OnClick = Button14Click
171 | end
172 | object Button15: TButton
173 | Left = 251
174 | Top = 456
175 | Width = 75
176 | Height = 25
177 | Caption = 'Get Window'
178 | TabOrder = 17
179 | OnClick = Button15Click
180 | end
181 | object Button16: TButton
182 | Left = 170
183 | Top = 518
184 | Width = 75
185 | Height = 25
186 | Caption = 'Get Elemnt'
187 | TabOrder = 18
188 | OnClick = Button16Click
189 | end
190 | object Button17: TButton
191 | Left = 251
192 | Top = 518
193 | Width = 118
194 | Height = 25
195 | Caption = 'Get Elemnt By Text'
196 | TabOrder = 19
197 | OnClick = Button17Click
198 | end
199 | object Button18: TButton
200 | Left = 380
201 | Top = 518
202 | Width = 118
203 | Height = 25
204 | Caption = 'Get Elemnt By Name'
205 | TabOrder = 20
206 | OnClick = Button18Click
207 | end
208 | object Button19: TButton
209 | Left = 544
210 | Top = 430
211 | Width = 153
212 | Height = 25
213 | Caption = 'Elements By ClassName'
214 | TabOrder = 21
215 | OnClick = Button19Click
216 | end
217 | object Button20: TButton
218 | Left = 380
219 | Top = 549
220 | Width = 149
221 | Height = 25
222 | Caption = 'Get/Click Elemnt By Name'
223 | TabOrder = 22
224 | OnClick = Button20Click
225 | end
226 | object Button21: TButton
227 | Left = 544
228 | Top = 549
229 | Width = 153
230 | Height = 25
231 | Caption = 'Speedbuttons By ClassName'
232 | TabOrder = 23
233 | OnClick = Button21Click
234 | end
235 | object Button22: TButton
236 | Left = 544
237 | Top = 488
238 | Width = 153
239 | Height = 25
240 | Caption = 'Click Speedbutton'
241 | TabOrder = 24
242 | OnClick = Button22Click
243 | end
244 | object Button23: TButton
245 | Left = 128
246 | Top = 560
247 | Width = 117
248 | Height = 25
249 | Caption = 'Get Grid Items'
250 | TabOrder = 25
251 | OnClick = Button23Click
252 | end
253 | object Button24: TButton
254 | Left = 128
255 | Top = 591
256 | Width = 117
257 | Height = 25
258 | Caption = 'Get List Items'
259 | TabOrder = 26
260 | OnClick = Button24Click
261 | end
262 | object Button25: TButton
263 | Left = 251
264 | Top = 580
265 | Width = 117
266 | Height = 25
267 | Caption = 'Get List Item Text'
268 | TabOrder = 27
269 | OnClick = Button25Click
270 | end
271 | object Button26: TButton
272 | Left = 374
273 | Top = 580
274 | Width = 149
275 | Height = 25
276 | Caption = 'Get Grid Item Text'
277 | TabOrder = 28
278 | OnClick = Button26Click
279 | end
280 | object ComboBox1: TComboBox
281 | Left = 544
282 | Top = 461
283 | Width = 153
284 | Height = 21
285 | Style = csDropDownList
286 | TabOrder = 29
287 | Items.Strings = (
288 | 'TButton'
289 | 'TEdit'
290 | 'TSpeedButton'
291 | 'TTabSheet'
292 | 'TAutomationStringGrid'
293 | 'TListBox'
294 | 'TComboBox'
295 | 'TAutomatedCombobox'
296 | 'TAutomatedEdit'
297 | 'TRadioButton'
298 | 'TPageControl'
299 | 'TCheckBox'
300 | 'TToolBar'
301 | 'TToolButton')
302 | end
303 | object ComboBox2: TComboBox
304 | Left = 544
305 | Top = 522
306 | Width = 153
307 | Height = 21
308 | Style = csDropDownList
309 | TabOrder = 30
310 | Items.Strings = (
311 | '1'
312 | '2'
313 | '3')
314 | end
315 | object Button27: TButton
316 | Left = 544
317 | Top = 580
318 | Width = 149
319 | Height = 25
320 | Caption = 'Get TabItem Text'
321 | TabOrder = 31
322 | OnClick = Button27Click
323 | end
324 | object Button28: TButton
325 | Left = 374
326 | Top = 606
327 | Width = 149
328 | Height = 25
329 | Caption = 'Right-Click on Grid'
330 | TabOrder = 32
331 | OnClick = Button28Click
332 | end
333 | object ComboBox3: TComboBox
334 | Left = 544
335 | Top = 610
336 | Width = 153
337 | Height = 21
338 | Style = csDropDownList
339 | TabOrder = 33
340 | Items.Strings = (
341 | '0'
342 | '1'
343 | '2')
344 | end
345 | object Button29: TButton
346 | Left = 728
347 | Top = 487
348 | Width = 121
349 | Height = 25
350 | Caption = 'Click ToolButon'
351 | TabOrder = 34
352 | OnClick = Button29Click
353 | end
354 | object ComboBox4: TComboBox
355 | Left = 728
356 | Top = 520
357 | Width = 121
358 | Height = 21
359 | Style = csDropDownList
360 | TabOrder = 35
361 | Items.Strings = (
362 | '1'
363 | '2'
364 | '3'
365 | '4')
366 | end
367 | object Button30: TButton
368 | Left = 728
369 | Top = 549
370 | Width = 121
371 | Height = 25
372 | Caption = 'Right-Click on TB'
373 | TabOrder = 36
374 | OnClick = Button28Click
375 | end
376 | object Button31: TButton
377 | Left = 8
378 | Top = 522
379 | Width = 75
380 | Height = 25
381 | Caption = 'Set Text'
382 | TabOrder = 37
383 | OnClick = Button31Click
384 | end
385 | object Edit1: TEdit
386 | Left = 8
387 | Top = 551
388 | Width = 114
389 | Height = 21
390 | TabOrder = 38
391 | Text = 'This is a test'
392 | end
393 | end
394 |
--------------------------------------------------------------------------------
/Commands/Commands.pas:
--------------------------------------------------------------------------------
1 | {***************************************************************************}
2 | { }
3 | { DelphiWebDriver }
4 | { }
5 | { Copyright 2017 inpwtepydjuf@gmail.com }
6 | { }
7 | {***************************************************************************}
8 | { }
9 | { Licensed under the Apache License, Version 2.0 (the "License"); }
10 | { you may not use this file except in compliance with the License. }
11 | { You may obtain a copy of the License at }
12 | { }
13 | { http://www.apache.org/licenses/LICENSE-2.0 }
14 | { }
15 | { Unless required by applicable law or agreed to in writing, software }
16 | { distributed under the License is distributed on an "AS IS" BASIS, }
17 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
18 | { See the License for the specific language governing permissions and }
19 | { limitations under the License. }
20 | { }
21 | {***************************************************************************}
22 | unit Commands;
23 |
24 | interface
25 |
26 | uses
27 | Sessions,
28 | Vcl.Forms,
29 | CommandRegistry,
30 | HttpServerCommand;
31 |
32 | type
33 | TUnimplementedCommand = class(TRestCommand)
34 | public
35 | procedure Execute(AOwner: TForm); override;
36 | end;
37 |
38 | type
39 | ///
40 | /// Handles 'GET' '/status'
41 | ///
42 | TStatusCommand = class(TRESTCommand)
43 | public
44 | procedure Execute(AOwner: TForm); override;
45 |
46 | class function GetCommand: String; override;
47 | class function GetRoute: String; override;
48 | end;
49 |
50 | type
51 | TGetSessionsCommand = class(TRESTCommand)
52 | public
53 | procedure Execute(AOwner: TForm); override;
54 |
55 | class function GetCommand: String; override;
56 | class function GetRoute: String; override;
57 | end;
58 |
59 | type
60 | TGetSessionCommand = class(TRESTCommand)
61 | public
62 | procedure Execute(AOwner: TForm); override;
63 |
64 | class function GetCommand: String; override;
65 | class function GetRoute: String; override;
66 | end;
67 |
68 | type
69 | TGetTitleCommand = class(TRestCommand)
70 | public
71 | procedure Execute(AOwner: TForm); override;
72 |
73 | class function GetCommand: String; override;
74 | class function GetRoute: String; override;
75 | end;
76 |
77 | type
78 | TSessionTimeoutsCommand = class(TRESTCommand)
79 | public
80 | procedure Execute(AOwner: TForm); override;
81 |
82 | class function GetCommand: String; override;
83 | class function GetRoute: String; override;
84 | end;
85 |
86 | type
87 | TPostImplicitWaitCommand = class(TRestCommand)
88 | public
89 | procedure Execute(AOwner: TForm); override;
90 |
91 | class function GetCommand: String; override;
92 | class function GetRoute: String; override;
93 | end;
94 |
95 | type
96 | TGetElementCommand = class(TRestCommand)
97 | public
98 | procedure Execute(AOwner: TForm); override;
99 |
100 | class function GetCommand: String; override;
101 | class function GetRoute: String; override;
102 | end;
103 |
104 | type
105 | TGetWindowCommand = class(TRestCommand)
106 | public
107 | procedure Execute(AOwner: TForm); override;
108 |
109 | class function GetCommand: String; override;
110 | class function GetRoute: String; override;
111 | end;
112 |
113 | var
114 | Sessions: TSessions;
115 |
116 | implementation
117 |
118 | uses
119 | windows,
120 | Vcl.stdctrls,
121 | System.Classes,
122 | System.SysUtils,
123 | vcl.controls,
124 | System.JSON,
125 | System.Types,
126 | System.StrUtils,
127 | System.JSON.Types,
128 | System.JSON.Writers,
129 | System.JSON.Builders,
130 | Utils,
131 | Session;
132 |
133 | procedure TStatusCommand.Execute(AOwner: TForm);
134 | begin
135 | try
136 | ResponseJSON(Sessions.GetSessionStatus(self.Params[1]));
137 | except on e: Exception do
138 | Error(404);
139 | end;
140 | end;
141 |
142 | class function TStatusCommand.GetCommand: String;
143 | begin
144 | result := 'GET';
145 | end;
146 |
147 | class function TStatusCommand.GetRoute: String;
148 | begin
149 | result := '/status';
150 | end;
151 |
152 | procedure TSessionTimeoutsCommand.Execute(AOwner: TForm);
153 | var
154 | jsonObj : TJSONObject;
155 | requestType: String;
156 | value: String;
157 |
158 | begin
159 | // Set timeout for the session
160 |
161 | // Decode the incoming JSON and see what we have
162 | jsonObj := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(self.StreamContents),0) as TJSONObject;
163 | try
164 | (jsonObj as TJsonObject).TryGetValue('type', requestType);
165 | (jsonObj as TJsonObject).TryGetValue('ms', value);
166 | finally
167 | jsonObj.Free;
168 | end;
169 |
170 | ResponseJSON(Sessions.SetSessionTimeouts(self.Params[1], StrToInt(value)));
171 | end;
172 |
173 | procedure TPostImplicitWaitCommand.Execute(AOwner: TForm);
174 | var
175 | jsonObj : TJSONObject;
176 | requestType: String;
177 | value: String;
178 |
179 | begin
180 | // Set timeout for the session
181 |
182 | // Decode the incoming JSON and see what we have
183 | jsonObj := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(self.StreamContents),0) as TJSONObject;
184 | try
185 | (jsonObj as TJsonObject).TryGetValue('type', requestType);
186 | (jsonObj as TJsonObject).TryGetValue('ms', value);
187 | finally
188 | jsonObj.Free;
189 | end;
190 |
191 | ResponseJSON(Sessions.SetSessionImplicitTimeouts(self.Params[1], StrToInt(value)));
192 | end;
193 |
194 | procedure TGetElementCommand.Execute(AOwner: TForm);
195 | begin
196 | ResponseJSON('{''TGetElementCommand'':'''+ self.Params[1] + '''}');
197 | end;
198 |
199 | procedure TGetSessionCommand.Execute(AOwner: TForm);
200 | begin
201 | try
202 | ResponseJSON(Sessions.GetSessionStatus(self.Params[1]));
203 | except on e: Exception do
204 | Error(404);
205 | end;
206 | end;
207 |
208 | procedure TGetSessionsCommand.Execute(AOwner: TForm);
209 | begin
210 | // No longer correct, needs to be a json array
211 | ResponseJSON(Sessions.GetSessionStatus(self.Params[1]));
212 | end;
213 |
214 | class function TGetSessionsCommand.GetCommand: String;
215 | begin
216 | result := 'GET';
217 | end;
218 |
219 | class function TGetSessionsCommand.GetRoute: String;
220 | begin
221 | result := '/sessions';
222 | end;
223 |
224 | class function TGetSessionCommand.GetCommand: String;
225 | begin
226 | result := 'GET';
227 | end;
228 |
229 | class function TGetSessionCommand.GetRoute: String;
230 | begin
231 | result := '/session/(.*)';
232 | end;
233 |
234 | class function TGetElementCommand.GetCommand: String;
235 | begin
236 | result := 'GET';
237 | end;
238 |
239 | class function TGetElementCommand.GetRoute: String;
240 | begin
241 | result := '/session/(.*)/element';
242 | end;
243 |
244 |
245 | procedure TUnimplementedCommand.Execute(AOwner: TForm);
246 | begin
247 | Error(501);
248 | end;
249 |
250 | procedure TGetTitleCommand.Execute(AOwner: TForm);
251 | var
252 | caption : String;
253 | begin
254 | // Here we are assuming it is a form
255 | caption := AOwner.Caption; // Never gets a caption for some reason
256 | ResponseJSON(caption);
257 | end;
258 |
259 | class function TGetTitleCommand.GetCommand: String;
260 | begin
261 | result := 'GET';
262 | end;
263 |
264 | class function TGetTitleCommand.GetRoute: String;
265 | begin
266 | result := '/session/(.*)/title';
267 | end;
268 |
269 | procedure TGetWindowCommand.Execute(AOwner: TForm);
270 | var
271 | handle : HWND;
272 | begin
273 | try
274 | handle := AOwner.Handle;
275 | ResponseJSON(intToStr(handle));
276 | except on e: Exception do
277 | Sessions.ErrorResponse ('7', 'no such element', 'An element could not be located on the page using the given search parameteres');
278 | end;
279 | end;
280 |
281 | class function TSessionTimeoutsCommand.GetCommand: String;
282 | begin
283 | result := 'POST';
284 | end;
285 |
286 | class function TSessionTimeoutsCommand.GetRoute: String;
287 | begin
288 | result := '/session/(.*)/timeouts';
289 | end;
290 |
291 | class function TPostImplicitWaitCommand.GetCommand: String;
292 | begin
293 | result := 'POST';
294 | end;
295 |
296 | class function TPostImplicitWaitCommand.GetRoute: String;
297 | begin
298 | result := '/session/(.*)/timeouts/implicit_wait';
299 | end;
300 |
301 | class function TGetWindowCommand.GetCommand: String;
302 | begin
303 | result := 'GET';
304 | end;
305 |
306 | class function TGetWindowCommand.GetRoute: String;
307 | begin
308 | result := '/session/(.*)/window';
309 | end;
310 |
311 | initialization
312 | Sessions := TSessions.Create;
313 |
314 | finalization
315 | Sessions.Free;
316 |
317 | end.
318 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/TestClient/Unit3.pas:
--------------------------------------------------------------------------------
1 | unit Unit3;
2 |
3 | interface
4 |
5 | uses
6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
7 | Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
8 |
9 | type
10 | TForm3 = class(TForm)
11 | ListBox1: TListBox;
12 | btnStartSession: TButton;
13 | Button1: TButton;
14 | Button2: TButton;
15 | StaticText1: TStaticText;
16 | Button3: TButton;
17 | Button4: TButton;
18 | Button5: TButton;
19 | Button6: TButton;
20 | Button7: TButton;
21 | Button8: TButton;
22 | Button9: TButton;
23 | Button10: TButton;
24 | Button11: TButton;
25 | Button12: TButton;
26 | Button13: TButton;
27 | Button14: TButton;
28 | Button15: TButton;
29 | Button16: TButton;
30 | Button17: TButton;
31 | Button18: TButton;
32 | Button19: TButton;
33 | Button20: TButton;
34 | Button21: TButton;
35 | Button22: TButton;
36 | Button23: TButton;
37 | Button24: TButton;
38 | Button25: TButton;
39 | Button26: TButton;
40 | ComboBox1: TComboBox;
41 | ComboBox2: TComboBox;
42 | Button27: TButton;
43 | Button28: TButton;
44 | ComboBox3: TComboBox;
45 | Button29: TButton;
46 | ComboBox4: TComboBox;
47 | Button30: TButton;
48 | Button31: TButton;
49 | Edit1: TEdit;
50 | procedure btnStartSessionClick(Sender: TObject);
51 | procedure Button1Click(Sender: TObject);
52 | procedure Button2Click(Sender: TObject);
53 | procedure Button3Click(Sender: TObject);
54 | procedure Button4Click(Sender: TObject);
55 | procedure Button5Click(Sender: TObject);
56 | procedure Button6Click(Sender: TObject);
57 | procedure Button7Click(Sender: TObject);
58 | procedure Button8Click(Sender: TObject);
59 | procedure Button9Click(Sender: TObject);
60 | procedure Button10Click(Sender: TObject);
61 | procedure Button11Click(Sender: TObject);
62 | procedure Button12Click(Sender: TObject);
63 | procedure Button13Click(Sender: TObject);
64 | procedure DeleteClick(Sender: TObject);
65 | procedure Button14Click(Sender: TObject);
66 | procedure Button15Click(Sender: TObject);
67 | procedure Button16Click(Sender: TObject);
68 | procedure Button17Click(Sender: TObject);
69 | procedure Button18Click(Sender: TObject);
70 | procedure Button19Click(Sender: TObject);
71 | procedure Button20Click(Sender: TObject);
72 | procedure Button21Click(Sender: TObject);
73 | procedure Button22Click(Sender: TObject);
74 | procedure Button23Click(Sender: TObject);
75 | procedure Button24Click(Sender: TObject);
76 | procedure Button25Click(Sender: TObject);
77 | procedure Button26Click(Sender: TObject);
78 | procedure Button27Click(Sender: TObject);
79 | procedure Button28Click(Sender: TObject);
80 | procedure Button29Click(Sender: TObject);
81 | procedure Button31Click(Sender: TObject);
82 | private
83 | { Private declarations }
84 | FSessionId: String;
85 |
86 | function Get(const resource: String): string;
87 | function Delete(const resource: String): string;
88 | function Post(const resource: String; const parameters: String = ''): string;
89 | function Sanitize(value: String): String;
90 | public
91 | { Public declarations }
92 | end;
93 |
94 | var
95 | Form3: TForm3;
96 |
97 | implementation
98 |
99 | uses
100 | IdHTTP,
101 | System.JSON,
102 | System.JSON.Types,
103 | System.JSON.Writers,
104 | System.JSON.Builders,
105 | System.StrUtils;
106 |
107 | {$R *.dfm}
108 |
109 | function TForm3.Sanitize(value: String): String;
110 | begin
111 | value := StringReplace(value,#$A,'',[rfReplaceAll]);
112 | value := StringReplace(value,#$D,'',[rfReplaceAll]);
113 |
114 | result := value;
115 | end;
116 |
117 | function TForm3.Post(const resource: String; const parameters: String = ''): string;
118 | var
119 | lHTTP: TIdHTTP;
120 | val : String;
121 | jsonToSend : TStringStream;
122 | begin
123 | lHTTP := TIdHTTP.Create(nil);
124 | lHTTP.Request.ContentType := 'application/json; charset=utf-8';
125 | try
126 | val := Sanitize(parameters);
127 | jsonToSend := TStringStream.create(val, TEncoding.UTF8);
128 | try
129 | Result := lHTTP.Post('http://127.0.0.1:4723/' + resource, jsonToSend);
130 | finally
131 | jsonToSend.Free;
132 | end;
133 | finally
134 | lHTTP.Free;
135 | end;
136 | end;
137 |
138 | function TForm3.Delete(const resource: String): string;
139 | var
140 | lHTTP: TIdHTTP;
141 | begin
142 | lHTTP := TIdHTTP.Create(nil);
143 | try
144 | Result := lHTTP.Delete('http://127.0.0.1:4723/' + resource);
145 | finally
146 | lHTTP.Free;
147 | end;
148 | end;
149 |
150 | function TForm3.Get(const resource: String): string;
151 | var
152 | lHTTP: TIdHTTP;
153 | begin
154 | lHTTP := TIdHTTP.Create(nil);
155 | try
156 | Result := lHTTP.Get('http://127.0.0.1:4723/' + resource);
157 | finally
158 | lHTTP.Free;
159 | end;
160 | end;
161 |
162 | procedure TForm3.btnStartSessionClick(Sender: TObject);
163 | var
164 | LJSONValue: TJSONValue;
165 | Builder: TJSONObjectBuilder;
166 | Writer: TJsonTextWriter;
167 | StringWriter: TStringWriter;
168 | StringBuilder: TStringBuilder;
169 | Parameters: String;
170 | result: String;
171 |
172 | begin
173 | FSessionId := '';
174 |
175 | StringBuilder := TStringBuilder.Create;
176 | StringWriter := TStringWriter.Create(StringBuilder);
177 | Writer := TJsonTextWriter.Create(StringWriter);
178 | Writer.Formatting := TJsonFormatting.Indented;
179 | Builder := TJSONObjectBuilder.Create(Writer);
180 |
181 | Builder
182 | .BeginObject
183 | .BeginObject('desiredCapabilities')
184 | .Add('platformName', 'iOS')
185 | .Add('app', 'c:\ProgramData\JHC\F63\Qual\Automation\DealServer2.exe')
186 | .Add('args', '4099')
187 | .EndObject
188 | .EndObject;
189 |
190 | Parameters := StringBuilder.ToString;
191 |
192 | result := Post('session', parameters);
193 |
194 | listBox1.Items.add(result);
195 |
196 | // Decode the JSon
197 | LJSONValue := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(result),0);
198 | FSessionID := LJSONValue.GetValue('sessionId');
199 |
200 | StaticText1.Caption := FSessionId;
201 | end;
202 |
203 | procedure TForm3.Button10Click(Sender: TObject);
204 | var
205 | result : String;
206 | begin
207 | result := post('session/' + self.FSessionId + '/element/Button2/click', '');
208 | end;
209 |
210 | procedure TForm3.Button11Click(Sender: TObject);
211 | var
212 | result : String;
213 | begin
214 | result := post('session/' + self.FSessionId + '/element/ButtonNotThere/click', '');
215 | listBox1.Items.add(result);
216 | end;
217 |
218 | procedure TForm3.Button12Click(Sender: TObject);
219 | var
220 | result : String;
221 | begin
222 | result := Get('session/' + self.FSessionId + '/title');
223 | listBox1.Items.add(result);
224 | end;
225 |
226 | procedure TForm3.Button13Click(Sender: TObject);
227 | var
228 | result : String;
229 | begin
230 | result := get('session/' + self.FSessionId + '/element/AutomatedEdit1/text');
231 | listBox1.Items.add(result);
232 | end;
233 |
234 | procedure TForm3.Button14Click(Sender: TObject);
235 | var
236 | result : String;
237 | begin
238 | result := Delete('session/ieueihflkjflkjfhe76rj');
239 | listBox1.Items.add(result);
240 | end;
241 |
242 | procedure TForm3.Button15Click(Sender: TObject);
243 | var
244 | result : String;
245 | begin
246 | result := Get('session/' + self.FSessionId + '/window');
247 | listBox1.Items.add(result);
248 | end;
249 |
250 | procedure TForm3.Button16Click(Sender: TObject);
251 | var
252 | result : String;
253 | Builder: TJSONObjectBuilder;
254 | Writer: TJsonTextWriter;
255 | StringWriter: TStringWriter;
256 | StringBuilder: TStringBuilder;
257 | Parameters: String;
258 |
259 | begin
260 | StringBuilder := TStringBuilder.Create;
261 | StringWriter := TStringWriter.Create(StringBuilder);
262 | Writer := TJsonTextWriter.Create(StringWriter);
263 | Writer.Formatting := TJsonFormatting.Indented;
264 | Builder := TJSONObjectBuilder.Create(Writer);
265 |
266 | Builder
267 | .BeginObject
268 | .Add('using', 'name')
269 | .Add('value', 'This is Form1 - The Hosting Form')
270 | .EndObject;
271 |
272 | Parameters := StringBuilder.ToString;
273 |
274 | result := post('session/' + self.FSessionId + '/element', parameters);
275 | listBox1.Items.add(result);
276 | end;
277 |
278 | procedure TForm3.Button17Click(Sender: TObject);
279 | var
280 | result : String;
281 | Builder: TJSONObjectBuilder;
282 | Writer: TJsonTextWriter;
283 | StringWriter: TStringWriter;
284 | StringBuilder: TStringBuilder;
285 | Parameters: String;
286 |
287 | begin
288 | StringBuilder := TStringBuilder.Create;
289 | StringWriter := TStringWriter.Create(StringBuilder);
290 | Writer := TJsonTextWriter.Create(StringWriter);
291 | Writer.Formatting := TJsonFormatting.Indented;
292 | Builder := TJSONObjectBuilder.Create(Writer);
293 |
294 | Builder
295 | .BeginObject
296 | .Add('using', 'link text')
297 | .Add('value', 'Get Title')
298 | .EndObject;
299 |
300 | Parameters := StringBuilder.ToString;
301 |
302 | result := post('session/' + self.FSessionId + '/element', parameters);
303 | listBox1.Items.add(result);
304 | end;
305 |
306 | procedure TForm3.Button18Click(Sender: TObject);
307 | var
308 | result : String;
309 | Builder: TJSONObjectBuilder;
310 | Writer: TJsonTextWriter;
311 | StringWriter: TStringWriter;
312 | StringBuilder: TStringBuilder;
313 | Parameters: String;
314 |
315 | begin
316 | StringBuilder := TStringBuilder.Create;
317 | StringWriter := TStringWriter.Create(StringBuilder);
318 | Writer := TJsonTextWriter.Create(StringWriter);
319 | Writer.Formatting := TJsonFormatting.Indented;
320 | Builder := TJSONObjectBuilder.Create(Writer);
321 |
322 | Builder
323 | .BeginObject
324 | .Add('using', 'name')
325 | .Add('value', 'Button3')
326 | .EndObject;
327 |
328 | Parameters := StringBuilder.ToString;
329 |
330 | result := post('session/' + self.FSessionId + '/element', parameters);
331 | listBox1.Items.add(result);
332 | end;
333 |
334 | procedure TForm3.Button19Click(Sender: TObject);
335 | var
336 | result : String;
337 | Builder: TJSONObjectBuilder;
338 | Writer: TJsonTextWriter;
339 | StringWriter: TStringWriter;
340 | StringBuilder: TStringBuilder;
341 | Parameters: String;
342 |
343 | begin
344 | StringBuilder := TStringBuilder.Create;
345 | StringWriter := TStringWriter.Create(StringBuilder);
346 | Writer := TJsonTextWriter.Create(StringWriter);
347 | Writer.Formatting := TJsonFormatting.Indented;
348 | Builder := TJSONObjectBuilder.Create(Writer);
349 |
350 | Builder
351 | .BeginObject
352 | .Add('using', 'class name')
353 | .Add('value', ComboBox1.Text)
354 | .EndObject;
355 |
356 | Parameters := StringBuilder.ToString;
357 |
358 | result := post('session/' + self.FSessionId + '/elements', parameters);
359 | listBox1.Items.add(result);
360 | end;
361 |
362 | procedure TForm3.Button1Click(Sender: TObject);
363 | var
364 | result : String;
365 | begin
366 | result := Get('status');
367 | listBox1.Items.add(result);
368 | end;
369 |
370 | procedure TForm3.Button20Click(Sender: TObject);
371 | var
372 | result : String;
373 | Builder: TJSONObjectBuilder;
374 | Writer: TJsonTextWriter;
375 | StringWriter: TStringWriter;
376 | StringBuilder: TStringBuilder;
377 | Parameters: String;
378 | handle: String;
379 | jsonObj: TJSONObject;
380 | jsonPair: TJsonObject;
381 | req: String;
382 |
383 | begin
384 | StringBuilder := TStringBuilder.Create;
385 | StringWriter := TStringWriter.Create(StringBuilder);
386 | Writer := TJsonTextWriter.Create(StringWriter);
387 | Writer.Formatting := TJsonFormatting.Indented;
388 | Builder := TJSONObjectBuilder.Create(Writer);
389 |
390 | Builder
391 | .BeginObject
392 | .Add('using', 'name')
393 | .Add('value', 'Button3')
394 | .EndObject;
395 |
396 | Parameters := StringBuilder.ToString;
397 |
398 | result := post('session/' + self.FSessionId + '/element', parameters);
399 | listBox1.Items.add(result);
400 |
401 | // Decode it and get the handle
402 | jsonObj := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(result),0) as TJSONObject;
403 | try
404 | (jsonObj as TJsonObject).TryGetValue('value', jsonPair);
405 | (jsonPair as TJsonObject).TryGetValue('ELEMENT', handle);
406 | finally
407 | jsonObj.Free;
408 | end;
409 |
410 | req := 'session/' + self.FSessionId + '/element/' + handle + '/click';
411 |
412 | result := post('session/' + self.FSessionId + '/element/' + handle + '/click');
413 |
414 | listBox1.Items.Add(result);
415 | end;
416 |
417 | procedure TForm3.Button21Click(Sender: TObject);
418 | var
419 | result : String;
420 | Builder: TJSONObjectBuilder;
421 | Writer: TJsonTextWriter;
422 | StringWriter: TStringWriter;
423 | StringBuilder: TStringBuilder;
424 | Parameters: String;
425 |
426 | begin
427 | StringBuilder := TStringBuilder.Create;
428 | StringWriter := TStringWriter.Create(StringBuilder);
429 | Writer := TJsonTextWriter.Create(StringWriter);
430 | Writer.Formatting := TJsonFormatting.Indented;
431 | Builder := TJSONObjectBuilder.Create(Writer);
432 |
433 | Builder
434 | .BeginObject
435 | .Add('using', 'class name')
436 | .Add('value', 'TSpeedButton')
437 | .EndObject;
438 |
439 | Parameters := StringBuilder.ToString;
440 |
441 | result := post('session/' + self.FSessionId + '/elements', parameters);
442 | listBox1.Items.add(result);
443 | end;
444 |
445 | procedure TForm3.Button22Click(Sender: TObject);
446 | var
447 | result : String;
448 | Builder: TJSONObjectBuilder;
449 | Writer: TJsonTextWriter;
450 | StringWriter: TStringWriter;
451 | StringBuilder: TStringBuilder;
452 | Parameters: String;
453 | jsonObj: TJSONObject;
454 | jsonPair: TJsonObject;
455 | req: String;
456 | handle: String;
457 |
458 | begin
459 | StringBuilder := TStringBuilder.Create;
460 | StringWriter := TStringWriter.Create(StringBuilder);
461 | Writer := TJsonTextWriter.Create(StringWriter);
462 | Writer.Formatting := TJsonFormatting.Indented;
463 | Builder := TJSONObjectBuilder.Create(Writer);
464 |
465 | Builder
466 | .BeginObject
467 | .Add('using', 'name')
468 | .Add('value', 'SpeedButton' + COmbobox2.Text)
469 | .EndObject;
470 |
471 | Parameters := StringBuilder.ToString;
472 |
473 | result := post('session/' + self.FSessionId + '/element', parameters);
474 | listBox1.Items.add(result);
475 |
476 | // Decode it and get the handle
477 | jsonObj := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(result),0) as TJSONObject;
478 | try
479 | (jsonObj as TJsonObject).TryGetValue('value', jsonPair);
480 | (jsonPair as TJsonObject).TryGetValue('ELEMENT', handle);
481 | finally
482 | jsonObj.Free;
483 | end;
484 |
485 | req := 'session/' + self.FSessionId + '/element/' + handle + '/click';
486 |
487 | result := post(req);
488 |
489 | listBox1.Items.Add(result);
490 | end;
491 |
492 | procedure TForm3.Button23Click(Sender: TObject);
493 | var
494 | result : String;
495 | Builder: TJSONObjectBuilder;
496 | Writer: TJsonTextWriter;
497 | StringWriter: TStringWriter;
498 | StringBuilder: TStringBuilder;
499 | jsonObj: TJSONObject;
500 | jsonPair: TJsonObject;
501 | req: String;
502 | handle: String;
503 |
504 | begin
505 | StringBuilder := TStringBuilder.Create;
506 | StringWriter := TStringWriter.Create(StringBuilder);
507 | Writer := TJsonTextWriter.Create(StringWriter);
508 | Writer.Formatting := TJsonFormatting.Indented;
509 | Builder := TJSONObjectBuilder.Create(Writer);
510 |
511 | Builder
512 | .BeginObject
513 | .Add('using', 'name')
514 | .Add('value', 'AutomationStringGrid1')
515 | .EndObject;
516 |
517 | result := post('session/' + self.FSessionId + '/element', StringBuilder.ToString);
518 | listBox1.Items.add(result);
519 |
520 | // Decode it and get the handle
521 | jsonObj := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(result),0) as TJSONObject;
522 | try
523 | (jsonObj as TJsonObject).TryGetValue('value', jsonPair);
524 | (jsonPair as TJsonObject).TryGetValue('ELEMENT', handle);
525 | finally
526 | jsonObj.Free;
527 | end;
528 |
529 | req := 'session/' + self.FSessionId + '/element/' + handle + '/elements';
530 |
531 | StringBuilder := TStringBuilder.Create;
532 | StringWriter := TStringWriter.Create(StringBuilder);
533 | Writer := TJsonTextWriter.Create(StringWriter);
534 | Writer.Formatting := TJsonFormatting.Indented;
535 | Builder := TJSONObjectBuilder.Create(Writer);
536 |
537 |
538 | // Header / HeaderItem / Text
539 | // DataItem / Text
540 |
541 | Builder
542 | .BeginObject
543 | .Add('using', 'class name')
544 | .Add('value', 'DataItem')
545 | .EndObject;
546 |
547 | result := post('session/' + self.FSessionId + '/element/' + handle + '/elements', StringBuilder.ToString);
548 |
549 | listBox1.Items.Add(result);
550 | end;
551 |
552 | procedure TForm3.Button24Click(Sender: TObject);
553 | var
554 | result : String;
555 | Builder: TJSONObjectBuilder;
556 | Writer: TJsonTextWriter;
557 | StringWriter: TStringWriter;
558 | StringBuilder: TStringBuilder;
559 | jsonObj: TJSONObject;
560 | jsonPair: TJsonObject;
561 | req: String;
562 | handle: String;
563 |
564 | begin
565 | StringBuilder := TStringBuilder.Create;
566 | StringWriter := TStringWriter.Create(StringBuilder);
567 | Writer := TJsonTextWriter.Create(StringWriter);
568 | Writer.Formatting := TJsonFormatting.Indented;
569 | Builder := TJSONObjectBuilder.Create(Writer);
570 |
571 | Builder
572 | .BeginObject
573 | .Add('using', 'name')
574 | .Add('value', 'ListBox1')
575 | .EndObject;
576 |
577 | result := post('session/' + self.FSessionId + '/element', StringBuilder.ToString);
578 | listBox1.Items.add(result);
579 |
580 | // Decode it and get the handle
581 | jsonObj := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(result),0) as TJSONObject;
582 | try
583 | (jsonObj as TJsonObject).TryGetValue('value', jsonPair);
584 | (jsonPair as TJsonObject).TryGetValue('ELEMENT', handle);
585 | finally
586 | jsonObj.Free;
587 | end;
588 |
589 | req := 'session/' + self.FSessionId + '/element/' + handle + '/elements';
590 |
591 | StringBuilder := TStringBuilder.Create;
592 | StringWriter := TStringWriter.Create(StringBuilder);
593 | Writer := TJsonTextWriter.Create(StringWriter);
594 | Writer.Formatting := TJsonFormatting.Indented;
595 | Builder := TJSONObjectBuilder.Create(Writer);
596 |
597 |
598 | // Header / HeaderItem / Text
599 | // DataItem / Text
600 |
601 | Builder
602 | .BeginObject
603 | .Add('using', 'class name')
604 | .Add('value', 'DataItem')
605 | .EndObject;
606 |
607 | result := post('session/' + self.FSessionId + '/element/' + handle + '/elements', StringBuilder.ToString);
608 |
609 | listBox1.Items.Add(result);
610 | end;
611 |
612 | procedure TForm3.Button25Click(Sender: TObject);
613 | var
614 | result : String;
615 |
616 | begin
617 | result := get('session/' + self.FSessionId + '/element/ListBox1.0/text');
618 |
619 | listBox1.Items.Add(result);
620 | end;
621 |
622 | procedure TForm3.Button26Click(Sender: TObject);
623 | var
624 | result : String;
625 |
626 | begin
627 | result := get('session/' + self.FSessionId + '/element/AutomationStringGrid1.1.1/text');
628 | listBox1.Items.Add(result);
629 | end;
630 |
631 | procedure TForm3.Button27Click(Sender: TObject);
632 | var
633 | result : String;
634 |
635 | begin
636 | result := get('session/' + self.FSessionId + '/element/PageControl1.' + Combobox3.text + '/text');
637 | listBox1.Items.Add(result);
638 | end;
639 |
640 | procedure TForm3.Button28Click(Sender: TObject);
641 | var
642 | result : String;
643 | Builder: TJSONObjectBuilder;
644 | Writer: TJsonTextWriter;
645 | StringWriter: TStringWriter;
646 | StringBuilder: TStringBuilder;
647 | Parameters: String;
648 |
649 | begin
650 | StringBuilder := TStringBuilder.Create;
651 | StringWriter := TStringWriter.Create(StringBuilder);
652 | Writer := TJsonTextWriter.Create(StringWriter);
653 | Writer.Formatting := TJsonFormatting.Indented;
654 | Builder := TJSONObjectBuilder.Create(Writer);
655 |
656 | Builder
657 | .BeginObject
658 | .Add('script', 'right click')
659 | .BeginObject('args')
660 | .Add('first', 'ToolButton5')
661 | .EndObject
662 | .EndObject;
663 |
664 | Parameters := StringBuilder.ToString;
665 |
666 | result := post('session/' + self.FSessionId + '/execute', parameters);
667 | listBox1.Items.Add(result);
668 | end;
669 |
670 | procedure TForm3.Button29Click(Sender: TObject);
671 | var
672 | result : String;
673 | Builder: TJSONObjectBuilder;
674 | Writer: TJsonTextWriter;
675 | StringWriter: TStringWriter;
676 | StringBuilder: TStringBuilder;
677 | Parameters: String;
678 | jsonObj: TJSONObject;
679 | jsonPair: TJsonObject;
680 | req: String;
681 | handle: String;
682 |
683 | begin
684 | StringBuilder := TStringBuilder.Create;
685 | StringWriter := TStringWriter.Create(StringBuilder);
686 | Writer := TJsonTextWriter.Create(StringWriter);
687 | Writer.Formatting := TJsonFormatting.Indented;
688 | Builder := TJSONObjectBuilder.Create(Writer);
689 |
690 | StringBuilder := TStringBuilder.Create;
691 | StringWriter := TStringWriter.Create(StringBuilder);
692 | Writer := TJsonTextWriter.Create(StringWriter);
693 | Writer.Formatting := TJsonFormatting.Indented;
694 | Builder := TJSONObjectBuilder.Create(Writer);
695 |
696 | Builder
697 | .BeginObject
698 | .Add('using', 'name')
699 | .Add('value', 'ToolButton' + Combobox4.Text)
700 | .EndObject;
701 |
702 | Parameters := StringBuilder.ToString;
703 |
704 | result := post('session/' + self.FSessionId + '/element', parameters);
705 | listBox1.Items.add(result);
706 |
707 | // Decode it and get the handle
708 | jsonObj := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(result),0) as TJSONObject;
709 | try
710 | (jsonObj as TJsonObject).TryGetValue('value', jsonPair);
711 | (jsonPair as TJsonObject).TryGetValue('ELEMENT', handle);
712 | finally
713 | jsonObj.Free;
714 | end;
715 |
716 | req := 'session/' + self.FSessionId + '/element/' + handle + '/click';
717 |
718 | result := post('session/' + self.FSessionId + '/element/' + handle + '/click');
719 |
720 | listBox1.Items.Add(result);
721 | end;
722 |
723 | procedure TForm3.Button2Click(Sender: TObject);
724 | var
725 | result : String;
726 | Builder: TJSONObjectBuilder;
727 | Writer: TJsonTextWriter;
728 | StringWriter: TStringWriter;
729 | StringBuilder: TStringBuilder;
730 | Parameters: String;
731 |
732 | begin
733 | StringBuilder := TStringBuilder.Create;
734 | StringWriter := TStringWriter.Create(StringBuilder);
735 | Writer := TJsonTextWriter.Create(StringWriter);
736 | Writer.Formatting := TJsonFormatting.Indented;
737 | Builder := TJSONObjectBuilder.Create(Writer);
738 |
739 | Builder
740 | .BeginObject
741 | .Add('type', 'implicit')
742 | .Add('ms', '200')
743 | .EndObject;
744 |
745 | Parameters := StringBuilder.ToString;
746 |
747 | result := post('session/' + self.FSessionId + '/timeouts', parameters);
748 | listBox1.Items.add(result);
749 | end;
750 |
751 | procedure TForm3.Button31Click(Sender: TObject);
752 | var
753 | result : String;
754 | Builder: TJSONObjectBuilder;
755 | Writer: TJsonTextWriter;
756 | StringWriter: TStringWriter;
757 | StringBuilder: TStringBuilder;
758 | jsonObj: TJSONObject;
759 | jsonPair: TJsonObject;
760 | req: String;
761 | handle: String;
762 |
763 | begin
764 | StringBuilder := TStringBuilder.Create;
765 | StringWriter := TStringWriter.Create(StringBuilder);
766 | Writer := TJsonTextWriter.Create(StringWriter);
767 | Writer.Formatting := TJsonFormatting.Indented;
768 | Builder := TJSONObjectBuilder.Create(Writer);
769 |
770 | // First get the handle of the control
771 | Builder
772 | .BeginObject
773 | .Add('using', 'name')
774 | .Add('value', 'Edit1')
775 | .EndObject;
776 |
777 | result := post('session/' + self.FSessionId + '/element', StringBuilder.ToString);
778 | listBox1.Items.add(result);
779 |
780 | // Decode it and get the handle
781 | jsonObj := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(result),0) as TJSONObject;
782 | try
783 | (jsonObj as TJsonObject).TryGetValue('value', jsonPair);
784 | (jsonPair as TJsonObject).TryGetValue('ELEMENT', handle);
785 | finally
786 | jsonObj.Free;
787 | end;
788 |
789 | req := 'session/' + self.FSessionId + '/element/' + handle + '/value';
790 |
791 | StringBuilder := TStringBuilder.Create;
792 | StringWriter := TStringWriter.Create(StringBuilder);
793 | Writer := TJsonTextWriter.Create(StringWriter);
794 | Writer.Formatting := TJsonFormatting.Indented;
795 | Builder := TJSONObjectBuilder.Create(Writer);
796 |
797 | Builder
798 | .BeginObject
799 | .Add('value', Edit1.text)
800 | .EndObject;
801 |
802 | result := post(req, StringBuilder.ToString);
803 | listBox1.Items.add(result);
804 | end;
805 |
806 | procedure TForm3.Button3Click(Sender: TObject);
807 | var
808 | result : String;
809 | begin
810 | result := post('session/' + self.FSessionId + '/timeouts/implicit_wait', '');
811 | listBox1.Items.add(result);
812 | end;
813 |
814 | procedure TForm3.Button4Click(Sender: TObject);
815 | var
816 | result : String;
817 | Builder: TJSONObjectBuilder;
818 | Writer: TJsonTextWriter;
819 | StringWriter: TStringWriter;
820 | StringBuilder: TStringBuilder;
821 |
822 | begin
823 | StringBuilder := TStringBuilder.Create;
824 | StringWriter := TStringWriter.Create(StringBuilder);
825 | Writer := TJsonTextWriter.Create(StringWriter);
826 | Writer.Formatting := TJsonFormatting.Indented;
827 | Builder := TJSONObjectBuilder.Create(Writer);
828 |
829 | Builder
830 | .BeginObject
831 | .Add('using', 'name')
832 | .Add('value', 'Button1')
833 | .EndObject;
834 |
835 | result := post('session/' + self.FSessionId + '/element', StringBuilder.ToString);
836 | listBox1.Items.add(result);
837 | end;
838 |
839 | procedure TForm3.Button5Click(Sender: TObject);
840 | var
841 | result : String;
842 | begin
843 | // For example
844 | result := get('session/' + self.FSessionId);
845 | listBox1.Items.add(result);
846 | end;
847 |
848 | procedure TForm3.Button6Click(Sender: TObject);
849 | var
850 | result : String;
851 | begin
852 | result := get('sessions');
853 | listBox1.Items.add(result);
854 | end;
855 |
856 | procedure TForm3.Button7Click(Sender: TObject);
857 | var
858 | result : String;
859 | begin
860 | result := get('session/' + self.FSessionId + '/window_handle');
861 | listBox1.Items.add(result);
862 | end;
863 |
864 | procedure TForm3.Button8Click(Sender: TObject);
865 | var
866 | result : String;
867 | begin
868 | result := get('error/' + self.FSessionId + '/window_handle');
869 | listBox1.Items.add(result);
870 | end;
871 |
872 | procedure TForm3.Button9Click(Sender: TObject);
873 | var
874 | result : String;
875 | begin
876 | result := post('session/' + self.FSessionId + '/element/Button1/click', '');
877 | listBox1.Items.add(result);
878 | end;
879 |
880 | procedure TForm3.DeleteClick(Sender: TObject);
881 | var
882 | result : String;
883 | begin
884 | result := Delete('session/' + self.FSessionId);
885 | listBox1.Items.add(result);
886 | end;
887 |
888 | end.
889 |
--------------------------------------------------------------------------------
/TestClient/TestClient.dproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {AD8B89D5-8BC4-42CC-AFE0-A4E9E8A176AA}
4 | 18.2
5 | VCL
6 | TestClient.dpr
7 | True
8 | Debug
9 | Win32
10 | 1
11 | Application
12 |
13 |
14 | true
15 |
16 |
17 | true
18 | Base
19 | true
20 |
21 |
22 | true
23 | Base
24 | true
25 |
26 |
27 | true
28 | Cfg_1
29 | true
30 | true
31 |
32 |
33 | true
34 | Base
35 | true
36 |
37 |
38 | true
39 | Cfg_2
40 | true
41 | true
42 |
43 |
44 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
45 | TestClient
46 | $(BDS)\bin\delphi_PROJECTICON.ico
47 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
48 | System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)
49 | .\$(Platform)\$(Config)
50 | .\$(Platform)\$(Config)
51 | false
52 | false
53 | false
54 | false
55 | false
56 |
57 |
58 | $(BDS)\bin\default_app.manifest
59 | true
60 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
61 | Debug
62 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
63 | 1033
64 | DBXSqliteDriver;IndyIPCommon;RESTComponents;bindcompdbx;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;advchartd320;vclFireDAC;IndySystem;NMWrappers320;tethering;svnui;dsnapcon;FireDACADSDriver;madExcept_;FireDACMSAccDriver;fmxFireDAC;vclimg;madBasic_;TeeDB;FireDAC;AutomatedControls;vcltouch;vcldb;bindcompfmx;svn;FireDACSqliteDriver;FireDACPgDriver;inetdb;FMXTee;soaprtl;DbxCommonDriver;FmxTeeUI;FireDACIBDriver;fmx;fmxdae;xmlrtl;soapmidas;frx24;fmxobj;vclwinx;Tee;rtl;madDisAsm_;DbxClientDriver;DocGen320;frxTee24;CustomIPTransport;vcldsnap;dbexpress;IndyCore;VersionInfo320;vclx;bindcomp;appanalytics;dsnap;FireDACCommon;IndyIPClient;Package1;bindcompvcl;RESTBackendComponents;frxe24;TeeUI;VCLRESTComponents;soapserver;dbxcds;VclSmp;adortl;vclie;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;IndyProtocols;inetdbxpress;frxDB24;FireDACCommonODBC;FireDACCommonDriver;XACompPackage320;inet;fmxase;$(DCC_UsePackage)
65 |
66 |
67 | DEBUG;$(DCC_Define)
68 | true
69 | false
70 | true
71 | true
72 | true
73 |
74 |
75 | true
76 | true
77 | false
78 |
79 |
80 | false
81 | RELEASE;$(DCC_Define)
82 | 0
83 | 0
84 |
85 |
86 | true
87 | true
88 |
89 |
90 |
91 | MainSource
92 |
93 |
94 |
95 | dfm
96 |
97 |
98 | Cfg_2
99 | Base
100 |
101 |
102 | Base
103 |
104 |
105 | Cfg_1
106 | Base
107 |
108 |
109 |
110 | Delphi.Personality.12
111 | Application
112 |
113 |
114 |
115 | TestClient.dpr
116 |
117 |
118 |
119 |
120 |
121 | TestClient.exe
122 | true
123 |
124 |
125 |
126 |
127 | 1
128 |
129 |
130 | 1
131 |
132 |
133 |
134 |
135 | Contents\Resources
136 | 1
137 |
138 |
139 |
140 |
141 | classes
142 | 1
143 |
144 |
145 |
146 |
147 | Contents\MacOS
148 | 0
149 |
150 |
151 | 1
152 |
153 |
154 | Contents\MacOS
155 | 1
156 |
157 |
158 |
159 |
160 | 1
161 |
162 |
163 | 1
164 |
165 |
166 | 1
167 |
168 |
169 |
170 |
171 | res\drawable-xxhdpi
172 | 1
173 |
174 |
175 |
176 |
177 | library\lib\mips
178 | 1
179 |
180 |
181 |
182 |
183 | 1
184 |
185 |
186 | 1
187 |
188 |
189 | 0
190 |
191 |
192 | 1
193 |
194 |
195 | Contents\MacOS
196 | 1
197 |
198 |
199 | library\lib\armeabi-v7a
200 | 1
201 |
202 |
203 | 1
204 |
205 |
206 |
207 |
208 | 0
209 |
210 |
211 | Contents\MacOS
212 | 1
213 | .framework
214 |
215 |
216 |
217 |
218 | 1
219 |
220 |
221 | 1
222 |
223 |
224 |
225 |
226 | 1
227 |
228 |
229 | 1
230 |
231 |
232 | 1
233 |
234 |
235 |
236 |
237 | 1
238 |
239 |
240 | 1
241 |
242 |
243 | 1
244 |
245 |
246 |
247 |
248 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
249 | 1
250 |
251 |
252 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
253 | 1
254 |
255 |
256 |
257 |
258 | 1
259 |
260 |
261 | 1
262 |
263 |
264 | 1
265 |
266 |
267 |
268 |
269 | 1
270 |
271 |
272 | 1
273 |
274 |
275 | 1
276 |
277 |
278 |
279 |
280 | library\lib\armeabi
281 | 1
282 |
283 |
284 |
285 |
286 | 0
287 |
288 |
289 | 1
290 |
291 |
292 | Contents\MacOS
293 | 1
294 |
295 |
296 |
297 |
298 | 1
299 |
300 |
301 | 1
302 |
303 |
304 | 1
305 |
306 |
307 |
308 |
309 | res\drawable-normal
310 | 1
311 |
312 |
313 |
314 |
315 | res\drawable-xhdpi
316 | 1
317 |
318 |
319 |
320 |
321 | res\drawable-large
322 | 1
323 |
324 |
325 |
326 |
327 | 1
328 |
329 |
330 | 1
331 |
332 |
333 | 1
334 |
335 |
336 |
337 |
338 | Assets
339 | 1
340 |
341 |
342 | Assets
343 | 1
344 |
345 |
346 |
347 |
348 | ..\
349 | 1
350 |
351 |
352 | ..\
353 | 1
354 |
355 |
356 |
357 |
358 | res\drawable-hdpi
359 | 1
360 |
361 |
362 |
363 |
364 | library\lib\armeabi-v7a
365 | 1
366 |
367 |
368 |
369 |
370 | Contents
371 | 1
372 |
373 |
374 |
375 |
376 | ..\
377 | 1
378 |
379 |
380 |
381 |
382 | Assets
383 | 1
384 |
385 |
386 | Assets
387 | 1
388 |
389 |
390 |
391 |
392 | 1
393 |
394 |
395 | 1
396 |
397 |
398 | 1
399 |
400 |
401 |
402 |
403 | res\values
404 | 1
405 |
406 |
407 |
408 |
409 | res\drawable-small
410 | 1
411 |
412 |
413 |
414 |
415 | res\drawable
416 | 1
417 |
418 |
419 |
420 |
421 | 1
422 |
423 |
424 | 1
425 |
426 |
427 | 1
428 |
429 |
430 |
431 |
432 | 1
433 |
434 |
435 |
436 |
437 | res\drawable
438 | 1
439 |
440 |
441 |
442 |
443 | 0
444 |
445 |
446 | 0
447 |
448 |
449 | Contents\Resources\StartUp\
450 | 0
451 |
452 |
453 | 0
454 |
455 |
456 | 0
457 |
458 |
459 | 0
460 |
461 |
462 |
463 |
464 | library\lib\armeabi-v7a
465 | 1
466 |
467 |
468 |
469 |
470 | 0
471 | .bpl
472 |
473 |
474 | 1
475 | .dylib
476 |
477 |
478 | Contents\MacOS
479 | 1
480 | .dylib
481 |
482 |
483 | 1
484 | .dylib
485 |
486 |
487 | 1
488 | .dylib
489 |
490 |
491 |
492 |
493 | res\drawable-mdpi
494 | 1
495 |
496 |
497 |
498 |
499 | res\drawable-xlarge
500 | 1
501 |
502 |
503 |
504 |
505 | res\drawable-ldpi
506 | 1
507 |
508 |
509 |
510 |
511 | 0
512 | .dll;.bpl
513 |
514 |
515 | 1
516 | .dylib
517 |
518 |
519 | Contents\MacOS
520 | 1
521 | .dylib
522 |
523 |
524 | 1
525 | .dylib
526 |
527 |
528 | 1
529 | .dylib
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 | True
543 |
544 |
545 | 12
546 |
547 |
548 |
549 |
550 |
551 |
--------------------------------------------------------------------------------