@diegosouzacdv/jev-browser-mcp 0.6.2 → 0.7.0
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 +281 -105
- package/config/ui-testing.json +2 -2
- package/docs/jev-browser-mcp.md +281 -105
- package/mcp_servers/jev-browser-npm/src/config.mjs +27 -12
- package/mcp_servers/jev-browser-npm/src/flow.mjs +1714 -865
- package/mcp_servers/jev-browser-npm/src/server.mjs +174 -27
- package/package.json +1 -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.
|
|
20
|
+
"args": ["--yes", "@diegosouzacdv/jev-browser-mcp@0.7.0"],
|
|
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.
|
|
35
|
+
npm install @diegosouzacdv/jev-browser-mcp@0.7.0
|
|
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.
|
|
43
|
+
npm install --global @diegosouzacdv/jev-browser-mcp@0.7.0
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
Depois configure o servidor MCP com `command: "jev-browser-mcp"` e `args: []`.
|
|
@@ -49,14 +49,23 @@ Para atualizar, rode `npm install --global
|
|
|
49
49
|
|
|
50
50
|
O padrão `computer` exige Chrome ou Edge instalado. Se optar por `harness`,
|
|
51
51
|
configure `JEV_BROWSER_MODE=harness` antes de instalar o navegador gerenciado
|
|
52
|
-
pelo Playwright com `npx --yes @diegosouzacdv/jev-browser-mcp@0.
|
|
53
|
-
|
|
54
|
-
O padrão é `computer`: o pacote abre o Chrome/Edge instalado e usa um perfil
|
|
55
|
-
persistente exclusivo em `browser.computer_user_data_dir`.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
52
|
+
pelo Playwright com `npx --yes @diegosouzacdv/jev-browser-mcp@0.7.0 --install-browser`.
|
|
53
|
+
|
|
54
|
+
O padrão é `computer`: o pacote abre o Chrome/Edge instalado e usa um perfil
|
|
55
|
+
persistente exclusivo por processo MCP em `browser.computer_user_data_dir`. O
|
|
56
|
+
template aceita `{browser}` e `{session}`; por padrão, `{session}` é `pid-<PID>`.
|
|
57
|
+
Use um `JEV_BROWSER_SESSION_ID` único por instância para manter um nome estável
|
|
58
|
+
entre reinicializações. Um
|
|
59
|
+
`JEV_BROWSER_PROFILE` explícito também recebe o sufixo da sessão, a menos que o
|
|
60
|
+
caminho contenha `{session}`. Assim, processos MCP independentes não disputam o
|
|
61
|
+
mesmo perfil. Clientes conectados ao mesmo processo MCP compartilham a sessão;
|
|
62
|
+
para isolamento entre harnesses, execute uma instância por sessão. No modo
|
|
63
|
+
`harness`, a instalação baixa uma vez o Chrome/Edge que o Playwright controlará.
|
|
64
|
+
Personalize as escolhas com `JEV_BROWSER_MODE`, `JEV_BROWSER_CHANNEL` e
|
|
65
|
+
`JEV_BROWSER_PROFILE`. Sem um ID estável, o perfil é específico do processo e
|
|
66
|
+
uma reinicialização começa outra sessão. O browser permanece aquecido enquanto
|
|
67
|
+
o processo MCP estiver ativo e fecha quando o harness encerra o processo.
|
|
68
|
+
`JEV_PROVIDER_URL`
|
|
60
69
|
e `JEV_MODEL` podem substituir os valores centrais; a credencial continua no
|
|
61
70
|
nome de variável declarado em `jev.credential_env`.
|
|
62
71
|
|
|
@@ -76,8 +85,12 @@ publicada.
|
|
|
76
85
|
|
|
77
86
|
### Contrato do pacote
|
|
78
87
|
|
|
79
|
-
O executável oferece `browser_health`, `choose_next_action`
|
|
80
|
-
sessão do browser por processo e reutiliza
|
|
88
|
+
O executável oferece `browser_health`, `describe_actions`, `choose_next_action`
|
|
89
|
+
e `run_browser_flow`, mantém uma sessão do browser por processo e reutiliza
|
|
90
|
+
essa sessão entre chamadas. `browser_health` informa versão, sessão e
|
|
91
|
+
capacidades; `describe_actions` publica o schema atual das ações, opções,
|
|
92
|
+
aliases e placeholders. Consulte essas ferramentas antes de construir um plano
|
|
93
|
+
para evitar nomes de campos desatualizados. O plano
|
|
81
94
|
passado ao Jev continua declarativo: clique, preenchimento, seleção nativa,
|
|
82
95
|
hover, espera, teclas aprovadas, asserções por elemento, upload restrito a uma
|
|
83
96
|
raiz local configurada e reações idempotentes a um comentário único. Também
|
|
@@ -112,9 +125,14 @@ Cada plano pode usar:
|
|
|
112
125
|
- `navigate` para mudar de página no meio do fluxo. Com a continuidade ligada,
|
|
113
126
|
um `initial_url` de mesma origem diferente da URL ativa produz erro claro; use
|
|
114
127
|
`navigate` ou `continue_from_current_page: false` para escolher o destino;
|
|
115
|
-
- `click`, `
|
|
116
|
-
papel/nome acessível ou
|
|
117
|
-
`text`, `test_id`
|
|
128
|
+
- `click`, `check`, `uncheck`, `type`, `clear`, `hover`, `select_option`,
|
|
129
|
+
`press` e `assert_*` aceitam papel/nome acessível ou localizadores como
|
|
130
|
+
`label`, `placeholder`, `title`, `text`, `test_id` e `selector`;
|
|
131
|
+
- `screenshot` e `clear_storage` atuam na página/contexto atual; `upload_file`
|
|
132
|
+
recebe o arquivo e o alvo de upload. Os limites e formatos estão descritos nas
|
|
133
|
+
seções de evidências e upload;
|
|
134
|
+
- `navigate_menu` para percorrer uma sequência de rótulos de menu; veja a seção
|
|
135
|
+
de navegação de menus para o formato e as opções;
|
|
118
136
|
- `name_match: "exact" | "contains" | "regex"` para controlar a comparação do
|
|
119
137
|
nome acessível; regex rejeita construções com backtracking excessivo. O papel
|
|
120
138
|
`switch` funciona em cliques, verificações e asserções;
|
|
@@ -131,8 +149,11 @@ Cada plano pode usar:
|
|
|
131
149
|
espaços/glyphs de uso privado, como ícones Font Awesome; controles
|
|
132
150
|
desabilitados não aparecem no diagnóstico, mas continuam contando para que o
|
|
133
151
|
índice aponte ao controle correto;
|
|
134
|
-
- `selector` com CSS ou XPath como último recurso. O MCP identifica essa escolha
|
|
135
|
-
em `warnings`; não é permitido enviar JavaScript nem coordenadas;
|
|
152
|
+
- `selector` com CSS ou XPath como último recurso. O MCP identifica essa escolha
|
|
153
|
+
em `warnings`; não é permitido enviar JavaScript nem coordenadas;
|
|
154
|
+
- quando `click` falha porque o alvo está fora da viewport ou não está visível,
|
|
155
|
+
o MCP tenta rolar o alvo até a tela; se isso não bastar, tenta focar o controle
|
|
156
|
+
e enviar `Enter`, sem repetir cegamente o clique;
|
|
136
157
|
- `timeout_seconds` opcional em cada etapa, limitado pela configuração central;
|
|
137
158
|
- `type` com `mode: "keys"` para digitar sequencialmente em campos com máscara,
|
|
138
159
|
`blur: true` para desfocar o campo e `sensitive: false` para permitir que o
|
|
@@ -140,7 +161,7 @@ Cada plano pode usar:
|
|
|
140
161
|
de ambiente do processo MCP, sem colocá-lo no plano. Nesse modo, `\n` envia
|
|
141
162
|
Enter e `\t` envia Tab;
|
|
142
163
|
- `wait_for_text`, `wait_for_value`, `wait_for_enabled` e `wait_for_condition`
|
|
143
|
-
(`url`, `network_idle`, `hidden
|
|
164
|
+
(`url`, `network_idle`, `hidden` ou `angular_idle`). `wait` recebe
|
|
144
165
|
`ms` para uma pausa curta e limitada. `angular_idle` aguarda requisições
|
|
145
166
|
`$http` e digest do AngularJS. `wait_for_text` aceita `fail_on: {"role":"alert"}` para
|
|
146
167
|
interromper a espera assim que um alerta visível aparecer e incluir seu texto
|
|
@@ -150,10 +171,34 @@ Cada plano pode usar:
|
|
|
150
171
|
`ready_stable_ms`; WebSocket, EventSource e polling não relacionado não
|
|
151
172
|
bloqueiam a espera. Se não surgir requisição correspondente, o passo conclui
|
|
152
173
|
após a janela de silêncio;
|
|
174
|
+
- `assert_network` valida resposta HTTP observada (inclusive sucesso 2xx ou erro
|
|
175
|
+
esperado); `wait_for_request` aguarda uma resposta usando `*` como curinga na
|
|
176
|
+
URL e filtros opcionais de método/status; `assert_ws` confere texto, pares
|
|
177
|
+
JSON esperados ou código de fechamento de WebSocket;
|
|
178
|
+
- `evaluate` lê somente caminhos de propriedades como `navigator.mediaDevices`,
|
|
179
|
+
`document.readyState` ou `location.pathname`. Não aceita código, chamadas de
|
|
180
|
+
função, armazenamento local ou propriedades de credenciais. Strings e números
|
|
181
|
+
voltam diretamente; objetos e arrays retornam somente tipo, chaves e tamanho,
|
|
182
|
+
sem despejar seus valores;
|
|
183
|
+
- `new_tab`, `switch_tab` e `new_context` abrem/selecionam abas e criam contexto
|
|
184
|
+
separado dentro do fluxo; `target_page: "popup"` mantém popups abertos para
|
|
185
|
+
passos posteriores;
|
|
186
|
+
- `if_visible` em um clique torna a ação condicional e
|
|
187
|
+
`when: {"visible":"..."}` em cada plano limita as opções do Jev às que
|
|
188
|
+
correspondem à tela atual;
|
|
189
|
+
- `fill` é alias de `type`, `press_key` de `press`, `duration_ms` de `wait.ms` e
|
|
190
|
+
`value` de campos de texto. `timeout_ms` funciona por etapa. Placeholders usam
|
|
191
|
+
`{nome}`; referências desconhecidas e `{{nome}}` são recusadas antes da
|
|
192
|
+
navegação;
|
|
153
193
|
- `press` (o alias legado `press_key` também é aceito) com `PageDown`, `PageUp`,
|
|
154
194
|
`Home`, `End`, setas, `Enter`, `Escape`, `Tab`, `Shift+Tab`, `Space`,
|
|
155
195
|
`Backspace` ou `Delete`. `clear` limpa um campo sem exigir texto. Sem alvo,
|
|
156
196
|
`press` envia a tecla ao elemento focado; com alvo, usa o localizador informado;
|
|
197
|
+
- `screenshot` grava uma imagem local; `full_page: true` inclui a página inteira.
|
|
198
|
+
Também é possível pedir uma captura após qualquer etapa com `screenshot: true`;
|
|
199
|
+
- `clear_storage` limpa cookies, local/session storage, IndexedDB, Cache Storage
|
|
200
|
+
e service workers do contexto atual. Como opção de fluxo,
|
|
201
|
+
`options.clear_storage: true` também recarrega a página antes do snapshot inicial;
|
|
157
202
|
- `assert_text`, `assert_value`, `assert_visible`, `assert_hidden` e
|
|
158
203
|
`assert_enabled`; `assert_text`
|
|
159
204
|
pode receber apenas `role` quando a região, como `alert`, não tem nome acessível;
|
|
@@ -169,19 +214,25 @@ Cada plano pode usar:
|
|
|
169
214
|
|
|
170
215
|
As proteções e evidências por etapa usam estes campos:
|
|
171
216
|
|
|
172
|
-
- `confirm_dialog` recebe `expected_text` e `button`. Em diálogos HTML, o MCP
|
|
173
|
-
confere o texto antes de localizar e clicar no botão. Também trata diálogos
|
|
174
|
-
nativos `alert`/`confirm`: precisa haver uma etapa `confirm_dialog` logo após
|
|
175
|
-
o clique que os abre, o texto deve corresponder e um diálogo inesperado é
|
|
176
|
-
fechado sem aceitar;
|
|
177
|
-
- `
|
|
217
|
+
- `confirm_dialog` recebe `expected_text` e `button`. Em diálogos HTML, o MCP
|
|
218
|
+
confere o texto antes de localizar e clicar no botão. Também trata diálogos
|
|
219
|
+
nativos `alert`/`confirm`: precisa haver uma etapa `confirm_dialog` logo após
|
|
220
|
+
o clique que os abre, o texto deve corresponder e um diálogo inesperado é
|
|
221
|
+
fechado sem aceitar;
|
|
222
|
+
- `confirm_modal` combina o clique no gatilho, a conferência do texto e o clique
|
|
223
|
+
afirmativo em uma única etapa protegida. Também aceita os aliases
|
|
224
|
+
`trigger`/`confirm`, por exemplo
|
|
225
|
+
`{"action":"confirm_modal","trigger":"Salvar","expected_text":"Confirma a alteração?","confirm":"OK"}`;
|
|
226
|
+
- `mutating: true` marca etapas que gravam dados ou disparam efeitos externos.
|
|
178
227
|
O MCP também classifica botões conhecidos como `Salvar`, `Emitir`, `Cancelar`
|
|
179
228
|
ou `Sim` pelo nome e pelo controle resolvido, inclusive quando o plano usa um
|
|
180
229
|
seletor CSS. `options.dry_run: true` executa até a primeira etapa mutável e
|
|
181
230
|
para antes dela; retorna `dry_run_stopped_before_step` e um
|
|
182
|
-
`confirmation_token` temporário, de uso único e vinculado ao fluxo e à página.
|
|
183
|
-
Reenvie a mesma chamada com `options.confirmation_token` para
|
|
184
|
-
|
|
231
|
+
`confirmation_token` temporário, de uso único e vinculado ao fluxo e à página.
|
|
232
|
+
Reenvie a mesma chamada com `options.confirmation_token` para retomar no passo
|
|
233
|
+
pausado sem repetir os passos anteriores; o MCP confere a rota e o alvo da
|
|
234
|
+
mutação antes de executá-la. Ele pausa novamente antes de cada outra etapa
|
|
235
|
+
mutável. Sem `dry_run`,
|
|
185
236
|
o primeiro pedido de ação mutável também retorna `status: "confirmation_required"`
|
|
186
237
|
e token; nenhuma etapa mutável roda sem essa autorização. O token expira após
|
|
187
238
|
dez minutos por padrão;
|
|
@@ -217,9 +268,23 @@ incluindo respostas 2xx ou erros esperados como 404. Exemplo:
|
|
|
217
268
|
}
|
|
218
269
|
```
|
|
219
270
|
|
|
220
|
-
Essa asserção aparece na evidência como `response_status`, separado do campo
|
|
221
|
-
`status` da etapa (`passed` ou `failed`). `message_contains` lê somente resposta
|
|
222
|
-
da mesma origem e respeita o limite configurado para captura de corpos.
|
|
271
|
+
Essa asserção aparece na evidência como `response_status`, separado do campo
|
|
272
|
+
`status` da etapa (`passed` ou `failed`). `message_contains` lê somente resposta
|
|
273
|
+
da mesma origem e respeita o limite configurado para captura de corpos.
|
|
274
|
+
`assert_network`, `wait_for_request` e `expected_outcome.request` consultam o
|
|
275
|
+
histórico limitado de respostas depois do marcador da etapa ou do início do
|
|
276
|
+
fluxo. O limite vem de `jev_browser_mcp.browser.max_network_history_events` e
|
|
277
|
+
está em 4096 eventos nesta configuração; assim, chamadas anteriores ao marcador
|
|
278
|
+
não satisfazem a asserção.
|
|
279
|
+
|
|
280
|
+
Para aguardar a API antes de abrir a interface, passe
|
|
281
|
+
`options.wait_for_http: {"url":"http://localhost:8000/health","timeout_ms":30000}`.
|
|
282
|
+
Também aceita apenas a URL como string ou `{ "url": "...", "timeout_seconds": 30 }`.
|
|
283
|
+
O probe faz GET e tenta novamente até o limite; qualquer resposta abaixo de 500
|
|
284
|
+
indica que o servidor respondeu (inclusive 4xx), enquanto 5xx e erros de conexão
|
|
285
|
+
são repetidos. Ao expirar, `reason` inclui a última causa. Por segurança, a URL
|
|
286
|
+
precisa ser loopback ou usar o mesmo host de `initial_url`; isso permite, por
|
|
287
|
+
exemplo, Vite em `localhost:5173` e API em `localhost:8000`.
|
|
223
288
|
|
|
224
289
|
Exemplo de parâmetro e extração: passe `params: {"pedido":"1528721"}`, filtre
|
|
225
290
|
com `within: {"row_containing_exact":"{pedido}"}`, e use uma etapa
|
|
@@ -227,8 +292,10 @@ com `within: {"row_containing_exact":"{pedido}"}`, e use uma etapa
|
|
|
227
292
|
A etapa seguinte pode localizar o mesmo documento com `name: "{documento}"`.
|
|
228
293
|
|
|
229
294
|
Em `wait_for_condition` com `condition: "hidden"`, use qualquer um desses
|
|
230
|
-
localizadores, `near` ou `within`;
|
|
231
|
-
|
|
295
|
+
localizadores, `near` ou `within`; para esperar texto desaparecer, use
|
|
296
|
+
`{"condition":"hidden","text":"Carregando..."}`. Para esperar que texto suma
|
|
297
|
+
antes do primeiro passo, use `options.ready: {"hidden_text":"Carregando..."}`.
|
|
298
|
+
Para aguardar o fim de uma chamada específica, use `condition: "network_idle"` com
|
|
232
299
|
`url_contains`. O filtro considera somente a atividade correspondente e termina
|
|
233
300
|
após a janela configurada sem atividade; também termina caso nenhuma requisição
|
|
234
301
|
correspondente apareça. Para validar status e corpo, prefira `assert_network`.
|
|
@@ -239,7 +306,7 @@ ocorrência zero-based dentro desse escopo; sem `index`, o MCP exige exatamente
|
|
|
239
306
|
um alvo. Para uma página com rótulo `for` quebrado, `label` também procura o
|
|
240
307
|
controle próximo ao texto visível do rótulo.
|
|
241
308
|
|
|
242
|
-
`within` pode combinar um container e uma linha. Use, por exemplo,
|
|
309
|
+
`within` pode combinar um container e uma linha. Use, por exemplo,
|
|
243
310
|
`{"role":"cell","name":"Documento A","within":{"role":"table","row_containing_word":"1528721"}}`.
|
|
244
311
|
`row_containing_word` usa limites de palavra para não confundir `1528721` com
|
|
245
312
|
`15287210`; `row_containing_exact` continua disponível para texto de célula
|
|
@@ -274,13 +341,14 @@ Exemplos para controles legados sem nome acessível:
|
|
|
274
341
|
{"action":"click","selector":"#save-document"}
|
|
275
342
|
```
|
|
276
343
|
|
|
277
|
-
|
|
278
|
-
`
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
344
|
+
Por padrão, controles sem nome não são devolvidos em listas separadas. Defina
|
|
345
|
+
`options.include_unnamed_controls: true` para receber
|
|
346
|
+
`unnamed_controls_initial` e `unnamed_controls_final`, cada uma com papel,
|
|
347
|
+
índice Playwright por papel, rótulo mais próximo e um trecho HTML sanitizado.
|
|
348
|
+
Nomes vazios ou compostos apenas por espaços e glyphs da área Unicode de uso
|
|
349
|
+
privado (como ícones Font Awesome) entram nessa lista e podem ser selecionados
|
|
350
|
+
com `name: ""` e o mesmo índice. O alias redundante `unnamed_controls` foi
|
|
351
|
+
removido. O placeholder conta como nome acessível.
|
|
284
352
|
O snapshot também resume campos de formulário com `id`, `name`, valor, estado
|
|
285
353
|
desabilitado, rótulo e índice zero-based entre campos de mesmo nome. Valores
|
|
286
354
|
sensíveis, como senha, token e cartão, são ocultados. `snapshot_include_hidden`
|
|
@@ -291,10 +359,14 @@ Em uma etapa `type`, `text` contém o valor a digitar; use `target_text` para
|
|
|
291
359
|
localizar pelo texto visível próximo ao campo. Esse localizador exige `role`
|
|
292
360
|
`textbox`, `searchbox` ou `combobox`.
|
|
293
361
|
|
|
294
|
-
Por padrão, o MCP executa todos os passos antes de avaliar
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
362
|
+
Por padrão, o MCP executa todos os passos antes de avaliar os critérios.
|
|
363
|
+
`expected_outcome` aceita texto descritivo ou uma asserção estruturada, por
|
|
364
|
+
exemplo `{"text":"Tecnologia atualizada com sucesso."}` ou
|
|
365
|
+
`{"request":"PUT */api/tecnologia","status":200}`. A forma estruturada pode
|
|
366
|
+
incluir `message_contains` e reprova se a resposta correspondente não for
|
|
367
|
+
observada. Valores dentro de campos não contam como texto visível.
|
|
368
|
+
`stop_on_expected: true` habilita parada antecipada quando o texto esperado
|
|
369
|
+
aparece fora dos campos; mantenha `false` para fluxos com várias etapas.
|
|
298
370
|
|
|
299
371
|
Os erros de validação apontam o campo inválido e os campos aceitos. Os limites
|
|
300
372
|
de `timeout_seconds` informam o máximo configurado, em vez de exigir tentativa
|
|
@@ -330,11 +402,13 @@ verificar:
|
|
|
330
402
|
{"action":"audit_accessibility","standard":"wcag2aa"}
|
|
331
403
|
```
|
|
332
404
|
|
|
333
|
-
O MCP usa `@axe-core/playwright` com as tags WCAG 2.0 e 2.1 A/AA. O retorno
|
|
334
|
-
resume as violações por regra, impacto e quantidade de nós, sem copiar HTML ou
|
|
335
|
-
trechos da página.
|
|
336
|
-
|
|
337
|
-
|
|
405
|
+
O MCP usa `@axe-core/playwright` com as tags WCAG 2.0 e 2.1 A/AA. O retorno
|
|
406
|
+
resume as violações por regra, impacto e quantidade de nós, sem copiar HTML ou
|
|
407
|
+
trechos da página. A etapa falha quando encontra violações no impacto definido
|
|
408
|
+
por `fail_on_impact`; o padrão é `minor`, e níveis abaixo do limite são relatados
|
|
409
|
+
sem bloquear o fluxo. A auditoria automática encontra problemas comuns, mas não
|
|
410
|
+
comprova conformidade WCAG completa; combine-a com revisão manual e testes com
|
|
411
|
+
usuários assistivos.
|
|
338
412
|
|
|
339
413
|
Para ações em iframe, acrescente `"frame": "payment-iframe"`; o valor precisa
|
|
340
414
|
corresponder ao atributo `name` ou `title` do iframe. O snapshot inclui o
|
|
@@ -431,25 +505,63 @@ validadores.
|
|
|
431
505
|
harness e CI. O processo MCP conserva browser, contexto e página entre
|
|
432
506
|
chamadas; cookies, local storage e estado da página permanecem enquanto o
|
|
433
507
|
processo estiver ativo. Encerre o processo para descartar o contexto isolado.
|
|
434
|
-
- `computer` abre o Chrome ou Edge instalado em modo visível e usa o diretório
|
|
435
|
-
persistente `browser.computer_user_data_dir`, separado por navegador
|
|
436
|
-
|
|
437
|
-
|
|
508
|
+
- `computer` abre o Chrome ou Edge instalado em modo visível e usa o diretório
|
|
509
|
+
persistente `browser.computer_user_data_dir`, separado por navegador e por
|
|
510
|
+
processo MCP. Não
|
|
511
|
+
reutiliza o perfil pessoal já aberto. Faça login uma vez nesse perfil; os
|
|
512
|
+
cookies permanecem nele entre chamadas.
|
|
513
|
+
|
|
514
|
+
`fresh_context: true` abre um contexto descartável, sem cookies nem storage do
|
|
515
|
+
perfil persistente; requer `initial_url` e fecha esse contexto ao terminar. Use
|
|
516
|
+
`clear_storage: true` para limpar cookies, local/session storage, IndexedDB,
|
|
517
|
+
Cache Storage e service workers antes de recarregar a página atual. Para salvar
|
|
518
|
+
e reutilizar o estado de autenticação de uma conta de teste, use um nome simples
|
|
519
|
+
em `storage_state`:
|
|
520
|
+
|
|
521
|
+
```json
|
|
522
|
+
{"options":{"storage_state":"aluno-a"}}
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
O estado fica em `storage-state/<nome>.json` dentro da pasta de artefatos, com
|
|
526
|
+
permissões restritas no sistema operacional; não use uma conta real nem
|
|
527
|
+
compartilhe esse arquivo. `storage_state` não pode ser combinado com
|
|
528
|
+
`fresh_context` ou `clear_storage`.
|
|
438
529
|
|
|
439
530
|
`browser.max_flow_steps` limita os passos de cada plano candidato; os planos
|
|
440
|
-
não são somados. `browser.max_text_entry_chars` limita cada valor digitado. O
|
|
441
|
-
`status`, o plano escolhido, as ações executadas, a última
|
|
442
|
-
se o
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
531
|
+
não são somados. `browser.max_text_entry_chars` limita cada valor digitado. O
|
|
532
|
+
resultado contém `status`, o plano escolhido, as ações executadas, a última
|
|
533
|
+
captura acessível e se o texto descritivo esperado apareceu. `expected_outcome`
|
|
534
|
+
como string é descrição, não uma asserção: `expected_outcome_visible` é
|
|
535
|
+
informado separadamente, e um plano concluído pode passar mesmo se a frase não
|
|
536
|
+
estiver visível. Use `{ "text": "..." }` ou
|
|
537
|
+
`{ "request": "...", "status": 200 }` para exigir uma condição; as
|
|
538
|
+
verificações ficam em `expected_outcome_checks`, e uma condição não satisfeita
|
|
539
|
+
reprova o fluxo. As asserções `assert_*`, auditorias de acessibilidade e
|
|
540
|
+
downloads também aparecem em campos próprios do resultado.
|
|
541
|
+
|
|
542
|
+
Os status do fluxo incluem `passed`, `failed`, `incomplete`, `environment_error`,
|
|
543
|
+
`dry_run` e `confirmation_required`. O fluxo fica `passed` se não houve falha ou
|
|
544
|
+
pausa de mutação e o texto esperado apareceu, uma asserção/auditoria/download
|
|
545
|
+
passou ou todas as etapas do plano foram executadas. `incomplete` é devolvido
|
|
546
|
+
quando nenhuma dessas condições se aplica; confiança do Jev, sozinha, não
|
|
547
|
+
comprova o resultado. `environment_error` identifica falha de
|
|
548
|
+
navegação, autenticação ou sessão do browser; `navigation_error` contém o código
|
|
549
|
+
detectado, como `ERR_CONNECTION_REFUSED`, `AUTHENTICATION_REQUIRED` ou
|
|
550
|
+
`BROWSER_DISCONNECTED`, e `reason` orienta a recuperação. Se uma navegação falhar
|
|
551
|
+
e a chamada seguinte tentar reutilizar a página, o MCP informa que a navegação
|
|
552
|
+
anterior não carregou; reinicie a navegação com
|
|
553
|
+
`continue_from_current_page: false` (ou o alias `reuse_page: false`). Uma sessão
|
|
554
|
+
desconectada pode ser reaberta por `browser_health`; o fluxo só é repetido
|
|
555
|
+
automaticamente uma vez se nenhuma etapa mutável tiver sido executada.
|
|
556
|
+
|
|
557
|
+
`current_url` é devolvido para diagnóstico sem query string nem fragmento; IDs
|
|
558
|
+
longos no caminho também podem ser redigidos. `timings_ms.ready_ms` mede a espera
|
|
559
|
+
da SPA; `warnings` registra capturas vazias durante transições; e `failed_step`
|
|
560
|
+
identifica índice, ação, localizador, timeout e erro resumido quando uma etapa
|
|
561
|
+
falha. Cada etapa executada também registra a composição do localizador usado
|
|
562
|
+
e, quando disponível, `resolved_target` com tag, `id`, papel, nome acessível,
|
|
563
|
+
`title` casado e `href` sanitizado do elemento resolvido. Etapas `type` só
|
|
564
|
+
incluem o valor final do campo quando `sensitive: false`.
|
|
453
565
|
|
|
454
566
|
Com `capture_network_error_bodies: true`, respostas JSON de erro da mesma
|
|
455
567
|
origem são capturadas mesmo quando usam transferência chunked e não enviam
|
|
@@ -473,29 +585,34 @@ continua informada mesmo quando a lista é truncada.
|
|
|
473
585
|
O `run_browser_flow` aceita `options` com `fast_path`, `snapshot_scope`,
|
|
474
586
|
`block_trackers`, `block_fonts`, `local_only`, `busy_selectors`,
|
|
475
587
|
`auto_angular_idle`, `login_url_contains`, `login_text`, `capture_console_errors`,
|
|
476
|
-
`capture_network_errors`, `capture_network_error_bodies`, `ready_timeout_seconds`,
|
|
477
|
-
`ready_network_idle`, `ready_stable_ms`, `ready_text`, `continue_from_current_page`,
|
|
478
|
-
`reuse_page`, `step_timeout_seconds`, `max_flow_steps`, `return_snapshot`,
|
|
588
|
+
`capture_network_errors`, `capture_network_error_bodies`, `ready_timeout_seconds`,
|
|
589
|
+
`ready_network_idle`, `ready_stable_ms`, `ready_text`, `ready`, `continue_from_current_page`,
|
|
590
|
+
`reuse_page`, `reuse_page_match`, `step_timeout_seconds`, `max_flow_steps`, `return_snapshot`,
|
|
479
591
|
`screenshot_on_failure`, `screenshot_on_success`, `trace_on_failure`,
|
|
480
|
-
`trace_on_success`, `record_video`, `snapshot_include_hidden`, `stop_on_expected`,
|
|
592
|
+
`trace_on_success`, `record_video`, `snapshot_include_hidden`, `include_unnamed_controls`, `stop_on_expected`,
|
|
481
593
|
`dry_run`, `confirmation_token`, `report_path`, `permissions`, `fake_media`,
|
|
482
594
|
`viewport`, `mobile`, `device_scale_factor`, `locale`, `timezone_id`,
|
|
483
|
-
`color_scheme`, `geolocation`
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
de
|
|
488
|
-
|
|
489
|
-
|
|
595
|
+
`color_scheme`, `geolocation`, `console_levels`, `fresh_context`,
|
|
596
|
+
`clear_storage`, `storage_state`, `wait_for_http` e `allow_mutations`. Sem override,
|
|
597
|
+
os padrões são lidos de `jev_browser_mcp` em
|
|
598
|
+
`config/ui-testing.json`: um plano candidato pula a chamada Decisions;
|
|
599
|
+
captura de console e screenshot de falha ficam ligadas; trace, rede e bloqueio
|
|
600
|
+
de recursos ficam desligados; o plano roda até o fim e campos ocultos não são
|
|
601
|
+
acrescentados ao snapshot. `return_snapshot: "diff"` é o padrão, e as listas de
|
|
602
|
+
controles sem nome só aparecem com `include_unnamed_controls: true`. O browser
|
|
603
|
+
espera a SPA renderizar uma captura acessível estável na navegação inicial.
|
|
604
|
+
Depois, a continuidade fica ligada por
|
|
490
605
|
padrão: `continue_from_current_page: true` mantém a página e seu estado entre
|
|
491
606
|
chamadas na mesma origem, não repete `page.goto` e consulta um snapshot atual
|
|
492
607
|
sem esperar novamente por `load`/`networkidle`. As etapas continuam aguardando
|
|
493
608
|
seus próprios alvos e condições. `reuse_page` segue como alias legado; defina
|
|
494
609
|
`continue_from_current_page: false` para iniciar cada chamada em `initial_url`.
|
|
495
610
|
Se a página atual e `initial_url` tiverem origens diferentes, o MCP navega para
|
|
496
|
-
`initial_url`.
|
|
497
|
-
|
|
498
|
-
`continue_from_current_page: false`. `
|
|
611
|
+
`initial_url`. URLs da mesma origem são comparadas após normalizar e ordenar a
|
|
612
|
+
query string. Se a rota normalizada diferir, o MCP pede uma etapa `navigate` ou
|
|
613
|
+
`continue_from_current_page: false`. `reuse_page_match: "path"` ignora a query;
|
|
614
|
+
um plano cuja primeira etapa seja `navigate` pode trocar a rota explicitamente.
|
|
615
|
+
`snapshot_scope` aceita `body`, `main` ou
|
|
499
616
|
`dialog`; se `main` não existir, o snapshot usa `body`.
|
|
500
617
|
|
|
501
618
|
`block_trackers: true` bloqueia analytics/trackers e os tipos de recurso
|
|
@@ -511,14 +628,27 @@ precisaria chamar o provedor Jev; use exatamente um plano com `fast_path: true`.
|
|
|
511
628
|
`allow_mutations: true` pula a confirmação humana somente para URLs em
|
|
512
629
|
`localhost`, `127.0.0.1` ou `::1`; use esse modo apenas em ambientes locais
|
|
513
630
|
controlados.
|
|
514
|
-
`step_timeout_seconds` define o timeout padrão por etapa e cada etapa pode
|
|
515
|
-
substituí-lo com `timeout_seconds`. `max_flow_steps` reduz o limite por chamada,
|
|
516
|
-
sem superar o teto da configuração. `return_snapshot` aceita `
|
|
517
|
-
`none`; `diff` retorna linhas acessíveis novas desde o snapshot inicial.
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
631
|
+
`step_timeout_seconds` define o timeout padrão por etapa e cada etapa pode
|
|
632
|
+
substituí-lo com `timeout_seconds`. `max_flow_steps` reduz o limite por chamada,
|
|
633
|
+
sem superar o teto da configuração. `return_snapshot` aceita `diff`, `full` ou
|
|
634
|
+
`none`; `diff` retorna linhas acessíveis novas desde o snapshot inicial.
|
|
635
|
+
|
|
636
|
+
`options.ready` aguarda condições da aplicação antes do primeiro snapshot e da
|
|
637
|
+
seleção do plano. Aceita `"network_idle"`,
|
|
638
|
+
`{"hidden_text":"Aguarde."}` e `{"selector":"#cdTecnologia","has_value":true}`;
|
|
639
|
+
uma lista combina condições, e todas precisam passar. `has_value` aceita
|
|
640
|
+
`true` (valor não vazio), `false` (vazio) ou o valor textual exato.
|
|
641
|
+
`ready_text` também pode exigir uma frase no snapshot inicial;
|
|
642
|
+
`ready_network_idle: true` solicita uma espera best-effort por `networkidle`.
|
|
643
|
+
`ready_timeout_seconds` limita a espera de inicialização e `ready_stable_ms`
|
|
644
|
+
define a janela usada para considerar o snapshot estável.
|
|
645
|
+
|
|
646
|
+
`console_levels` aceita `log`, `info`, `debug`, `warn` e `error`. Com
|
|
647
|
+
`console_levels: ["log","warn","error"]` e `capture_network_errors`, o retorno
|
|
648
|
+
traz mensagens do console agrupadas por texto e nível (`console_messages` com
|
|
649
|
+
`count`), além de `console_errors` para compatibilidade. `network_failures`
|
|
650
|
+
contém eventos limitados em quantidade e tamanho. Mensagens idênticas do console
|
|
651
|
+
são agrupadas em uma entrada com `count`.
|
|
522
652
|
Respostas HTTP 4xx/5xx e requisições que falham são listadas; query strings,
|
|
523
653
|
fragmentos, valores de formulário e nomes de arquivo são removidos ou
|
|
524
654
|
sanitizados. `capture_network_error_bodies: true` lê somente respostas JSON
|
|
@@ -552,15 +682,18 @@ Para testar microfone, conceda permissão no escopo da chamada:
|
|
|
552
682
|
{
|
|
553
683
|
"options": {
|
|
554
684
|
"permissions": ["microphone"],
|
|
555
|
-
"fake_media": "fixtures/resposta-aluno.wav",
|
|
685
|
+
"fake_media": {"audio":"fixtures/resposta-aluno.wav"},
|
|
556
686
|
"block_trackers": true
|
|
557
687
|
}
|
|
558
688
|
}
|
|
559
689
|
```
|
|
560
690
|
|
|
561
|
-
`fake_media`
|
|
562
|
-
|
|
563
|
-
|
|
691
|
+
`fake_media` aceita tanto o caminho WAV direto quanto o objeto
|
|
692
|
+
`{"audio":"caminho.wav"}`. Exige um WAV RIFF válido dentro de
|
|
693
|
+
`JEV_BROWSER_UPLOAD_ROOT` e respeita os mesmos limites de upload. Ao informar
|
|
694
|
+
`fake_media`, o MCP concede automaticamente a permissão `microphone`, adiciona
|
|
695
|
+
as opções de dispositivo falso do Chromium e usa o arquivo como entrada de
|
|
696
|
+
áudio. Sem esse arquivo, a
|
|
564
697
|
permissão de microfone usa o dispositivo autorizado pelo browser; no modo
|
|
565
698
|
`computer`, o sistema operacional ainda pode pedir acesso ao dispositivo.
|
|
566
699
|
|
|
@@ -580,9 +713,10 @@ andamento, sem repetir o clique.
|
|
|
580
713
|
|
|
581
714
|
Se o Chrome/Edge não iniciar porque o perfil persistente já está aberto, o erro
|
|
582
715
|
identifica o PID que o mantém ocupado quando o sistema consegue associar o
|
|
583
|
-
perfil ao processo. Em Windows, o MCP consulta a linha de comando dos processos
|
|
584
|
-
Chrome/Edge; em outros sistemas, usa o `SingletonLock` do Chromium.
|
|
585
|
-
|
|
716
|
+
perfil ao processo. Em Windows, o MCP consulta a linha de comando dos processos
|
|
717
|
+
Chrome/Edge; em outros sistemas, usa o `SingletonLock` do Chromium. O caminho
|
|
718
|
+
padrão já separa processos por PID; configure `JEV_BROWSER_PROFILE` para mudar
|
|
719
|
+
a raiz e `JEV_BROWSER_SESSION_ID` para nomear a instância.
|
|
586
720
|
Resultados MCP incluem `server_version`; erros também começam com a versão do
|
|
587
721
|
servidor para facilitar a comparação entre instalações. A ferramenta
|
|
588
722
|
`browser_health` informa se a sessão está ativa e tenta reconectar um browser
|
|
@@ -591,11 +725,50 @@ reiniciar somente o navegador administrado por este processo MCP. Um fluxo pode
|
|
|
591
725
|
ser repetido automaticamente uma vez após `BROWSER_DISCONNECTED` quando nenhuma
|
|
592
726
|
etapa mutável foi executada.
|
|
593
727
|
|
|
594
|
-
`harness_browser` e `computer_browser` aceitam `chrome` ou `msedge`.
|
|
595
|
-
`computer_user_data_dir` deve ficar fora do repositório e conter `{browser}
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
728
|
+
`harness_browser` e `computer_browser` aceitam `chrome` ou `msedge`.
|
|
729
|
+
`computer_user_data_dir` deve ficar fora do repositório e conter `{browser}` e
|
|
730
|
+
`{session}`;
|
|
731
|
+
o diretório persistente armazena dados de login e é resolvido sob a pasta home
|
|
732
|
+
do usuário quando começa com `~`. O Playwright MCP fica desabilitado até
|
|
733
|
+
`ORQUESTRADOR_MCP_PLAYWRIGHT_ENABLED=1` ser configurado no ambiente do harness.
|
|
734
|
+
|
|
735
|
+
## Preparar smoke autenticado local
|
|
736
|
+
|
|
737
|
+
O MCP não cria a identidade nem os dados do sistema testado. Para um smoke de
|
|
738
|
+
administração, suba a API e a UI locais, use um banco descartável com dados
|
|
739
|
+
fictícios e uma identidade OIDC de teste que tenha explicitamente a claim
|
|
740
|
+
`administrator`. Mantenha as regras de autorização de produção iguais; um token
|
|
741
|
+
de operador legado não deve ser promovido para admin só para fazer o smoke.
|
|
742
|
+
|
|
743
|
+
Faça o preflight nesta ordem:
|
|
744
|
+
|
|
745
|
+
1. `browser_health` confirma a versão, o perfil/sessão e a conexão do navegador.
|
|
746
|
+
Se o perfil estiver ocupado, use outro `JEV_BROWSER_SESSION_ID` ou
|
|
747
|
+
`JEV_BROWSER_PROFILE`; não encerre o Chrome do operador.
|
|
748
|
+
2. `options.wait_for_http` aguarda a API local responder antes de abrir a UI.
|
|
749
|
+
Informe a URL da interface em `initial_url` e a rota de health da API no
|
|
750
|
+
probe.
|
|
751
|
+
3. `run_browser_flow` confirma que a tela administrativa esperada está visível
|
|
752
|
+
e que a identidade abriu com papel administrativo. Se aparecer a tela de
|
|
753
|
+
login, configure a conta de teste ou o provedor OIDC local; não copie o token
|
|
754
|
+
para `flow`, `params` ou logs. Use `text_env` para campos secretos.
|
|
755
|
+
4. Valide primeiro uma prévia read-only com `assert_*`, `assert_network` e
|
|
756
|
+
captura de evidência. Para um fluxo que poderia gravar dados, use
|
|
757
|
+
`dry_run: true`; ele para antes da primeira etapa marcada como mutável.
|
|
758
|
+
5. Só execute o passo de gravação em dados fictícios, depois de conferir o texto
|
|
759
|
+
do diálogo com `confirm_modal`/`confirm_dialog` e autorizar o token de
|
|
760
|
+
confirmação. Reinicializações de serviços e consultas diretas ao banco ficam
|
|
761
|
+
fora do smoke de tela.
|
|
762
|
+
|
|
763
|
+
Esse preflight é um roteiro composto por `browser_health`, `wait_for_http` e
|
|
764
|
+
asserções da própria aplicação; não há uma ferramenta genérica que valide a
|
|
765
|
+
claim OIDC `administrator`. A checagem do papel precisa usar um sinal visível ou
|
|
766
|
+
uma asserção específica do sistema consumidor.
|
|
767
|
+
|
|
768
|
+
Um `expected_outcome` descreve o objetivo; o resultado `passed` vem das
|
|
769
|
+
asserções explícitas ou da conclusão do plano. Verifique
|
|
770
|
+
`expected_outcome_visible` separadamente quando a frase global fizer parte do
|
|
771
|
+
critério do teste.
|
|
599
772
|
|
|
600
773
|
Defina o valor secreto na variável indicada por `jev.credential_env`, usando o
|
|
601
774
|
secret manager ou ambiente do processo que inicia o harness. Não grave a chave
|
|
@@ -639,10 +812,13 @@ valores dos controles são substituídos e hrefs têm query string e fragmento
|
|
|
639
812
|
removidos; padrões de PII também são mascarados. Com fast-path, um plano não
|
|
640
813
|
gera chamada remota. Os passos, valores digitados, valores esperados pelas
|
|
641
814
|
asserções, caminhos e conteúdo dos arquivos não são enviados.
|
|
642
|
-
Não inclua segredos em `flow`, `expected_outcome` ou nas descrições. A resposta
|
|
643
|
-
retorna o plano escolhido quando houver decisão, custo/confiança do provedor
|
|
644
|
-
quando disponíveis e o snapshot final sanitizado.
|
|
645
|
-
|
|
815
|
+
Não inclua segredos em `flow`, `expected_outcome` ou nas descrições. A resposta
|
|
816
|
+
retorna o plano escolhido quando houver decisão, custo/confiança do provedor
|
|
817
|
+
quando disponíveis e o snapshot final sanitizado. Um `expected_outcome` em
|
|
818
|
+
texto simples é descritivo: `expected_outcome_visible` indica separadamente se
|
|
819
|
+
a frase apareceu, e completar o plano pode resultar em `passed` mesmo que ela
|
|
820
|
+
não apareça. Use a forma estruturada para tornar texto ou resposta de rede uma
|
|
821
|
+
condição obrigatória; se ela não passar, o fluxo falha.
|
|
646
822
|
|
|
647
823
|
`network_idle` é uma espera limitada e opcional. Polling e conexões contínuas
|
|
648
824
|
não relacionadas a `url_contains` não bloqueiam o modo filtrado; prefira
|
package/config/ui-testing.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"harness_browser": "chrome",
|
|
6
6
|
"playwright_mcp_package": "@playwright/mcp@0.0.79",
|
|
7
7
|
"computer_browser": "chrome",
|
|
8
|
-
"computer_user_data_dir": "~/.cache/orquestrador/jev-browser-{browser}",
|
|
8
|
+
"computer_user_data_dir": "~/.cache/orquestrador/jev-browser-{browser}-session-{session}",
|
|
9
9
|
"max_flow_steps": 24,
|
|
10
10
|
"max_text_entry_chars": 2000
|
|
11
11
|
},
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"block_fonts_default": false,
|
|
69
69
|
"local_only_default": false,
|
|
70
70
|
"auto_angular_idle_default": false,
|
|
71
|
-
"return_snapshot_default": "
|
|
71
|
+
"return_snapshot_default": "diff",
|
|
72
72
|
"busy_selectors_default": [],
|
|
73
73
|
"login_url_contains_default": ["/auth"],
|
|
74
74
|
"login_text_default": [],
|