Ctrl K
ComunidadGuías…

__tests__/gsc-pages.test.js

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

Archivo original ↗Preguntar a KiBot
/*
 * THE ADDRESSES BEHIND A REASON — the half of the reading that was missing.
 *
 * Pulse showed "Geblokkeerd door robots.txt = 9" for days. True, and useless: nobody can fix a
 * number. The nine URLs exist, one click deeper in the console, and the walk never went there.
 *
 * Two of these tests exist because of traps that were sitting in the way:
 *
 *   THE DUPLICATE CHECK WOULD HAVE EATEN THEM. The walk records the reason row first, then opens it
 *   and records the URLs behind it — same kind, same label, same value. addGscHealth refuses a
 *   finding it already has, so that second call was thrown away, and with it the only actionable
 *   part. A repeat that carries addresses is not a repeat.
 *
 *   THE COLLECTOR IS LAST-WINS, WHICH WOULD HAVE DROPPED THEM TOO. The count moving from 9 to 8 must
 *   update the row, but it must not lose the addresses read on the earlier call, because the row and
 *   its addresses arrive separately.
 */
import { describe, it, expect } from 'vitest';
import { createRequire } from 'module';
import { tmpdir } from 'node:os';
import { join } from 'node:path';

const require = createRequire(import.meta.url);
// jobs.js resolves its directory at load time and persists every change to disk. Point it at a
// temp dir BEFORE requiring it, so a test never writes into a real /profiles/jobs.
process.env.PROFILE_DIR = join(tmpdir(), `gb-gsc-pages-test-${process.pid}`);
const gsc = require('../src/gscWatch');
const jobsMod = require('../src/jobs');

const PROPERTY = 'sc-domain:my-app.engineer';
const runWith = (...jobIds) => ({ steps: jobIds.map((id) => ({ output: { __jobId: id } })) });
const jobs = (map) => (id) => map[id] || null;

const REASON = 'Geblokkeerd door robots.txt';
const NINE = [
  'https://my-app.engineer/api/me/export',
  'https://my-app.engineer/api/showcase',
  'https://my-app.engineer/api/explore/screenshot?owner=carla&app=shop',
];

describe('a finding carries the addresses behind it', () => {
  it('the collector keeps pages, and merges the ones that came in a separate call', () => {
    const job = {
      gscHealth: [
        { kind: 'indexing', label: REASON, value: '9', detail: 'ours to fix' },
        { kind: 'indexing', label: REASON, value: '9', pages: NINE },
      ],
    };
    const [found] = gsc.findingsOf(runWith('j1'), jobs({ j1: job }));
    expect(found.label).toBe(REASON);
    expect(found.value).toBe('9');
    expect(found.detail).toBe('ours to fix');
    expect(found.pages).toEqual(NINE);
  });

  it('a later pass with a NEW count keeps the addresses the earlier one read', () => {
    // The row and its addresses arrive in two calls; last-wins on the value must not mean
    // last-wins on the pages, or a changed count silently empties the only useful part.
    const job = {
      gscHealth: [
        { kind: 'indexing', label: REASON, value: '9', pages: NINE },
        { kind: 'indexing', label: REASON, value: '8' },
      ],
    };
    const [found] = gsc.findingsOf(runWith('j1'), jobs({ j1: job }));
    expect(found.value).toBe('8');
    expect(found.pages).toEqual(NINE);
  });

  it('a finding with no pages still works and simply has none', () => {
    const job = { gscHealth: [{ kind: 'manual_action', label: 'manual actions', value: 'Geen problemen' }] };
    const [found] = gsc.findingsOf(runWith('j1'), jobs({ j1: job }));
    expect(found.pages).toEqual([]);
  });
});

describe('what Pulse is shown', () => {
  const rowFor = (pages) => gsc.feedRowsFor(
    [{ kind: 'indexing', label: REASON, value: String(pages.length), detail: '', pages }],
    { property: PROPERTY },
  )[0];

  it('the addresses are in the fields, numbered, with a count', () => {
    const row = rowFor(NINE);
    expect(row.fields.pages).toBe('3');
    expect(row.fields['page 1']).toBe(NINE[0]);
    expect(row.fields['page 3']).toBe(NINE[2]);
  });

  it('the title stays the reason alone — the key must not move when the addresses do', () => {
    // A title carrying the count or the URLs makes every pass a new row, and the page fills with
    // history instead of showing the current state. This is the same rule the counts already follow.
    const one = rowFor([NINE[0]]);
    const three = rowFor(NINE);
    expect(one.title).toBe(REASON);
    expect(three.title).toBe(REASON);
    expect(one.url).toBe(three.url);
  });

  it('a long list is capped and says how many it did not list', () => {
    const many = Array.from({ length: 40 }, (_, i) => `https://my-app.engineer/learn/page-${i}`);
    const row = rowFor(many);
    expect(row.fields.pages).toBe('40');
    expect(row.fields['page 25']).toBe(many[24]);
    expect(row.fields['page 26']).toBeUndefined();
    expect(row.fields['and more']).toMatch(/15 further/);
  });

  it('a finding without addresses gets no pages fields at all', () => {
    const row = rowFor([]);
    expect(row.fields.pages).toBeUndefined();
    expect(row.fields['page 1']).toBeUndefined();
  });
});

describe('storing them on the job', () => {
  const freshJob = () => ({ id: 'job-1', gscHealth: [], steps: [] });

  it('a repeat that carries addresses is NOT a duplicate — it fills them in', () => {
    const j = freshJob();
    const first = jobsMod.addGscHealth(j, { kind: 'indexing', label: REASON, value: '9' });
    expect(first).toBeTruthy();
    expect(first.pages).toEqual([]);

    const second = jobsMod.addGscHealth(j, { kind: 'indexing', label: REASON, value: '9', pages: NINE });
    expect(second, 'the addresses must not be refused as a duplicate').toBeTruthy();
    expect(second.pages).toEqual(NINE);
    expect(j.gscHealth).toHaveLength(1);        // one finding, now complete — not two
  });

  it('a true repeat, with nothing new, is still refused', () => {
    const j = freshJob();
    jobsMod.addGscHealth(j, { kind: 'indexing', label: REASON, value: '9', pages: NINE });
    expect(jobsMod.addGscHealth(j, { kind: 'indexing', label: REASON, value: '9', pages: NINE })).toBeNull();
    expect(j.gscHealth).toHaveLength(1);
  });

  it('only real addresses are kept — a count or a label is not a URL', () => {
    const j = freshJob();
    const r = jobsMod.addGscHealth(j, {
      kind: 'indexing', label: REASON, value: '9',
      pages: ['https://my-app.engineer/a', '9', 'Geblokkeerd door robots.txt', '', null,
              '/relative/path', 'https://my-app.engineer/a'],
    });
    expect(r.pages).toEqual(['https://my-app.engineer/a']);
  });
});