moviestar

POD Provider Compatibility Guide

This guide explains how to adapt the MovieStar integration testing approach for different POD providers. For general adaptation, see Adapting for Your App.

Documentation index: See README.md for complete documentation navigation.

Solid POD Providers

All Solid POD providers must implement the Solid-OIDC specification, which uses:

The core OAuth + DPoP + Puppeteer approach works with any compliant Solid POD provider. Only provider-specific UI selectors and configuration details need adjustment.

Tested Providers

Provider Status Notes
Community Solid Server (CSS) Tested Used in MovieStar
Node Solid Server (NSS) Compatible Solid-OIDC support
Enterprise Solid Server (ESS) Compatible Commercial offering
Custom implementations Unknown Must implement Solid-OIDC

Provider-Specific Configuration

Community Solid Server (CSS)

Used by: MovieStar integration tests

Login flow:

Token expiry: 3600 seconds (1 hour)

Refresh tokens: Supported but not always returned

Configuration:

{
  "email": "test@example.com",
  "password": "your-password",
  "securityKey": "1234",
  "issuer": "https://pods.dev.solidcommunity.au/"
}

Puppeteer selectors (current):

// Email field
await page.waitForSelector('input[name="email"]');

// Password field
await page.waitForSelector('input[name="password"]');

// Security key field
await page.waitForSelector('input[id="securityKey"]');

// Consent button
await page.$('button:has-text("Yes")');

Node Solid Server (NSS)

Login flow:

Key differences from CSS:

Modify for NSS:

// In pod_auth_automator.dart
final usernameInput = await page.waitForSelector(
  'input[name="username"]'  // Changed from 'email'
);

final consentButton = await page.waitForSelector(
  'button[name="approve"]'  // Changed from 'yes'
);

Configuration:

{
  "username": "testuser",
  "password": "your-password",
  "issuer": "https://your-nss-server.example.com/"
}

Enterprise Solid Server (ESS)

Login flow:

Key considerations:

Requires:

Example adaptation:

// Navigate to SSO login page
await page.goto(authUrl);

// Wait for SSO provider redirect
await page.waitForNavigation();

// Fill SSO credentials
await page.type('#sso-username', credentials['username']);
await page.type('#sso-password', credentials['password']);

// Submit SSO form
await page.click('button[type="submit"]');

// Handle consent screen (if separate)
await page.waitForSelector('.consent-form');
await page.click('button[name="consent"]');

Adapting Puppeteer Selectors

Finding Correct Selectors

Run browser automation in non-headless mode to inspect elements:

dart run integration_test/tools/generate_auth_data.dart --no-headless

Use Chrome DevTools to find selectors:

Common Selector Patterns

By ID:

await page.waitForSelector('#username');

By name attribute:

await page.waitForSelector('input[name="email"]');

By class:

await page.waitForSelector('.login-button');

By text content:

await page.$('button:has-text("Login")');

By type and attribute:

await page.waitForSelector('input[type="password"]');

Updating Selectors in Code

File: integration_test/helpers/pod_auth_automator.dart

Section: _fillLoginForm() method

Future<void> _fillLoginForm(pw.Page page) async {
  // Update these selectors for your POD provider
  final emailInput = await page.waitForSelector(
    'input[name="email"]'  // ← Change this
  );
  await emailInput.type(credentials['email']);

  final passwordInput = await page.waitForSelector(
    'input[name="password"]'  // ← Change this
  );
  await passwordInput.type(credentials['password']);

  // Security key may not exist for all providers
  if (credentials.containsKey('securityKey')) {
    final securityKeyInput = await page.$(
      'input[id="securityKey"]'  // ← Change this
    );
    if (securityKeyInput != null) {
      await securityKeyInput.type(credentials['securityKey']);
    }
  }

  // Submit button selector
  final submitButton = await page.waitForSelector(
    'button[type="submit"]'  // ← Change this
  );
  await submitButton.click();
}

Troubleshooting Provider Issues

Timeout Waiting for Selector

Symptom: Puppeteer timeout waiting for login form elements

Cause: Selector doesn’t match your provider’s HTML

Solution:

Symptom: Puppeteer can’t find consent button

Cause: Different consent screen implementation

Solution:

Try alternative button selectors:

// Option 1: By text
await page.$('button:has-text("Consent")');

// Option 2: By value
await page.$('button[value="consent"]');

// Option 3: By name
await page.$('input[name="authorize"]');

// Option 4: By class
await page.$('.consent-button');

OAuth Client Registration Fails

Symptom: 400/401 error during client registration

Cause: Provider requires additional metadata fields

Solution:

Update client metadata in oauth_helpers.dart:

final clientMetadata = {
  'client_name': 'YourApp E2E Test Client',
  'redirect_uris': [redirectUri],
  'grant_types': ['authorization_code', 'refresh_token'],
  'response_types': ['code'],
  'token_endpoint_auth_method': 'none',
  'scope': 'openid profile offline_access',  // May be required
  'application_type': 'native',  // Or 'web'
};

Token Format Differences

Symptom: solidpod package can’t parse tokens

Cause: Provider returns non-standard token structure

Solution:

Log token response for debugging:

print('Token response: ${jsonEncode(tokenResponse)}');

Verify it contains required fields:

Provider Comparison

Feature CSS NSS ESS
Login field email username Varies
2FA support Security key No Varies
Consent screen “Yes” button “Approve” Custom
Token expiry 3600s Varies Configurable
Refresh tokens Sometimes Yes Yes
DPoP required Yes Yes Yes

Testing Your Adaptation

Step 1: Verify Selectors

Run manual extraction to test selectors:

flutter run integration_test/tools/generate_auth_data.dart -d linux

If login succeeds, selectors are correct.

Step 2: Test Automation

Run automated extraction:

dart run integration_test/tools/generate_auth_data.dart

Should complete in 15-20 seconds without errors.

Step 3: Verify Auth Data

Check generated file structure:

cat integration_test/fixtures/complete_auth_data.json | jq .

Should contain web_id, rsa_info, auth_response.

Step 4: Run Integration Tests

Test with your app:

flutter test integration_test/workflows/your_test.dart \
  -d linux --dart-define=INTERACT=0

See Also