Compare commits
19 Commits
replay_err
...
master
|
@ -1,4 +1,5 @@
|
|||
.idea
|
||||
.vscode
|
||||
**/__pycache__/
|
||||
**/main.py
|
||||
**/main.py
|
||||
*.http
|
|
@ -12,7 +12,7 @@ class AntiCaptcha:
|
|||
ep: str = ""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.ep = "https://localhost:8443"
|
||||
self.ep = os.environ.get("REPLAY_ADDR")
|
||||
|
||||
def __request_json_post__ (self, path: str, object: dict):
|
||||
"""
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
import base64
|
||||
import json
|
||||
import os
|
||||
import requests
|
||||
|
||||
class API_Proxy:
|
||||
"""
|
||||
## API Proxy
|
||||
---
|
||||
O Serviço API Proxy permite realizar chamadas a api externas proxiadas pelo Replay. Dessa forma, as chamadas podem ficar pré- configuradas dentro do Replay.
|
||||
|
||||
Caso o robô ou aplicação desejem alterar algum parâmetro antes da chamada ainda é possível, para isso, deve-se modificar a estrutura da requisição.
|
||||
|
||||
Para entender melhor a como funciona a estrutura de requisição, você pode visitar a documentaçao oficial ou dar uma olhada no método "do ()" deste client.
|
||||
"""
|
||||
|
||||
ep: str = ""
|
||||
|
||||
APIProxyRequest = {
|
||||
"Name": None,
|
||||
"Method": None,
|
||||
"Url": None,
|
||||
"Header": None,
|
||||
"Body": None,
|
||||
"Readonly": None
|
||||
}
|
||||
|
||||
APIProxyResponse = {
|
||||
"Status": None,
|
||||
"StatusCode": None,
|
||||
"Header": None,
|
||||
"Body": None
|
||||
}
|
||||
|
||||
def __init__ (self):
|
||||
self.ep = os.environ.get("REPLAY_ADDR")
|
||||
|
||||
def __request_json_post__(self, path: str, object: dict):
|
||||
|
||||
"""
|
||||
## HTTP JSON POST
|
||||
---
|
||||
Este método é responsável por realizar requisições HTTP do tipo POST para objetos JSON.
|
||||
|
||||
Ele retorna o corpo de resposta da requisição, ou uma mensagem de erro, que indica qual foi a irregularidade ocorrida ao chamar a API.
|
||||
"""
|
||||
|
||||
url = self.ep + path
|
||||
print("Calling: " + url)
|
||||
|
||||
apikey = os.environ.get('REPLAY_APIKEY')
|
||||
headers = {"X-API-KEY": apikey}
|
||||
res = requests.post(url, json = object, headers = headers, verify = False)
|
||||
|
||||
if res.status_code >= 400:
|
||||
raise Exception(f"HTTP ERROR: {str(res.status_code)} - {res.text}")
|
||||
|
||||
|
||||
return json.loads(res.text)
|
||||
|
||||
|
||||
def do (self, request: dict):
|
||||
"""
|
||||
## API Proxy Do
|
||||
Faz o proxy da chamada remota e retorna qualquer que seja o resultado desta requisição.
|
||||
|
||||
---
|
||||
#### Parâmetros:
|
||||
- request: Estrutura APIProxyRequest definida nesta mesma classe. Instancie-a e altere os valores das chaves de acordo com sua necessidade, veja abaixo como:
|
||||
|
||||
{
|
||||
"Name": "Nome de template da chamada",
|
||||
|
||||
"Method": "Método de requisição (GET, POST, PUT, ...)",
|
||||
|
||||
"Url": "Url da API que se deseja chamar",
|
||||
|
||||
"Header": {
|
||||
"Chave da configuração de cabeçalho": "Valor associado",
|
||||
|
||||
...
|
||||
},
|
||||
|
||||
"Body": "Elementos pertencentes ao corpo da requisição",
|
||||
|
||||
"Readonly":
|
||||
|
||||
- True: Mesmo que seja encontrado um template correspondente ao valor de "Name" passado, as configurações desta estrutura prevalecerão na requisição.
|
||||
|
||||
- False: Caso um template seja encontrado em correspondência ao valor passado em "Name", as configurações do mesmo sobrescreverão as informações passadas nesta estrutura.
|
||||
}
|
||||
|
||||
---
|
||||
#### Retorna:
|
||||
-> Estrutura APIProxyResponse já definida nesta classe.
|
||||
"""
|
||||
|
||||
do_response = self.__request_json_post__ ("/ipc/apiproxy/do", request)
|
||||
|
||||
do_response["body"] = base64.b64decode(do_response["body"])
|
||||
do_response["body"] = str(do_response["body"], "utf-8")
|
||||
|
||||
if do_response["header"]["Content-Type"].find("json") != -1:
|
||||
do_response["body"] = json.loads(do_response["body"])
|
||||
|
||||
return do_response
|
|
@ -0,0 +1,14 @@
|
|||
Feature: The API Proxy client
|
||||
Scenario: A HTTP request with json body response
|
||||
Given a API Proxy client
|
||||
And an APIProxyRequest instance filled with the method GET for the API url: https://pokeapi.co/api/v2/pokemon/ditto
|
||||
When a request is made with the previous instance
|
||||
Then the body of this response must be a python dictionary
|
||||
And the pokemon name, contained in the response body, must be ditto
|
||||
|
||||
|
||||
Scenario: A HTTP request with text body response
|
||||
Given a API Proxy client
|
||||
And an APIProxyRequest instance filled with the method GET for the API url: https://www.slashdot.org
|
||||
When a request is made with the previous instance
|
||||
Then the response body content type must be string
|
|
@ -0,0 +1,39 @@
|
|||
from re import A
|
||||
from behave import *
|
||||
from cli import API_Proxy
|
||||
|
||||
# =========================== JSON RESPONSE BODY ===========================
|
||||
@given(u'a API Proxy client')
|
||||
def step_impl(context):
|
||||
context.client = API_Proxy ()
|
||||
|
||||
@given(u'an APIProxyRequest instance filled with the method GET for the API url: https://pokeapi.co/api/v2/pokemon/ditto')
|
||||
def step_impl(context):
|
||||
context.request = context.client.APIProxyRequest
|
||||
context.request["Method"] = "GET"
|
||||
context.request["Url"] = "https://pokeapi.co/api/v2/pokemon/ditto"
|
||||
|
||||
@when(u'a request is made with the previous instance')
|
||||
def step_impl(context):
|
||||
context.response = context.client.do (context.request)
|
||||
|
||||
@then(u'the body of this response must be a python dictionary')
|
||||
def step_impl(context):
|
||||
assert type (context.response["body"]) == dict, "Something went wrong calling the pokemon/ditto API."
|
||||
|
||||
@then(u'the pokemon name, contained in the response body, must be ditto')
|
||||
def step_impl(context):
|
||||
assert context.response["body"]["forms"][0]["name"] == "ditto", "This pokemon is not Ditto."
|
||||
|
||||
|
||||
|
||||
# =========================== TEXT RESPONSE BODY ===========================
|
||||
@given(u'an APIProxyRequest instance filled with the method GET for the API url: https://www.slashdot.org')
|
||||
def step_impl(context):
|
||||
context.request = context.client.APIProxyRequest
|
||||
context.request["Method"] = "GET"
|
||||
context.request["Url"] = "https://www.slashdot.org"
|
||||
|
||||
@then(u'the response body content type must be string')
|
||||
def step_impl(context):
|
||||
assert type (context.response["body"]) == str, "Something went wrong calling the slashdot API."
|
|
@ -16,7 +16,7 @@ class AutoHotKey:
|
|||
ep: str = ""
|
||||
|
||||
def __init__ (self):
|
||||
self.ep = "https://localhost:8443"
|
||||
self.ep = os.environ.get("REPLAY_ADDR")
|
||||
|
||||
def __request_raw_post__ (self, path: str, data: str = ""):
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ class AutoIt:
|
|||
ep: str = ""
|
||||
|
||||
def __init__ (self):
|
||||
self.ep = "https://localhost:8443"
|
||||
self.ep = os.environ.get("REPLAY_ADDR")
|
||||
|
||||
def __request_raw_post__ (self, path: str, data: str = ""):
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ class Chrome:
|
|||
ep: str = ""
|
||||
|
||||
def __init__(self):
|
||||
self.ep = "https://localhost:8443"
|
||||
self.ep = os.environ.get("REPLAY_ADDR")
|
||||
|
||||
def __request_get__(self, data: str):
|
||||
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
from datetime import datetime
|
||||
import json
|
||||
|
||||
import requests
|
||||
|
||||
class DataAPI:
|
||||
"""
|
||||
## Data API
|
||||
---
|
||||
Esta classe permite a execução de comandos básicos SQL para o banco de dados remoto do Replay.
|
||||
|
||||
Para que a classe funcione corretamente, é necessário que o usuário tenha acesso à chave da API do BD remoto. Devendo passá-la como parâmetro ao instanciar a classe DataAPI. Por exemplo:
|
||||
d_api = DataAPI ("ahsgcn21390-dsaf_dain2eq81288sad9")
|
||||
"""
|
||||
|
||||
ep: str = ""
|
||||
|
||||
def __init__ (self, api_key: str):
|
||||
self.ep = "https://dataapi.digitalcircle.com.br"
|
||||
self.api_key = api_key
|
||||
|
||||
def __request_json_post__ (self, object: dict):
|
||||
|
||||
"""
|
||||
## HTTP JSON POST
|
||||
---
|
||||
Este método é responsável por realizar requisições HTTP do tipo POST para objetos JSON.
|
||||
|
||||
Ele retorna o corpo de resposta da requisição, ou uma mensagem de erro, que indica qual foi a irregularidade ocorrida ao chamar a API.
|
||||
"""
|
||||
|
||||
url = self.ep + "/"
|
||||
print("Calling: " + url)
|
||||
|
||||
headers = {"X-API-KEY": self.api_key}
|
||||
res = requests.post(url, json = object, headers = headers, verify = False)
|
||||
|
||||
if res.status_code >= 400:
|
||||
raise Exception(f"HTTP ERROR: {str(res.status_code)} - {res.text}")
|
||||
if res.headers.get("Content-Type") != None and res.headers.get("Content-Type").find("json") != -1:
|
||||
return json.loads(res.text)
|
||||
else:
|
||||
return res.text
|
||||
|
||||
def do (self, dataAPI_request: dict):
|
||||
"""
|
||||
## DataAPI Do
|
||||
Este método é responsável pela execução dos comandos SQL no Banco de Dados remoto.
|
||||
|
||||
---
|
||||
#### Parâmetros de dataAPI_request:
|
||||
- Col: Nome da tabela SQL em que se quer realizar a operação (OBRIGATÓRIO)
|
||||
- Op: Operação que se quer desenvolver. São elas: "R", "C", "D", "U" (OBRIGATÓRIO)
|
||||
- R: Retrieve (Busca informações da coluna da tabela)
|
||||
- C: Create (Cria uma nova tabela)
|
||||
- D: Delete (Deleta uma tabela ou as colunas de uma tabela)
|
||||
- U: Update (Atualiza as informações de uma tabela)
|
||||
|
||||
- Q: Nome do atributo (coluna) que se quer consultar ou alterar na tabela SQL
|
||||
- Id: Identificador da instância (linha) da tabela que se quer realizar a operação
|
||||
- Data: Dados que se quer inserir na tabela
|
||||
|
||||
---
|
||||
#### Retorna:
|
||||
-> O retorno do comando feito, qualquer que seja ele.
|
||||
"""
|
||||
|
||||
return self.__request_json_post__(dataAPI_request)
|
||||
|
||||
def registrar_exec (self, register_table: str, check: bool):
|
||||
"""
|
||||
## Registrar Execução
|
||||
Esta função é utilizada para realizar um registro de execuções falhas e bem sucedidas de um robô. Tudo é feito diretamente na Base de Dados remota, eliminando a necessidade de planilhas Excel locais.
|
||||
|
||||
---
|
||||
#### Parâmetros:
|
||||
- register_table: Tabela utilizada para os registros de execução. Para começos de projeto, procure criar uma nova tabela, cheque se ela já existe utilizando a operação de Retrieve pelo método Do.
|
||||
- check: Assume dois valores dependendo do sucesso da execução do robô: True ou False.
|
||||
- True: Execução obteve sucesso.
|
||||
- False: Execução falhou em algum ponto.
|
||||
|
||||
---
|
||||
#### Retorna:
|
||||
---
|
||||
"""
|
||||
|
||||
today_date = datetime.now().isoformat()[:10]
|
||||
|
||||
table_check = self.do({
|
||||
"Col": register_table,
|
||||
"Op": "R",
|
||||
"Q": f"@[?date=='{today_date}']"
|
||||
})
|
||||
|
||||
if len(table_check["data"]) > 0:
|
||||
data = table_check["data"][0]
|
||||
id = str(int(data["ID"]))
|
||||
|
||||
if check:
|
||||
success = int(data["exec"]) + 1
|
||||
|
||||
try:
|
||||
self.do({
|
||||
"Col": register_table,
|
||||
"Op": "U",
|
||||
"Id": id,
|
||||
"Data": {
|
||||
"exec": success
|
||||
}
|
||||
})
|
||||
except:
|
||||
return "Algo falhou ao registrar a execução"
|
||||
|
||||
else:
|
||||
fail = int(data["err"]) + 1
|
||||
|
||||
try:
|
||||
self.do({
|
||||
"Col": register_table,
|
||||
"Op": "U",
|
||||
"Id": id,
|
||||
"Data": {
|
||||
"err": fail
|
||||
}
|
||||
})
|
||||
except:
|
||||
return "Algo falhou ao registrar a execução"
|
||||
|
||||
else:
|
||||
if check:
|
||||
success = 1
|
||||
fail = 0
|
||||
else:
|
||||
success = 0
|
||||
fail = 1
|
||||
|
||||
try:
|
||||
self.do({
|
||||
"Col": register_table,
|
||||
"Op": "C",
|
||||
"Data": {
|
||||
"date": today_date,
|
||||
"exec": success,
|
||||
"err": fail,
|
||||
}
|
||||
})
|
||||
except:
|
||||
return "Algo falhou ao registrar a execução"
|
|
@ -0,0 +1,13 @@
|
|||
Feature: The Data API Client
|
||||
Scenario: Testing the data_API.do() method
|
||||
Given a data_API client
|
||||
When a new table is created with the value "Bond" for the query "the_name_is"
|
||||
Then the value retrieved from the new table associated with the query "the_name_is" must be "Bond"
|
||||
|
||||
|
||||
Scenario: Testing the data_API.registrar_exec method
|
||||
Given a data_API client
|
||||
When the registrar_exec method is called with True for check
|
||||
And the registrar_exec method is called with False for check
|
||||
And data is retrieved from the table
|
||||
Then there must be at least 1 register for "exec" and "err" today
|
|
@ -0,0 +1,53 @@
|
|||
from behave import *
|
||||
from cli import *
|
||||
|
||||
# ============================= DATA_API DO =============================
|
||||
@given(u'a data_API client')
|
||||
def step_impl(context):
|
||||
context.client = DataAPI ("Insira aqui a chave de API. Você pode obtê-la pedindo ao fornecedor deste client.")
|
||||
|
||||
@when(u'a new table is created with the value "Bond" for the query "the_name_is"')
|
||||
def step_impl(context):
|
||||
context.client.do ({
|
||||
"Col": "newTestTable",
|
||||
"Op": "C",
|
||||
"Data": {
|
||||
"the_name_is": "Bond",
|
||||
"James": "Bond"
|
||||
}
|
||||
})
|
||||
|
||||
@then(u'the value retrieved from the new table associated with the query "the_name_is" must be "Bond"')
|
||||
def step_impl(context):
|
||||
context.retrieved_data = context.client.do({
|
||||
"Col": "newTestTable",
|
||||
"Op": "R"
|
||||
})["data"][0]
|
||||
|
||||
context.query_value = context.retrieved_data["the_name_is"]
|
||||
|
||||
assert context.query_value == "Bond", "Something went wrong with the method Do"
|
||||
|
||||
|
||||
# ============================= DATA_API REGISTRAR_EXEC =============================
|
||||
@when(u'the registrar_exec method is called with True for check')
|
||||
def step_impl(context):
|
||||
context.client.registrar_exec("anotherNewTestTable", True)
|
||||
|
||||
@when(u'the registrar_exec method is called with False for check')
|
||||
def step_impl(context):
|
||||
context.client.registrar_exec("anotherNewTestTable", False)
|
||||
|
||||
@when(u'data is retrieved from the table')
|
||||
def step_impl(context):
|
||||
today_date = datetime.now().isoformat()[:10]
|
||||
|
||||
context.retrieved_data = context.client.do({
|
||||
"Col": "anotherNewTestTable",
|
||||
"Op": "R",
|
||||
"Q": f"@[?date=='{today_date}']"
|
||||
})["data"][0]
|
||||
|
||||
@then(u'there must be at least 1 register for "exec" and "err" today')
|
||||
def step_impl(context):
|
||||
assert context.retrieved_data["exec"] > 0 and context.retrieved_data["err"] > 0, "Something went wrong with the method registrar_exec"
|
|
@ -13,7 +13,7 @@ class Excel:
|
|||
ep: str = ""
|
||||
|
||||
def __init__ (self):
|
||||
self.ep = "https://localhost:8443"
|
||||
self.ep = os.environ.get("REPLAY_ADDR")
|
||||
|
||||
def __request_json_post__ (self, path: str, object: dict):
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ class Ocr:
|
|||
ep: str = ""
|
||||
|
||||
def __init__ (self):
|
||||
self.ep = "https://localhost:8443"
|
||||
self.ep = os.environ.get("REPLAY_ADDR")
|
||||
|
||||
def __request_json_post__ (self, path: str, object: dict):
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ class Replay:
|
|||
ep: str = ""
|
||||
|
||||
def __init__ (self):
|
||||
self.ep = "https://localhost:8443"
|
||||
self.ep = os.environ.get("REPLAY_ADDR")
|
||||
|
||||
def __request_get__ (self, data: str):
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ class Wingui:
|
|||
ep: str = ""
|
||||
|
||||
def __init__(self):
|
||||
self.ep = "https://localhost:8443"
|
||||
self.ep = os.environ.get("REPLAY_ADDR")
|
||||
|
||||
def __requestget__(self, data: str):
|
||||
|
||||
|
|
|
@ -0,0 +1,205 @@
|
|||
from time import sleep
|
||||
from behave import *
|
||||
from cli import Wingui
|
||||
|
||||
# =========================== Clip_read & Clip_write ===========================
|
||||
@given(u'a winGUI client')
|
||||
def step_impl(context):
|
||||
context.client = Wingui ()
|
||||
|
||||
@when(u'the clip_write method is called to store the text "There is a light that never goes out"')
|
||||
def step_impl(context):
|
||||
context.client.clip_write("There is a light that never goes out")
|
||||
|
||||
@then(u'when the clip_read method is called, it must return the same text')
|
||||
def step_impl(context):
|
||||
assert context.client.clip_read() == "There is a light that never goes out", "Something went wrong with the clipboard."
|
||||
|
||||
|
||||
|
||||
# =========================== Screen_scale & Screen_size ===========================
|
||||
@when(u'the screen_scale method is called')
|
||||
def step_impl(context):
|
||||
context.scale = context.client.screen_scale()
|
||||
|
||||
@when(u'the screen_size method is also called')
|
||||
def step_impl(context):
|
||||
context.size = context.client.screen_size()
|
||||
|
||||
@then(u'the returns of both must be equal')
|
||||
def step_impl(context):
|
||||
assert context.scale == context.size, "Something went wrong while getting the screen dimensions."
|
||||
|
||||
# Please note that most of the other screen methods use image recognition and, because of that, it is not possible to test them on every computer, since there is no way to know wich images are being displayed on the screen.
|
||||
# Also, the other methods wich do not use image recognition are simply too difficult to test.
|
||||
|
||||
|
||||
|
||||
# =========================== Proc_exec & Proc_all ===========================
|
||||
@when(u'the proc_exec method is called with "mspaint"')
|
||||
def step_impl(context):
|
||||
context.client.proc_exec("mspaint")
|
||||
|
||||
@when(u'the proc_all method is called')
|
||||
def step_impl(context):
|
||||
context.procs = context.client.proc_all()
|
||||
|
||||
@then(u'there must be a process with the name "mspaint.exe" inside the list')
|
||||
def step_impl(context):
|
||||
for proc in context.procs:
|
||||
if "mspaint.exe" in proc["Name"]:
|
||||
context.client.proc_kill(proc["Pid"])
|
||||
assert True
|
||||
return
|
||||
|
||||
assert False, "Something went wrong executing Microsoft Paint."
|
||||
|
||||
|
||||
|
||||
# =========================== Proc_name ===========================
|
||||
@given(u'the initialization of Microsoft Paint')
|
||||
def step_impl(context):
|
||||
context.client.proc_exec("mspaint")
|
||||
|
||||
@given(u'the "Name" and "Pid" infos about this process')
|
||||
def step_impl(context):
|
||||
context.procs = context.client.proc_all()
|
||||
|
||||
for proc in context.procs:
|
||||
if "mspaint.exe" in proc["Name"]:
|
||||
context.proc_name = proc["Name"]
|
||||
context.proc_pid = proc["Pid"]
|
||||
|
||||
@when(u'the proc_name method is called with the "Pid" collected')
|
||||
def step_impl(context):
|
||||
context.name_return = context.client.proc_name(context.proc_pid)
|
||||
|
||||
@then(u'the return must be te same as the "Name" collected')
|
||||
def step_impl(context):
|
||||
assert context.name_return == context.proc_name, "Something went wrong with some of the proc methods."
|
||||
|
||||
context.client.proc_kill(context.proc_pid)
|
||||
|
||||
|
||||
|
||||
# =========================== Proc_pids ===========================
|
||||
@when(u'the proc_pids is called')
|
||||
def step_impl(context):
|
||||
context.all_pids = context.client.proc_pids()
|
||||
|
||||
@then(u'the "Pid" info collected must be inside the array returned')
|
||||
def step_impl(context):
|
||||
assert context.proc_pid in context.all_pids, "Something went wrong catching all of the pids."
|
||||
|
||||
context.client.proc_kill(context.proc_pid)
|
||||
|
||||
|
||||
|
||||
# =========================== Window_list and Window_hwnd ===========================
|
||||
@when(u'the window_hwnd method is called with the parameter "mspaint.exe"')
|
||||
def step_impl(context):
|
||||
sleep(0.5)
|
||||
context.paint_hwnd = context.client.window_hwnd("mspaint.exe")
|
||||
|
||||
@when(u'the window_list method is called')
|
||||
def step_impl(context):
|
||||
context.windows = context.client.window_list()
|
||||
|
||||
@then(u'the return of window_hwnd must be the value of one of the "Hwnd" keys returned in window_list')
|
||||
def step_impl(context):
|
||||
for window in context.windows:
|
||||
if context.paint_hwnd[0] == window["Hwnd"]:
|
||||
assert True
|
||||
sleep(0.5)
|
||||
context.client.proc_kill(context.proc_pid)
|
||||
|
||||
return
|
||||
|
||||
assert False, "Something went wrong catching the Paint window."
|
||||
|
||||
|
||||
|
||||
# # =================== Window_activate, Window_activetitle and Window_activehwnd ===================
|
||||
# @given(u'the window hwnd obtained from the "Name" info')
|
||||
# def step_impl(context):
|
||||
# context.paint_hwnd = context.client.window_hwnd(context.proc_name)
|
||||
|
||||
# @when(u'the window_activate method is called with the Paint Hwnd obtained')
|
||||
# def step_impl(context):
|
||||
# sleep(0.5)
|
||||
# context.client.window_activate (context.paint_hwnd[0])
|
||||
# sleep(0.5)
|
||||
|
||||
# @when(u'the methods window_activetitle and window_activehwnd are called')
|
||||
# def step_impl(context):
|
||||
# context.paint_title = context.client.window_activetitle()
|
||||
# context.paint_win_hwnd = context.client.window_activehwnd()
|
||||
|
||||
# context.client.window_close(context.paint_hwnd[0])
|
||||
|
||||
# @then(u'the returned value from window_activetitle must contain the substring "Paint"')
|
||||
# def step_impl(context):
|
||||
# assert "Paint" in context.paint_title, f"The active title obtained is not from Paint.\nActive Title: {context.paint_title}"
|
||||
|
||||
# for window in context.client.window_list():
|
||||
# if context.paint_hwnd == window["Hwnd"]:
|
||||
# print(f"""
|
||||
|
||||
# ---------------------------
|
||||
# Hwnd associated title: {window["Title"]}
|
||||
# ---------------------------
|
||||
|
||||
# """)
|
||||
|
||||
# @then(u'the returned value from window_activehwnd must be equal to the hwnd previously obtained')
|
||||
# def step_impl(context):
|
||||
# assert context.paint_win_hwnd == context.paint_hwnd, "The Hwnd obtained is not from Paint"
|
||||
|
||||
|
||||
|
||||
# ======================================== Display methods ========================================
|
||||
@given(u'the current resolution of the display')
|
||||
def step_impl(context):
|
||||
context.sys_info = context.client.display_res()
|
||||
|
||||
context.prev_width = context.sys_info["DmPelsWidth"]
|
||||
context.prev_height = context.sys_info["DmPelsHeight"]
|
||||
|
||||
@when(u'the display_setres method is called to set the display resolution in 800x600')
|
||||
def step_impl(context):
|
||||
context.new_sys_info = context.sys_info
|
||||
context.new_sys_info["DmPelsWidth"] = 800
|
||||
context.new_sys_info["DmPelsHeight"] = 600
|
||||
|
||||
try:
|
||||
context.client.display_setres(context.new_sys_info)
|
||||
sleep(5)
|
||||
except:
|
||||
raise "Your system configuration does not support 800x600 resolution"
|
||||
|
||||
@then(u'the new display resolution must be 800x600')
|
||||
def step_impl(context):
|
||||
context.new_sys_info = context.client.display_res()
|
||||
|
||||
assert context.new_sys_info["DmPelsWidth"] == 800 and \
|
||||
context.new_sys_info["DmPelsHeight"] == 600, \
|
||||
\
|
||||
"Something went wrong setting your system resolution to 800x600.\n\nCheck if this resolution is available in your configurations, if so, please disregard this message."
|
||||
|
||||
@then(u'the methods must be able to set your resolution to the previous one')
|
||||
def step_impl(context):
|
||||
context.new_sys_info["DmPelsWidth"] = context.prev_width
|
||||
context.new_sys_info["DmPelsHeight"] = context.prev_height
|
||||
|
||||
try:
|
||||
context.client.display_setres(context.new_sys_info)
|
||||
sleep(5)
|
||||
except:
|
||||
raise "Error!"
|
||||
|
||||
context.curr_sys_info = context.client.display_res()
|
||||
|
||||
assert context.curr_sys_info["DmPelsWidth"] == context.prev_width and \
|
||||
context.curr_sys_info["DmPelsHeight"] == context.prev_height, \
|
||||
\
|
||||
"Sorry for the inconvenience, but something went wrong resetting your resolution to the previous one.\n\nPlease go to your system configurations to do this step manually."
|
|
@ -0,0 +1,73 @@
|
|||
Feature: The winGUI API client
|
||||
|
||||
Scenario: Testing the clip_read and clip_write methods
|
||||
Given a winGUI client
|
||||
When the clip_write method is called to store the text "There is a light that never goes out"
|
||||
Then when the clip_read method is called, it must return the same text
|
||||
|
||||
|
||||
Scenario: Testing the screen_scale and screen_size methods
|
||||
Given a winGUI client
|
||||
When the screen_scale method is called
|
||||
And the screen_size method is also called
|
||||
Then the returns of both must be equal
|
||||
|
||||
# Please note that most of the other screen methods use image recognition and, because of that, it is not possible to test them on every computer, since there is no way to know wich images are being displayed on the screen.
|
||||
# Also, the other methods wich do not use image recognition are simply too difficult to test.
|
||||
|
||||
|
||||
Scenario: Testing proc_exec and proc_all methods
|
||||
Given a winGUI client
|
||||
When the proc_exec method is called with "mspaint"
|
||||
And the proc_all method is called
|
||||
Then there must be a process with the name "mspaint.exe" inside the list
|
||||
|
||||
|
||||
Scenario: Testing proc_name method
|
||||
Given a winGUI client
|
||||
And the initialization of Microsoft Paint
|
||||
And the "Name" and "Pid" infos about this process
|
||||
When the proc_name method is called with the "Pid" collected
|
||||
Then the return must be te same as the "Name" collected
|
||||
|
||||
|
||||
Scenario: Testing proc_pids method
|
||||
Given a winGUI client
|
||||
And the initialization of Microsoft Paint
|
||||
And the "Name" and "Pid" infos about this process
|
||||
When the proc_pids is called
|
||||
Then the "Pid" info collected must be inside the array returned
|
||||
|
||||
|
||||
Scenario: Testing the window_list and window_hwnd methods
|
||||
Given a winGUI client
|
||||
And the initialization of Microsoft Paint
|
||||
And the "Name" and "Pid" infos about this process
|
||||
|
||||
When the window_hwnd method is called with the parameter "mspaint.exe"
|
||||
And the window_list method is called
|
||||
|
||||
Then the return of window_hwnd must be the value of one of the "Hwnd" keys returned in window_list
|
||||
|
||||
|
||||
# Scenario: Testing window_activate, window_activetitle and window_activehwnd
|
||||
# Given a winGUI client
|
||||
# And the initialization of Microsoft Paint
|
||||
# And the "Name" and "Pid" infos about this process
|
||||
# And the window hwnd obtained from the "Name" info
|
||||
|
||||
# When the window_activate method is called with the Paint Hwnd obtained
|
||||
# And the methods window_activetitle and window_activehwnd are called
|
||||
|
||||
# Then the returned value from window_activetitle must contain the substring "Paint"
|
||||
# And the returned value from window_activehwnd must be equal to the hwnd previously obtained
|
||||
|
||||
|
||||
Scenario: Testing the display methods
|
||||
Given a winGUI client
|
||||
And the current resolution of the display
|
||||
|
||||
When the display_setres method is called to set the display resolution in 800x600
|
||||
|
||||
Then the new display resolution must be 800x600
|
||||
And the methods must be able to set your resolution to the previous one
|
Loading…
Reference in New Issue