sincron-auto 1.0.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.
@@ -0,0 +1,497 @@
1
+ # Exemplos de Comandos Playwright MCP
2
+
3
+ Este documento fornece exemplos práticos de como usar os comandos Playwright MCP para testes visuais e funcionais.
4
+
5
+ ## Navegação
6
+
7
+ ### Navegar para uma URL
8
+
9
+ ```typescript
10
+ mcp__playwright__navigate({
11
+ url: "http://localhost:3000"
12
+ })
13
+ ```
14
+
15
+ ### Aguardar navegação para URL específica
16
+
17
+ ```typescript
18
+ mcp__playwright__wait_for_url({
19
+ url: "/dashboard",
20
+ timeout: 5000 // opcional, em ms
21
+ })
22
+ ```
23
+
24
+ ## Query de Elementos
25
+
26
+ ### Buscar elemento por seletor
27
+
28
+ ```typescript
29
+ mcp__playwright__query_selector({
30
+ selector: "#btn-submit"
31
+ })
32
+ // Retorna: elemento encontrado ou erro se não existir
33
+ ```
34
+
35
+ ### Buscar múltiplos elementos
36
+
37
+ ```typescript
38
+ mcp__playwright__query_selector_all({
39
+ selector: ".task-item"
40
+ })
41
+ // Retorna: array de elementos
42
+ ```
43
+
44
+ ## Interações
45
+
46
+ ### Clicar em elemento
47
+
48
+ ```typescript
49
+ mcp__playwright__click({
50
+ selector: "#btn-submit",
51
+ timeout: 5000 // opcional
52
+ })
53
+ ```
54
+
55
+ ### Preencher campo de input
56
+
57
+ ```typescript
58
+ mcp__playwright__fill({
59
+ selector: "#email",
60
+ value: "usuario@exemplo.com"
61
+ })
62
+ ```
63
+
64
+ ### Digitar texto (simula digitação real)
65
+
66
+ ```typescript
67
+ mcp__playwright__type({
68
+ selector: "#search",
69
+ text: "buscar produto",
70
+ delay: 100 // delay entre teclas em ms
71
+ })
72
+ ```
73
+
74
+ ### Pressionar tecla
75
+
76
+ ```typescript
77
+ mcp__playwright__press({
78
+ selector: "#search",
79
+ key: "Enter"
80
+ })
81
+ ```
82
+
83
+ ### Selecionar opção em dropdown
84
+
85
+ ```typescript
86
+ mcp__playwright__select_option({
87
+ selector: "#country",
88
+ value: "BR"
89
+ })
90
+ ```
91
+
92
+ ### Marcar/desmarcar checkbox
93
+
94
+ ```typescript
95
+ mcp__playwright__check({
96
+ selector: "#accept-terms"
97
+ })
98
+
99
+ mcp__playwright__uncheck({
100
+ selector: "#newsletter"
101
+ })
102
+ ```
103
+
104
+ ## Captura de Tela
105
+
106
+ ### Screenshot de página inteira
107
+
108
+ ```typescript
109
+ mcp__playwright__screenshot({
110
+ path: "./screenshots/full-page.png",
111
+ fullPage: true
112
+ })
113
+ ```
114
+
115
+ ### Screenshot de elemento específico
116
+
117
+ ```typescript
118
+ mcp__playwright__screenshot({
119
+ path: "./screenshots/login-form.png",
120
+ selector: "#login-form"
121
+ })
122
+ ```
123
+
124
+ ## Verificação de CSS e Estilos
125
+
126
+ ### Obter propriedade computada de CSS
127
+
128
+ ```typescript
129
+ mcp__playwright__eval({
130
+ expression: "getComputedStyle(document.querySelector('#btn-submit')).backgroundColor"
131
+ })
132
+ // Retorna: "rgb(37, 99, 235)"
133
+ ```
134
+
135
+ ### Verificar múltiplas propriedades
136
+
137
+ ```typescript
138
+ mcp__playwright__eval({
139
+ expression: `
140
+ const btn = document.querySelector('#btn-submit');
141
+ const style = getComputedStyle(btn);
142
+ return {
143
+ backgroundColor: style.backgroundColor,
144
+ color: style.color,
145
+ fontSize: style.fontSize,
146
+ fontFamily: style.fontFamily,
147
+ padding: style.padding
148
+ };
149
+ `
150
+ })
151
+ ```
152
+
153
+ ### Verificar alinhamento
154
+
155
+ ```typescript
156
+ mcp__playwright__eval({
157
+ expression: `
158
+ const elem = document.querySelector('#login-form');
159
+ const rect = elem.getBoundingClientRect();
160
+ const parent = elem.parentElement.getBoundingClientRect();
161
+
162
+ // Check if horizontally centered
163
+ const horizontalCenter = Math.abs(
164
+ (parent.width / 2) - (rect.left - parent.left + rect.width / 2)
165
+ ) < 5;
166
+
167
+ // Check if vertically centered
168
+ const verticalCenter = Math.abs(
169
+ (parent.height / 2) - (rect.top - parent.top + rect.height / 2)
170
+ ) < 5;
171
+
172
+ return { horizontalCenter, verticalCenter };
173
+ `
174
+ })
175
+ ```
176
+
177
+ ## Responsividade
178
+
179
+ ### Definir viewport (tamanho da tela)
180
+
181
+ ```typescript
182
+ // Mobile
183
+ mcp__playwright__set_viewport({
184
+ width: 320,
185
+ height: 568
186
+ })
187
+
188
+ // Tablet
189
+ mcp__playwright__set_viewport({
190
+ width: 768,
191
+ height: 1024
192
+ })
193
+
194
+ // Desktop
195
+ mcp__playwright__set_viewport({
196
+ width: 1920,
197
+ height: 1080
198
+ })
199
+ ```
200
+
201
+ ### Testar responsividade completa
202
+
203
+ ```typescript
204
+ // 1. Definir viewport mobile
205
+ mcp__playwright__set_viewport({ width: 320, height: 568 })
206
+
207
+ // 2. Capturar screenshot
208
+ mcp__playwright__screenshot({ path: "./mobile.png" })
209
+
210
+ // 3. Verificar se menu mobile está visível
211
+ mcp__playwright__eval({
212
+ expression: `
213
+ const mobileMenu = document.querySelector('.mobile-menu');
214
+ return mobileMenu && getComputedStyle(mobileMenu).display !== 'none';
215
+ `
216
+ })
217
+
218
+ // 4. Mudar para desktop
219
+ mcp__playwright__set_viewport({ width: 1920, height: 1080 })
220
+
221
+ // 5. Verificar se menu desktop está visível
222
+ mcp__playwright__eval({
223
+ expression: `
224
+ const desktopMenu = document.querySelector('.desktop-menu');
225
+ return desktopMenu && getComputedStyle(desktopMenu).display !== 'none';
226
+ `
227
+ })
228
+ ```
229
+
230
+ ## Detecção de Problemas Visuais
231
+
232
+ ### Detectar sobreposições
233
+
234
+ ```typescript
235
+ mcp__playwright__eval({
236
+ expression: `
237
+ function checkOverlaps() {
238
+ const elements = Array.from(document.querySelectorAll('body *'));
239
+ let overlaps = [];
240
+
241
+ for (let i = 0; i < elements.length; i++) {
242
+ const rect1 = elements[i].getBoundingClientRect();
243
+ if (rect1.width === 0 || rect1.height === 0) continue;
244
+
245
+ for (let j = i + 1; j < elements.length; j++) {
246
+ const rect2 = elements[j].getBoundingClientRect();
247
+ if (rect2.width === 0 || rect2.height === 0) continue;
248
+
249
+ // Check if rectangles overlap
250
+ const overlap = !(
251
+ rect1.right < rect2.left ||
252
+ rect1.left > rect2.right ||
253
+ rect1.bottom < rect2.top ||
254
+ rect1.top > rect2.bottom
255
+ );
256
+
257
+ if (overlap && !elements[i].contains(elements[j]) && !elements[j].contains(elements[i])) {
258
+ overlaps.push({
259
+ element1: elements[i].tagName + (elements[i].id ? '#' + elements[i].id : ''),
260
+ element2: elements[j].tagName + (elements[j].id ? '#' + elements[j].id : '')
261
+ });
262
+ }
263
+ }
264
+ }
265
+
266
+ return overlaps;
267
+ }
268
+ checkOverlaps();
269
+ `
270
+ })
271
+ ```
272
+
273
+ ### Detectar barras de rolagem duplas
274
+
275
+ ```typescript
276
+ mcp__playwright__eval({
277
+ expression: `
278
+ const scrollableElements = Array.from(document.querySelectorAll('*')).filter(el => {
279
+ const style = getComputedStyle(el);
280
+ return (
281
+ style.overflow === 'auto' ||
282
+ style.overflow === 'scroll' ||
283
+ style.overflowX === 'auto' ||
284
+ style.overflowX === 'scroll' ||
285
+ style.overflowY === 'auto' ||
286
+ style.overflowY === 'scroll'
287
+ );
288
+ });
289
+
290
+ return {
291
+ count: scrollableElements.length,
292
+ elements: scrollableElements.map(el => ({
293
+ tag: el.tagName,
294
+ id: el.id,
295
+ class: el.className
296
+ }))
297
+ };
298
+ `
299
+ })
300
+ ```
301
+
302
+ ### Verificar elementos fora da viewport
303
+
304
+ ```typescript
305
+ mcp__playwright__eval({
306
+ expression: `
307
+ const viewportWidth = window.innerWidth;
308
+ const viewportHeight = window.innerHeight;
309
+
310
+ const elementsOutside = Array.from(document.querySelectorAll('body *')).filter(el => {
311
+ const rect = el.getBoundingClientRect();
312
+ return (
313
+ rect.right < 0 ||
314
+ rect.left > viewportWidth ||
315
+ rect.bottom < 0 ||
316
+ rect.top > viewportHeight
317
+ );
318
+ }).map(el => ({
319
+ tag: el.tagName,
320
+ id: el.id,
321
+ class: el.className,
322
+ position: el.getBoundingClientRect()
323
+ }));
324
+
325
+ return elementsOutside;
326
+ `
327
+ })
328
+ ```
329
+
330
+ ## Acessibilidade
331
+
332
+ ### Verificar contraste de cores (WCAG)
333
+
334
+ ```typescript
335
+ mcp__playwright__eval({
336
+ expression: `
337
+ function getLuminance(r, g, b) {
338
+ const [rs, gs, bs] = [r, g, b].map(c => {
339
+ c = c / 255;
340
+ return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
341
+ });
342
+ return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
343
+ }
344
+
345
+ function getContrastRatio(rgb1, rgb2) {
346
+ const l1 = getLuminance(...rgb1);
347
+ const l2 = getLuminance(...rgb2);
348
+ const lighter = Math.max(l1, l2);
349
+ const darker = Math.min(l1, l2);
350
+ return (lighter + 0.05) / (darker + 0.05);
351
+ }
352
+
353
+ function rgbStringToArray(rgb) {
354
+ const match = rgb.match(/rgb\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)/);
355
+ return match ? [parseInt(match[1]), parseInt(match[2]), parseInt(match[3])] : null;
356
+ }
357
+
358
+ const btn = document.querySelector('button');
359
+ const style = getComputedStyle(btn);
360
+ const fg = rgbStringToArray(style.color);
361
+ const bg = rgbStringToArray(style.backgroundColor);
362
+
363
+ if (fg && bg) {
364
+ const ratio = getContrastRatio(fg, bg);
365
+ return {
366
+ ratio: ratio.toFixed(2),
367
+ wcagAA: ratio >= 4.5,
368
+ wcagAAA: ratio >= 7
369
+ };
370
+ }
371
+ return { error: 'Could not parse colors' };
372
+ `
373
+ })
374
+ ```
375
+
376
+ ### Verificar área mínima de toque (44x44px)
377
+
378
+ ```typescript
379
+ mcp__playwright__eval({
380
+ expression: `
381
+ const interactiveElements = document.querySelectorAll('button, a, input, select, textarea');
382
+ const tooSmall = Array.from(interactiveElements).filter(el => {
383
+ const rect = el.getBoundingClientRect();
384
+ return rect.width < 44 || rect.height < 44;
385
+ }).map(el => ({
386
+ tag: el.tagName,
387
+ id: el.id,
388
+ width: el.getBoundingClientRect().width,
389
+ height: el.getBoundingClientRect().height
390
+ }));
391
+
392
+ return {
393
+ total: interactiveElements.length,
394
+ tooSmall: tooSmall.length,
395
+ details: tooSmall
396
+ };
397
+ `
398
+ })
399
+ ```
400
+
401
+ ## Aguardar Condições
402
+
403
+ ### Aguardar elemento estar visível
404
+
405
+ ```typescript
406
+ mcp__playwright__wait_for_selector({
407
+ selector: "#success-message",
408
+ state: "visible",
409
+ timeout: 5000
410
+ })
411
+ ```
412
+
413
+ ### Aguardar elemento ser removido
414
+
415
+ ```typescript
416
+ mcp__playwright__wait_for_selector({
417
+ selector: ".loading-spinner",
418
+ state: "detached",
419
+ timeout: 10000
420
+ })
421
+ ```
422
+
423
+ ## Fluxo Completo: Teste de Formulário de Login
424
+
425
+ ```typescript
426
+ // 1. Navegar para página
427
+ mcp__playwright__navigate({ url: "http://localhost:3000/login" })
428
+
429
+ // 2. Verificar elementos existem
430
+ mcp__playwright__query_selector({ selector: "#email" })
431
+ mcp__playwright__query_selector({ selector: "#password" })
432
+ mcp__playwright__query_selector({ selector: "#btn-submit" })
433
+
434
+ // 3. Capturar screenshot inicial
435
+ mcp__playwright__screenshot({ path: "./login-initial.png" })
436
+
437
+ // 4. Preencher formulário
438
+ mcp__playwright__fill({ selector: "#email", value: "usuario@teste.com" })
439
+ mcp__playwright__fill({ selector: "#password", value: "senha123" })
440
+
441
+ // 5. Verificar botão está habilitado
442
+ mcp__playwright__eval({
443
+ expression: "!document.querySelector('#btn-submit').disabled"
444
+ })
445
+
446
+ // 6. Clicar em submit
447
+ mcp__playwright__click({ selector: "#btn-submit" })
448
+
449
+ // 7. Aguardar navegação
450
+ mcp__playwright__wait_for_url({ url: "/dashboard" })
451
+
452
+ // 8. Capturar screenshot final
453
+ mcp__playwright__screenshot({ path: "./login-success.png" })
454
+
455
+ // 9. Verificar estética do formulário
456
+ mcp__playwright__set_viewport({ width: 320, height: 568 })
457
+ mcp__playwright__eval({
458
+ expression: `
459
+ const form = document.querySelector('form');
460
+ const style = getComputedStyle(form);
461
+ return {
462
+ centered: style.margin === 'auto' || style.justifyContent === 'center',
463
+ noOverflow: style.overflow !== 'scroll',
464
+ appropriatePadding: parseInt(style.padding) >= 16
465
+ };
466
+ `
467
+ })
468
+ ```
469
+
470
+ ## Dicas e Boas Práticas
471
+
472
+ ### 1. Sempre usar timeouts apropriados
473
+ - Operações rápidas (clicks): 5000ms
474
+ - Navegação: 10000ms
475
+ - Carregamento de dados: 15000ms
476
+
477
+ ### 2. Capturar screenshots em pontos-chave
478
+ - Estado inicial
479
+ - Após cada interação importante
480
+ - Estados de erro
481
+ - Estado final
482
+
483
+ ### 3. Testar em múltiplas resoluções
484
+ - Mobile: 320x568, 375x667, 414x896
485
+ - Tablet: 768x1024, 1024x768
486
+ - Desktop: 1366x768, 1920x1080, 2560x1440
487
+
488
+ ### 4. Verificar estados interativos
489
+ - Hover (não disponível via Playwright MCP, verificar CSS)
490
+ - Active (verificar após click)
491
+ - Focus (verificar após navegação por teclado)
492
+ - Disabled (verificar propriedade)
493
+
494
+ ### 5. Documentar falhas com evidências
495
+ - Sempre incluir screenshot quando teste falhar
496
+ - Incluir valores esperados vs obtidos
497
+ - Registrar seletor usado e resultado
@@ -0,0 +1,180 @@
1
+ # Fluxo de Mensagens entre Agentes
2
+
3
+ ## Notificações e Comunicação
4
+
5
+ ### 1. Orquestrador → Estrutura
6
+ **Momento**: Primeira execução (quando `sincron-auto-state` não existe)
7
+ **Mensagem**: Demanda do usuário
8
+ **Ação**: Estrutura configura permissões
9
+
10
+ ---
11
+
12
+ ### 2. Estrutura → Gestor Projeto
13
+ **Momento**: Após configurar permissões
14
+ **Mensagem**: Demanda do usuário + configuração completa
15
+ **Ação**: Gestor Projeto cria `sincron-auto-state` e inicia planejamento
16
+
17
+ ---
18
+
19
+ ### 3. Orquestrador → Gestor Projeto
20
+ **Momento**: Quando `sincron-auto-state` já existe
21
+ **Mensagem**: Demanda do usuário
22
+ **Ação**: Gestor Projeto interpreta tipo de demanda
23
+
24
+ ---
25
+
26
+ ### 4. Gestor Projeto → Construtor
27
+ **Momento**: Após Skill Gerenciar identificar próxima task
28
+ **Ação prévia**: Gestor atualiza status da task de `pendente` para `em execução`
29
+ **Mensagem**:
30
+ ```json
31
+ {
32
+ "task_id": "task-001",
33
+ "name": "Nome da Task",
34
+ "description": "Descrição do que fazer",
35
+ "user_stories": ["..."],
36
+ "acceptance_criteria": ["..."],
37
+ "status": "em execução"
38
+ }
39
+ ```
40
+ **Ação**: Construtor implementa a task
41
+
42
+ ---
43
+
44
+ ### 5. Construtor → Avaliador
45
+ **Momento**: Após concluir construção da task
46
+ **Mensagem**:
47
+ ```json
48
+ {
49
+ "task_id": "task-001",
50
+ "status": "ready_for_evaluation",
51
+ "files_changed": ["file1.js", "file2.html"],
52
+ "summary": "Resumo do que foi implementado"
53
+ }
54
+ ```
55
+ **Ação**: Avaliador inicia processo de avaliação
56
+
57
+ ---
58
+
59
+ ### 6a. Avaliador → Construtor (Task Rejeitada)
60
+ **Momento**: Quando task não passa na avaliação
61
+ **Mensagem**:
62
+ ```json
63
+ {
64
+ "task_id": "task-001",
65
+ "status": "rejected",
66
+ "evaluation_number": 1,
67
+ "issues_found": [
68
+ {
69
+ "type": "functional | visual",
70
+ "severity": "critical | high | medium | low",
71
+ "description": "Descrição do problema",
72
+ "recommendation": "Como corrigir",
73
+ "related_criteria": "Critério não atendido"
74
+ }
75
+ ]
76
+ }
77
+ ```
78
+ **Ação**: Construtor corrige problemas e reenvia para Avaliador
79
+
80
+ ---
81
+
82
+ ### 6b. Avaliador → Gestor Projeto (Task Aprovada)
83
+ **Momento**: Quando task passa em todos os critérios
84
+ **Mensagem**:
85
+ ```json
86
+ {
87
+ "task_id": "task-001",
88
+ "status": "approved",
89
+ "evaluation_number": 2,
90
+ "summary": "Task aprovada após 2 iterações"
91
+ }
92
+ ```
93
+ **Ação**:
94
+ - Gestor Projeto atualiza status da task de `em execução` para `completo`
95
+ - Identifica próxima task (por FIFO - ordem de criação)
96
+ - Se houver próxima: atualiza para `em execução` e envia para Construtor
97
+ - Se não houver: notifica Orquestrador
98
+
99
+ ---
100
+
101
+ ### 7. Gestor Projeto → Orquestrador
102
+ **Momento**: Quando todas as tasks estão `completo`
103
+ **Mensagem**:
104
+ ```json
105
+ {
106
+ "status": "all_tasks_completed",
107
+ "total_tasks": 15,
108
+ "completed_tasks": 15,
109
+ "timestamp": "2026-01-26T18:30:00Z"
110
+ }
111
+ ```
112
+ **Ação**: Orquestrador compila relatório final
113
+
114
+ ---
115
+
116
+ ## Ciclo Completo de Uma Task
117
+
118
+ ```
119
+ Gestor Projeto
120
+ ↓ (envia task)
121
+ Construtor
122
+ ↓ (ready_for_evaluation)
123
+ Avaliador
124
+
125
+ ├─ (rejected) → Construtor → (ready_for_evaluation) → Avaliador
126
+ └─ (approved) → Gestor Projeto
127
+
128
+ (atualiza para completo)
129
+
130
+ (pega próxima task ou notifica Orquestrador)
131
+ ```
132
+
133
+ ---
134
+
135
+ ## Estados e Transições
136
+
137
+ ### Task Status Flow
138
+ ```
139
+ pendente
140
+
141
+ (Gestor envia para Construtor)
142
+
143
+ em execução
144
+
145
+ (Construtor envia para Avaliador)
146
+
147
+ ├─ Avaliação: REJEITADA
148
+ │ ↓
149
+ │ (volta para Construtor)
150
+ │ ↓
151
+ │ (Construtor corrige)
152
+ │ ↓
153
+ │ (reenvia para Avaliador)
154
+ │ ↓
155
+ └─ Avaliação: APROVADA
156
+
157
+ (notifica Gestor)
158
+
159
+ completo
160
+ ```
161
+
162
+ ---
163
+
164
+ ## Responsabilidades de Atualização
165
+
166
+ | Arquivo | Quem Cria | Quem Atualiza | Quando Atualiza |
167
+ |---------|-----------|---------------|-----------------|
168
+ | `sincron-auto-state` | Gestor Projeto | Gestor Projeto | - Ao criar tasks (Skill Projetar)<br>- `pendente` → `em execução` (ao enviar para Construtor)<br>- `em execução` → `completo` (após aprovação do Avaliador) |
169
+ | `relatorio-avaliacao.json` | Avaliador | Avaliador | - A cada avaliação (aprovada ou rejeitada)<br>- Incrementa evaluation_number em reavaliações |
170
+ | `settings.local.json` | Estrutura | Estrutura | - Uma única vez na configuração inicial |
171
+ | `reports/relatorio-*.md` | Orquestrador | Orquestrador | - Ao finalizar todas as tasks do projeto |
172
+
173
+ ---
174
+
175
+ ## Perguntas em Aberto
176
+
177
+ 1. O Construtor notifica alguém quando inicia a construção?
178
+ 2. Há timeout para construção/avaliação?
179
+ 3. Como lidar com erros/crashes de um agente?
180
+ 4. Sistema deve ter logs de todas as comunicações?