Skip to content

Commit 4c02622

Browse files
authored
Merge pull request #1 from addpipe/next
v1.1.0
2 parents 88f062b + 28d42bc commit 4c02622

4 files changed

Lines changed: 122 additions & 11 deletions

File tree

README.md

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ const webcamTester = insertWebcamTestLibrary("webcam-tester-container", {
106106
// Specific tests to run (default: all)
107107
"getUserMedia",
108108
"secureContext",
109+
"permissionsPolicy",
109110
"cameraPermissions",
110111
"micPermissions",
111112
"devices",
@@ -148,49 +149,56 @@ What does the library test?
148149
- Ensures the page is running in a secure context (HTTPS, localhost, file:// etc.)
149150
- **Result**: Success if secure, error if not secure
150151

151-
### 3. Checks Camera Permissions
152+
### 3. Checks Permissions Policy
153+
- Verifies that Permissions Policy (formerly Feature Policy) allows camera and microphone access
154+
- **Expandable Info**: Shows detailed policy status for each feature with explanations
155+
- **Result**: Success if all features allowed, warning if some blocked, info if API not supported
156+
157+
**Why this matters:** Even if a user grants camera/microphone permissions, the Permissions Policy can block access at the browser level. This is common in iframes or when restrictive HTTP headers are set.
158+
159+
### 4. Checks Camera Permissions
152160

153161
- Requests camera permissions from the user
154162
- Allows selection of specific camera device (if `allowCameraSelection: true`); on Chrome and Firefox, the selection made in the library UI has higher priority
155163
- Sets up the camera preview if successful
156164
- **Result**: Success if granted, error with specific reason if denied
157165

158-
### 4. Checks Microphone Permissions
166+
### 5. Checks Microphone Permissions
159167

160168
- Requests microphone permissions from the user
161169
- Allows selection of specific microphone device (if `allowMicSelection: true`); on Chrome and Firefox, the selection made in the library UI has higher priority
162170
- Works independently from camera permissions
163171
- **Result**: Success if granted, error with specific reason if denied
164172

165-
### 5. Enumerates Devices
173+
### 6. Enumerates Devices
166174

167175
- Lists all available audio inputs, video inputs, and audio outputs
168176
- Shows which devices are currently selected
169177
- **Expandable Info**: Shows detailed device lists by category with selection indicators
170178
- **Result**: Success with device count
171179

172-
### 6. Tests Active Streams and Tracks
180+
### 7. Tests Active Streams and Tracks
173181

174182
- Verifies is active media streams or tracks are working correctly
175183
- Displays current capture resolution for video
176184
- Shows status for both audio and video tracks
177185
- **Result**: Success with resolution info, warning if partial capture
178186

179-
### 7. Tests Resolutions
187+
### 8. Tests Resolutions
180188

181189
- Tests 8 standard resolutions: 144p, 240p, 360p, 480p, 720p, 1080p, 1440p, 4K
182190
- Measures frame rates for each supported resolution
183191
- **Expandable Info**: Shows all tested resolutions with status and frame rates
184192
- **Result**: Success with supported count and average FPS
185193

186-
### 8. Tests Lighting
194+
### 9. Tests Lighting
187195

188196
- Analyzes camera brightness using pixel data analysis
189197
- Provides recommendations for optimal lighting
190198
- **Expandable Info**: Shows brightness scale (0-255) with explanations
191199
- **Result**: Success/warning based on lighting conditions with brightness value
192200

193-
### 9. Checks Other APIs
201+
### 10. Checks Other APIs
194202

195203
- Tests availability of other web APIs:
196204
- [MediaStream Recording API](https://developer.mozilla.org/en-US/docs/Web/API/MediaStream_Recording_API) (for recording)
@@ -610,9 +618,18 @@ See [LICENSE](LICENSE) for full details or visit https://www.gnu.org/licenses/ag
610618
611619
## Changelog
612620
621+
### v1.1.0
622+
- Added Permissions Policy test to check if camera and microphone are allowed by browser policies
623+
- Provides detailed explanations of policy status for camera and microphone
624+
- Fix a bug where sometimes in React the target element was not found
625+
613626
### v1.0.0
614627
615628
- Initial release
616629
- Core testing functionality
617630
- Configuration options
618631
- API methods and callbacks
632+
633+
---
634+
635+
**Built with ❤️ by the [addpipe.com](addpipe.com) team**

dist/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export type TestType = 'success' | 'error' | 'warning' | 'info';
1010
export type TestName =
1111
| 'getUserMedia'
1212
| 'secureContext'
13+
| 'permissionsPolicy'
1314
| 'cameraPermissions'
1415
| 'micPermissions'
1516
| 'devices'

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@addpipe/webcam-tester",
3-
"version": "1.0.0",
3+
"version": "1.1.0",
44
"description": "A JavaScript library for testing webcam and microphone functionality in web browsers",
55
"main": "dist/webcam-tester.js",
66
"module": "dist/webcam-tester.esm.js",

src/webcam-tester.js

Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@
426426
darkTheme: false,
427427
uiLess: false,
428428
title: "Webcam Tester",
429-
tests: ["getUserMedia", "secureContext", "cameraPermissions", "micPermissions", "devices", "capture", "resolutions", "lighting", "otherApis"],
429+
tests: ["getUserMedia", "secureContext", "permissionsPolicy", "cameraPermissions", "micPermissions", "devices", "capture", "resolutions", "lighting", "otherApis"],
430430
callbacks: {
431431
onTestStart: null,
432432
onTestComplete: null,
@@ -467,8 +467,12 @@
467467
init() {
468468
this.injectCSS();
469469
if (!this.config.uiLess) {
470-
this.createHTML();
471-
this.bindEvents();
470+
const elementExists = !!document.getElementById(this.containerId);
471+
const timeout = elementExists ? 0 : 1000;
472+
setTimeout(() => {
473+
this.createHTML();
474+
this.bindEvents();
475+
}, timeout);
472476
}
473477
}
474478

@@ -967,6 +971,7 @@
967971
const testMap = {
968972
getUserMedia: () => this.testGetUserMedia(),
969973
secureContext: () => this.testSecureContext(),
974+
permissionsPolicy: () => this.testPermissionsPolicy(),
970975
cameraPermissions: () => this.testCameraPermissions(),
971976
micPermissions: () => this.testMicPermissions(),
972977
devices: () => this.testDeviceEnumeration(),
@@ -1015,6 +1020,93 @@
10151020
}
10161021
}
10171022

1023+
async testPermissionsPolicy() {
1024+
this.setLoadingState("Checking permissions policy...");
1025+
await this.sleep(400);
1026+
1027+
const policies = [];
1028+
const policyResults = [];
1029+
let hasIssues = false;
1030+
1031+
// Check if Permissions Policy API is supported
1032+
if (!document.featurePolicy && !document.permissionsPolicy) {
1033+
this.addTestResult("permissionsPolicy", "⚠️", "Permissions Policy API not supported in this browser", "warning");
1034+
return;
1035+
}
1036+
1037+
const policy = document.permissionsPolicy || document.featurePolicy;
1038+
1039+
// Check camera policy
1040+
try {
1041+
const cameraAllowed = policy.allowsFeature("camera");
1042+
if (cameraAllowed) {
1043+
policies.push("Camera allowed");
1044+
policyResults.push({ name: "camera", allowed: true });
1045+
} else {
1046+
policies.push("Camera blocked by policy");
1047+
policyResults.push({ name: "camera", allowed: false });
1048+
hasIssues = true;
1049+
}
1050+
} catch (error) {
1051+
policyResults.push({ name: "camera", allowed: null, error: true });
1052+
}
1053+
1054+
// Check microphone policy
1055+
try {
1056+
const micAllowed = policy.allowsFeature("microphone");
1057+
if (micAllowed) {
1058+
policies.push("Microphone allowed");
1059+
policyResults.push({ name: "microphone", allowed: true });
1060+
} else {
1061+
policies.push("Microphone blocked by policy");
1062+
policyResults.push({ name: "microphone", allowed: false });
1063+
hasIssues = true;
1064+
}
1065+
} catch (error) {
1066+
policyResults.push({ name: "microphone", allowed: false, error: true });
1067+
}
1068+
1069+
// Check display-capture (screen sharing) policy
1070+
// try {
1071+
// const displayCaptureAllowed = policy.allowsFeature("display-capture");
1072+
// if (displayCaptureAllowed) {
1073+
// policies.push("Screen capture allowed");
1074+
// policyResults.push({ name: "display-capture", allowed: true });
1075+
// } else {
1076+
// policyResults.push({ name: "display-capture", allowed: false });
1077+
// }
1078+
// } catch (error) {
1079+
// policyResults.push({ name: "display-capture", allowed: null, error: true });
1080+
// }
1081+
1082+
// Create detailed policy info for expandable section
1083+
let policyInfo = "<div><strong>Feature Policies:</strong></div>";
1084+
policyResults.forEach((result) => {
1085+
let status = "❓";
1086+
let statusText = "Unknown";
1087+
1088+
if (result.error) {
1089+
status = "⚠️";
1090+
statusText = "Unable to check";
1091+
} else if (result.allowed === true) {
1092+
status = "✅";
1093+
statusText = "Allowed";
1094+
} else if (result.allowed === false) {
1095+
status = "❌";
1096+
statusText = "Blocked by policy";
1097+
}
1098+
1099+
policyInfo += `<div class="capability-item"><span class="capability-status">${status}</span>${result.name}: ${statusText}</div>`;
1100+
});
1101+
1102+
// Determine result type and message
1103+
if (hasIssues) {
1104+
this.addTestResult("permissionsPolicy", "⚠️", "Some features blocked by Permissions Policy", "warning", `Policies: ${policies.join(", ")}`, true, policyInfo);
1105+
} else {
1106+
this.addTestResult("permissionsPolicy", "✅", "Camera & Microphone allowed by Permissions Policy", "success", `Policies: ${policies.join(", ")}`, true, policyInfo);
1107+
}
1108+
}
1109+
10181110
async testCameraPermissions() {
10191111
this.setLoadingState("Requesting camera permissions...");
10201112

@@ -1418,6 +1510,7 @@
14181510
const testMap = {
14191511
getUserMedia: () => this.testGetUserMedia(),
14201512
secureContext: () => this.testSecureContext(),
1513+
permissionsPolicy: () => this.testPermissionsPolicy(),
14211514
cameraPermissions: () => this.testCameraPermissions(),
14221515
micPermissions: () => this.testMicPermissions(),
14231516
devices: () => this.testDeviceEnumeration(),

0 commit comments

Comments
 (0)