ui: gate community wizard capabilities

This commit is contained in:
a.tolmachev
2026-05-03 17:11:30 +00:00
parent 10433d5193
commit 49c46c0d0b
14 changed files with 221 additions and 225 deletions
+2 -2
View File
@@ -13,8 +13,8 @@ test('shell and wizard expose stable diagnostics hooks', async ({ page }) => {
await page.goto('/wizard/');
await expect(page.locator('[data-testid="wizard-protocol-grid"]')).toBeVisible();
await expect(page.locator('[data-testid="wizard-protocol-rest"]')).toBeVisible();
await expect(page.locator('[data-testid="wizard-protocol-websocket"]')).toBeVisible();
await expect(page.locator('[data-testid="wizard-protocol-soap"]')).toBeVisible();
await expect(page.locator('[data-testid="wizard-protocol-websocket"]')).toBeHidden();
await expect(page.locator('[data-testid="wizard-protocol-soap"]')).toBeHidden();
await expect(page.locator('html')).toHaveAttribute('data-crank-bootstrap-state', 'ready');
});
+9 -206
View File
@@ -1,14 +1,5 @@
const { test, expect } = require('@playwright/test');
const {
SOAP_TEST_WSDL,
buildSoapOperationPayload,
buildWebsocketWindowOperationPayload,
createOperation,
getCurrentWorkspace,
login,
localized,
uniqueName,
} = require('./helpers');
const { login, localized } = require('./helpers');
test('wizard loads and protocol selection updates flow', async ({ page }) => {
await login(page);
@@ -20,201 +11,13 @@ test('wizard loads and protocol selection updates flow', async ({ page }) => {
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 }) => {
test('community wizard hides premium protocols and explains edition scope', 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;
}
});
await page.goto('/wizard/');
await expect(page.locator('[data-testid="wizard-protocol-rest"]')).toBeVisible();
await expect(page.locator('[data-testid="wizard-protocol-graphql"]')).toBeVisible();
await expect(page.locator('[data-testid="wizard-protocol-grpc"]')).toBeVisible();
await expect(page.locator('[data-testid="wizard-protocol-websocket"]')).toBeHidden();
await expect(page.locator('[data-testid="wizard-protocol-soap"]')).toBeHidden();
await expect(page.locator('#wizard-edition-protocol-note')).toContainText(localized('Commercial editions unlock', 'коммерческих редакциях'));
});