// @vitest-environment jsdom // // A removed line owns no line in Actual, so it cannot carry a band. It leaves a // rule on the edge of the line that took its place instead. The mock project has // no such change, so this drives the renderer with a git payload of its own. import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest' import { cleanup, fireEvent, render, waitFor } from '@testing-library/react' import React from 'react' vi.mock('../src/renderer/src/terminals', () => { let n = 0 return { Terminal: () => null, lid: () => ++n } }) import { App } from '../src/renderer/src/App' import { ProjectProvider } from '../src/renderer/src/project' import { installBridge, removeBridge } from './stub-bridge' const HEAD = 'keep\ngone\ntail\n' const DISK = 'keep\ntail\n' beforeAll(() => { globalThis.ResizeObserver = class { observe(): void {} unobserve(): void {} disconnect(): void {} } as never if (!Element.prototype.scrollIntoView) Element.prototype.scrollIntoView = (): void => {} }) beforeEach(() => { installBridge([{ path: 'demo.txt', status: 'M', staged: false, original: HEAD, updated: DISK }], { 'demo.txt': DISK }) }) afterEach(() => { cleanup() localStorage.clear() removeBridge() }) async function openRow(): Promise { const c = render().container const row = await waitFor(() => { const r = c.querySelector('.git-row') if (!r) throw new Error('git not ready') return r }) fireEvent.click(row) await waitFor(() => expect(c.querySelector('.code-edit')).toBeTruthy()) return c } describe('a change that only removes a line', () => { it('rules the edge of the line below it, and tints nothing', async () => { const c = await openRow() await waitFor(() => expect(c.querySelectorAll('.ce-gaprule')).toHaveLength(1)) expect(c.querySelector('.ce-band')).toBeNull() expect(c.querySelector('.ce-gutter .chg')).toBeNull() }) it('hands the removed line to the hover panel', async () => { const c = await openRow() const scroll = await waitFor(() => { const el = c.querySelector('.ce-scroll') if (!el || !c.querySelector('.ce-gaprule')) throw new Error('rule not ready') return el }) // 'tail' took the place of the removed line, and sits on line 2. fireEvent.mouseMove(scroll, { clientY: 10 + 20 + 5 }) const peek = await waitFor(() => { const p = c.querySelector('.peek') if (!p) throw new Error('peek not ready') return p }) expect(Array.from(peek.querySelectorAll('.ln-row.del')).map((el) => el.textContent?.replace(/^\d+/, ''))).toEqual(['gone']) }) })