@diegosouzacdv/jev-browser-mcp 0.7.0 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +359 -71
- package/config/ui-testing.json +31 -10
- package/docs/jev-browser-mcp.md +359 -71
- package/mcp_servers/jev-browser-npm/bin/jev-browser-mcp.cjs +4 -1
- package/mcp_servers/jev-browser-npm/src/browser-flow-runs.mjs +57 -0
- package/mcp_servers/jev-browser-npm/src/config.mjs +136 -37
- package/mcp_servers/jev-browser-npm/src/environment-profiles.mjs +241 -0
- package/mcp_servers/jev-browser-npm/src/flow.mjs +1159 -292
- package/mcp_servers/jev-browser-npm/src/server.mjs +281 -126
- package/mcp_servers/jev-browser-npm/src/test-integrations.mjs +655 -0
- package/mcp_servers/jev-browser-npm/src/test-suites.mjs +438 -0
- package/mcp_servers/jev-browser-npm/src/upload-staging.mjs +80 -0
- package/package.json +7 -1
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ versão em produção, use o número explícito no argumento do pacote:
|
|
|
17
17
|
"mcpServers": {
|
|
18
18
|
"jev-browser": {
|
|
19
19
|
"command": "npx",
|
|
20
|
-
"args": ["--yes", "@diegosouzacdv/jev-browser-mcp@0.7.
|
|
20
|
+
"args": ["--yes", "@diegosouzacdv/jev-browser-mcp@0.7.2"],
|
|
21
21
|
"env": {
|
|
22
22
|
"OPENROUTER_API_KEY": "${OPENROUTER_API_KEY}",
|
|
23
23
|
"JEV_BROWSER_MODE": "computer"
|
|
@@ -32,7 +32,7 @@ um secret manager ou pelo ambiente do processo; não grave a chave no arquivo
|
|
|
32
32
|
de configuração. Para instalar no projeto Node do próprio harness:
|
|
33
33
|
|
|
34
34
|
```sh
|
|
35
|
-
npm install @diegosouzacdv/jev-browser-mcp@0.7.
|
|
35
|
+
npm install @diegosouzacdv/jev-browser-mcp@0.7.2
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
Se o harness executa o MCP repetidamente nesta máquina, instale uma versão
|
|
@@ -40,7 +40,7 @@ fixa globalmente para evitar a resolução e o download feitos pelo `npx` em cad
|
|
|
40
40
|
inicialização:
|
|
41
41
|
|
|
42
42
|
```sh
|
|
43
|
-
npm install --global @diegosouzacdv/jev-browser-mcp@0.7.
|
|
43
|
+
npm install --global @diegosouzacdv/jev-browser-mcp@0.7.2
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
Depois configure o servidor MCP com `command: "jev-browser-mcp"` e `args: []`.
|
|
@@ -48,8 +48,8 @@ Para atualizar, rode `npm install --global
|
|
|
48
48
|
@diegosouzacdv/jev-browser-mcp@<versão>` e reinicie o processo do harness.
|
|
49
49
|
|
|
50
50
|
O padrão `computer` exige Chrome ou Edge instalado. Se optar por `harness`,
|
|
51
|
-
configure `JEV_BROWSER_MODE=harness` antes de instalar o navegador gerenciado
|
|
52
|
-
pelo Playwright com `npx --yes @diegosouzacdv/jev-browser-mcp@0.7.
|
|
51
|
+
configure `JEV_BROWSER_MODE=harness` antes de instalar o navegador gerenciado
|
|
52
|
+
pelo Playwright com `npx --yes @diegosouzacdv/jev-browser-mcp@0.7.2 --install-browser`.
|
|
53
53
|
|
|
54
54
|
O padrão é `computer`: o pacote abre o Chrome/Edge instalado e usa um perfil
|
|
55
55
|
persistente exclusivo por processo MCP em `browser.computer_user_data_dir`. O
|
|
@@ -85,22 +85,49 @@ publicada.
|
|
|
85
85
|
|
|
86
86
|
### Contrato do pacote
|
|
87
87
|
|
|
88
|
-
O executável oferece `browser_health`, `describe_actions`, `choose_next_action
|
|
89
|
-
e `
|
|
90
|
-
essa sessão entre chamadas. `browser_health` informa versão, sessão e
|
|
88
|
+
O executável oferece `browser_health`, `describe_actions`, `choose_next_action`,
|
|
89
|
+
`run_browser_flow`, `run_test_suite` e `get_browser_flow_result`, mantém uma sessão do browser
|
|
90
|
+
por processo e reutiliza essa sessão entre chamadas. `browser_health` informa versão, sessão e
|
|
91
91
|
capacidades; `describe_actions` publica o schema atual das ações, opções,
|
|
92
|
-
aliases
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
92
|
+
aliases, placeholders, campos obrigatórios de `flow`/plano e requisitos
|
|
93
|
+
condicionais por ação. `run_browser_flow` agrega campos obrigatórios ausentes
|
|
94
|
+
em todos os planos e etapas antes de abrir o navegador. Consulte essas ferramentas
|
|
95
|
+
antes de construir um plano para evitar nomes de campos desatualizados. O plano
|
|
96
|
+
passado ao Jev continua declarativo: clique, preenchimento, seleção nativa,
|
|
97
|
+
hover, espera, teclas aprovadas, asserções por elemento, upload restrito ao
|
|
98
|
+
staging da sessão ou a uma raiz local configurada e reações idempotentes a um
|
|
99
|
+
comentário único. Também
|
|
100
|
+
aceita um nome de iframe para as ações que ocorrem dentro dele. Não aceita
|
|
101
|
+
JavaScript enviado pelo harness nem coordenadas. Além de papel/nome acessível,
|
|
99
102
|
aceita `label`, `placeholder`, `title`, `text`, `test_id` e `selector`; CSS/XPath
|
|
100
103
|
são o último recurso e geram um aviso no resultado. Ele usa a
|
|
101
|
-
biblioteca Playwright diretamente, sem iniciar um segundo servidor MCP do
|
|
102
|
-
Playwright. O transporte MCP usa `stdio`; toda saída de diagnóstico vai para
|
|
103
|
-
`stderr` para não misturar com JSON-RPC.
|
|
104
|
+
biblioteca Playwright diretamente, sem iniciar um segundo servidor MCP do
|
|
105
|
+
Playwright. O transporte MCP usa `stdio`; toda saída de diagnóstico vai para
|
|
106
|
+
`stderr` para não misturar com JSON-RPC.
|
|
107
|
+
|
|
108
|
+
### Validar o MCP com Chromium e uma aplicação sintética
|
|
109
|
+
|
|
110
|
+
O teste ponta a ponta do pacote inicia o servidor MCP real por `stdio`, abre o
|
|
111
|
+
Chromium controlado pelo Playwright e exercita uma aplicação HTTP local
|
|
112
|
+
descartável. Ele cobre descoberta das ferramentas, busca com resposta 200,
|
|
113
|
+
erro 503 com corpo, upload de fixture Unicode seguido de download e comparação
|
|
114
|
+
de conteúdo, além de execução em segundo plano e relatório de suíte. Não acessa
|
|
115
|
+
SAFI, redes externas, bancos ou serviços remotos.
|
|
116
|
+
|
|
117
|
+
No checkout do repositório, instale as dependências e o navegador uma vez e
|
|
118
|
+
execute somente esse cenário:
|
|
119
|
+
|
|
120
|
+
```sh
|
|
121
|
+
npm ci
|
|
122
|
+
node mcp_servers/jev-browser-npm/bin/jev-browser-mcp.cjs --install-browser
|
|
123
|
+
node --test mcp_servers/jev-browser-npm/tests/stdio.test.mjs
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
O teste cria e remove sua aplicação e seus arquivos temporários. Para validar
|
|
127
|
+
Oracle, PostgreSQL ou servidores FTP/FTPS/SFTP, configure serviços de teste
|
|
128
|
+
isolados e credenciais pelo ambiente e use os perfis explicitamente descritos
|
|
129
|
+
em “Perfis e integrações de teste”; o cenário sintético não representa essas
|
|
130
|
+
integrações reais.
|
|
104
131
|
|
|
105
132
|
O modo `computer` grava cookies no perfil exclusivo configurado, e conteúdo da
|
|
106
133
|
página pode conter instruções maliciosas. O Jev recebe a captura acessível com
|
|
@@ -174,18 +201,39 @@ Cada plano pode usar:
|
|
|
174
201
|
- `assert_network` valida resposta HTTP observada (inclusive sucesso 2xx ou erro
|
|
175
202
|
esperado); `wait_for_request` aguarda uma resposta usando `*` como curinga na
|
|
176
203
|
URL e filtros opcionais de método/status; `assert_ws` confere texto, pares
|
|
177
|
-
JSON esperados ou código de fechamento de WebSocket
|
|
204
|
+
JSON esperados ou código de fechamento de WebSocket. `wait_for_request`
|
|
205
|
+
consulta o histórico desde o começo da chamada, inclusive requisições feitas
|
|
206
|
+
durante a navegação inicial e dentro de iframes; URLs cobertas por uma
|
|
207
|
+
asserção ficam retidas mesmo quando a SPA excede o buffer circular;
|
|
178
208
|
- `evaluate` lê somente caminhos de propriedades como `navigator.mediaDevices`,
|
|
179
209
|
`document.readyState` ou `location.pathname`. Não aceita código, chamadas de
|
|
180
210
|
função, armazenamento local ou propriedades de credenciais. Strings e números
|
|
181
211
|
voltam diretamente; objetos e arrays retornam somente tipo, chaves e tamanho,
|
|
182
212
|
sem despejar seus valores;
|
|
213
|
+
- `http_request` executa GET/HEAD e, com perfil DEV/HML e autorização explícita,
|
|
214
|
+
também POST/PUT/PATCH/DELETE com a sessão da página; aceita JSON ou multipart,
|
|
215
|
+
limita a resposta e pode extrair campos escalares para variáveis do fluxo.
|
|
216
|
+
`inspect_cookies`
|
|
217
|
+
retorna apenas metadados e valores redigidos; `read_angular_state` devolve o
|
|
218
|
+
nome do estado e nomes dos parâmetros, sem valores. Inspeções continuam
|
|
219
|
+
exigindo `local_only: true` e página em loopback. `http_request` exige
|
|
220
|
+
`local_only` ou um perfil, fica restrito à mesma origem, não segue
|
|
221
|
+
redirecionamentos e não inclui o corpo sem `include_body: true`;
|
|
222
|
+
- `frame: "first"` seleciona o primeiro iframe; `frame: {"url_contains":"..."}`
|
|
223
|
+
localiza um iframe pela URL. Uma string diferente continua buscando o nome ou
|
|
224
|
+
título exato do frame;
|
|
225
|
+
- `navigate_menu` aceita `path` para menus acessíveis ou `screen` para procurar
|
|
226
|
+
código/nome pela tela Acesso Rápido do SAFI. O segundo caminho usa a interface
|
|
227
|
+
do SAFI e preserva as verificações de acesso do próprio aplicativo;
|
|
183
228
|
- `new_tab`, `switch_tab` e `new_context` abrem/selecionam abas e criam contexto
|
|
184
229
|
separado dentro do fluxo; `target_page: "popup"` mantém popups abertos para
|
|
185
230
|
passos posteriores;
|
|
186
231
|
- `if_visible` em um clique torna a ação condicional e
|
|
187
232
|
`when: {"visible":"..."}` em cada plano limita as opções do Jev às que
|
|
188
233
|
correspondem à tela atual;
|
|
234
|
+
- `near: {"text":"..."}` com `role` e `name` procura o controle com esse nome
|
|
235
|
+
entre os elementos posteriores à âncora; o nome pedido não é descartado nem
|
|
236
|
+
substituído pelo primeiro botão/link seguinte;
|
|
189
237
|
- `fill` é alias de `type`, `press_key` de `press`, `duration_ms` de `wait.ms` e
|
|
190
238
|
`value` de campos de texto. `timeout_ms` funciona por etapa. Placeholders usam
|
|
191
239
|
`{nome}`; referências desconhecidas e `{{nome}}` são recusadas antes da
|
|
@@ -199,11 +247,18 @@ Cada plano pode usar:
|
|
|
199
247
|
- `clear_storage` limpa cookies, local/session storage, IndexedDB, Cache Storage
|
|
200
248
|
e service workers do contexto atual. Como opção de fluxo,
|
|
201
249
|
`options.clear_storage: true` também recarrega a página antes do snapshot inicial;
|
|
202
|
-
- `assert_text`, `assert_value`, `
|
|
203
|
-
`assert_enabled`; `
|
|
204
|
-
|
|
250
|
+
- `assert_text`, `assert_value`, `assert_attribute`, `assert_visible`,
|
|
251
|
+
`assert_hidden` e `assert_enabled`; `assert_attribute` compara um atributo
|
|
252
|
+
por igualdade ou substring e não inclui o valor observado no resultado;
|
|
253
|
+
`assert_text` pode receber apenas `role` quando a região, como `alert`, não tem
|
|
254
|
+
nome acessível;
|
|
205
255
|
- `upload_file` para input rotulado, botão que abre o seletor de arquivo ou
|
|
206
256
|
dropzone;
|
|
257
|
+
- `generate_fixture`, `assert_download`, `assert_db`, `assert_log`,
|
|
258
|
+
`start_email_capture`, `assert_email`, `assert_remote_file`,
|
|
259
|
+
`delete_remote_file` e `run_hook` cobrem dados e serviços externos de teste;
|
|
260
|
+
os limites, pré-requisitos e regras por ambiente estão na seção
|
|
261
|
+
[Perfis e integrações de teste](#perfis-e-integrações-de-teste);
|
|
207
262
|
- `target_page: "popup"` para continuar no popup aberto com `expect_popup: true`;
|
|
208
263
|
locators semânticos também atravessam open Shadow DOM. Shadow DOM fechado não
|
|
209
264
|
é acessível ao Playwright;
|
|
@@ -222,7 +277,10 @@ As proteções e evidências por etapa usam estes campos:
|
|
|
222
277
|
- `confirm_modal` combina o clique no gatilho, a conferência do texto e o clique
|
|
223
278
|
afirmativo em uma única etapa protegida. Também aceita os aliases
|
|
224
279
|
`trigger`/`confirm`, por exemplo
|
|
225
|
-
`{"action":"confirm_modal","trigger":"Salvar","expected_text":"Confirma a alteração?","confirm":"OK"}
|
|
280
|
+
`{"action":"confirm_modal","trigger":"Salvar","trigger_match":"contains","expected_text":"Confirma a alteração?","confirm":"OK"}`.
|
|
281
|
+
O nome do gatilho é exato por padrão; `trigger_match` também aceita `exact` e
|
|
282
|
+
`regex`. O texto esperado é conferido antes de clicar no botão afirmativo. O
|
|
283
|
+
clique no gatilho ainda respeita a autorização de mutação;
|
|
226
284
|
- `mutating: true` marca etapas que gravam dados ou disparam efeitos externos.
|
|
227
285
|
O MCP também classifica botões conhecidos como `Salvar`, `Emitir`, `Cancelar`
|
|
228
286
|
ou `Sim` pelo nome e pelo controle resolvido, inclusive quando o plano usa um
|
|
@@ -250,10 +308,19 @@ booleanos. Use `{pedido}` em `flow`, `expected_outcome` e nos campos textuais do
|
|
|
250
308
|
plano para reutilizar um valor sem editar o roteiro em vários lugares. A ação
|
|
251
309
|
`extract` lê `text` (padrão), `value` ou `attribute` de um elemento e salva o
|
|
252
310
|
resultado na variável indicada por `as`; etapas seguintes podem usar
|
|
253
|
-
`{documento}`. O valor extraído é tratado como sensível e fica oculto no
|
|
254
|
-
resultado por padrão; use `sensitive: false` só quando for apropriado exibi-lo.
|
|
255
|
-
|
|
256
|
-
|
|
311
|
+
`{documento}`. O valor extraído é tratado como sensível e fica oculto no
|
|
312
|
+
resultado por padrão; use `sensitive: false` só quando for apropriado exibi-lo.
|
|
313
|
+
Valores que correspondem a segredos já detectados continuam redigidos. Para
|
|
314
|
+
provar que um atributo corresponde a um valor sem devolvê-lo ao harness, use
|
|
315
|
+
`assert_attribute` com `match: "exact"` (padrão) ou `match: "contains"`.
|
|
316
|
+
Por exemplo, para validar o caminho de um documento em um iframe:
|
|
317
|
+
|
|
318
|
+
```json
|
|
319
|
+
{"action":"assert_attribute","selector":"iframe#documento","attribute":"src","expected":"/documento.pdf","match":"contains"}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
`resolved_target.match_strategy` informa quando um rótulo foi
|
|
323
|
+
associado por proximidade (`label-proximity`) em vez de um `label[for]` direto.
|
|
257
324
|
|
|
258
325
|
A ação `assert_network` verifica respostas observadas depois da etapa anterior,
|
|
259
326
|
incluindo respostas 2xx ou erros esperados como 404. Exemplo:
|
|
@@ -271,11 +338,26 @@ incluindo respostas 2xx ou erros esperados como 404. Exemplo:
|
|
|
271
338
|
Essa asserção aparece na evidência como `response_status`, separado do campo
|
|
272
339
|
`status` da etapa (`passed` ou `failed`). `message_contains` lê somente resposta
|
|
273
340
|
da mesma origem e respeita o limite configurado para captura de corpos.
|
|
274
|
-
`assert_network
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
341
|
+
`assert_network` consulta respostas desde o marcador da etapa e usa a resposta
|
|
342
|
+
da navegação inicial como fallback quando nenhuma resposta posterior corresponde.
|
|
343
|
+
`wait_for_request` e `expected_outcome.request` consultam desde o início do fluxo.
|
|
344
|
+
O MCP arma observadores de `wait_for_request` antes dos passos quando o padrão
|
|
345
|
+
pode ser resolvido; se depender de variável extraída, arma assim que a variável
|
|
346
|
+
estiver disponível. A observação retém a resposta mesmo que ela termine durante
|
|
347
|
+
um clique ou que tráfego posterior ultrapasse o buffer circular. `assert_network`
|
|
348
|
+
mantém respostas correspondentes no histórico limitado por
|
|
349
|
+
`jev_browser_mcp.browser.max_network_history_events`. A captura de página também
|
|
350
|
+
observa requisições de iframes.
|
|
351
|
+
Um único plano `fast_path` composto apenas por `assert_network` e
|
|
352
|
+
`wait_for_request` não espera um snapshot visual, então endpoints que respondem
|
|
353
|
+
sem HTML também podem ser verificados. `navigation_http_status` registra um
|
|
354
|
+
status HTTP de erro recebido pela navegação inicial; ele não é uma falha de rede.
|
|
355
|
+
|
|
356
|
+
`options.capture_network: "all"` inclui até o limite de diagnóstico eventos
|
|
357
|
+
com URL sem query string, método, status, tipo de recurso, duração e cabeçalhos
|
|
358
|
+
de resposta de uma allowlist. `capture_network_url_contains` filtra as URLs.
|
|
359
|
+
Quando o Chromium informa cookies bloqueados, `blocked_cookies` mostra nome,
|
|
360
|
+
domínio, caminho, flags e motivo, sem revelar valores.
|
|
279
361
|
|
|
280
362
|
Para aguardar a API antes de abrir a interface, passe
|
|
281
363
|
`options.wait_for_http: {"url":"http://localhost:8000/health","timeout_ms":30000}`.
|
|
@@ -312,10 +394,38 @@ controle próximo ao texto visível do rótulo.
|
|
|
312
394
|
`15287210`; `row_containing_exact` continua disponível para texto de célula
|
|
313
395
|
exato. `check` e `uncheck` alteram checkboxes, e `select_option` aceita rótulo
|
|
314
396
|
exato (`option`), valor (`value`) ou rótulo parcial único (`label_contains`).
|
|
315
|
-
`navigate_menu` percorre uma lista de rótulos exatos e abre `#open_btn` quando o
|
|
316
|
-
primeiro item ainda está oculto. Se vários itens visíveis tiverem o mesmo
|
|
317
|
-
rótulo, seleciona a última ocorrência, útil quando o submenu recém-aberto
|
|
318
|
-
repete o nome da categoria pai.
|
|
397
|
+
`navigate_menu` percorre uma lista de rótulos exatos e abre `#open_btn` quando o
|
|
398
|
+
primeiro item ainda está oculto. Se vários itens visíveis tiverem o mesmo
|
|
399
|
+
rótulo, seleciona a última ocorrência, útil quando o submenu recém-aberto
|
|
400
|
+
repete o nome da categoria pai. Para o SAFI, `screen` pesquisa o nome ou código
|
|
401
|
+
na tela Acesso Rápido, exige um resultado único e clica no link oficial da linha;
|
|
402
|
+
por exemplo, `{"action":"navigate_menu","screen":"TCN00022"}`.
|
|
403
|
+
|
|
404
|
+
Em uma instância local do SAFI, `http_request` pode obter a lista de telas pela
|
|
405
|
+
sessão já aberta sem ler o HTML:
|
|
406
|
+
|
|
407
|
+
```json
|
|
408
|
+
{
|
|
409
|
+
"flow": "Consultar telas disponíveis no perfil atual do SAFI",
|
|
410
|
+
"initial_url": "http://localhost:8011/safi/",
|
|
411
|
+
"candidate_plans": {
|
|
412
|
+
"inspect": {
|
|
413
|
+
"description": "Ler a lista de telas do SAFI no ambiente local",
|
|
414
|
+
"steps": [{
|
|
415
|
+
"action": "http_request",
|
|
416
|
+
"url": "/safi/api/menu/telas_menu",
|
|
417
|
+
"include_body": true
|
|
418
|
+
}]
|
|
419
|
+
}
|
|
420
|
+
},
|
|
421
|
+
"options": { "local_only": true, "fast_path": true }
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
O endpoint usa a sessão atual e pode retornar uma lista específica do perfil.
|
|
426
|
+
Os valores de cookies nunca são retornados. O acesso ao menu continua sujeito
|
|
427
|
+
às permissões verificadas pela própria interface; não use esse diagnóstico
|
|
428
|
+
contra produção.
|
|
319
429
|
|
|
320
430
|
```json
|
|
321
431
|
{
|
|
@@ -423,21 +533,173 @@ asserções são aceitos. `comment` também é aceito em planos e passos, mas é
|
|
|
423
533
|
ignorado e não é enviado ao Jev. Campos fora do contrato continuam sendo
|
|
424
534
|
recusados.
|
|
425
535
|
|
|
426
|
-
### Upload de arquivos
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
536
|
+
### Upload de arquivos
|
|
537
|
+
|
|
538
|
+
Por padrão, `browser_health` cria e devolve `upload_staging_directory` dentro do
|
|
539
|
+
projeto local: `<JEV_BROWSER_PROJECT_ROOT ou diretório de trabalho do MCP>/.jev-browser/tmp/uploads/mcp-<pid>-<sessão>`.
|
|
540
|
+
O harness deve copiar para essa pasta somente os arquivos de fixture que o
|
|
541
|
+
fluxo precisa, e usar o caminho absoluto retornado por `browser_health`. Se o
|
|
542
|
+
processo MCP iniciar com outro diretório de trabalho, defina
|
|
543
|
+
`JEV_BROWSER_PROJECT_ROOT` como o caminho absoluto do projeto. Em um MCP remoto,
|
|
544
|
+
esse caminho pertence ao host do servidor; o harness precisa conseguir gravar
|
|
545
|
+
no mesmo host ou volume.
|
|
546
|
+
|
|
547
|
+
Cada caminho passado ao fluxo precisa ser absoluto; o MCP resolve links
|
|
548
|
+
simbólicos e recusa qualquer arquivo fora do staging privado daquela sessão e
|
|
549
|
+
da raiz explícita configurada, se houver.
|
|
550
|
+
Só aceita arquivos regulares, até 5 arquivos por passo, 10 MiB por arquivo e
|
|
551
|
+
25 MiB no total do passo, conforme `jev_browser_mcp.browser` em
|
|
552
|
+
`config/ui-testing.json`. O operador pode ajustar os limites no arquivo ou com
|
|
553
|
+
`JEV_BROWSER_MAX_UPLOAD_FILE_BYTES` e
|
|
554
|
+
`JEV_BROWSER_MAX_UPLOAD_TOTAL_BYTES`; o teto total precisa ser pelo menos o
|
|
555
|
+
limite por arquivo. `browser_health` e `describe_actions` mostram os valores
|
|
556
|
+
ativos. Esse teto pertence ao MCP e ao navegador local; alterá-lo não aumenta
|
|
557
|
+
o limite de arquivo aceito pelo provedor Jev. Os bytes são lidos e validados no
|
|
558
|
+
processo local antes de serem entregues ao Playwright. O MCP não envia esses
|
|
559
|
+
bytes ao Jev nem os inclui diretamente na resposta; texto que o próprio site
|
|
560
|
+
exibir na interface ainda pode aparecer no snapshot devolvido ao harness.
|
|
561
|
+
|
|
562
|
+
Depois de um fluxo que usa `upload_file`, `generate_fixture` ou multipart com
|
|
563
|
+
arquivos, o MCP remove todos os arquivos e subpastas da pasta exclusiva da
|
|
564
|
+
sessão, inclusive quando o fluxo falha. Arquivos fornecidos pela raiz
|
|
565
|
+
`JEV_BROWSER_UPLOAD_ROOT` não são apagados. Um
|
|
566
|
+
`dry_run` ou `confirmation_required` preserva os arquivos para que a próxima
|
|
567
|
+
chamada confirmada possa usá-los; o encerramento normal do servidor também
|
|
568
|
+
limpa essa pasta. O diretório e os diretórios pais permanecem, prontos para uma
|
|
569
|
+
próxima chamada. O original fora da pasta de staging não é tocado.
|
|
570
|
+
|
|
571
|
+
`JEV_BROWSER_UPLOAD_ROOT` continua disponível como uma raiz explícita adicional;
|
|
572
|
+
o MCP aceita arquivos tanto dela quanto do staging privado do projeto e nunca
|
|
573
|
+
apaga arquivos da raiz explícita. A pasta privada gerenciada no projeto continua
|
|
574
|
+
disponível para fixtures geradas pelo MCP e multipart; só o staging gerenciado
|
|
575
|
+
é limpo automaticamente. Não aponte para o disco inteiro ou para a pasta home.
|
|
576
|
+
|
|
577
|
+
Fixtures `generate_fixture` aceitam `kind: "pdf"`, `"text"` ou `"bytes"`,
|
|
578
|
+
`as`, `file_name` (inclusive Unicode), `content` para PDF/texto e `size_bytes`
|
|
579
|
+
para bytes determinísticos. São criadas em
|
|
580
|
+
`.jev-browser/tmp/uploads/` dentro do projeto e expostas como variável para
|
|
581
|
+
passos seguintes. O tamanho máximo é o menor entre
|
|
582
|
+
`max_upload_file_bytes` configurado e **47 MiB**, limite atual do provedor Jev
|
|
583
|
+
para um arquivo. `assert_download` compara SHA-256, tamanho e tipo MIME do
|
|
584
|
+
último download com o fixture informado. O original do fixture continua sendo
|
|
585
|
+
temporário e é limpo no teardown do fluxo ou da suíte.
|
|
586
|
+
|
|
587
|
+
### Perfis e integrações de teste
|
|
588
|
+
|
|
589
|
+
O MCP lê perfis opcionais de `.jev-browser/profiles.json` no projeto. Para outro
|
|
590
|
+
arquivo dentro do projeto, defina `JEV_BROWSER_PROFILES_FILE` com caminho
|
|
591
|
+
absoluto. O arquivo é JSON versão 1 e nunca deve conter senhas ou tokens:
|
|
592
|
+
campos como `connection_env`, `password_env` e `username_env` guardam somente o
|
|
593
|
+
nome da variável de ambiente, e os valores são lidos pelo processo MCP.
|
|
594
|
+
|
|
595
|
+
Exemplo mínimo de perfil DEV:
|
|
596
|
+
|
|
597
|
+
```json
|
|
598
|
+
{
|
|
599
|
+
"version": 1,
|
|
600
|
+
"profiles": {
|
|
601
|
+
"dev": {
|
|
602
|
+
"environment": "dev",
|
|
603
|
+
"application_origins": ["http://localhost:8000"],
|
|
604
|
+
"database": {
|
|
605
|
+
"engine": "postgresql",
|
|
606
|
+
"connection_env": "JEV_TEST_DATABASE_URL",
|
|
607
|
+
"timeout_ms": 5000,
|
|
608
|
+
"max_rows": 100
|
|
609
|
+
},
|
|
610
|
+
"log_sources": {"api": "logs/test-api.log"},
|
|
611
|
+
"smtp_capture": {"port": 0, "bind_address": "127.0.0.1", "max_messages": 20},
|
|
612
|
+
"remotes": {},
|
|
613
|
+
"hooks": {}
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
`database.engine` suporta `postgresql` e `oracle`. PostgreSQL usa
|
|
620
|
+
`connection_env`; Oracle usa `connect_env`, `user_env` e `password_env`. Ambos
|
|
621
|
+
exigem `timeout_ms` e `max_rows`. `assert_db` aceita apenas um `SELECT` sem
|
|
622
|
+
comandos adicionais, usa binds, transação somente leitura, timeout e teto de
|
|
623
|
+
linhas do perfil. Configure também as credenciais para uma identidade de banco
|
|
624
|
+
com privilégios somente de leitura; a transação read-only do MCP complementa
|
|
625
|
+
essa separação. Essa ação é somente leitura em DEV, HML e PRD.
|
|
626
|
+
|
|
627
|
+
`application_origins` é a allowlist de origens HTTP. `http_request` usa a sessão
|
|
628
|
+
da página, aceita `GET`, `HEAD`, `POST`, `PUT`, `PATCH` e `DELETE`, JSON ou
|
|
629
|
+
multipart. POST/PUT/PATCH/DELETE exigem `options.allow_mutations: true` e um
|
|
630
|
+
perfil DEV/HML cuja allowlist inclua a origem. PRD recusa mutações. HML só
|
|
631
|
+
permite escrita na aplicação com essa autorização explícita. Para uma página
|
|
632
|
+
local sem perfil, `local_only: true` só libera GET/HEAD em loopback.
|
|
633
|
+
`extract` usa caminhos JSON e só expõe valores escalares; campos com nomes
|
|
634
|
+
sensíveis entram na redação automática.
|
|
635
|
+
|
|
636
|
+
`log_sources` define nomes e caminhos de arquivos que o MCP pode consultar.
|
|
637
|
+
`assert_log` lê apenas essas origens e pode restringir o trecho ao que foi
|
|
638
|
+
escrito desde o início do fluxo ou desde `step:N`; logs são sempre somente
|
|
639
|
+
leitura. Configure caminhos absolutos apenas quando a política local exigir;
|
|
640
|
+
prefira caminhos relativos ao projeto.
|
|
641
|
+
|
|
642
|
+
`smtp_capture` sobe um servidor de captura limitado a `127.0.0.1` ou `::1`;
|
|
643
|
+
`port: 0` escolhe uma porta livre. Use `start_email_capture` antes de acionar o
|
|
644
|
+
envio na aplicação e depois `assert_email` com destinatário, assunto ou corpo.
|
|
645
|
+
O servidor guarda as mensagens somente em memória durante a chamada/suíte e as
|
|
646
|
+
remove no teardown. A resposta e o relatório registram a asserção e horário,
|
|
647
|
+
sem incluir assunto ou corpo.
|
|
648
|
+
|
|
649
|
+
`remotes` permite verificar arquivos em FTP, FTPS ou SFTP, limitado a um
|
|
650
|
+
`root` remoto configurado. Credenciais vêm de `username_env` e `password_env`;
|
|
651
|
+
SFTP também exige `host_fingerprint_env` para validar a chave do host.
|
|
652
|
+
Configure cada usuário remoto em uma pasta isolada/chroot compatível com o
|
|
653
|
+
`root` allowlisted.
|
|
654
|
+
`assert_remote_file` verifica existência e, opcionalmente, tamanho e SHA-256.
|
|
655
|
+
`delete_remote_file` é destrutivo: só funciona em perfil DEV com
|
|
656
|
+
`allow_mutations: true`. Banco e logs permanecem somente leitura em todos os
|
|
657
|
+
ambientes.
|
|
658
|
+
|
|
659
|
+
`hooks` são scripts Node nomeados e allowlisted, com caminho dentro do projeto,
|
|
660
|
+
argumentos declarados (`string`, `integer` ou `boolean`), comprimento máximo e
|
|
661
|
+
`timeout_ms` obrigatório. Não há shell nem comando arbitrário; hooks só podem
|
|
662
|
+
ser definidos/executados em DEV e precisam de `allow_mutations: true`. PRD
|
|
663
|
+
recusa hooks e qualquer etapa marcada `mutating: true`.
|
|
664
|
+
|
|
665
|
+
### Suítes JSON e relatórios
|
|
666
|
+
|
|
667
|
+
Guarde uma definição por PBI em `.jev-browser/suites/<id>.json`. Ela possui
|
|
668
|
+
`version: 1`, `id`, `criteria` e opcionalmente `description`, `params`,
|
|
669
|
+
`environment_profile`, `flows`, `setup` e `teardown`. Cada fluxo reutilizável
|
|
670
|
+
tem `flow`, `candidate_plans` e opcionalmente `initial_url`, `expected_outcome`,
|
|
671
|
+
`params` e `options`; cada critério tem `id`, `description` e `flow`, que pode
|
|
672
|
+
referenciar um fluxo pelo nome ou declará-lo inline. Placeholders usam
|
|
673
|
+
`{nome}` e recebem prioridade dos parâmetros do pedido sobre os parâmetros do
|
|
674
|
+
arquivo.
|
|
675
|
+
|
|
676
|
+
Antes de abrir o navegador, `run_test_suite` valida todo o JSON, caminhos de
|
|
677
|
+
relatório, placeholders, limites, perfil e todas as etapas de setup, critérios
|
|
678
|
+
e teardown. Executa sequencialmente por padrão e tenta teardown mesmo se setup
|
|
679
|
+
ou critério falhar. A suíte mantém a sessão do browser e a captura de integrações
|
|
680
|
+
durante suas etapas, depois limpa os arquivos temporários. Um relatório
|
|
681
|
+
Markdown é salvo por padrão em `.jev-browser/reports/`; `report_path` aceita um
|
|
682
|
+
caminho relativo dentro do projeto. O relatório inclui status por critério,
|
|
683
|
+
passos, duração, localizadores, evidências de rede, banco, logs, e-mail, arquivos,
|
|
684
|
+
screenshots e limpeza. URLs de evidência perdem query, fragmento e segmentos que
|
|
685
|
+
parecem IDs; valores de campos e corpos de mensagens não são incluídos. Valores
|
|
686
|
+
secretos conhecidos por variáveis de ambiente e parâmetros sensíveis são
|
|
687
|
+
redigidos. O tamanho do arquivo é limitado por
|
|
688
|
+
`max_test_suite_report_bytes`; se o relatório atingir o teto, o resultado
|
|
689
|
+
informa `report_truncated: true` e o próprio Markdown marca o truncamento.
|
|
690
|
+
|
|
691
|
+
Para permitir polling quando a chamada for longa, use `background: true` e
|
|
692
|
+
consulte o `run_id` com `get_browser_flow_result`. A definição da suíte precisa
|
|
693
|
+
ser criada no projeto do processo MCP antes da chamada. `describe_actions`
|
|
694
|
+
publica o formato da suíte, ferramentas, opções, ações, campos condicionais e
|
|
695
|
+
limites atualmente configurados; `browser_health` informa versões e capacidades.
|
|
696
|
+
|
|
697
|
+
Consulte `browser_health` para descobrir a pasta da sessão e, então, passe o
|
|
698
|
+
caminho absoluto do arquivo preparado pelo harness:
|
|
699
|
+
|
|
700
|
+
```json
|
|
701
|
+
{"action":"upload_file","target":"input","label":"Nota fiscal","file_path":"/projeto/.jev-browser/tmp/uploads/mcp-1234-pid-1234/nota.pdf"}
|
|
702
|
+
```
|
|
441
703
|
|
|
442
704
|
Para uma área de arrastar, use o papel e o nome acessível da dropzone. Para um
|
|
443
705
|
botão que abre a janela nativa, use `target: "button"`; sem `target`, a presença
|
|
@@ -447,9 +709,9 @@ de `label` seleciona o input e `role`/`name` seleciona esse botão.
|
|
|
447
709
|
{"action":"upload_file","target":"dropzone","role":"region","name":"Anexos","file_paths":["/fixtures/a.pdf","/fixtures/b.png"]}
|
|
448
710
|
```
|
|
449
711
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
712
|
+
O limite evita que um plano transforme o MCP em leitor arbitrário de arquivos
|
|
713
|
+
do computador; sem uma raiz explícita, só a pasta temporária isolada da sessão
|
|
714
|
+
é autorizada.
|
|
453
715
|
|
|
454
716
|
Exemplo de chamada:
|
|
455
717
|
|
|
@@ -528,7 +790,9 @@ compartilhe esse arquivo. `storage_state` não pode ser combinado com
|
|
|
528
790
|
`fresh_context` ou `clear_storage`.
|
|
529
791
|
|
|
530
792
|
`browser.max_flow_steps` limita os passos de cada plano candidato; os planos
|
|
531
|
-
não são somados.
|
|
793
|
+
não são somados. O padrão é 24 e pode ser aumentado em `config/ui-testing.json`
|
|
794
|
+
ou por `JEV_BROWSER_MAX_FLOW_STEPS` (por exemplo, `30`).
|
|
795
|
+
`options.max_flow_steps` pode reduzir esse teto por chamada. `browser.max_text_entry_chars` limita cada valor digitado. O
|
|
532
796
|
resultado contém `status`, o plano escolhido, as ações executadas, a última
|
|
533
797
|
captura acessível e se o texto descritivo esperado apareceu. `expected_outcome`
|
|
534
798
|
como string é descrição, não uma asserção: `expected_outcome_visible` é
|
|
@@ -547,12 +811,17 @@ quando nenhuma dessas condições se aplica; confiança do Jev, sozinha, não
|
|
|
547
811
|
comprova o resultado. `environment_error` identifica falha de
|
|
548
812
|
navegação, autenticação ou sessão do browser; `navigation_error` contém o código
|
|
549
813
|
detectado, como `ERR_CONNECTION_REFUSED`, `AUTHENTICATION_REQUIRED` ou
|
|
550
|
-
`BROWSER_DISCONNECTED`,
|
|
814
|
+
`BROWSER_DISCONNECTED`, `BROWSER_PAGE_NOT_RESTORED` ou
|
|
815
|
+
`BROWSER_PROFILE_IN_USE`, e `reason` orienta a recuperação. Se uma navegação falhar
|
|
551
816
|
e a chamada seguinte tentar reutilizar a página, o MCP informa que a navegação
|
|
552
817
|
anterior não carregou; reinicie a navegação com
|
|
553
818
|
`continue_from_current_page: false` (ou o alias `reuse_page: false`). Uma sessão
|
|
554
|
-
desconectada pode ser reaberta por `browser_health
|
|
555
|
-
|
|
819
|
+
desconectada pode ser reaberta por `browser_health`. `run_browser_flow` também
|
|
820
|
+
tenta reconectar e repetir uma vez quando a desconexão acontece antes da primeira
|
|
821
|
+
etapa; a repetição exige `initial_url`. Sem essa URL, o resultado informa
|
|
822
|
+
`BROWSER_PAGE_NOT_RESTORED`, e chamadas posteriores em `reuse_page` continuam
|
|
823
|
+
recusadas até uma nova navegação explícita. Se qualquer etapa já executou ou
|
|
824
|
+
há token de confirmação de mutação, o MCP não repete o fluxo automaticamente.
|
|
556
825
|
|
|
557
826
|
`current_url` é devolvido para diagnóstico sem query string nem fragmento; IDs
|
|
558
827
|
longos no caminho também podem ser redigidos. `timings_ms.ready_ms` mede a espera
|
|
@@ -568,9 +837,14 @@ origem são capturadas mesmo quando usam transferência chunked e não enviam
|
|
|
568
837
|
`Content-Length`. Corpos acima do limite, com formato inválido ou que não
|
|
569
838
|
podem ser lidos com segurança são omitidos e explicados em `warnings`.
|
|
570
839
|
|
|
571
|
-
`jev_browser_mcp.browser.max_action_timeout_seconds` limita esperas por ações,
|
|
572
|
-
seletores e condições. `
|
|
573
|
-
de
|
|
840
|
+
`jev_browser_mcp.browser.max_action_timeout_seconds` limita esperas por ações,
|
|
841
|
+
seletores e condições. `JEV_BROWSER_PROJECT_ROOT` troca o diretório de projeto
|
|
842
|
+
usado para staging quando o diretório de trabalho do MCP não é o projeto. A
|
|
843
|
+
pasta `.jev-browser/tmp/uploads` deve ser tratada como temporária e ignorada
|
|
844
|
+
pelo Git. `JEV_BROWSER_UPLOAD_ROOT` adiciona uma raiz absoluta escolhida pelo
|
|
845
|
+
operador para arquivos fornecidos pelo harness; o MCP não apaga arquivos dessa
|
|
846
|
+
raiz. O staging privado do projeto continua ativo para fixtures e multipart
|
|
847
|
+
gerados pelo MCP.
|
|
574
848
|
`jev_browser_mcp.browser.max_upload_files`, `max_upload_path_chars`,
|
|
575
849
|
`max_upload_file_bytes` e `max_upload_total_bytes` limitam quantidade e tamanho.
|
|
576
850
|
Não configure a raiz como o disco inteiro ou a pasta home: use uma pasta de
|
|
@@ -584,8 +858,9 @@ continua informada mesmo quando a lista é truncada.
|
|
|
584
858
|
|
|
585
859
|
O `run_browser_flow` aceita `options` com `fast_path`, `snapshot_scope`,
|
|
586
860
|
`block_trackers`, `block_fonts`, `local_only`, `busy_selectors`,
|
|
587
|
-
`auto_angular_idle`, `login_url_contains`, `login_text`, `capture_console_errors`,
|
|
588
|
-
`capture_network_errors`, `capture_network_error_bodies`, `
|
|
861
|
+
`auto_angular_idle`, `login_url_contains`, `login_text`, `capture_console_errors`,
|
|
862
|
+
`capture_network_errors`, `capture_network_error_bodies`, `capture_network`,
|
|
863
|
+
`capture_network_url_contains`, `ready_timeout_seconds`,
|
|
589
864
|
`ready_network_idle`, `ready_stable_ms`, `ready_text`, `ready`, `continue_from_current_page`,
|
|
590
865
|
`reuse_page`, `reuse_page_match`, `step_timeout_seconds`, `max_flow_steps`, `return_snapshot`,
|
|
591
866
|
`screenshot_on_failure`, `screenshot_on_success`, `trace_on_failure`,
|
|
@@ -642,6 +917,16 @@ uma lista combina condições, e todas precisam passar. `has_value` aceita
|
|
|
642
917
|
`ready_network_idle: true` solicita uma espera best-effort por `networkidle`.
|
|
643
918
|
`ready_timeout_seconds` limita a espera de inicialização e `ready_stable_ms`
|
|
644
919
|
define a janela usada para considerar o snapshot estável.
|
|
920
|
+
|
|
921
|
+
Se a duração prevista ultrapassar o timeout de chamada do harness, passe
|
|
922
|
+
`background: true` em `run_browser_flow`. A chamada retorna um `run_id`; consulte
|
|
923
|
+
`get_browser_flow_result` com esse ID e, opcionalmente, `wait_ms` de até 30000
|
|
924
|
+
para aguardar a conclusão, mantendo esse valor abaixo do timeout do harness.
|
|
925
|
+
No resultado da consulta, `status` indica se a execução terminou; o status do
|
|
926
|
+
fluxo em si fica em `result.status`. Os resultados ficam na memória do processo
|
|
927
|
+
MCP por 30 minutos e saem antes se o limite de execuções retidas for atingido.
|
|
928
|
+
Reiniciar o servidor apaga execuções e resultados pendentes. O modo síncrono
|
|
929
|
+
permanece disponível para fluxos curtos.
|
|
645
930
|
|
|
646
931
|
`console_levels` aceita `log`, `info`, `debug`, `warn` e `error`. Com
|
|
647
932
|
`console_levels: ["log","warn","error"]` e `capture_network_errors`, o retorno
|
|
@@ -649,6 +934,8 @@ traz mensagens do console agrupadas por texto e nível (`console_messages` com
|
|
|
649
934
|
`count`), além de `console_errors` para compatibilidade. `network_failures`
|
|
650
935
|
contém eventos limitados em quantidade e tamanho. Mensagens idênticas do console
|
|
651
936
|
são agrupadas em uma entrada com `count`.
|
|
937
|
+
Controles sem nome acessível aparecem em um único aviso com a contagem e alguns
|
|
938
|
+
exemplos, em vez de gerar uma mensagem por controle.
|
|
652
939
|
Respostas HTTP 4xx/5xx e requisições que falham são listadas; query strings,
|
|
653
940
|
fragmentos, valores de formulário e nomes de arquivo são removidos ou
|
|
654
941
|
sanitizados. `capture_network_error_bodies: true` lê somente respostas JSON
|
|
@@ -689,8 +976,9 @@ Para testar microfone, conceda permissão no escopo da chamada:
|
|
|
689
976
|
```
|
|
690
977
|
|
|
691
978
|
`fake_media` aceita tanto o caminho WAV direto quanto o objeto
|
|
692
|
-
`{"audio":"caminho.wav"}`. Exige um WAV RIFF válido dentro
|
|
693
|
-
`JEV_BROWSER_UPLOAD_ROOT` e respeita os mesmos limites de
|
|
979
|
+
`{"audio":"caminho.wav"}`. Exige um WAV RIFF válido dentro do staging privado
|
|
980
|
+
do projeto ou de `JEV_BROWSER_UPLOAD_ROOT` e respeita os mesmos limites de
|
|
981
|
+
upload. Ao informar
|
|
694
982
|
`fake_media`, o MCP concede automaticamente a permissão `microphone`, adiciona
|
|
695
983
|
as opções de dispositivo falso do Chromium e usa o arquivo como entrada de
|
|
696
984
|
áudio. Sem esse arquivo, a
|
|
@@ -718,12 +1006,12 @@ Chrome/Edge; em outros sistemas, usa o `SingletonLock` do Chromium. O caminho
|
|
|
718
1006
|
padrão já separa processos por PID; configure `JEV_BROWSER_PROFILE` para mudar
|
|
719
1007
|
a raiz e `JEV_BROWSER_SESSION_ID` para nomear a instância.
|
|
720
1008
|
Resultados MCP incluem `server_version`; erros também começam com a versão do
|
|
721
|
-
servidor para facilitar a comparação entre instalações. A ferramenta
|
|
722
|
-
`browser_health` informa se a sessão está ativa e tenta reconectar um browser
|
|
723
|
-
que encerrou desde a chamada anterior. Passe `{"restart":true}` para fechar e
|
|
724
|
-
reiniciar somente o navegador administrado por este processo MCP.
|
|
725
|
-
|
|
726
|
-
|
|
1009
|
+
servidor para facilitar a comparação entre instalações. A ferramenta
|
|
1010
|
+
`browser_health` informa se a sessão está ativa e tenta reconectar um browser
|
|
1011
|
+
que encerrou desde a chamada anterior. Passe `{"restart":true}` para fechar e
|
|
1012
|
+
reiniciar somente o navegador administrado por este processo MCP. Perfil ocupado
|
|
1013
|
+
é devolvido como `BROWSER_PROFILE_IN_USE` com o PID detectado e não provoca
|
|
1014
|
+
encerramento do Chrome/Edge existente.
|
|
727
1015
|
|
|
728
1016
|
`harness_browser` e `computer_browser` aceitam `chrome` ou `msedge`.
|
|
729
1017
|
`computer_user_data_dir` deve ficar fora do repositório e conter `{browser}` e
|