// @ts-check const { test, expect } = require('@playwright/test'); const { openTerminal, typeCommand } = require('./helpers'); // The vim simulator renders into a fixed full-screen overlay appended to // ; text assertions below run against the whole body and pass/fail // on the overlay's presence or absence. test.describe('Fake terminal — vim simulator', () => { test.beforeEach(async ({ page }) => { await page.goto('/'); await openTerminal(page); }); test('vim with no filename shows the splash and q exits', async ({ page }) => { await typeCommand(page, 'vim'); await expect(page.locator('body')).toContainText('VIM - Vi sIgnificantly worse M'); await expect(page.locator('body')).toContainText('version 0.0.0-alpha'); await page.keyboard.press('q'); await expect(page.locator('body')).not.toContainText('VIM - Vi sIgnificantly worse M'); // terminal is usable again await typeCommand(page, 'hostname'); await expect(page.locator('.terminal-content > div').nth(-2)).toHaveText('homelab'); }); test('vim with a filename opens a buffer; insert, save & quit', async ({ page }) => { await typeCommand(page, 'vim notes.txt'); await expect(page.locator('body')).toContainText('Welcome to notes.txt!'); await expect(page.locator('body')).toContainText('"notes.txt"'); // insert mode, type text at column 0 await page.keyboard.press('i'); await expect(page.locator('body')).toContainText('-- INSERT --'); await page.keyboard.type('hello'); await expect(page.locator('body')).toContainText('helloWelcome to notes.txt!'); // back to normal mode await page.keyboard.press('Escape'); await expect(page.locator('body')).not.toContainText('-- INSERT --'); // :wq saves (simulated) and exits await page.keyboard.type(':wq'); await page.keyboard.press('Enter'); await expect(page.locator('body')).not.toContainText('Welcome to notes.txt!'); await expect(page.locator('.terminal-content')).toContainText('File saved (simulated).'); }); test('vim normal-mode navigation and line deletion', async ({ page }) => { await typeCommand(page, 'vim file.md'); await expect(page.locator('body')).toContainText('Welcome to file.md!'); // open a new line below (o), type, escape await page.keyboard.press('o'); await expect(page.locator('body')).toContainText('-- INSERT --'); await page.keyboard.type('line two'); await page.keyboard.press('Escape'); // both lines present await expect(page.locator('body')).toContainText('Welcome to file.md!'); await expect(page.locator('body')).toContainText('line two'); // G jumps to the last line, dd deletes it (Shift+D in this sim). // Use innerText: deleted lines are hidden (display:none) but remain // in the DOM, so textContent would still contain them. await page.keyboard.press('G'); await page.keyboard.press('Shift+D'); await expect.poll(async () => page.evaluate(() => document.body.innerText) ).not.toContain('line two'); await expect(page.locator('body')).toContainText('Welcome to file.md!'); // :q! force-quits await page.keyboard.type(':q!'); await page.keyboard.press('Enter'); await expect(page.locator('body')).not.toContainText('Welcome to file.md!'); }); });