Ctrl K
ComunidadGuías…

test/contextual-mates-browser.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');

test('two ordinary Mates and canonical retain isolated conversations through popover, strip hint and native workspace', async function (t) {
  var child = cp.fork(path.join(__dirname, 'fixtures/contextual-clay-server.cjs'), [], { stdio: ['ignore', 'pipe', 'pipe', 'ipc'] });
  t.after(function () { child.kill('SIGTERM'); }); var output = '';
  child.stdout.on('data', function (v) { output += v; }); child.stderr.on('data', function (v) { output += v; });
  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); }); });
  var browser = await playwright.chromium.launch(); t.after(async function () { await browser.close(); });
  var page = await browser.newPage({ viewport: { width: 1280, height: 800 }, reducedMotion: 'reduce' }); page.setDefaultTimeout(10000);
  var errors = []; page.on('pageerror', function (error) { errors.push(error.message); });
  var origin = 'http://127.0.0.1:' + info.port; var mates = info.ordinaryMates;
  await page.goto(origin + '/fixture/login?to=alpha');
  await page.waitForFunction(function () { return !document.querySelector('.icon-strip-brand').disabled; });
  var preference = { left: 420, top: 80, width: 510, height: 620 };
  assert.equal((await page.request.put(origin + '/api/user/contextual-clay-geometry', { headers: { 'X-Clay-Settings': '1' }, data: preference })).status(), 200);
  await page.reload(); await page.waitForFunction(function () { return !document.querySelector('.icon-strip-brand').disabled; });
  await page.evaluate(async function () { window.mateStore = (await import('/p/alpha/modules/store.js')).store; });
  var projectSession = await page.evaluate(function () { return window.mateStore.get('activeSessionId'); });
  await page.locator('#input').fill('Original project writing');
  function icon(mate) { return page.locator('.icon-strip-project-mate[data-mate-id="' + mate.id + '"]'); }
  function pane(mate) { return page.frameLocator('#contextual-clay iframe[data-mate-id="' + mate.id + '"]'); }
  async function ready(mate, index) { await pane(mate).locator('#messages').getByText('ORDINARY_MATE_' + index + '_PRIVATE_HISTORY', { exact: false }).waitFor(); await pane(mate).locator('#input-wrapper:not([inert])').waitFor(); }
  await icon(mates[0]).click(); await ready(mates[0], 0);
  var hint = page.locator('#contextual-mate-hint'); assert.match(await hint.textContent(), /Click again to open Arch/);
  assert.equal(await icon(mates[0]).getAttribute('aria-describedby'), 'contextual-mate-hint');
  assert.equal(await page.locator('#contextual-clay strong').textContent(), mates[0].name);
  var box = await page.locator('#contextual-clay').boundingBox(); var badge = await hint.boundingBox(); assert.ok(badge.x + badge.width <= box.x - 6 || badge.y + badge.height <= box.y - 6);
  await pane(mates[0]).locator('#input').fill('Arch owns this draft only.');
  var heldUpload; var uploadReady; var started = new Promise(function (resolve) { uploadReady = resolve; });
  var uploadPattern = '**/p/' + mates[0].slug + '/api/upload';
  await page.route(uploadPattern, function (route) { heldUpload = route; uploadReady(); });
  await pane(mates[0]).locator('#contextual-attach-btn').click();
  var choose = page.waitForEvent('filechooser'); await pane(mates[0]).locator('#attach-file-btn').click(); await (await choose).setFiles({ name: 'arch-private.txt', mimeType: 'text/plain', buffer: Buffer.from('Arch attachment') });
  await started;
  await icon(mates[1]).click(); await ready(mates[1], 1);
  assert.equal(await pane(mates[1]).locator('#image-preview-bar').getByText('arch-private.txt').count(), 0);
  await heldUpload.continue(); await page.unroute(uploadPattern);
  await icon(mates[0]).click();
  await pane(mates[0]).locator('#image-preview-bar').getByText('arch-private.txt', { exact: false }).waitFor();
  var question = page.request.get(origin + '/fixture/ordinary-question?index=0');
  var card = pane(mates[0]).locator('.ask-user-container:not(.answered)'); await card.waitFor(); var questionId = await card.getAttribute('data-tool-id');
  await icon(mates[1]).click(); await ready(mates[1], 1);
  assert.equal(await pane(mates[1]).locator('#input').getAttribute('placeholder'), 'Message this Mate…');
  assert.equal(await pane(mates[1]).locator('#input').getAttribute('aria-label'), 'Message ' + mates[1].name);
  assert.equal(await pane(mates[1]).locator('#input').inputValue(), ''); assert.equal(await pane(mates[1]).locator('.ask-user-container').count(), 0);
  assert.equal(await pane(mates[1]).locator('#image-preview-bar').getByText('arch-private.txt').count(), 0);
  await pane(mates[1]).locator('#input').fill('Second Mate owns a different draft.');
  assert.equal(await page.locator('#contextual-clay iframe:visible').count(), 1);
  assert.ok((await hint.boundingBox()).x + (await hint.boundingBox()).width < 1280);
  await icon(mates[1]).hover(); assert.equal(await page.locator('.icon-strip-tooltip').count(), 0, 'Persistent hint replaces the competing hover tooltip');
  await page.screenshot({ path: '/tmp/contextual-mates-long-name-light.png', animations: 'disabled' });
  var visualFrame = page.frames().find(function (frame) { return frame.url().includes(mates[1].slug); });
  await page.evaluate(async function () { (await import('/p/alpha/modules/theme.js')).applyTheme('clay-dark'); });
  await visualFrame.evaluate(async function () { (await import('./modules/theme.js')).applyTheme('clay-dark'); });
  await page.screenshot({ path: '/tmp/contextual-mates-long-name-dark.png', animations: 'disabled' });
  await page.evaluate(async function () { (await import('/p/alpha/modules/theme.js')).applyTheme('clay-light'); });
  await visualFrame.evaluate(async function () { (await import('./modules/theme.js')).applyTheme('clay-light'); });
  await page.locator('.icon-strip-brand').click();
  var canonical = page.frameLocator('#contextual-clay iframe[data-canonical="true"]');
  await canonical.locator('#messages').getByText('Isolated canonical integration conversation.', { exact: true }).waitFor(); await canonical.locator('#input-wrapper:not([inert])').waitFor();
  assert.equal(await canonical.locator('#input').inputValue(), ''); await canonical.locator('#input').fill('Canonical private draft.');
  assert.equal(await canonical.locator('#messages').getByText('ORDINARY_MATE_0_PRIVATE_HISTORY', { exact: false }).count(), 0);
  for (var index of [0, 1]) {
    for (var fresh of ['true', 'false']) {
      var catalog = await (await page.request.get(origin + '/fixture/ordinary-catalog?index=' + index + '&fresh=' + fresh)).json();
      assert.ok(Array.isArray(catalog.tools)); assert.ok(catalog.canonicalNames.length >= 28);
      catalog.canonicalNames.forEach(function (name) { assert.equal(catalog.tools.some(function (tool) { return tool.name === name; }), false, 'Ordinary Mate lacks canonical ' + name); });
    }
  }
  var ordinaryWindow = page.frames().find(function (frame) { return frame.url().includes(mates[1].slug); });
  assert.equal(await ordinaryWindow.evaluate(async function () { return (await import('./modules/contextual-clay-session.js')).contextualScreenReference(); }), null);
  assert.equal(await pane(mates[0]).locator('#messages').getByText('Isolated canonical integration conversation.', { exact: true }).count(), 0);
  var foreign = await browser.newContext();
  assert.equal((await foreign.request.get(origin + '/p/' + mates[0].slug + '/', { headers: { Cookie: 'relay_auth_user=fixture-foreign-token' } })).status(), 403);
  await foreign.close();
  await icon(mates[0]).click(); assert.equal(await pane(mates[0]).locator('#input').inputValue(), 'Arch owns this draft only.'); assert.equal(await card.getAttribute('data-tool-id'), questionId);
  assert.equal(await page.locator('#input').inputValue(), 'Original project writing');
  await icon(mates[0]).click(); await page.waitForURL('**/p/' + mates[0].slug + '/');
  await page.waitForFunction(function () { return document.body.classList.contains('contextual-clay-native') && !document.getElementById('input-wrapper').inert; });
  assert.equal(await page.evaluate(function () { return window.mateStore.get('activeSessionId'); }), mates[0].sessionId);
  assert.equal(await page.locator('#input').inputValue(), 'Arch owns this draft only.'); assert.equal(await pane(mates[0]).locator('#input').inputValue(), '');
  assert.equal(await hint.isVisible(), false); assert.equal(await page.locator('body.mate-workspace-active').count(), 1);
  assert.match(await page.locator('#image-preview-bar').textContent(), /arch-private/);
  var nativeCard = page.locator('.ask-user-container[data-tool-id="' + questionId + '"]'); await nativeCard.getByText('Tests', { exact: true }).click(); await nativeCard.locator('.ask-user-submit').click(); assert.equal((await (await question).json()).status, 'submitted');
  await page.locator('#input').fill('Edited in native Arch workspace.');
  await icon(mates[1]).click();
  assert.equal(new URL(page.url()).pathname, '/p/' + mates[0].slug + '/');
  assert.equal(await page.locator('#input').inputValue(), 'Edited in native Arch workspace.');
  assert.equal(await page.evaluate(function () { return window.mateStore.get('activeSessionId'); }), mates[0].sessionId);
  assert.equal(await pane(mates[1]).locator('#input').inputValue(), 'Second Mate owns a different draft.');
  await page.locator('[data-clay-close]').click();
  assert.equal(new URL(page.url()).pathname, '/p/' + mates[0].slug + '/');
  await page.waitForFunction(function () { return document.body.classList.contains('contextual-clay-native'); });
  assert.equal(await page.locator('#input').inputValue(), 'Edited in native Arch workspace.');
  await page.locator('#contextual-workspace-back').click(); await page.waitForURL('**/p/alpha/');
  await page.waitForFunction(function () { return document.getElementById('input').value === 'Original project writing'; });
  assert.equal(await page.evaluate(function () { return window.mateStore.get('activeSessionId'); }), projectSession);
  await icon(mates[1]).click(); assert.equal(await pane(mates[1]).locator('#input').inputValue(), 'Second Mate owns a different draft.');
  await hint.click(); await page.waitForURL('**/p/' + mates[1].slug + '/'); await page.waitForFunction(function () { return document.body.classList.contains('contextual-clay-native'); });
  assert.equal(await page.locator('#input').inputValue(), 'Second Mate owns a different draft.');
  await page.locator('#contextual-workspace-back').click(); await page.waitForURL('**/p/alpha/'); await page.waitForFunction(function () { return !window.mateStore.get('contextualWorkspace'); });
  await icon(mates[0]).focus(); await page.keyboard.press('Enter'); assert.equal(await pane(mates[0]).locator('#input').inputValue(), 'Edited in native Arch workspace.');
  await pane(mates[0]).locator('#input').press('Escape'); assert.equal(await hint.isVisible(), false); assert.equal(await icon(mates[0]).getAttribute('aria-describedby'), null);
  await icon(mates[0]).click({ button: 'right' }); await page.locator('.project-ctx-menu').waitFor(); assert.equal(await page.locator('#contextual-clay').isVisible(), false); await page.keyboard.press('Escape');
  await icon(mates[0]).focus(); await page.keyboard.press('Shift+F10'); await page.locator('.project-ctx-menu').waitFor(); await page.keyboard.press('Escape');
  assert.equal(await page.locator('#contextual-clay').isVisible(), false);
  await icon(mates[1]).click(); await page.setViewportSize({ width: 390, height: 844 });
  await page.waitForFunction(function () { return !!document.querySelector('.contextual-mate-mobile-trigger'); });
  assert.equal(await icon(mates[1]).isVisible(), true); assert.equal(await hint.isVisible(), true);
  badge = await hint.boundingBox(); box = await page.locator('#contextual-clay').boundingBox(); assert.ok(badge.x >= 46 && badge.x + badge.width <= 390 && badge.y + badge.height <= box.y);
  await page.screenshot({ path: '/tmp/contextual-mates-narrow-light.png', animations: 'disabled' });
  await page.evaluate(async function () { (await import('/p/alpha/modules/theme.js')).applyTheme('clay-dark'); });
  var secondFrame = page.frames().find(function (frame) { return frame.url().includes(mates[1].slug); }); await secondFrame.evaluate(async function () { (await import('./modules/theme.js')).applyTheme('clay-dark'); });
  await page.screenshot({ path: '/tmp/contextual-mates-narrow-dark.png', animations: 'disabled' });
  assert.deepEqual((await (await page.request.get(origin + '/api/user/contextual-clay-geometry')).json()).geometry, preference);
  await icon(mates[1]).click(); await page.waitForURL('**/p/' + mates[1].slug + '/'); await page.locator('#contextual-workspace-back').click(); await page.waitForURL('**/p/alpha/');
  await page.setViewportSize({ width: 1280, height: 800 }); await page.waitForFunction(function () { return !window.mateStore.get('contextualWorkspace'); });
  await icon(mates[1]).click();
  await page.evaluate(function (slug) { window.savedProjectRegistry = window.mateStore.get('projectsHubList'); window.mateStore.set({ projectsHubList: window.savedProjectRegistry.map(function (project) { return project.slug === slug ? Object.assign({}, project, { contentAccess: false }) : project; }) }); }, mates[1].slug);
  assert.equal(await page.locator('#contextual-clay').isVisible(), false); assert.equal(await hint.isVisible(), false);
  await page.evaluate(function () { window.mateStore.set({ projectsHubList: window.savedProjectRegistry }); });
  await page.evaluate(async function (id) { var list = window.mateStore.get('cachedMatesList'); window.savedMateRegistry = list; window.mateStore.set({ cachedMatesList: list.map(function (mate) { return mate.id === id ? Object.assign({}, mate, { createdBy: 'foreign' }) : mate; }) }); (await import('/p/alpha/modules/project-mate-navigation.js')).activateContextualMate(id); }, mates[1].id);
  assert.equal(await page.locator('#contextual-clay').isVisible(), false);
  await page.evaluate(function () { window.mateStore.set({ cachedMatesList: window.savedMateRegistry }); });
  await icon(mates[0]).click();
  await page.evaluate(function (id) { var items = window.mateStore.get('cachedMatesList'); window.mateStore.set({ cachedMatesList: items.map(function (mate) { return mate.id === id ? Object.assign({}, mate, { archived: true }) : mate; }) }); }, mates[0].id);
  assert.equal(await page.locator('#contextual-clay').isVisible(), false); assert.equal(await hint.isVisible(), false);
  await page.evaluate(async function (id) { await (await import('/p/alpha/modules/project-mate-navigation.js')).activateContextualMate(id); }, mates[0].id); assert.equal(await page.locator('#contextual-clay').isVisible(), false);
  await icon(mates[1]).click(); await page.evaluate(function (id) { window.mateStore.set({ cachedMatesList: window.mateStore.get('cachedMatesList').filter(function (mate) { return mate.id !== id; }) }); }, mates[1].id);
  assert.equal(await page.locator('#contextual-clay').isVisible(), false);
  await page.locator('.icon-strip-brand').click(); assert.equal(await canonical.locator('#input').inputValue(), 'Canonical private draft.');
  var direct = await browser.newPage({ viewport: { width: 1280, height: 800 } });
  await direct.goto(origin + '/fixture/login?to=alpha'); await direct.goto(origin + '/p/' + mates[1].slug + '/');
  await direct.locator('#messages').getByText('ORDINARY_MATE_1_PRIVATE_HISTORY', { exact: false }).waitFor();
  await direct.evaluate(async function () { window.directStore = (await import('./modules/store.js')).store; });
  await direct.waitForFunction(function (session) { return window.directStore.get('activeSessionId') === session && !window.directStore.get('replayingHistory'); }, mates[1].sessionId);
  await direct.locator('#input').fill('Writing in a directly opened native Mate.');
  var directIcon = direct.locator('.icon-strip-project-mate[data-mate-id="' + mates[1].id + '"]'); await directIcon.click();
  var directPane = direct.frameLocator('#contextual-clay iframe'); await directPane.locator('#input').waitFor();
  await direct.waitForFunction(function () { return document.getElementById('input-wrapper').inert && document.getElementById('input').value === ''; });
  await direct.waitForFunction(function () { var frame = document.querySelector('#contextual-clay iframe'); return frame && frame.contentDocument.getElementById('input') && frame.contentDocument.getElementById('input').value === 'Writing in a directly opened native Mate.'; });
  assert.equal(await directPane.locator('#input').inputValue(), 'Writing in a directly opened native Mate.');
  await directPane.locator('#input').fill('Edited in direct-entry popover.');
  await direct.locator('[data-clay-close]').click(); assert.equal(await direct.locator('#input').inputValue(), 'Edited in direct-entry popover.');
  assert.equal(await direct.locator('#input-wrapper').evaluate(function (el) { return el.inert; }), false);
  await directIcon.click(); await directPane.locator('#input-wrapper:not([inert])').waitFor(); await directIcon.click();
  await direct.waitForFunction(function () { return document.body.classList.contains('contextual-clay-native'); });
  assert.equal(await direct.locator('#input').inputValue(), 'Edited in direct-entry popover.');
  await direct.locator('#contextual-workspace-back').click(); await direct.waitForURL('**/p/alpha/');
  await direct.goto(origin + '/p/' + mates[1].slug + '/');
  await direct.locator('#messages').getByText('ORDINARY_MATE_1_PRIVATE_HISTORY', { exact: false }).waitFor();
  await directIcon.click();
  await direct.evaluate(async function (id) { var state = (await import('./modules/store.js')).store; state.set({ cachedMatesList: state.get('cachedMatesList').filter(function (mate) { return mate.id !== id; }) }); }, mates[1].id);
  assert.equal(await direct.locator('#contextual-clay').isVisible(), false);
  assert.equal(await direct.locator('#input-wrapper').evaluate(function (el) { return el.inert; }), false, 'Removed native origin cannot trap project navigation');
  await direct.close();
  var touchContext = await browser.newContext({ viewport: { width: 390, height: 844 }, isMobile: true, hasTouch: true });
  var touch = await touchContext.newPage(); await touch.goto(origin + '/fixture/login?to=alpha');
  await touch.waitForFunction(function () { return !document.querySelector('.icon-strip-brand').disabled; });
  await touch.getByRole('button', { name: 'Chat', exact: true }).tap();
  await touch.locator('.mobile-chat-chip[data-mate-id="' + mates[1].id + '"]').tap();
  var touchPane = touch.frameLocator('#contextual-clay iframe'); await touchPane.locator('#messages').getByText('ORDINARY_MATE_1_PRIVATE_HISTORY', { exact: false }).waitFor();
  assert.match(await touch.locator('#contextual-mate-hint').textContent(), /^Tap again to open /);
  var touchIcon = touch.locator('.contextual-mate-mobile-trigger'); assert.ok((await touchIcon.boundingBox()).width >= 44);
  await touchPane.locator('#input-wrapper:not([inert])').waitFor(); await touchPane.locator('#input').fill('Touch presentation retains its exact Mate.');
  await touchIcon.tap(); await touch.waitForURL('**/p/' + mates[1].slug + '/');
  await touch.waitForFunction(function () { return document.body.classList.contains('contextual-clay-native'); });
  assert.equal(await touch.locator('#input').inputValue(), 'Touch presentation retains its exact Mate.');
  await touch.locator('#contextual-workspace-back').tap(); await touch.waitForURL('**/p/alpha/'); await touchContext.close();


  assert.deepEqual(errors, []);
  t.diagnostic('Two ordinary Mates plus canonical: isolated sessions/drafts/attachments/question, first/second clicks, native routes/Back, pill actions and placement, keyboard/right-click, narrow icon, archived/deleted refusal and ordinary canonical-catalog exclusion.');
});