markdown-prose-classes.test.ts2.5 KBView on GitHub
/**
 * The editable and read-only markdown views must render a document identically. They used to hold
 * byte-identical copies of the class string and drifted apart whenever one was edited, so a doc
 * looked different depending on whether you could edit it. These pin the single source of truth.
 */
import { readFileSync } from 'node:fs';
import { join } from 'node:path';

import { MARKDOWN_PROSE_CLASS } from '@/components/markdown-prose-classes';

const ROOT = join(__dirname, '../..');
const EDITOR = readFileSync(join(ROOT, 'components/markdown-editor.tsx'), 'utf8');
const READ_ONLY = readFileSync(join(ROOT, 'components/read-only-markdown-view.tsx'), 'utf8');

/** `[&_hr]:mt-14` → 14. */
function spacing(prop: 'mt' | 'mb', selector: string): number {
  const m = new RegExp(`\\[&_${selector}\\]:${prop}-(\\d+)`).exec(MARKDOWN_PROSE_CLASS);
  if (!m) throw new Error(`no ${prop} for ${selector}`);
  return Number(m[1]);
}

describe('MARKDOWN_PROSE_CLASS', () => {
  it('is the only place either view defines its typography', () => {
    for (const src of [EDITOR, READ_ONLY]) {
      expect(src).toContain('class: MARKDOWN_PROSE_CLASS');
      // An inline heading or rule rule here is the drift this file exists to prevent.
      expect(src).not.toMatch(/\[&_h1\]:/);
      expect(src).not.toMatch(/horizontalRule: \{/);
    }
  });

  it('leaves the section rule at its original symmetric margin', () => {
    // Breathing room above a section break is authored in the markdown (a zero-width-space
    // paragraph before the `---`), not imposed by the stylesheet — so a document that wants the
    // space asks for it and one that does not is not padded against its will.
    expect(MARKDOWN_PROSE_CLASS).toContain('[&_hr]:my-4');
    expect(MARKDOWN_PROSE_CLASS).not.toMatch(/\[&_hr\]:mt-/);
  });

  it('zeroes the top margin of a heading that directly follows a rule', () => {
    // Otherwise the gap under the rule is the heading's mt, not the rule's mb, and every section
    // opens with a different amount of space depending on its heading level.
    for (const h of ['h1', 'h2', 'h3']) {
      expect(MARKDOWN_PROSE_CLASS).toContain(`[&_hr+${h}]:mt-0`);
    }
  });

  it('does not push the whole page down for a document that opens on a heading', () => {
    expect(MARKDOWN_PROSE_CLASS).toContain('[&>h1:first-child]:mt-0');
  });

  it('keeps headings in descending order of the space above them', () => {
    expect(spacing('mt', 'h1')).toBeGreaterThan(spacing('mt', 'h2'));
    expect(spacing('mt', 'h2')).toBeGreaterThan(spacing('mt', 'h3'));
  });
});