@diegosouzacdv/jev-browser-mcp 0.4.2 → 0.6.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 +256 -160
- package/config/ui-testing.json +18 -18
- package/docs/jev-browser-mcp.md +256 -160
- package/mcp_servers/jev-browser-npm/src/flow.mjs +1960 -1408
- package/mcp_servers/jev-browser-npm/src/server.mjs +146 -21
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,10 +17,10 @@ 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.6.0"],
|
|
21
21
|
"env": {
|
|
22
22
|
"OPENROUTER_API_KEY": "${OPENROUTER_API_KEY}",
|
|
23
|
-
"JEV_BROWSER_MODE": "computer"
|
|
23
|
+
"JEV_BROWSER_MODE": "computer"
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -31,18 +31,30 @@ O formato de interpolação de variáveis varia por harness. Injete a chave por
|
|
|
31
31
|
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
|
-
```sh
|
|
35
|
-
npm install @diegosouzacdv/jev-browser-mcp
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
34
|
+
```sh
|
|
35
|
+
npm install @diegosouzacdv/jev-browser-mcp
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Se o harness executa o MCP repetidamente nesta máquina, instale uma versão
|
|
39
|
+
fixa globalmente para evitar a resolução e o download feitos pelo `npx` em cada
|
|
40
|
+
inicialização:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
npm install --global @diegosouzacdv/jev-browser-mcp@0.6.0
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Depois configure o servidor MCP com `command: "jev-browser-mcp"` e `args: []`.
|
|
47
|
+
Para atualizar, rode `npm install --global
|
|
48
|
+
@diegosouzacdv/jev-browser-mcp@<versão>` e reinicie o processo do harness.
|
|
49
|
+
|
|
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 --install-browser`.
|
|
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`. No modo `harness`, a
|
|
56
|
+
instalação baixa uma vez o Chrome/Edge que o Playwright controlará. Personalize
|
|
57
|
+
as escolhas com `JEV_BROWSER_MODE`, `JEV_BROWSER_CHANNEL` e
|
|
46
58
|
`JEV_BROWSER_PROFILE`. O browser permanece aquecido enquanto o processo MCP
|
|
47
59
|
estiver ativo e fecha quando o harness encerra o processo. `JEV_PROVIDER_URL`
|
|
48
60
|
e `JEV_MODEL` podem substituir os valores centrais; a credencial continua no
|
|
@@ -52,28 +64,28 @@ Uma aplicação Node também pode importar `createJevBrowserServer` por
|
|
|
52
64
|
`@diegosouzacdv/jev-browser-mcp/server` e conectar o servidor ao transporte MCP
|
|
53
65
|
que ela já utiliza.
|
|
54
66
|
|
|
55
|
-
O pacote é montado em uma pasta temporária isolada: o publicador usa o campo
|
|
56
|
-
`files` do `package.json` para copiar somente o código Node, a configuração
|
|
57
|
-
compartilhada e esta documentação, que também vira o `README.md` da raiz do
|
|
58
|
-
pacote. Assim, o npm não inclui o README geral do orquestrador na página do MCP.
|
|
59
|
-
Para gerar e conferir o pacote antes de publicar, execute
|
|
60
|
-
`npm run pack:jev-browser-mcp`; para publicar uma versão já autenticada no npm, execute
|
|
61
|
-
`npm run publish:jev-browser-mcp`. A instalação por npm é a recomendada; use a
|
|
62
|
-
referência GitHub somente quando precisar experimentar uma revisão ainda não
|
|
63
|
-
publicada.
|
|
67
|
+
O pacote é montado em uma pasta temporária isolada: o publicador usa o campo
|
|
68
|
+
`files` do `package.json` para copiar somente o código Node, a configuração
|
|
69
|
+
compartilhada e esta documentação, que também vira o `README.md` da raiz do
|
|
70
|
+
pacote. Assim, o npm não inclui o README geral do orquestrador na página do MCP.
|
|
71
|
+
Para gerar e conferir o pacote antes de publicar, execute
|
|
72
|
+
`npm run pack:jev-browser-mcp`; para publicar uma versão já autenticada no npm, execute
|
|
73
|
+
`npm run publish:jev-browser-mcp`. A instalação por npm é a recomendada; use a
|
|
74
|
+
referência GitHub somente quando precisar experimentar uma revisão ainda não
|
|
75
|
+
publicada.
|
|
64
76
|
|
|
65
77
|
### Contrato do pacote
|
|
66
78
|
|
|
67
|
-
O executável oferece `choose_next_action` e `run_browser_flow`, mantém uma
|
|
79
|
+
O executável oferece `browser_health`, `choose_next_action` e `run_browser_flow`, mantém uma
|
|
68
80
|
sessão do browser por processo e reutiliza essa sessão entre chamadas. O plano
|
|
69
81
|
passado ao Jev continua declarativo: clique, preenchimento, seleção nativa,
|
|
70
82
|
hover, espera, teclas aprovadas, asserções por elemento, upload restrito a uma
|
|
71
83
|
raiz local configurada e reações idempotentes a um comentário único. Também
|
|
72
|
-
aceita um nome de iframe para as ações que ocorrem dentro dele. Não aceita
|
|
73
|
-
JavaScript enviado pelo harness nem coordenadas. Além de papel/nome acessível,
|
|
74
|
-
aceita `label`, `placeholder`, `title`, `text`, `test_id` e `selector`; CSS/XPath
|
|
75
|
-
são o último recurso e geram um aviso no resultado. Ele usa a
|
|
76
|
-
biblioteca Playwright diretamente, sem iniciar um segundo servidor MCP do
|
|
84
|
+
aceita um nome de iframe para as ações que ocorrem dentro dele. Não aceita
|
|
85
|
+
JavaScript enviado pelo harness nem coordenadas. Além de papel/nome acessível,
|
|
86
|
+
aceita `label`, `placeholder`, `title`, `text`, `test_id` e `selector`; CSS/XPath
|
|
87
|
+
são o último recurso e geram um aviso no resultado. Ele usa a
|
|
88
|
+
biblioteca Playwright diretamente, sem iniciar um segundo servidor MCP do
|
|
77
89
|
Playwright. O transporte MCP usa `stdio`; toda saída de diagnóstico vai para
|
|
78
90
|
`stderr` para não misturar com JSON-RPC.
|
|
79
91
|
|
|
@@ -89,55 +101,114 @@ a página inicial, captura o snapshot acessível e pede ao Jev que escolha um
|
|
|
89
101
|
plano. Em seguida, executa o plano inteiro na mesma sessão e confere o
|
|
90
102
|
resultado esperado na tela.
|
|
91
103
|
|
|
92
|
-
Cada plano pode usar:
|
|
93
|
-
|
|
94
|
-
- `click`, `type`, `hover`, `select_option`, `press`, `assert_*` e upload com
|
|
95
|
-
papel/nome acessível ou um localizador: `label`, `placeholder`, `title`,
|
|
96
|
-
`text`, `test_id` ou `selector`;
|
|
97
|
-
- `near: {"text":"..."}` para localizar o controle logo depois de um texto,
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
- `
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
- `
|
|
114
|
-
`
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
`
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
104
|
+
Cada plano pode usar:
|
|
105
|
+
|
|
106
|
+
- `click`, `type`, `hover`, `select_option`, `press`, `assert_*` e upload com
|
|
107
|
+
papel/nome acessível ou um localizador: `label`, `placeholder`, `title`,
|
|
108
|
+
`text`, `test_id` ou `selector`;
|
|
109
|
+
- `near: {"text":"..."}` para localizar o controle logo depois de um texto,
|
|
110
|
+
`within: {"row_containing":"..."}` para limitar por trecho e
|
|
111
|
+
`within: {"row_containing_exact":"..."}` para exigir um elemento com o
|
|
112
|
+
texto exato na linha, sem casar com `15287210` ao procurar `1528721`;
|
|
113
|
+
- `within: {"role":"dialog"}` sem `name` para usar o único diálogo visível;
|
|
114
|
+
o MCP ignora diálogos visualmente ocultos, inclusive os que ficaram no DOM
|
|
115
|
+
com `opacity: 0`;
|
|
116
|
+
- `name: ""` com `index` não negativo para controles sem nome. O resultado
|
|
117
|
+
inclui um aviso porque a posição pode mudar entre execuções. O índice é
|
|
118
|
+
zero-based para o mesmo papel e inclui nomes vazios ou compostos só por
|
|
119
|
+
espaços/glyphs de uso privado, como ícones Font Awesome; controles
|
|
120
|
+
desabilitados não aparecem no diagnóstico, mas continuam contando para que o
|
|
121
|
+
índice aponte ao controle correto;
|
|
122
|
+
- `selector` com CSS ou XPath como último recurso. O MCP identifica essa escolha
|
|
123
|
+
em `warnings`; não é permitido enviar JavaScript nem coordenadas;
|
|
124
|
+
- `timeout_seconds` opcional em cada etapa, limitado pela configuração central;
|
|
125
|
+
- `type` com `mode: "keys"` para digitar sequencialmente em campos com máscara,
|
|
126
|
+
`blur: true` para desfocar o campo e `sensitive: false` para permitir que o
|
|
127
|
+
valor apareça nas evidências. Nesse modo, `\n` envia Enter e `\t` envia Tab;
|
|
128
|
+
- `wait_for_text`, `wait_for_value`, `wait_for_enabled` e `wait_for_condition`
|
|
129
|
+
(`network_idle`, `hidden`, `text_hidden` ou `angular_idle`). `wait` recebe
|
|
130
|
+
`ms` para uma pausa curta e limitada. `angular_idle` aguarda requisições
|
|
131
|
+
`$http` e digest do AngularJS. `wait_for_text` aceita `fail_on: {"role":"alert"}` para
|
|
132
|
+
interromper a espera assim que um alerta visível aparecer e incluir seu texto
|
|
133
|
+
no erro. Se o alerta contiver o texto esperado, a etapa passa; caso contrário,
|
|
134
|
+
o alerta interrompe a espera. `network_idle` aceita `url_contains` para
|
|
135
|
+
aguardar só as requisições correspondentes;
|
|
136
|
+
- `press` (o alias legado `press_key` também é aceito) com `PageDown`, `PageUp`,
|
|
137
|
+
`Home`, `End`, setas, `Enter`, `Escape`, `Tab` ou `Shift+Tab`. Sem alvo,
|
|
138
|
+
envia a tecla ao elemento focado; com alvo, usa o localizador informado;
|
|
139
|
+
- `assert_text`, `assert_value`, `assert_visible`, `assert_hidden` e
|
|
140
|
+
`assert_enabled`; `assert_text`
|
|
141
|
+
pode receber apenas `role` quando a região, como `alert`, não tem nome acessível;
|
|
123
142
|
- `upload_file` para input rotulado, botão que abre o seletor de arquivo ou
|
|
124
143
|
dropzone;
|
|
125
144
|
- `audit_accessibility` com axe-core para WCAG 2.1 A/AA;
|
|
126
|
-
- `like_comment` e `unlike_comment`, que localizam uma linha pelo autor e texto,
|
|
127
|
-
não repetem uma reação já no estado pedido e distinguem `Curtir` de
|
|
128
|
-
`Descurtir`.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
145
|
+
- `like_comment` e `unlike_comment`, que localizam uma linha pelo autor e texto,
|
|
146
|
+
não repetem uma reação já no estado pedido e distinguem `Curtir` de
|
|
147
|
+
`Descurtir`.
|
|
148
|
+
|
|
149
|
+
As proteções e evidências por etapa usam estes campos:
|
|
150
|
+
|
|
151
|
+
- `confirm_dialog` recebe `expected_text` e `button`. O MCP exige um diálogo
|
|
152
|
+
visível único e confere se ele contém o texto esperado antes de clicar; se o
|
|
153
|
+
alerta mudou, a etapa falha sem clicar no botão. Reserve `click` comum para
|
|
154
|
+
ações que não dependem do conteúdo de uma confirmação;
|
|
155
|
+
- `mutating: true` marca etapas que gravam dados ou disparam efeitos externos.
|
|
156
|
+
Com `options.dry_run: true`, o fluxo para imediatamente antes da primeira
|
|
157
|
+
etapa marcada e retorna `dry_run_stopped_before_step` e `mutating_steps`.
|
|
158
|
+
Marque toda ação que grava ou envia algo, mesmo quando não for um botão
|
|
159
|
+
chamado Salvar;
|
|
160
|
+
- `duration_ms` aparece em cada etapa concluída ou falha. `mutating_steps`
|
|
161
|
+
lista as etapas marcadas e informa quais foram executadas;
|
|
162
|
+
- `screenshot: true` salva uma captura depois da etapa e inclui seu caminho na
|
|
163
|
+
evidência da etapa;
|
|
164
|
+
- `options.report_path` grava um resumo `.md` ou JUnit `.xml`. O caminho deve
|
|
165
|
+
ser absoluto e estar dentro de `JEV_BROWSER_ARTIFACT_DIR` (ou do diretório de
|
|
166
|
+
artefatos configurado). O relatório resume versão/status, duração, alvo e
|
|
167
|
+
`resolved_target`, asserções de rede, falhas de rede e caminhos das capturas.
|
|
168
|
+
|
|
169
|
+
`run_browser_flow` também aceita `params` como mapa de texto, números e
|
|
170
|
+
booleanos. Use `{pedido}` em `flow`, `expected_outcome` e nos campos textuais do
|
|
171
|
+
plano para reutilizar um valor sem editar o roteiro em vários lugares. A ação
|
|
172
|
+
`extract` lê `text` (padrão), `value` ou `attribute` de um elemento e salva o
|
|
173
|
+
resultado na variável indicada por `as`; etapas seguintes podem usar
|
|
174
|
+
`{documento}`. O valor extraído é tratado como sensível e fica oculto no
|
|
175
|
+
resultado por padrão; use `sensitive: false` só quando for apropriado exibi-lo.
|
|
176
|
+
`resolved_target.match_strategy` informa quando um rótulo foi
|
|
177
|
+
associado por proximidade (`label-proximity`) em vez de um `label[for]` direto.
|
|
178
|
+
|
|
179
|
+
A ação `assert_network` verifica respostas observadas depois da etapa anterior,
|
|
180
|
+
incluindo respostas 2xx ou erros esperados como 404. Exemplo:
|
|
181
|
+
|
|
182
|
+
```json
|
|
183
|
+
{
|
|
184
|
+
"action": "assert_network",
|
|
185
|
+
"url_contains": "/documentoFinanceiro/atualizar",
|
|
186
|
+
"method": "PUT",
|
|
187
|
+
"status": 404,
|
|
188
|
+
"message_contains": "Boleto não encontrado"
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Essa asserção aparece na evidência como `response_status`, separado do campo
|
|
193
|
+
`status` da etapa (`passed` ou `failed`). `message_contains` lê somente resposta
|
|
194
|
+
da mesma origem e respeita o limite configurado para captura de corpos.
|
|
195
|
+
|
|
196
|
+
Exemplo de parâmetro e extração: passe `params: {"pedido":"1528721"}`, filtre
|
|
197
|
+
com `within: {"row_containing_exact":"{pedido}"}`, e use uma etapa
|
|
198
|
+
`{"action":"extract","role":"cell","name":"{pedido}","within":{"row_containing_exact":"{pedido}"},"as":"documento"}`.
|
|
199
|
+
A etapa seguinte pode localizar o mesmo documento com `name: "{documento}"`.
|
|
200
|
+
|
|
201
|
+
Em `wait_for_condition` com `condition: "hidden"`, use qualquer um desses
|
|
202
|
+
localizadores, `near` ou `within`; `text_hidden` recebe o texto direto. Para
|
|
203
|
+
aguardar o fim de uma chamada específica, use `condition: "network_idle"` com
|
|
204
|
+
`url_contains`; o MCP precisa observar a requisição depois da etapa anterior e
|
|
205
|
+
esperar que ela termine.
|
|
206
|
+
|
|
207
|
+
Quando vários controles têm o mesmo papel e nome, `within` limita a busca a um
|
|
208
|
+
container acessível único, como uma linha, card ou diálogo. `index` escolhe uma
|
|
209
|
+
ocorrência zero-based dentro desse escopo; sem `index`, o MCP exige exatamente
|
|
210
|
+
um alvo. Para uma página com rótulo `for` quebrado, `label` também procura o
|
|
211
|
+
controle próximo ao texto visível do rótulo.
|
|
141
212
|
|
|
142
213
|
```json
|
|
143
214
|
{
|
|
@@ -149,49 +220,52 @@ controle próximo ao texto visível do rótulo.
|
|
|
149
220
|
```
|
|
150
221
|
|
|
151
222
|
```json
|
|
152
|
-
{"action":"click","role":"button","name":"Add to cart","index":0}
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
Exemplos para controles legados sem nome acessível:
|
|
156
|
-
|
|
157
|
-
```json
|
|
158
|
-
{"action":"type","role":"textbox","label":"Vencimento","text":"05/10/2026"}
|
|
159
|
-
{"action":"type","role":"textbox","target_text":"Vencimento","text":"05/10/2026"}
|
|
160
|
-
{"action":"click","role":"link","title":"Editar documento","within":{"row_containing":"1528721"}}
|
|
161
|
-
{"action":"press","key":"Enter","role":"textbox","placeholder":"Busca rápida"}
|
|
162
|
-
{"action":"click","role":"button","name":"","index":0}
|
|
163
|
-
{"action":"click","selector":"#save-document"}
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
O reconhecimento retorna `unnamed_controls_initial` e
|
|
167
|
-
`unnamed_controls_final`, cada um com papel, índice Playwright por papel, rótulo
|
|
168
|
-
mais próximo e um trecho HTML sanitizado dos controles visíveis e habilitados
|
|
169
|
-
sem nome.
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
`
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
e
|
|
223
|
+
{"action":"click","role":"button","name":"Add to cart","index":0}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Exemplos para controles legados sem nome acessível:
|
|
227
|
+
|
|
228
|
+
```json
|
|
229
|
+
{"action":"type","role":"textbox","label":"Vencimento","text":"05/10/2026"}
|
|
230
|
+
{"action":"type","role":"textbox","target_text":"Vencimento","text":"05/10/2026"}
|
|
231
|
+
{"action":"click","role":"link","title":"Editar documento","within":{"row_containing":"1528721"}}
|
|
232
|
+
{"action":"press","key":"Enter","role":"textbox","placeholder":"Busca rápida"}
|
|
233
|
+
{"action":"click","role":"button","name":"","index":0}
|
|
234
|
+
{"action":"click","selector":"#save-document"}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
O reconhecimento retorna `unnamed_controls_initial` e
|
|
238
|
+
`unnamed_controls_final`, cada um com papel, índice Playwright por papel, rótulo
|
|
239
|
+
mais próximo e um trecho HTML sanitizado dos controles visíveis e habilitados
|
|
240
|
+
sem nome. Nomes vazios ou compostos apenas por espaços e glyphs da área Unicode
|
|
241
|
+
de uso privado (como ícones Font Awesome) entram nessa lista e podem ser
|
|
242
|
+
selecionados com `name: ""` e o mesmo índice. `unnamed_controls` continua
|
|
243
|
+
disponível como alias da lista final. O placeholder conta como nome acessível.
|
|
244
|
+
O snapshot também resume campos de formulário com `id`, `name`, valor, estado
|
|
245
|
+
desabilitado, rótulo e índice zero-based entre campos de mesmo nome. Valores
|
|
246
|
+
sensíveis, como senha, token e cartão, são ocultados. `snapshot_include_hidden`
|
|
247
|
+
é `false` por padrão; defina `true` somente quando precisar inspecionar campos
|
|
248
|
+
ocultos também.
|
|
249
|
+
|
|
250
|
+
Em uma etapa `type`, `text` contém o valor a digitar; use `target_text` para
|
|
251
|
+
localizar pelo texto visível próximo ao campo. Esse localizador exige `role`
|
|
252
|
+
`textbox`, `searchbox` ou `combobox`.
|
|
253
|
+
|
|
254
|
+
Por padrão, o MCP executa todos os passos antes de avaliar `expected_outcome`.
|
|
255
|
+
Valores dentro de campos não contam como resultado visível. `stop_on_expected:
|
|
256
|
+
true` habilita parada antecipada quando o texto esperado aparece fora dos
|
|
257
|
+
campos; mantenha `false` para fluxos com várias etapas.
|
|
258
|
+
|
|
259
|
+
Os erros de validação apontam o campo inválido e os campos aceitos. Os limites
|
|
260
|
+
de `timeout_seconds` informam o máximo configurado, em vez de exigir tentativa
|
|
261
|
+
e erro.
|
|
189
262
|
|
|
190
263
|
### Captura de downloads
|
|
191
264
|
|
|
192
265
|
Marque o clique que deve iniciar um download com `expect_download: true`. O
|
|
193
|
-
Playwright começa a aguardar o evento antes do clique;
|
|
194
|
-
|
|
266
|
+
Playwright começa a aguardar o evento antes do clique; isso também captura
|
|
267
|
+
downloads gerados por `URL.createObjectURL` (por exemplo, PDFs Blob). Após a
|
|
268
|
+
transferência terminar, o MCP verifica o tamanho, sanitiza o nome sugerido e copia o arquivo
|
|
195
269
|
para `JEV_BROWSER_ARTIFACT_DIR` (ou para o diretório de artefatos configurado).
|
|
196
270
|
O resultado inclui a lista `downloaded_files`, com nome, caminho local e bytes;
|
|
197
271
|
cada passo também contém o arquivo capturado. Os limites contam arquivos e bytes
|
|
@@ -222,13 +296,13 @@ trechos da página. Qualquer violação reprova esse fluxo. A auditoria automát
|
|
|
222
296
|
encontra problemas comuns, mas não comprova conformidade WCAG completa; combine-a
|
|
223
297
|
com revisão manual e testes com usuários assistivos.
|
|
224
298
|
|
|
225
|
-
Para ações em iframe, acrescente `"frame": "payment-iframe"`; o valor precisa
|
|
226
|
-
corresponder ao atributo `name` ou `title` do iframe. O snapshot inclui o
|
|
227
|
-
conteúdo acessível dos iframes nomeados dentro do escopo, limitado pela
|
|
228
|
-
configuração. Se um alvo estiver ausente, o erro inclui até três nomes acessíveis
|
|
229
|
-
próximos quando o snapshot os encontrar. CSS/XPath são permitidos somente como
|
|
230
|
-
localizadores explícitos de último recurso e geram aviso. O plano não aceita
|
|
231
|
-
JavaScript enviado pelo harness nem coordenadas.
|
|
299
|
+
Para ações em iframe, acrescente `"frame": "payment-iframe"`; o valor precisa
|
|
300
|
+
corresponder ao atributo `name` ou `title` do iframe. O snapshot inclui o
|
|
301
|
+
conteúdo acessível dos iframes nomeados dentro do escopo, limitado pela
|
|
302
|
+
configuração. Se um alvo estiver ausente, o erro inclui até três nomes acessíveis
|
|
303
|
+
próximos quando o snapshot os encontrar. CSS/XPath são permitidos somente como
|
|
304
|
+
localizadores explícitos de último recurso e geram aviso. O plano não aceita
|
|
305
|
+
JavaScript enviado pelo harness nem coordenadas.
|
|
232
306
|
|
|
233
307
|
Os aliases `value` → `text` em `type`/`wait_for_text` e `value` → `expected` em
|
|
234
308
|
asserções são aceitos. `comment` também é aceito em planos e passos, mas é
|
|
@@ -311,9 +385,9 @@ do pacote Node ficam no bloco opcional `jev_browser_mcp`, que não altera o
|
|
|
311
385
|
contrato lido pelo servidor Python. Preserve a estrutura completa exigida pelos
|
|
312
386
|
validadores.
|
|
313
387
|
|
|
314
|
-
`browser.mode` aceita `harness` ou `computer`; o padrão é `computer`:
|
|
388
|
+
`browser.mode` aceita `harness` ou `computer`; o padrão é `computer`:
|
|
315
389
|
|
|
316
|
-
- `harness` usa Chrome headless e contexto isolado, adequado a execuções do
|
|
390
|
+
- `harness` usa Chrome headless e contexto isolado, adequado a execuções do
|
|
317
391
|
harness e CI; o estado de autenticação é descartado ao final da chamada.
|
|
318
392
|
- `computer` abre o Chrome ou Edge instalado em modo visível e usa o diretório
|
|
319
393
|
persistente `browser.computer_user_data_dir`, separado por navegador. Não
|
|
@@ -322,23 +396,23 @@ validadores.
|
|
|
322
396
|
|
|
323
397
|
`browser.max_flow_steps` limita a soma de passos declarados entre os planos e
|
|
324
398
|
`browser.max_text_entry_chars` limita cada valor digitado. O resultado contém
|
|
325
|
-
`status`, o plano escolhido, as ações executadas, a última captura acessível e
|
|
326
|
-
se o critério esperado apareceu. Quando existem asserções explícitas, `status`
|
|
327
|
-
também pode ser `passed` com todas elas satisfeitas; `assertions_passed` registra
|
|
328
|
-
esse resultado e `expected_outcome_visible` continua descrevendo somente o
|
|
329
|
-
texto global. `incomplete` significa que nenhum critério foi comprovado;
|
|
330
|
-
confiança do Jev não substitui essa verificação. `timings_ms.ready_ms` mede a
|
|
331
|
-
espera da SPA; `warnings` registra capturas vazias durante transições; e
|
|
332
|
-
`failed_step` identifica índice, ação, localizador, timeout e erro resumido
|
|
333
|
-
quando uma etapa falha. Cada etapa executada também registra a composição do
|
|
334
|
-
localizador usado e, quando disponível, `resolved_target` com tag, `id`, papel
|
|
335
|
-
|
|
336
|
-
do campo quando `sensitive: false`.
|
|
337
|
-
|
|
338
|
-
Com `capture_network_error_bodies: true`, respostas JSON de erro da mesma
|
|
339
|
-
origem são capturadas mesmo quando usam transferência chunked e não enviam
|
|
340
|
-
`Content-Length`. Corpos acima do limite, com formato inválido ou que não
|
|
341
|
-
podem ser lidos com segurança são omitidos e explicados em `warnings`.
|
|
399
|
+
`status`, o plano escolhido, as ações executadas, a última captura acessível e
|
|
400
|
+
se o critério esperado apareceu. Quando existem asserções explícitas, `status`
|
|
401
|
+
também pode ser `passed` com todas elas satisfeitas; `assertions_passed` registra
|
|
402
|
+
esse resultado e `expected_outcome_visible` continua descrevendo somente o
|
|
403
|
+
texto global. `incomplete` significa que nenhum critério foi comprovado;
|
|
404
|
+
confiança do Jev não substitui essa verificação. `timings_ms.ready_ms` mede a
|
|
405
|
+
espera da SPA; `warnings` registra capturas vazias durante transições; e
|
|
406
|
+
`failed_step` identifica índice, ação, localizador, timeout e erro resumido
|
|
407
|
+
quando uma etapa falha. Cada etapa executada também registra a composição do
|
|
408
|
+
localizador usado e, quando disponível, `resolved_target` com tag, `id`, papel,
|
|
409
|
+
nome acessível, `title` casado e `href` sanitizado do elemento resolvido.
|
|
410
|
+
Etapas `type` só incluem o valor final do campo quando `sensitive: false`.
|
|
411
|
+
|
|
412
|
+
Com `capture_network_error_bodies: true`, respostas JSON de erro da mesma
|
|
413
|
+
origem são capturadas mesmo quando usam transferência chunked e não enviam
|
|
414
|
+
`Content-Length`. Corpos acima do limite, com formato inválido ou que não
|
|
415
|
+
podem ser lidos com segurança são omitidos e explicados em `warnings`.
|
|
342
416
|
|
|
343
417
|
`jev_browser_mcp.browser.max_action_timeout_seconds` limita esperas por ações,
|
|
344
418
|
seletores e condições. `JEV_BROWSER_UPLOAD_ROOT` libera uploads somente dentro
|
|
@@ -354,20 +428,26 @@ Os limites de download ficam no mesmo bloco: `max_download_files`,
|
|
|
354
428
|
limita quantas descrições de violações axe entram no resultado; a contagem total
|
|
355
429
|
continua informada mesmo quando a lista é truncada.
|
|
356
430
|
|
|
357
|
-
O `run_browser_flow` aceita `options` com `fast_path`, `snapshot_scope`,
|
|
358
|
-
`block_trackers`, `capture_console_errors`, `capture_network_errors`,
|
|
359
|
-
`capture_network_error_bodies`, `ready_timeout_seconds`, `ready_network_idle`,
|
|
360
|
-
`ready_stable_ms`, `ready_text`, `reuse_page`, `screenshot_on_failure`,
|
|
361
|
-
`trace_on_failure`, `snapshot_include_hidden
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
de
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
`
|
|
370
|
-
`
|
|
431
|
+
O `run_browser_flow` aceita `options` com `fast_path`, `snapshot_scope`,
|
|
432
|
+
`block_trackers`, `capture_console_errors`, `capture_network_errors`,
|
|
433
|
+
`capture_network_error_bodies`, `ready_timeout_seconds`, `ready_network_idle`,
|
|
434
|
+
`ready_stable_ms`, `ready_text`, `continue_from_current_page`, `reuse_page`, `screenshot_on_failure`,
|
|
435
|
+
`trace_on_failure`, `snapshot_include_hidden`, `stop_on_expected`, `dry_run` e
|
|
436
|
+
`report_path`. Sem override,
|
|
437
|
+
os padrões são lidos de `jev_browser_mcp` em
|
|
438
|
+
`config/ui-testing.json`: um plano candidato pula a chamada Decisions;
|
|
439
|
+
captura de console e screenshot de falha ficam ligadas; trace, rede e bloqueio
|
|
440
|
+
de recursos ficam desligados; o plano roda até o fim e campos ocultos não são
|
|
441
|
+
acrescentados ao snapshot. O browser espera a SPA renderizar uma captura
|
|
442
|
+
acessível estável na navegação inicial. Depois, a continuidade fica ligada por
|
|
443
|
+
padrão: `continue_from_current_page: true` mantém a página e seu estado entre
|
|
444
|
+
chamadas na mesma origem, não repete `page.goto` e consulta um snapshot atual
|
|
445
|
+
sem esperar novamente por `load`/`networkidle`. As etapas continuam aguardando
|
|
446
|
+
seus próprios alvos e condições. `reuse_page` segue como alias legado; defina
|
|
447
|
+
`continue_from_current_page: false` para iniciar cada chamada em `initial_url`.
|
|
448
|
+
Se a página atual e `initial_url` tiverem origens diferentes, o MCP navega para
|
|
449
|
+
`initial_url`. `snapshot_scope` aceita `body`, `main` ou `dialog`; se `main` não
|
|
450
|
+
existir, o snapshot usa `body`.
|
|
371
451
|
|
|
372
452
|
`block_trackers: true` bloqueia os domínios e tipos de recurso listados na
|
|
373
453
|
configuração (analytics, Hotjar, fontes externas e mídia). Isso pode alterar o
|
|
@@ -375,12 +455,12 @@ layout ou o comportamento do site, então a opção é desligada por padrão.
|
|
|
375
455
|
|
|
376
456
|
Com `capture_console_errors` e `capture_network_errors`, o retorno traz
|
|
377
457
|
`console_errors` e `network_failures`, limitados em quantidade e tamanho.
|
|
378
|
-
Respostas HTTP 4xx/5xx e requisições que falham são listadas; query strings,
|
|
379
|
-
fragmentos, valores de formulário e nomes de arquivo são removidos ou
|
|
380
|
-
sanitizados. `capture_network_error_bodies: true` lê somente respostas JSON
|
|
381
|
-
4xx/5xx da mesma origem, limita o corpo e inclui apenas o campo textual
|
|
382
|
-
`message`, também sanitizado. Em falhas, `screenshot_on_failure` salva
|
|
383
|
-
screenshot local e retorna
|
|
458
|
+
Respostas HTTP 4xx/5xx e requisições que falham são listadas; query strings,
|
|
459
|
+
fragmentos, valores de formulário e nomes de arquivo são removidos ou
|
|
460
|
+
sanitizados. `capture_network_error_bodies: true` lê somente respostas JSON
|
|
461
|
+
4xx/5xx da mesma origem, limita o corpo e inclui apenas o campo textual
|
|
462
|
+
`message`, também sanitizado. Em falhas, `screenshot_on_failure` salva
|
|
463
|
+
screenshot local e retorna
|
|
384
464
|
`screenshot_path`. `trace_on_failure: true` também grava um `.zip` compatível
|
|
385
465
|
com o Trace Viewer do Playwright e retorna `trace_path`. O diretório padrão é
|
|
386
466
|
`~/.cache/orquestrador/jev-browser-artifacts`; `JEV_BROWSER_ARTIFACT_DIR` pode
|
|
@@ -388,6 +468,22 @@ substituí-lo por uma pasta absoluta fora do pacote. Screenshots e traces podem
|
|
|
388
468
|
conter dados visíveis da aplicação: mantenha o diretório local protegido e
|
|
389
469
|
compartilhe os arquivos somente se o teste permitir.
|
|
390
470
|
|
|
471
|
+
Screenshots por etapa usam `screenshot: true` no próprio passo; o MCP os grava
|
|
472
|
+
depois que a ação termina. `options.report_path` pode apontar para `.md` ou
|
|
473
|
+
JUnit `.xml` dentro da raiz de artefatos. O relatório inclui a versão, tempos,
|
|
474
|
+
localizadores resolvidos, respostas verificadas por `assert_network`, falhas de
|
|
475
|
+
rede e caminhos dos screenshots, para anexar a um PR ou card.
|
|
476
|
+
|
|
477
|
+
Se o Chrome/Edge não iniciar porque o perfil persistente já está aberto, o erro
|
|
478
|
+
identifica o PID que o mantém ocupado quando o sistema consegue associar o
|
|
479
|
+
perfil ao processo. Em Windows, o MCP consulta a linha de comando dos processos
|
|
480
|
+
Chrome/Edge; em outros sistemas, usa o `SingletonLock` do Chromium. Configure
|
|
481
|
+
`JEV_BROWSER_PROFILE` com outro diretório absoluto para usar uma sessão isolada.
|
|
482
|
+
Resultados MCP incluem `server_version`; erros também começam com a versão do
|
|
483
|
+
servidor para facilitar a comparação entre instalações. A ferramenta
|
|
484
|
+
`browser_health` informa se a sessão está ativa e tenta reconectar um browser
|
|
485
|
+
que encerrou desde a chamada anterior.
|
|
486
|
+
|
|
391
487
|
`harness_browser` e `computer_browser` aceitam `chrome` ou `msedge`.
|
|
392
488
|
`computer_user_data_dir` deve ficar fora do repositório e conter `{browser}`;
|
|
393
489
|
o diretório persistente armazena dados de login e é resolvido sob a pasta home
|
package/config/ui-testing.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 1,
|
|
3
3
|
"browser": {
|
|
4
|
-
"mode": "computer",
|
|
4
|
+
"mode": "computer",
|
|
5
5
|
"harness_browser": "chrome",
|
|
6
6
|
"playwright_mcp_package": "@playwright/mcp@0.0.79",
|
|
7
7
|
"computer_browser": "chrome",
|
|
@@ -22,23 +22,23 @@
|
|
|
22
22
|
},
|
|
23
23
|
"jev_browser_mcp": {
|
|
24
24
|
"browser": {
|
|
25
|
-
"max_action_timeout_seconds": 8,
|
|
26
|
-
"ready_timeout_seconds_default": 15,
|
|
27
|
-
"max_ready_timeout_seconds": 60,
|
|
28
|
-
"ready_network_idle_default": true,
|
|
29
|
-
"ready_stable_ms_default": 400,
|
|
30
|
-
"max_ready_stable_ms": 2000,
|
|
31
|
-
"post_step_ready_timeout_seconds_default": 5,
|
|
32
|
-
"max_step_timeout_seconds":
|
|
33
|
-
"key_delay_ms_default": 30,
|
|
34
|
-
"reuse_page_default":
|
|
35
|
-
"stop_on_expected_default": false,
|
|
36
|
-
"snapshot_include_hidden_default": false,
|
|
37
|
-
"visibility_poll_interval_ms_default": 50,
|
|
38
|
-
"capture_network_error_bodies_default": false,
|
|
39
|
-
"max_network_error_body_bytes": 65536,
|
|
40
|
-
"max_network_error_message_chars": 300,
|
|
41
|
-
"max_upload_files": 5,
|
|
25
|
+
"max_action_timeout_seconds": 8,
|
|
26
|
+
"ready_timeout_seconds_default": 15,
|
|
27
|
+
"max_ready_timeout_seconds": 60,
|
|
28
|
+
"ready_network_idle_default": true,
|
|
29
|
+
"ready_stable_ms_default": 400,
|
|
30
|
+
"max_ready_stable_ms": 2000,
|
|
31
|
+
"post_step_ready_timeout_seconds_default": 5,
|
|
32
|
+
"max_step_timeout_seconds": 300,
|
|
33
|
+
"key_delay_ms_default": 30,
|
|
34
|
+
"reuse_page_default": true,
|
|
35
|
+
"stop_on_expected_default": false,
|
|
36
|
+
"snapshot_include_hidden_default": false,
|
|
37
|
+
"visibility_poll_interval_ms_default": 50,
|
|
38
|
+
"capture_network_error_bodies_default": false,
|
|
39
|
+
"max_network_error_body_bytes": 65536,
|
|
40
|
+
"max_network_error_message_chars": 300,
|
|
41
|
+
"max_upload_files": 5,
|
|
42
42
|
"max_upload_path_chars": 4096,
|
|
43
43
|
"max_upload_file_bytes": 10485760,
|
|
44
44
|
"max_upload_total_bytes": 26214400,
|