Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
"typecheck": "tsc --noEmit",
"lint": "eslint src --ext .ts",
"lint:fix": "eslint src --ext .ts --fix",
"format": "prettier --write \"src/**/*.ts\"",
"format:check": "prettier --check \"src/**/*.ts\"",
"format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"",
"format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"",
"check": "npm run lint:fix && npm run typecheck",
"check:all": "npm run check && npm run test:run && npm run build",
"prepublishOnly": "npm run clean && npm run build",
Expand Down
8 changes: 1 addition & 7 deletions tests/cli/prefs-parsing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,7 @@ describe('parsePrefs', () => {

// Multiple prefs
it('should parse multiple preferences', () => {
expect(
parsePrefs([
'bool.pref=true',
'int.pref=42',
'string.pref=hello',
])
).toEqual({
expect(parsePrefs(['bool.pref=true', 'int.pref=42', 'string.pref=hello'])).toEqual({
'bool.pref': true,
'int.pref': 42,
'string.pref': 'hello',
Expand Down
13 changes: 3 additions & 10 deletions tests/firefox/connect-existing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,7 @@ describe('GeckodriverHttpDriver BiDi support', () => {

// Mock fetch for session creation
const wsUrl = opts?.webSocketUrl ?? null;
vi.doMock(
'node:module',
async (importOriginal) => await importOriginal()
);
vi.doMock('node:module', async (importOriginal) => await importOriginal());

// We need to mock global fetch
const mockFetch = vi.fn().mockResolvedValue({
Expand Down Expand Up @@ -129,9 +126,7 @@ describe('GeckodriverHttpDriver BiDi support', () => {
const { core } = await createConnectExistingCore({ webSocketUrl: undefined });
const driver = core.getDriver();

await expect(driver.getBidi()).rejects.toThrow(
/BiDi is not available.*webSocketUrl/
);
await expect(driver.getBidi()).rejects.toThrow(/BiDi is not available.*webSocketUrl/);
});

it('should open WebSocket and return BiDi handle', async () => {
Expand Down Expand Up @@ -178,9 +173,7 @@ describe('GeckodriverHttpDriver BiDi support', () => {

// Simulate response
if (wsEventListeners['message']) {
wsEventListeners['message'].forEach((h) =>
h(JSON.stringify({ id: sent.id, result: {} }))
);
wsEventListeners['message'].forEach((h) => h(JSON.stringify({ id: sent.id, result: {} })));
}

await expect(subscribePromise).resolves.toBeUndefined();
Expand Down
8 changes: 2 additions & 6 deletions tests/firefox/core.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,7 @@ describe('FirefoxCore sendBiDiCommand WebSocket readiness', () => {

// ASSERT: send() should now have been called
expect(mockSend).toHaveBeenCalledTimes(1);
expect(mockSend).toHaveBeenCalledWith(
expect.stringContaining('"method":"test.method"')
);
expect(mockSend).toHaveBeenCalledWith(expect.stringContaining('"method":"test.method"'));

// Simulate response to complete the promise
if (eventListeners['message']) {
Expand Down Expand Up @@ -236,9 +234,7 @@ describe('FirefoxCore sendBiDiCommand WebSocket readiness', () => {
const waitForWebSocketOpen = (core as any).waitForWebSocketOpen.bind(core);

// ASSERT: should reject with timeout error (using 50ms timeout for fast test)
await expect(waitForWebSocketOpen(mockWs, 50)).rejects.toThrow(
/timeout.*websocket/i
);
await expect(waitForWebSocketOpen(mockWs, 50)).rejects.toThrow(/timeout.*websocket/i);
});

it('should throw error when WebSocket is CLOSING', async () => {
Expand Down
20 changes: 7 additions & 13 deletions tests/firefox/events/network.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,7 @@ describe('NetworkEvents Header Parsing', () => {
});

it('should NOT return [object Object] for BiDi header values', () => {
const headers = [
{ name: 'Host', value: { type: 'string', value: 'www.example.com' } },
];
const headers = [{ name: 'Host', value: { type: 'string', value: 'www.example.com' } }];

const result = parseHeaders(headers);

Expand Down Expand Up @@ -152,9 +150,7 @@ describe('NetworkEvents Header Parsing', () => {
});

it('should handle BiDi bytes format (binary data)', () => {
const headers = [
{ name: 'X-Binary', value: { type: 'base64', bytes: 'SGVsbG8gV29ybGQ=' } },
];
const headers = [{ name: 'X-Binary', value: { type: 'base64', bytes: 'SGVsbG8gV29ybGQ=' } }];

const result = parseHeaders(headers);

Expand Down Expand Up @@ -208,9 +204,7 @@ describe('NetworkEvents Header Parsing', () => {
});

it('should handle numeric values in BiDi format', () => {
const headers = [
{ name: 'Content-Length', value: { type: 'string', value: 12345 } },
];
const headers = [{ name: 'Content-Length', value: { type: 'string', value: 12345 } }];

const result = parseHeaders(headers);

Expand All @@ -234,9 +228,7 @@ describe('NetworkEvents Header Parsing', () => {
});

it('should handle array with null and undefined items', () => {
const headers = [
{ name: 'X-Array-Mixed', value: ['valid', null, undefined, 'another', ''] },
];
const headers = [{ name: 'X-Array-Mixed', value: ['valid', null, undefined, 'another', ''] }];

const result = parseHeaders(headers);

Expand Down Expand Up @@ -327,7 +319,9 @@ describe('NetworkEvents Header Parsing', () => {

const result = parseHeaders(headers);

expect(result['x-custom-object']).toBe('{"custom":"property","another":123,"nested":{"deep":true}}');
expect(result['x-custom-object']).toBe(
'{"custom":"property","another":123,"nested":{"deep":true}}'
);
});

it('should handle deeply nested value extraction', () => {
Expand Down
19 changes: 17 additions & 2 deletions tests/firefox/snapshot/injected/elementCollector.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
// @vitest-environment jsdom

import { describe, it, expect, vi, beforeAll, afterEach } from 'vitest';
import { isVisible, isRelevant, isFocusable, isInteractive } from '@/firefox/snapshot/injected/elementCollector.js';
import {
isVisible,
isRelevant,
isFocusable,
isInteractive,
} from '@/firefox/snapshot/injected/elementCollector.js';

beforeAll(() => {
// jsdom getComputedStyle returns '' for opacity (browsers return '1')
Expand Down Expand Up @@ -81,7 +86,17 @@ describe('elementCollector', () => {
});

it('returns true for interactive tags', () => {
for (const tag of ['button', 'input', 'select', 'textarea', 'a', 'img', 'video', 'audio', 'iframe']) {
for (const tag of [
'button',
'input',
'select',
'textarea',
'a',
'img',
'video',
'audio',
'iframe',
]) {
const el = createElement(tag);
expect(isRelevant(el)).toBe(true);
}
Expand Down
3 changes: 2 additions & 1 deletion tests/firefox/snapshot/injected/snapshot.injected.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ describe('snapshot.injected - createSnapshot', () => {

describe('selector option', () => {
it('scopes to matched element', () => {
document.body.innerHTML = '<div id="app"><button>Inside</button></div><button>Outside</button>';
document.body.innerHTML =
'<div id="app"><button>Inside</button></div><button>Outside</button>';

const result = createSnapshot(1, { selector: '#app' });
expect(result.tree).not.toBeNull();
Expand Down
9 changes: 5 additions & 4 deletions tests/firefox/snapshot/injected/treeWalker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,13 @@ describe('treeWalker', () => {
const result = walkTree(document.body, 1);
expect(result.tree).not.toBeNull();
// Button should bubble up through irrelevant <aside> to body
const hasButton = result.tree!.children.some(c => c.tag === 'button');
const hasButton = result.tree!.children.some((c) => c.tag === 'button');
expect(hasButton).toBe(true);
});

it('bubbles deeply nested relevant child up', () => {
document.body.innerHTML = '<aside><aside><aside><button>Deep</button></aside></aside></aside>';
document.body.innerHTML =
'<aside><aside><aside><button>Deep</button></aside></aside></aside>';

const result = walkTree(document.body, 1);
expect(result.tree).not.toBeNull();
Expand All @@ -100,9 +101,9 @@ describe('treeWalker', () => {

const result = walkTree(document.body, 1);
expect(result.tree).not.toBeNull();
const nav = result.tree!.children.find(c => c.tag === 'nav');
const nav = result.tree!.children.find((c) => c.tag === 'nav');
expect(nav).toBeDefined();
const btn = nav!.children.find(c => c.tag === 'button');
const btn = nav!.children.find((c) => c.tag === 'button');
expect(btn).toBeDefined();
});
});
Expand Down
4 changes: 2 additions & 2 deletions tests/firefox/types.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ describe('FirefoxLaunchOptions', () => {
it('should accept prefs field', () => {
const options: FirefoxLaunchOptions = {
headless: true,
prefs: { 'a': 'b', 'num': 42, 'bool': true },
prefs: { a: 'b', num: 42, bool: true },
};
expect(options.prefs).toBeDefined();
expect(options.prefs).toEqual({ 'a': 'b', 'num': 42, 'bool': true });
expect(options.prefs).toEqual({ a: 'b', num: 42, bool: true });
});

it('should accept empty prefs object', () => {
Expand Down
4 changes: 3 additions & 1 deletion tests/helpers/firefox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import type { FirefoxLaunchOptions } from '@/firefox/types.js';
/**
* Creates a headless Firefox client for testing
*/
export async function createTestFirefox(options?: Partial<FirefoxLaunchOptions>): Promise<FirefoxClient> {
export async function createTestFirefox(
options?: Partial<FirefoxLaunchOptions>
): Promise<FirefoxClient> {
const defaultOptions: FirefoxLaunchOptions = {
headless: true,
enableBidiLogging: false,
Expand Down
38 changes: 22 additions & 16 deletions tests/integration/console.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@
*/

import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { createTestFirefox, closeFirefox, waitFor, waitForElementInSnapshot, waitForPageLoad } from '../helpers/firefox.js';
import {
createTestFirefox,
closeFirefox,
waitFor,
waitForElementInSnapshot,
waitForPageLoad,
} from '../helpers/firefox.js';
import type { FirefoxClient } from '@/firefox/index.js';
import { resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
Expand Down Expand Up @@ -69,11 +75,11 @@ describe('Console Capture Integration Tests', () => {

await firefox.clickByUid(logInfoBtn.uid);

// Wait for console message
await waitFor(async () => {
const messages = await firefox.getConsoleMessages();
return messages.some((msg) => msg.text.includes('Info message from button'));
}, 5000);
// Wait for console message
await waitFor(async () => {
const messages = await firefox.getConsoleMessages();
return messages.some((msg) => msg.text.includes('Info message from button'));
}, 5000);

const messages = await firefox.getConsoleMessages();
const buttonMessage = messages.find((msg) => msg.text.includes('Info message from button'));
Expand All @@ -100,11 +106,11 @@ describe('Console Capture Integration Tests', () => {

await firefox.clickByUid(logWarnBtn.uid);

// Wait for console message
await waitFor(async () => {
const messages = await firefox.getConsoleMessages();
return messages.some((msg) => msg.text.includes('Warning message from button'));
}, 5000);
// Wait for console message
await waitFor(async () => {
const messages = await firefox.getConsoleMessages();
return messages.some((msg) => msg.text.includes('Warning message from button'));
}, 5000);

const messages = await firefox.getConsoleMessages();
const warnMessage = messages.find((msg) => msg.text.includes('Warning message from button'));
Expand All @@ -131,11 +137,11 @@ describe('Console Capture Integration Tests', () => {

await firefox.clickByUid(logErrorBtn.uid);

// Wait for console message
await waitFor(async () => {
const messages = await firefox.getConsoleMessages();
return messages.some((msg) => msg.text.includes('Error message from button'));
}, 5000);
// Wait for console message
await waitFor(async () => {
const messages = await firefox.getConsoleMessages();
return messages.some((msg) => msg.text.includes('Error message from button'));
}, 5000);

const messages = await firefox.getConsoleMessages();
const errorMessage = messages.find((msg) => msg.text.includes('Error message from button'));
Expand Down
7 changes: 6 additions & 1 deletion tests/integration/form.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
*/

import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { createTestFirefox, closeFirefox, waitForElementInSnapshot, waitForPageLoad } from '../helpers/firefox.js';
import {
createTestFirefox,
closeFirefox,
waitForElementInSnapshot,
waitForPageLoad,
} from '../helpers/firefox.js';
import type { FirefoxClient } from '@/firefox/index.js';
import { resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
Expand Down
8 changes: 7 additions & 1 deletion tests/integration/network.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@
*/

import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { createTestFirefox, closeFirefox, waitFor, waitForElementInSnapshot, waitForPageLoad } from '../helpers/firefox.js';
import {
createTestFirefox,
closeFirefox,
waitFor,
waitForElementInSnapshot,
waitForPageLoad,
} from '../helpers/firefox.js';
import type { FirefoxClient } from '@/firefox/index.js';
import { resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
Expand Down
20 changes: 14 additions & 6 deletions tests/integration/snapshot.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
*/

import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { createTestFirefox, closeFirefox, waitForElementInSnapshot, waitForPageLoad } from '../helpers/firefox.js';
import {
createTestFirefox,
closeFirefox,
waitForElementInSnapshot,
waitForPageLoad,
} from '../helpers/firefox.js';
import type { FirefoxClient } from '@/firefox/index.js';
import { resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
Expand Down Expand Up @@ -161,9 +166,9 @@ describe('Snapshot Integration Tests', () => {
// Using :has() with unclosed parenthesis should trigger an exception
const invalidSelector = '#test:has(';

await expect(
firefox.takeSnapshot({ selector: invalidSelector })
).rejects.toThrow(/Invalid selector syntax/);
await expect(firefox.takeSnapshot({ selector: invalidSelector })).rejects.toThrow(
/Invalid selector syntax/
);
}, 10000);

it('should exclude children of hidden parents even in includeAll mode', async () => {
Expand All @@ -176,7 +181,8 @@ describe('Snapshot Integration Tests', () => {

// Check that elements inside hidden parent are NOT in snapshot
const hasHiddenButton = snapshot.json.uidMap.some(
(entry) => entry.css.includes('buttonInHiddenDiv') || entry.css.includes('id="buttonInHiddenDiv"')
(entry) =>
entry.css.includes('buttonInHiddenDiv') || entry.css.includes('id="buttonInHiddenDiv"')
);
const hasHiddenText = snapshot.json.uidMap.some(
(entry) => entry.css.includes('textInHiddenDiv') || entry.css.includes('id="textInHiddenDiv"')
Expand Down Expand Up @@ -232,7 +238,9 @@ describe('Snapshot Integration Tests', () => {

// Check that button inside visibility:hidden parent is NOT in snapshot
const hasInvisibleButton = snapshot.json.uidMap.some(
(entry) => entry.css.includes('buttonInInvisibleDiv') || entry.css.includes('id="buttonInInvisibleDiv"')
(entry) =>
entry.css.includes('buttonInInvisibleDiv') ||
entry.css.includes('id="buttonInInvisibleDiv"')
);

expect(hasInvisibleButton).toBe(false);
Expand Down
7 changes: 6 additions & 1 deletion tests/integration/tabs.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
*/

import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { createTestFirefox, closeFirefox, waitForElementInSnapshot, waitForPageLoad } from '../helpers/firefox.js';
import {
createTestFirefox,
closeFirefox,
waitForElementInSnapshot,
waitForPageLoad,
} from '../helpers/firefox.js';
import type { FirefoxClient } from '@/firefox/index.js';
import { resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
Expand Down
Loading