Skip to content

test: Add interoperability tests for browser state across language #29

Description

@bigboateng

Integration and Interoperability Tests

Overview

Add comprehensive integration tests to verify cross-language compatibility and consistent behavior across different storage providers.

Cross-Language Interoperability Tests

Playwright (TypeScript) to Selenium (Python) State Transfer

// Test capturing state in Playwright and restoring in Selenium
test('capture state in Playwright and restore in Selenium', async () => {
  // 1. Capture state in Playwright
  const browserState = new BrowserState({
    storageType: 'redis',
    redisOptions: { host: 'localhost', port: 6379 }
  });
  
  const sessionId = await browserState.mount();
  const browser = await playwright.chromium.launchPersistentContext(
    await browserState.getUserDataDir(),
    { headless: false }
  );
  
  // Perform some actions
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await page.fill('input', 'test data');
  
  // Save state
  await browserState.unmount();
  
  // 2. Verify state can be restored in Python
  const pythonState = await verifyPythonRestore(sessionId);
  assert(pythonState.inputValue === 'test data');
});

Python to TypeScript State Transfer

# Test capturing state in Selenium and restoring in Playwright
def test_capture_in_selenium_restore_in_playwright():
    # 1. Capture state in Selenium
    browser_state = BrowserState(
        BrowserStateOptions(
            user_id="test_user",
            redis_options={
                "host": "localhost",
                "port": 6379
            }
        )
    )
    
    session_id = browser_state.mount()
    driver = webdriver.Chrome(
        options=Options().add_argument(f"--user-data-dir={browser_state.get_user_data_dir()}")
    )
    
    # Perform actions
    driver.get("https://example.com")
    driver.find_element(By.ID, "input").send_keys("test data")
    
    # Save state
    browser_state.unmount()
    
    # 2. Verify state can be restored in TypeScript
    verify_typescript_restore(session_id)

Storage Provider Consistency Tests

Key Structure Consistency

test('verify consistent key structure across providers', async () => {
  const userId = 'test_user';
  const sessionId = 'test_session';
  
  // Test with different storage providers
  const providers = [
    new RedisStorageProvider({ host: 'localhost', port: 6379 }),
    new S3Storage('test-bucket'),
    new GCSStorage('test-bucket')
  ];
  
  for (const provider of providers) {
    // Upload same data
    await provider.upload(userId, sessionId, testData);
    
    // Verify same key structure is used
    const keys = await provider.listSessions(userId);
    assert(keys.includes(sessionId));
    
    // Verify data can be retrieved
    const data = await provider.download(userId, sessionId);
    assert(data === testData);
  }
});

Cross-Provider Migration Tests

State Migration Between Providers

test('migrate state between storage providers', async () => {
  const userId = 'test_user';
  const sessionId = 'test_session';
  
  // 1. Create state in Redis
  const redisProvider = new RedisStorageProvider({ host: 'localhost', port: 6379 });
  await redisProvider.upload(userId, sessionId, testData);
  
  // 2. Migrate to S3
  const s3Provider = new S3Storage('test-bucket');
  const data = await redisProvider.download(userId, sessionId);
  await s3Provider.upload(userId, sessionId, data);
  
  // 3. Verify data in S3
  const s3Data = await s3Provider.download(userId, sessionId);
  assert(s3Data === testData);
  
  // 4. Clean up Redis
  await redisProvider.deleteSession(userId, sessionId);
});

Additional Integration Tests

Concurrent Access Tests

test('handle concurrent access to same session', async () => {
  const userId = 'test_user';
  const sessionId = 'test_session';
  
  // Simulate multiple processes accessing same session
  const processes = Array(5).fill(null).map(() => 
    new BrowserState({
      storageType: 'redis',
      redisOptions: { host: 'localhost', port: 6379 }
    })
  );
  
  // Mount same session in all processes
  await Promise.all(processes.map(p => p.mount(sessionId)));
  
  // Verify no data corruption
  const states = await Promise.all(
    processes.map(p => p.getUserDataDir())
  );
  
  assert(new Set(states).size === 1);
});

Error Recovery Tests

test('handle storage provider failures gracefully', async () => {
  const userId = 'test_user';
  const sessionId = 'test_session';
  
  // Simulate Redis connection failure
  const provider = new RedisStorageProvider({
    host: 'invalid-host',
    port: 6379
  });
  
  try {
    await provider.upload(userId, sessionId, testData);
    throw new Error('Should have failed');
  } catch (error) {
    assert(error.message.includes('Failed to initialize Redis client'));
  }
});

Test Infrastructure Requirements

  1. Test Environment Setup

    • Docker compose for Redis, S3 (MinIO), and GCS (Fake-GCS-Server)
    • Python and Node.js test runners
    • Browser automation setup (Playwright and Selenium)
  2. Test Data

    • Sample browser states with various complexities
    • Test files of different sizes
    • Test data with special characters in paths
  3. CI/CD Integration

    • GitHub Actions workflow for running integration tests
    • Matrix testing across different Node.js and Python versions
    • Storage provider availability checks

Future Test Scenarios

  • Test with different browser types (Chrome, Firefox, Safari)
  • Test with different storage provider configurations
  • Test with different compression settings
  • Test with different TTL values
  • Test with different file size limits
  • Test with different key prefix configurations
  • Test with different temporary directory locations
  • Test with different TLS configurations
  • Test with different Redis database numbers
  • Test with different Redis connection options

Success Criteria

  1. All cross-language tests pass
  2. All storage provider consistency tests pass
  3. All migration tests pass
  4. All concurrent access tests pass
  5. All error recovery tests pass
  6. No data corruption in any test scenario
  7. Consistent key structure across all providers
  8. Proper cleanup after tests
  9. Clear error messages for all failure scenarios
  10. Documentation of test scenarios and results

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions