Skip to content

Conversation

@jonathanKingston
Copy link
Contributor

@jonathanKingston jonathanKingston commented Dec 19, 2025

Asana Task/Github Issue: https://app.asana.com/1/137249556945/project/1201614831475344/task/1210044338857086?focus=true

Description

Make the Presentation API shim spec-shaped for feature-detection code by allowing PresentationRequest construction, exposing urls/onconnectionavailable, and returning NotSupportedError rejections for unsupported operations.

This PR implements a spec-shaped PresentationRequest shim to support feature-detection code on sites that check for the Presentation API. The shim allows construction of PresentationRequest objects, exposes required properties (urls, onconnectionavailable), and returns NotSupportedError rejections for unsupported operations.

Testing Steps

Test Cases

1. PresentationRequest Constructor

Test 1.1: Basic construction with a single URL string

const request = new PresentationRequest('https://example.com/presentation');
console.log(request instanceof PresentationRequest); // Expected: true
console.log(request.urls); // Expected: ['https://example.com/presentation']

Test 1.2: Construction with an array of URLs

const request = new PresentationRequest([
  'https://example.com/page1',
  'https://example.com/page2'
]);
console.log(request.urls); // Expected: ['https://example.com/page1', 'https://example.com/page2']
console.log(request.urls.length); // Expected: 2

Test 1.3: Construction with an iterable

const urlSet = new Set(['https://example.com/a', 'https://example.com/b']);
const request = new PresentationRequest(urlSet);
console.log(request.urls.length); // Expected: 2

Test 1.4: Invalid constructor arguments should throw TypeError

// Empty array
try {
  new PresentationRequest([]);
} catch (e) {
  console.log(e instanceof TypeError); // Expected: true
  console.log(e.message.includes('At least one URL')); // Expected: true
}

// Invalid type (number)
try {
new PresentationRequest(123);
} catch (e) {
console.log(e instanceof TypeError); // Expected: true
}

// No arguments
try {
new PresentationRequest();
} catch (e) {
console.log(e instanceof TypeError); // Expected: true
}

2. URLs Property

Test 2.1: URLs property returns a copy (immutable)

const request = new PresentationRequest(['https://example.com']);
const urls1 = request.urls;
const urls2 = request.urls;
console.log(urls1 !== urls2); // Expected: true (different array instances)
urls1.push('https://modified.com');
console.log(request.urls.length); // Expected: 1 (original unchanged)

3. onconnectionavailable Property

Test 3.1: Property exists and is initially null

const request = new PresentationRequest('https://example.com');
console.log(request.onconnectionavailable); // Expected: null

Test 3.2: Property can be set to a function

const request = new PresentationRequest('https://example.com');
request.onconnectionavailable = (evt) => console.log('connected');
console.log(typeof request.onconnectionavailable); // Expected: 'function'

4. start() Method

Test 4.1: Returns a rejected Promise with NotSupportedError

const request = new PresentationRequest('https://example.com');
request.start().catch(err => {
  console.log(err.name); // Expected: 'NotSupportedError'
  console.log(err instanceof DOMException || err instanceof Error); // Expected: true
  console.log(err.message.includes('not supported')); // Expected: true
});

5. reconnect() Method

Test 5.1: Returns a rejected Promise with NotSupportedError

const request = new PresentationRequest('https://example.com');
request.reconnect('some-id').catch(err => {
  console.log(err.name); // Expected: 'NotSupportedError'
  console.log(err.message.includes('not supported')); // Expected: true
});

6. getAvailability() Method

Test 6.1: Returns a rejected Promise with NotSupportedError

const request = new PresentationRequest('https://example.com');
request.getAvailability().catch(err => {
  console.log(err.name); // Expected: 'NotSupportedError'
  console.log(err.message.includes('not supported')); // Expected: true
});

7. navigator.presentation Object

Test 7.1: Presentation object exists

console.log(typeof navigator.presentation); // Expected: 'object'
console.log(navigator.presentation !== null); // Expected: true

Test 7.2: defaultRequest property getter/setter

console.log(navigator.presentation.defaultRequest); // Expected: null (initially)

const request = new PresentationRequest('https://example.com');
navigator.presentation.defaultRequest = request;
console.log(navigator.presentation.defaultRequest === request); // Expected: true

