Ctrl K
ComunidadGuías…

test/contextual-clay-corrections.test.cjs

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
var test = require('node:test');
var assert = require('node:assert/strict');
var cp = require('node:child_process');
var path = require('node:path');
var playwright = require('playwright');
var browser, child, origin, page, frame, input, surface, trigger, sourceSlug;
var draft = 'Help me organise this project. Keep my current session open while we review the next steps.';

test.before(async function () {
  child = cp.fork(path.join(__dirname, 'fixtures/contextual-clay-server.cjs'), [], { stdio: ['ignore', 'pipe', 'pipe', 'ipc'] });
  var output = '';
  child.stdout.on('data', function (value) { output += value; });
  child.stderr.on('data', function (value) { output += value; });
  var info = await new Promise(function (resolve, reject) {
    var timer = setTimeout(function () { reject(new Error(output)); }, 15000);
    child.once('message', function (value) { clearTimeout(timer); resolve(value); });
    child.once('exit', function () { clearTimeout(timer); reject(new Error(output)); });
  });
  origin = 'http://127.0.0.1:' + info.port; sourceSlug = info.sourceSlug;
  browser = await playwright.chromium.launch();
});
test.after(async function () { if (browser) await browser.close(); if (child) child.kill('SIGTERM'); });
test.beforeEach(async function () {
  page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
  page.setDefaultTimeout(5000);
  await page.goto(origin + '/fixture/login?to=alpha');
  trigger = page.locator('.icon-strip-brand');
  await page.waitForFunction(function () { return !document.querySelector('.icon-strip-brand').disabled; });
  surface = page.locator('#contextual-clay');
  frame = page.frameLocator('#contextual-clay iframe');
  input = frame.locator('#input');
});
test.afterEach(async function () { await page.close(); });
async function open() {
  await trigger.click();
  await frame.locator('#messages').getByText('Isolated canonical integration conversation.', { exact: true }).waitFor();
  await input.waitFor();
  await frame.locator('#input-wrapper:not([inert])').waitFor();
}
async function geometry(t, label) {
  var result = await input.evaluate(function (element) {
    var stop = document.getElementById('generation-stop').getBoundingClientRect();
    var controls = ['stt-btn', 'stt-btn-picker', 'send-btn'].map(function (id) { var r = document.getElementById(id).getBoundingClientRect(); return { id: id, left: r.left, right: r.right, top: r.top, bottom: r.bottom }; });
    return { tracks: getComputedStyle(document.getElementById('input-row')).gridTemplateColumns, voiceArea: getComputedStyle(document.querySelector('.stt-controls')).gridArea, height: element.clientHeight, scrollHeight: element.scrollHeight, scrollTop: element.scrollTop, overflow: getComputedStyle(element).overflowY, caret: element.selectionEnd, value: element.value, stop: { left: stop.left, right: stop.right, top: stop.top, bottom: stop.bottom }, controls: controls };
  });
  t.diagnostic(label + ': ' + JSON.stringify(result));
  assert.equal(result.value, draft);
  assert.equal(result.caret, draft.length);
  assert.ok(result.scrollHeight <= result.height + 1 || result.overflow === 'auto', 'Capped draft has actual scrolling');
  assert.ok(result.scrollHeight - result.height - result.scrollTop <= 1, 'The final line and caret remain visible after resize');
  if (label.includes('running')) result.controls.forEach(function (r) {
    var stop = result.stop;
    assert.ok(stop.right <= r.left || stop.left >= r.right || stop.bottom <= r.top || stop.top >= r.bottom, 'Stop does not overlap ' + r.id);
  });
}

test('1: exact desktop draft retains its final line and separate running controls at 390x844', async function (t) {
  await open();
  await input.fill(draft);
  await page.setViewportSize({ width: 390, height: 844 });
  await page.waitForTimeout(200);
  await geometry(t, 'narrow idle');
  await page.request.get(origin + '/fixture/stream');
  await frame.locator('#generation-stop').waitFor({ state: 'visible' });
  await page.waitForTimeout(100);
  await geometry(t, 'narrow running');
  await input.fill(Array(20).fill(draft).join('\n'));
  assert.equal(await input.evaluate(function (element) { return getComputedStyle(element).overflowY === 'auto' && element.scrollHeight > element.clientHeight && element.offsetHeight <= 121; }), true);
});

