Ctrl K
ComunidadGuías…

__tests__/files-crop.test.js

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

Archivo original ↗Preguntar a KiBot
/**
 * upload_file must CONFIRM the crop/adjust dialog that sites (YouTube's banner + photo) pop after a
 * file is chosen — otherwise the image never commits and the agent stalls hunting for a button.
 */
import { describe, it, expect, beforeEach, afterAll } from 'vitest';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { EventEmitter } from 'node:events';
const { captureFileChoosers } = require('../src/fileChooser');

const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gb-fc-'));
process.env.PROFILE_DIR = dir;
const fa = await import('../src/fileAssets.js');
const filesMod = await import('../src/tools/files.js');
const files = filesMod.default || filesMod;
beforeEach(() => fs.rmSync(dir, { recursive: true, force: true }));
afterAll(() => fs.rmSync(dir, { recursive: true, force: true }));

function ctx(page) {
  const steps = [], said = [];
  return { steps, said, page: () => page, settle: async () => {}, step: (k, t) => steps.push([k, t]), observe: (t) => said.push(t), resetClickLoop: () => {}, session: () => ({}) };
}

describe('upload_file crop-confirm', () => {
  it.each([false, true])('handles a pending native file chooser when setFiles fails=%s', async (fails) => {
    const id = fa.put({ mime: 'image/png', kind: 'post', name: 'reference.png', bytes: Buffer.from([1, 2, 3]) });
    const page = new EventEmitter();
    page.$$ = async () => [];
    const context = new EventEmitter();
    context.pages = () => [page];
    captureFileChoosers(context);
    let received;
    page.emit('filechooser', { setFiles: async (file) => {
      if (fails) throw new Error('picker closed');
      received = file;
    } });
    const c = ctx(page);
    await files.upload_file(c, { assetId: id });
    if (fails) {
      expect(c.said.join(' ')).toMatch(/Could not set the file.*picker closed/);
      expect(c.steps).toEqual([]);
    } else {
      expect(received.name).toBe('reference.png');
      expect(received.buffer).toEqual(Buffer.from([1, 2, 3]));
      expect(c.steps[0][0]).toBe('upload');
    }
  });

  it.each(['image', 'post'])('uses a stored image labelled %s as the reference when no asset id is given', async (kind) => {
    fa.put({ mime: 'image/png', kind, name: 'reference.png', bytes: Buffer.from([1, 2, 3, 4]) });
    fa.put({ mime: 'video/mp4', kind: 'video', name: 'old-clip.mp4', bytes: Buffer.from([5, 6, 7, 8]) });
    let received;
    const input = { setInputFiles: async (f) => { received = f; } };
    const page = { $$: async (sel) => String(sel).includes('input[type=file]') ? [input] : [] };
    await files.upload_file(ctx(page), { kind: 'image' });
    expect(received.name).toBe('reference.png');
    expect(received.buffer).toEqual(Buffer.from([1, 2, 3, 4]));
  });

  it('reports a missing reference without substituting a video', async () => {
    fa.put({ mime: 'video/mp4', kind: 'video', bytes: Buffer.from([5, 6, 7, 8]) });
    const c = ctx({ $$: async () => { throw new Error('must not upload'); } });
    await files.upload_file(c, { kind: 'image' });
    expect(c.said.join(' ')).toMatch(/No stored file of kind "image"/);
    expect(c.steps).toEqual([]);
  });

  it('does not replace a missing explicit asset with a different image', async () => {
    fa.put({ mime: 'image/png', kind: 'image', bytes: Buffer.from([1, 2]) });
    const c = ctx({});
    await files.upload_file(c, { assetId: 'missing', kind: 'image' });
    expect(c.said.join(' ')).toMatch(/No stored file with id "missing"/);
    expect(c.steps).toEqual([]);
  });

  it('clicks the crop dialog confirm ("Gereed") after setting the file, not Cancel', async () => {
    const id = fa.put({ mime: 'image/png', kind: 'cover', name: 'b.png', bytes: Buffer.from([1, 2, 3, 4]) });
    const clicks = [];
    const input = { setInputFiles: async () => {} };
    const gereed = { innerText: async () => 'Gereed', isVisible: async () => true, click: async () => { clicks.push('gereed'); } };
    const cancel = { innerText: async () => 'Annuleren', isVisible: async () => true, click: async () => { clicks.push('cancel'); } };
    let btnCall = 0;
    const page = { $$: async (sel) => {
      if (String(sel).includes('input[type=file]')) return [input];
      btnCall += 1; return btnCall === 1 ? [cancel, gereed] : [];   // one confirmable dialog, then none
    } };
    const c = ctx(page);
    await files.upload_file(c, { assetId: id });
    expect(clicks).toContain('gereed');
    expect(clicks).not.toContain('cancel');
    expect(c.said.join(' ')).toMatch(/confirmed/i);
  });

  it('does not fabricate a confirm when no crop dialog is present', async () => {
    const id = fa.put({ mime: 'image/png', kind: 'profile', name: 'p.png', bytes: Buffer.from([9, 9]) });
    const input = { setInputFiles: async () => {} };
    const page = { $$: async (sel) => (String(sel).includes('input[type=file]') ? [input] : []) };
    const c = ctx(page);
    await files.upload_file(c, { assetId: id });
    expect(c.said.join(' ')).toMatch(/No crop dialog needed/i);
  });
});