navigator.presentation.defaultRequest = null;
console.log(navigator.presentation.defaultRequest); // Expected: null

Test 7.3: receiver property

console.log(navigator.presentation.receiver); // Expected: null

8. EventTarget Inheritance

Test 8.1: PresentationRequest extends EventTarget

const request = new PresentationRequest('https://example.com');
console.log(typeof request.addEventListener); // Expected: 'function'
console.log(typeof request.removeEventListener); // Expected: 'function'
console.log(typeof request.dispatchEvent); // Expected: 'function'

9. Feature Detection Compatibility

Test 9.1: Common feature detection patterns should work

// Pattern 1: Check for PresentationRequest
if ('PresentationRequest' in window) {
  console.log('PresentationRequest exists'); // Expected to log
}

// Pattern 2: Check navigator.presentation
if (navigator.presentation) {
console.log('navigator.presentation exists'); // Expected to log
}

// Pattern 3: Try to construct (graceful degradation)
try {
const request = new PresentationRequest('https://example.com');
request.getAvailability().catch(() => {
console.log('Presentation not available, falling back'); // Expected to log
});
} catch (e) {
console.log('Construction failed');
}

10. Real-world Site Testing

Test on sites known to use the Presentation API for feature detection:

  1. YouTube - Uses Presentation API for Cast functionality

    • Navigate to youtube.com
    • Verify page loads without errors
    • Check console for any PresentationRequest-related errors
  2. Netflix - May check for Presentation API

    • Navigate to netflix.com
    • Verify page loads without errors
  3. Any site with Cast/Presentation features

    • The page should load correctly
    • Feature detection should work (even if the feature itself is unavailable)
    • No console errors related to PresentationRequest being undefined

Regression Testing

  1. Ensure native Presentation API is not overwritten

    • On browsers that natively support Presentation API (Chrome), verify the shim does not activate
    • Check condition: window.navigator.presentation && window.PresentationRequest should prevent shim
  2. Integration test environment

    • Verify the shim IS applied in integration tests (note the this.injectName !== 'integration' check)

Expected Behaviour Summary

Feature Expected Result
new PresentationRequest(url) Creates object successfully
new PresentationRequest([]) Throws TypeError
request.urls Returns array of URLs
request.start() Returns rejected Promise (NotSupportedError)
request.reconnect() Returns rejected Promise (NotSupportedError)
request.getAvailability() Returns rejected Promise (NotSupportedError)
request.onconnectionavailable Property exists, initially null
navigator.presentation.defaultRequest Getter/setter works
EventTarget methods addEventListener, etc. available

Checklist

Please tick all that apply:

  • I have tested this change locally
  • I have tested this change locally in all supported browsers
  • This change will be visible to users
  • I have added automated tests that cover this change
  • I have ensured the change is gated by config
  • This change was covered by a ship review
  • This change was covered by a tech design
  • Any dependent config has been merged

Make the Presentation API shim spec-shaped for feature-detection code by allowing PresentationRequest construction, exposing urls/onconnectionavailable, and returning NotSupportedError rejections for unsupported operations.
@netlify
Copy link

netlify bot commented Dec 19, 2025

Deploy Preview for content-scope-scripts ready!

Name Link
🔨 Latest commit 8088db3
🔍 Latest deploy log https://app.netlify.com/projects/content-scope-scripts/deploys/694563a5eeb08a00083f96c2
😎 Deploy Preview https://deploy-preview-2121--content-scope-scripts.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 19, 2025

Temporary Branch Update

The temporary branch has been updated with the latest changes. Below are the details:

Please use the above install command to update to the latest version.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 19, 2025

[Beta] Generated file diff

Time updated: Fri, 19 Dec 2025 14:40:37 GMT

Android
    - android/adsjsContentScope.js
  • android/contentScope.js

File has changed

Apple
    - apple/contentScope.js

File has changed

Integration
    - integration/contentScope.js

File has changed

Windows
    - windows/contentScope.js

File has changed

Add webcompat integration-test assertions that PresentationRequest is constructible, exposes urls/onconnectionavailable, rejects unsupported operations with NotSupportedError, and allows setting navigator.presentation.defaultRequest.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants