const { test, expect } = require('@playwright/test'); const { SOAP_TEST_WSDL, buildSoapOperationPayload, buildWebsocketWindowOperationPayload, createOperation, getCurrentWorkspace, login, localized, uniqueName, } = require('./helpers'); test('wizard loads and protocol selection updates flow', async ({ page }) => { await login(page); await page.goto('/wizard/'); await expect(page.locator('[data-step-counter]').first()).toContainText(localized('Step', 'Шаг')); await expect(page.locator('#step-panel-1 .step-panel-title')).toContainText(localized('Choose a protocol', 'Выберите протокол')); await page.getByText(/graphql/i).first().click(); await page.locator('#btn-continue').click(); await expect(page.locator('#step-panel-2 .step-panel-title')).toContainText(localized('Select upstream', 'Выберите upstream')); }); test('soap wizard uploads wsdl, applies discovered binding and runs test', async ({ page }) => { await login(page); const workspace = await getCurrentWorkspace(page); const operation = await createOperation( page, workspace.id, buildSoapOperationPayload(uniqueName('playwright_soap_wizard')), ); await page.goto(`/wizard/?mode=edit&operationId=${encodeURIComponent(operation.operation_id)}`); await page.locator('#btn-continue').click(); await page.locator('#btn-continue').click(); await expect(page.locator('#step-panel-3-soap .step-panel-title')).toContainText(/WSDL/i); await page.evaluate((wsdl) => { const fileName = document.getElementById('wizard-soap-wsdl-name'); if (fileName) fileName.textContent = 'lead.wsdl'; }, SOAP_TEST_WSDL); await page.evaluate(async ({ workspaceId, operationId, wsdl }) => { const uploaded = await window.CrankApi.uploadWsdlFile( workspaceId, operationId, new TextEncoder().encode(wsdl), 'lead.wsdl', ); const services = await window.CrankApi.listSoapServices( workspaceId, operationId, null, ); window.renderSoapServiceCatalog(services.services || []); return uploaded; }, { workspaceId: workspace.id, operationId: operation.operation_id, wsdl: SOAP_TEST_WSDL, }); await expect(page.locator('#wizard-soap-services-list button')).toContainText('CreateLead'); await page.locator('#wizard-soap-services-list button').getByText('CreateLead').click(); await expect(page.locator('#soap-service-name')).toHaveValue('LeadService'); await expect(page.locator('#soap-port-name')).toHaveValue('LeadPort'); await expect(page.locator('#soap-operation-name')).toHaveValue('CreateLead'); await page.locator('#btn-continue').click(); await expect(page.locator('#step-panel-4 .step-panel-title')).toBeVisible(); await page.locator('#tool-input-schema').fill(JSON.stringify({ type: 'object', required: ['email'], properties: { email: { type: 'string' }, }, }, null, 2)); await page.locator('#tool-output-schema').fill(JSON.stringify({ type: 'object', required: ['id'], properties: { id: { type: 'string' }, }, }, null, 2)); await page.locator('#btn-continue').click(); await expect(page.locator('[data-i18n="wizard.step5.test_title"]')).toContainText(localized('Test run', 'Тестовый запуск')); await page.locator('#tool-input-mapping').fill(JSON.stringify({ email: '$.input.email', }, null, 2)); await page.locator('#tool-output-mapping').fill(JSON.stringify({ id: '$.response.body.id', }, null, 2)); await page.locator('#tool-exec-config').fill('timeout_ms: 1000'); await page.locator('#wizard-test-input').fill(JSON.stringify({ email: 'user@example.com' }, null, 2)); await page.locator('#wizard-run-test').click(); await expect(page.locator('#wizard-test-request-preview')).toHaveValue(/user@example.com/); await expect(page.locator('#wizard-test-response-preview')).toHaveValue(/lead_soap_123/); await expect(page.locator('#wizard-test-errors')).toHaveValue('[]'); }); test('websocket wizard reports bounded window success and reconnect exhaustion clearly', async ({ page }) => { await login(page); const workspace = await getCurrentWorkspace(page); const successOperation = await createOperation( page, workspace.id, buildWebsocketWindowOperationPayload(uniqueName('playwright_websocket_success')), ); const failureOperation = await createOperation( page, workspace.id, buildWebsocketWindowOperationPayload(uniqueName('playwright_websocket_failure'), { streaming: { max_items: 5, }, websocketOptions: { reconnect_max_attempts: 0, reconnect_backoff_ms: 0, }, }), ); await page.goto(`/wizard/?mode=edit&operationId=${encodeURIComponent(successOperation.operation_id)}`); await page.locator('#btn-continue').click(); await page.locator('#upstream-new-trigger').click(); await page.locator('#new-upstream-name').fill('fixture-websocket'); await page.locator('#new-upstream-url').fill('ws://127.0.0.1:3310'); await page.locator('#btn-continue').click(); await expect(page.locator('#step-panel-3-websocket .step-panel-title')).toContainText(/WebSocket/i); await page.locator('#websocket-path').fill('/events'); await page.locator('#websocket-subprotocols').fill(''); await page.locator('#websocket-subscribe-template').fill(''); await page.locator('#websocket-unsubscribe-template').fill(''); await page.locator('#btn-continue').click(); await page.locator('#btn-continue').click(); await page.locator('#wizard-test-input').fill('{}'); await page.evaluate(() => { const original = window.CrankApi.runOperationTest; window.__wizardRunTestOriginal = original; window.CrankApi.runOperationTest = async () => ({ ok: true, mode: 'window', request_preview: { body: { topic: 'telemetry' }, }, response_preview: { items: [ { seq: 1, value: 101 }, { seq: 2, value: 102 }, { seq: 3, value: 103 }, ], window_complete: true, truncated: false, has_more: false, }, errors: [], window: { window_complete: true, truncated: false, has_more: false, cursor: null, }, }); }); await page.locator('#wizard-run-test').click(); await expect(page.locator('#wizard-live-status-title')).toContainText(localized('WebSocket window test completed', 'WebSocket оконный тест завершен')); await expect(page.locator('#wizard-live-status-text')).toContainText(localized('bounded test window', 'тестового окна')); await expect(page.locator('#wizard-test-response-preview')).toHaveValue(/"seq": 1/); await expect(page.locator('#wizard-test-request-preview')).toHaveValue(/"topic": "telemetry"/); await expect(page.locator('#wizard-test-errors')).toHaveValue('[]'); await page.evaluate(() => { if (window.__wizardRunTestOriginal) { window.CrankApi.runOperationTest = window.__wizardRunTestOriginal; delete window.__wizardRunTestOriginal; } }); await page.goto(`/wizard/?mode=edit&operationId=${encodeURIComponent(failureOperation.operation_id)}`); await page.locator('#btn-continue').click(); await page.locator('#upstream-new-trigger').click(); await page.locator('#new-upstream-name').fill('fixture-websocket'); await page.locator('#new-upstream-url').fill('ws://127.0.0.1:3310'); await page.locator('#btn-continue').click(); await page.locator('#websocket-path').fill('/events'); await page.locator('#websocket-subprotocols').fill(''); await page.locator('#websocket-subscribe-template').fill(''); await page.locator('#websocket-unsubscribe-template').fill(''); await page.locator('#btn-continue').click(); await page.locator('#btn-continue').click(); await page.locator('#wizard-test-input').fill('{}'); await page.evaluate(() => { const original = window.CrankApi.runOperationTest; window.__wizardRunTestOriginal = original; window.CrankApi.runOperationTest = async () => ({ ok: false, mode: 'window', request_preview: { body: { topic: 'telemetry' }, }, response_preview: null, errors: [ { code: 'runtime_websocket_error', message: 'websocket reconnect policy exhausted', }, ], window: null, }); }); await page.locator('#wizard-run-test').click(); await expect(page.locator('#wizard-live-status-title')).toContainText(localized('WebSocket test returned errors', 'WebSocket тест завершился с ошибками')); await expect(page.locator('#wizard-live-status-text')).toContainText(localized('reconnect policy was exhausted', 'reconnect policy была исчерпана')); await expect(page.locator('#wizard-test-errors')).toHaveValue(/runtime_websocket_error/); await page.evaluate(() => { if (window.__wizardRunTestOriginal) { window.CrankApi.runOperationTest = window.__wizardRunTestOriginal; delete window.__wizardRunTestOriginal; } }); });