import { PlaywrightReproducer } from '../../src/plugins/reproducers/PlaywrightReproducer'; import { IAction } from '../../src/core/interfaces'; function makeAction(id: string, type: IAction['type'], overrides: Partial = {}): IAction { return { id, type, selector: '#btn', timestamp: 1000, seed: 42, stateId: 's1', ...overrides, }; } describe('PlaywrightReproducer', () => { let reproducer: PlaywrightReproducer; beforeEach(() => { reproducer = new PlaywrightReproducer(); }); describe('serialize', () => { it('serializes an action trace to valid JSON', () => { const trace = [makeAction('a1', 'click'), makeAction('a2', 'fill', { value: 'test' })]; const json = reproducer.serialize(trace); expect(() => JSON.parse(json)).not.toThrow(); }); it('round-trips through serialize/deserialize', () => { const trace = [ makeAction('a1', 'navigate', { url: 'http://localhost/', selector: undefined }), makeAction('a2', 'click'), makeAction('a3', 'fill', { value: '' }), ]; const json = reproducer.serialize(trace); const restored = reproducer.deserialize(json); expect(restored).toHaveLength(3); expect(restored[0].id).toBe('a1'); expect(restored[1].type).toBe('click'); expect(restored[2].value).toBe(''); }); it('serializes empty trace', () => { expect(reproducer.serialize([])).toBe('[]'); }); }); describe('deserialize', () => { it('throws on invalid JSON', () => { expect(() => reproducer.deserialize('not-json')).toThrow(); }); it('throws when JSON is not an array', () => { expect(() => reproducer.deserialize('{"id":"a1"}')).toThrow( 'PlaywrightReproducer.deserialize: expected a JSON array' ); }); it('preserves all action fields', () => { const action = makeAction('a1', 'fill', { value: 'hello', selector: 'input#email' }); const restored = reproducer.deserialize(reproducer.serialize([action])); expect(restored[0]).toEqual(action); }); }); describe('generateScript', () => { it('generates a non-empty string', () => { const trace = [makeAction('a1', 'click')]; const script = reproducer.generateScript(trace); expect(typeof script).toBe('string'); expect(script.length).toBeGreaterThan(0); }); it('includes playwright require', () => { const script = reproducer.generateScript([makeAction('a1', 'click')]); expect(script).toContain("require('playwright')"); }); it('generates navigate step', () => { const action = makeAction('a1', 'navigate', { url: 'http://localhost:3000', selector: undefined }); const script = reproducer.generateScript([action]); expect(script).toContain('page.goto'); expect(script).toContain('http://localhost:3000'); }); it('generates click step', () => { const script = reproducer.generateScript([makeAction('a1', 'click', { selector: '#submit' })]); expect(script).toContain('click()'); expect(script).toContain('#submit'); }); it('generates fill step with value', () => { const script = reproducer.generateScript([makeAction('a1', 'fill', { selector: '#email', value: '' })]); expect(script).toContain('fill'); expect(script).toContain('#email'); }); it('includes seed comment for reproducibility', () => { const script = reproducer.generateScript([makeAction('a1', 'click')]); expect(script).toContain('seed=42'); }); it('generates empty script for empty trace', () => { const script = reproducer.generateScript([]); expect(script).toContain('browser.close'); }); }); });