import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { manageDriverSession } from '../../src/driver/session-manager';
import {
interact,
screenshot,
keyboard,
waitFor,
getStyles,
executeJavaScript,
focusElement,
} from '../../src/driver/webview-interactions';
/**
* E2E tests for webview interactions.
* Now uses native Tauri IPC - works on all platforms (Linux, Windows, macOS)!
*/
describe('Webview Interactions E2E Tests', () => {
const TIMEOUT = 10000;
beforeAll(async () => {
// App is already started globally - just init the session
await manageDriverSession('start');
});
afterAll(async () => {
// Don't stop the app - it's managed globally
await manageDriverSession('stop');
});
describe('Gesture Interactions', () => {
it('should perform click interaction by selector', async () => {
const result = await interact({ action: 'click', selector: 'button' });
expect(result).toContain('Clicked');
}, TIMEOUT);
it('should perform click interaction by coordinates', async () => {
const result = await interact({ action: 'click', x: 100, y: 100 });
expect(result).toContain('Clicked');
}, TIMEOUT);
it('should perform double-click interaction', async () => {
const result = await interact({ action: 'double-click', selector: 'button' });
expect(result).toContain('Double-clicked');
}, TIMEOUT);
it('should perform long-press interaction', async () => {
const result = await interact({ action: 'long-press', selector: 'button', duration: 1000 });
expect(result).toContain('Long-pressed');
}, TIMEOUT);
it('should perform swipe gesture', async () => {
const result = await interact({
action: 'swipe',
fromX: 100,
fromY: 100,
toX: 300,
toY: 300,
duration: 500,
});
expect(result).toContain('Swiped');
}, TIMEOUT);
it('should perform scroll interaction', async () => {
const result = await interact({ action: 'scroll', scrollY: 100 });
expect(result).toContain('Scrolled');
}, TIMEOUT);
});
describe('Screenshot', () => {
it('should take full webview screenshot with valid data', async () => {
const result = await screenshot();
expect(result).toContain('screenshot captured');
expect(result).toContain('data:image/');
expect(result).toContain('base64,');
// Extract the base64 data
const base64Match = result.match(/data:image\/[^;]+;base64,([A-Za-z0-9+/=]+)/);
expect(base64Match).toBeTruthy();
if (base64Match) {
const base64Data = base64Match[1];
// Ensure the screenshot has meaningful content (not just a 1x1 pixel)
// A minimal valid PNG is about 67 characters,
// anything substantial should be much larger
expect(base64Data.length).toBeGreaterThan(100);
// Verify it's valid base64 (will throw if invalid)
expect(() => { return Buffer.from(base64Data, 'base64'); }).not.toThrow();
}
}, TIMEOUT);
});
describe('Keyboard Interactions', () => {
it('should type text into an element', async () => {
const result = await keyboard('type', '#greet-input', 'Hello World');
expect(result).toContain('Typed "Hello World"');
}, TIMEOUT);
it('should press a key', async () => {
const result = await keyboard('press', 'Enter');
expect(result).toContain('Pressed key: Enter');
}, TIMEOUT);
it('should press a key with modifiers', async () => {
const result = await keyboard('press', 'a', [ 'Control' ]);
expect(result).toContain('Pressed key: a');
expect(result).toContain('Control');
}, TIMEOUT);
it('should perform key down', async () => {
const result = await keyboard('down', 'Shift');
expect(result).toContain('Key down: Shift');
}, TIMEOUT);
it('should perform key up', async () => {
const result = await keyboard('up', 'Shift');
expect(result).toContain('Key up: Shift');
}, TIMEOUT);
});
describe('Wait Operations', () => {
it('should wait for element selector', async () => {
const result = await waitFor('selector', 'body', 5000);
expect(result).toContain('Element found');
}, TIMEOUT);
it('should wait for text content', async () => {
const result = await waitFor('text', 'Welcome to Tauri', 5000);
expect(result).toBeDefined();
expect(result).toContain('Text found');
}, TIMEOUT);
});
describe('Style Operations', () => {
it('should get computed styles for single element', async () => {
const result = await getStyles('body', [ 'color', 'background-color' ]);
expect(result).toBeDefined();
expect(result).not.toBe('');
// Should contain style information as JSON
const styles = JSON.parse(result);
expect(styles).toHaveProperty('color');
expect(styles).toHaveProperty('background-color');
// Verify the values are non-empty strings (actual CSS values)
expect(typeof styles.color).toBe('string');
expect(styles.color.length).toBeGreaterThan(0);
expect(typeof styles['background-color']).toBe('string');
}, TIMEOUT);
it('should get all computed styles', async () => {
const result = await getStyles('body');
expect(result).toBeDefined();
expect(result).not.toBe('');
// Should contain many style properties
const styles = JSON.parse(result);
const styleKeys = Object.keys(styles);
// Should have many CSS properties (typically 200+)
expect(styleKeys.length).toBeGreaterThan(50);
// Check for some common properties
expect(styles).toHaveProperty('display');
expect(styles).toHaveProperty('position');
expect(styles).toHaveProperty('margin-top'); // CSS splits margin into individual sides
}, TIMEOUT);
it('should get styles for multiple elements', async () => {
const result = await getStyles('div', undefined, true);
expect(result).toBeDefined();
expect(result).not.toBe('');
// Should be an array of style objects
const stylesArray = JSON.parse(result);
expect(Array.isArray(stylesArray)).toBe(true);
if (stylesArray.length > 0) {
// Each element should have style properties
expect(Object.keys(stylesArray[0]).length).toBeGreaterThan(50);
}
}, TIMEOUT);
});
describe('JavaScript Execution', () => {
it('should execute JavaScript code', async () => {
const result = await executeJavaScript('return 2 + 2');
expect(result).toContain('4');
}, TIMEOUT);
it('should execute JavaScript with arguments', async () => {
const result = await executeJavaScript(
'function(a, b) { return a + b; }',
[ 5, 3 ]
);
expect(result).toContain('8');
}, TIMEOUT);
});
describe('Focus and Keyboard Management', () => {
it('should focus on element', async () => {
const result = await focusElement('input');
expect(result).toContain('Focused element');
}, TIMEOUT);
it('should dismiss keyboard via executeJavaScript', async () => {
// First focus an element
await focusElement('input');
// Then dismiss keyboard by blurring
const result = await executeJavaScript('document.activeElement?.blur(); return "dismissed"');
expect(result).toContain('dismissed');
}, TIMEOUT);
});
});