test('2: Open Clay navigates to native Mate shell and Back restores the project', async function (t) {
  await open();
  await page.setViewportSize({ width: 390, height: 844 });
  await page.getByRole('button', { name: 'Open Clay', exact: true }).click();
  await page.waitForURL('**/p/' + sourceSlug + '/');
  await page.locator('#contextual-workspace-back').waitFor();
  assert.equal(await page.locator('body').evaluate(function (body) { return body.classList.contains('mate-workspace-active'); }), true);
  assert.equal(await surface.isVisible(), false);
  await page.getByRole('button', { name: 'Back to project', exact: true }).click();
  await page.waitForURL('**/p/alpha/');
  await page.locator('#header-title').getByText('Alpha destination', { exact: true }).waitFor();
  assert.equal(await page.locator('#header-full-access-btn').isVisible(), true);
  t.diagnostic('Actual canonical Mate route/shell, hidden popover, Back to original project verified.');
});

test('3: real authenticated review leads with named intent, with the unchanged exact payload initially collapsed', async function (t) {
  await open();
  var proposal = page.request.get(origin + '/fixture/propose?viewer=alpha&target=beta');
  var review = frame.locator('.ask-user-container:not(.answered)').last();
  await review.locator('.product-review-action').waitFor();
  assert.equal(await review.locator('.product-review-action').textContent(), 'Open conversation: Beta destination');
  assert.equal(await review.locator('.product-review pre').isVisible(), false);
  assert.doesNotMatch(await review.locator('.product-review-action, .product-review > p').allTextContents().then(function (items) { return items.join('\n'); }), /viewer:|session:|"action"/);
  var exact = await review.locator('.product-review pre').textContent();
  assert.match(exact, /Selected viewer: viewer:/);
  assert.match(exact, /"action":"navigate"/);
  await review.locator('summary').click();
  assert.equal(await review.locator('pre').isVisible(), true);
  assert.equal(await review.locator('pre').textContent(), exact);
  var reviewId = await review.getAttribute('data-tool-id');
  await review.getByText('Keep unchanged', { exact: true }).click();
  await review.locator('.ask-user-submit').click();
  assert.equal((await (await proposal).json()).status, 'cancelled');
  assert.equal(await frame.locator('.ask-user-container[data-tool-id=\"' + reviewId + '\"]').locator('.ask-user-answer-label').textContent(), 'Open conversation');
  t.diagnostic('Named action and target visible; exact viewer/session/action payload retained; real authenticated decline cancelled operation.');
});

test('4: mouse/keyboard opens enter the ready composer; delayed loading does not steal focus; inner Escape wins', async function (t) {
  var release;
  var gate = new Promise(function (resolve) { release = resolve; });
  await page.route('**/*contextual=1*', async function (route) { await gate; await route.continue(); });
  await trigger.click();
  await page.locator('#input').focus();
  release();
  await frame.locator('#messages').getByText('Isolated canonical integration conversation.', { exact: true }).waitFor();
  await frame.locator('#input-wrapper:not([inert])').waitFor();
  assert.equal(await page.locator('#input').evaluate(function (element) { return document.activeElement === element; }), true, 'Readiness must not take focus back after the user moves away');
  await surface.locator('[data-clay-close]').click();
  await trigger.click();
  assert.equal(await input.evaluate(function (element) { return document.activeElement === element; }), true, 'Mouse opening enters the ready composer');
  await page.keyboard.press('Escape');
  assert.equal(await surface.isVisible(), false, 'Composer Escape closed the popover before keyboard reopening');
  await trigger.focus(); await page.keyboard.press('Enter');
  t.diagnostic('Keyboard mode: ' + await surface.getAttribute('data-mode'));
  assert.equal(await input.evaluate(function (element) { return document.activeElement === element; }), true, 'Keyboard opening enters the ready composer');
  await frame.locator('#stt-btn-picker').click();
  await frame.locator('#speech-picker').waitFor();
  await page.keyboard.press('Escape');
  assert.equal(await frame.locator('#speech-picker').count(), 0);
  assert.equal(await surface.isVisible(), true);
  await input.focus(); await page.keyboard.press('Escape');
  assert.equal(await surface.isVisible(), false);
  await trigger.click(); await trigger.click();
  await page.waitForURL('**/p/' + sourceSlug + '/');
  await page.locator('#contextual-workspace-back').waitFor();
  await trigger.click();
  await page.waitForURL('**/p/alpha/');
  t.diagnostic('Delayed readiness preserved project focus; both entry methods focus the composer; inner voice menu consumes Escape; rapid cycle closes.');
});