Skip to content

Commit a2c0d5b

Browse files
Merge branch 'main' into dependabot/npm_and_yarn/main/fast-check-4.2.0
2 parents b5c4565 + 8b2c63a commit a2c0d5b

File tree

27 files changed

+879
-193
lines changed

27 files changed

+879
-193
lines changed

.cursorrules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ When asked about Content Scope Scripts topics, refer to these documentation file
66

77
- **API Reference**: `injected/docs/api-reference.md`
88
- **Feature Development**: `injected/docs/features-guide.md`
9-
- **Platform Integration**: `injected/docs/platform-integration.md`
9+
- **Platform Integration and engine support**: `injected/docs/platform-integration.md`
1010
- **Development Utilities**: `injected/docs/development-utilities.md`
1111
- **Testing**: `injected/docs/testing-guide.md`
1212
- **Favicon**: `injected/docs/favicon.md`

injected/README.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ Content Scope Scripts provides a unified API for browser privacy features across
1818

1919
## Key Concepts
2020

21+
### Project Structure
22+
23+
Content Scope Scripts contains two main sub-projects:
24+
25+
- **[Special Pages](../special-pages/)** - HTML/CSS/JS applications loaded into browsers (DuckPlayer, Release Notes, New Tab page, etc.)
26+
- **Injected Features** - Features injected into websites (privacy protections, compatibility fixes)
27+
28+
> **For Special Pages development**, see the [Special Pages README](../special-pages/README.md) for detailed getting started instructions.
29+
2130
### Features
2231
Features are JavaScript modules that implement privacy protections. Each feature:
2332
- Extends the `ConfigFeature` class for remote configuration support
@@ -65,13 +74,9 @@ npm run fake-extension # Runs an example extension used within the integration t
6574
- `unit-test/` - Unit test suite
6675
- `integration-test/` - Integration test suite
6776

68-
## Third-Party Libraries
69-
- [Adguard Scriptlets](https://github.com/AdguardTeam/Scriptlets)
70-
71-
---
77+
> **For detailed development setup instructions, debugging tips, and test build workflows, see the [Development Utilities](./docs/development-utilities.md) and [Testing Guide](./docs/testing-guide.md).**
7278
7379
## Third-Party Libraries
74-
We make use of the following submodules:
75-
- [Adguard Scriptlets](https://github.com/AdguardTeam/Scriptlets)
80+
- [Adguard Scriptlets](https://github.com/AdguardTeam/Scriptlets)
7681

7782
For detailed information about any specific topic, please refer to the [documentation](./docs/).

injected/docs/development-utilities.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,77 @@
44

55
To handle the difference in scope injection we expose multiple utilities which behave differently per browser in `src/utils.js` and `ContentFeature` base class. For Firefox the code exposed handles [xrays correctly](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Sharing_objects_with_page_scripts) without needing the features to be authored differently.
66

7+
## Development Setup
8+
9+
### Repository Access
10+
11+
1. **Clone the repository**: `https://github.com/duckduckgo/content-scope-scripts`
12+
2. **Request write-access** (for contributors): Submit a request via [Internal Support README](https://app.asana.com/1/137249556945/project/908478224964033/task/1209367367171662?focus=true) asking for `https://github.com/orgs/duckduckgo/teams/core` group access
13+
14+
### Local Development Setup
15+
16+
**Important**: Before cloning the repo on Windows, to avoid major headaches, make sure you clone it with unix-style line endings:
17+
18+
```shell
19+
git clone --config core.autocrlf=false https://github.com/duckduckgo/content-scope-scripts
20+
```
21+
22+
The Content Scope Scripts repo includes the build artifacts, which need to be generated as part of your commit.
23+
24+
### Initial Setup
25+
26+
Inside the repo, run:
27+
28+
```shell
29+
npm ci # Preferred over 'npm install' for accurate lockfile updates
30+
```
31+
32+
Ensure you have a version of node that matches what's in the `.nvmrc` file.
33+
34+
Now, to ensure everything's setup, try a full build:
35+
36+
```shell
37+
npm run build
38+
```
39+
40+
This will place built files into the top-level `build` folder. If this command ran successfully, you can continue with development.
41+
42+
### Windows Development
43+
44+
The tools should work on Windows, but if you have problems you _may_ wish to try using WSL.
45+
46+
**Optional:**: Use Windows Subsystem for Linux - [WSL Installation Guide](https://learn.microsoft.com/en-us/windows/wsl/install)
47+
48+
Once you have WSL running, make sure you have node and make installed:
49+
50+
```shell
51+
sudo apt update
52+
sudo apt install make
53+
```
54+
55+
For Node.js installation: [How to Install Node.js on Ubuntu/Debian](https://computingforgeeks.com/how-to-install-node-js-on-ubuntu-debian/)
56+
57+
Once node is installed, navigate to the repo path (e.g., `/mnt/c/dev/git/content-scope-scripts`) and:
58+
59+
```shell
60+
npm install # Install packages
61+
npm run build # Build JS artifacts
62+
```
63+
64+
After this, you can commit the generated files from your Windows environment through the usual git tools.
65+
66+
### Docker Alternative
67+
68+
If you don't want to install npm on your machine, you can use Docker instead:
69+
70+
```shell
71+
docker run -it --rm -v "<repo root>/submodules/content-scope-scripts:/content-scope-scripts" node:latest /bin/bash
72+
73+
root@<id>:/# cd /content-scope-scripts
74+
root@<id>:/content-scope-scripts# npm install
75+
root@<id>:/content-scope-scripts# npm run build
76+
```
77+
778
## ContentFeature Utilities
879

980
### `ContentFeature.defineProperty(object, propertyName, descriptor)`

injected/docs/platform-integration.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,41 @@
44

55
The [injected/entry-points/](https://github.com/duckduckgo/content-scope-scripts/tree/main/injected/entry-points) directory handles platform specific differences and is glue code into calling the contentScopeFeatures API.
66

7+
## Browser Compatibility
8+
9+
The following is a guideline for when using native JavaScript syntax or built-in global DOM objects. Testing is always advised, but code authors might be unable to replicate the code on the correct application environments (due to hardware or an updated local environment).
10+
11+
### Minimum Supported Engines
12+
13+
#### iOS
14+
15+
- **Safari 14** (minimum)
16+
- **Minimum support**: iOS 14 - [Review supported device and iOS versions](https://support.apple.com/en-us/102662)
17+
- **Engine**: WKWebView should behave like Safari 14 as this is the native engine
18+
19+
#### macOS
20+
21+
- **Safari 14** (minimum)
22+
- **Minimum support**: Catalina (potentially Safari 14 is native engine in non-updated device)
23+
- **Engine**: WKWebView should behave like Safari 14
24+
25+
#### Android
26+
27+
- **Android 23** (minimum) - [Product feedback request: Android - min supported version](https://app.asana.com/1/137249556945/project/908478224964033/task/1209367367171662?focus=true)
28+
- **Chrome 80+** (minimum)
29+
- **Reference**: See [pixel dashboard](https://app.asana.com/1/137249556945/project/908478224964033/task/1209367367171662?focus=true)
30+
31+
#### Windows
32+
33+
- **Edge-based** behavior expected
34+
- **Minimum**: Chrome 83 (if client has disabled all updates)
35+
- **Reference**: [Windows Browser: Minimum specs](https://app.asana.com/1/137249556945/project/908478224964033/task/1209367367171662?focus=true)
36+
37+
#### Extensions
38+
39+
- **Chrome**: Version 96+ - [Chrome manifest reference](https://github.com/duckduckgo/duckduckgo-privacy-extension/blob/249d8d6ebe38b9b8265ba311909c8971c422122c/browsers/chrome/manifest.json#L6)
40+
- **Firefox**: Version 91+ - [Firefox manifest reference](https://github.com/duckduckgo/duckduckgo-privacy-extension/blob/249d8d6ebe38b9b8265ba311909c8971c422122c/browsers/firefox/manifest.json#L6)
41+
742
## Platform-Specific Implementation Details
843

944
### Firefox

injected/docs/testing-guide.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,21 @@ To produce all artefacts that are used by platforms, just run the `npm run build
5050
```shell
5151
npm run build
5252
```
53+
54+
## Test Builds for Ship Review
55+
56+
Test builds are created with a GitHub workflow. The assets for Content Scope Scripts will be created on demand if they are absent (which they will be, if you're pointing to a branch of CSS).
57+
58+
1. Commit any changes to CSS and push a branch to the remote
59+
2. Make sure you commit the submodule reference update in the Windows PR
60+
3. Continue with "Build an installer for ship review / test"
61+
62+
## Debugging
63+
64+
### Adding Breakpoints
65+
66+
If you drop a `debugger;` line in the scripts and open DevTools window, the DevTools will breakpoint and navigate to that exact line in code when the debug point has been hit.
67+
68+
### Verifying CSS is Loaded
69+
70+
Open DevTools, go to the Console tab and enter `navigator.duckduckgo`. If it's defined, then Content Scope Scripts is running.

injected/integration-test/broker-protection-tests/broker-protection.spec.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,4 +664,47 @@ test.describe('Broker Protection communications', () => {
664664
dbp.isErrorMessage(response);
665665
});
666666
});
667+
668+
test.describe('condition', () => {
669+
test('a successful condition returns success with steps in the response', async ({ page }, workerInfo) => {
670+
const dbp = BrokerProtectionPage.create(page, workerInfo.project.use);
671+
await dbp.enabled();
672+
await dbp.navigatesTo('form.html');
673+
await dbp.receivesAction('condition-success.json');
674+
const response = await dbp.collector.waitForMessage('actionCompleted');
675+
dbp.isSuccessMessage(response);
676+
677+
// Check that the response contains an actions array
678+
const successResponse = await dbp.getSuccessResponse();
679+
680+
expect(successResponse).toHaveProperty('actions');
681+
expect(Array.isArray(successResponse.actions)).toBe(true);
682+
expect(successResponse.actions.length).toBeGreaterThan(0);
683+
});
684+
685+
test('a condition with failSilently returns success with empty actions array', async ({ page }, workerInfo) => {
686+
const dbp = BrokerProtectionPage.create(page, workerInfo.project.use);
687+
await dbp.enabled();
688+
await dbp.navigatesTo('form.html');
689+
await dbp.receivesAction('condition-fail-silently.json');
690+
const response = await dbp.collector.waitForMessage('actionCompleted');
691+
dbp.isSuccessMessage(response);
692+
693+
// Check that the response does not contain an actions array
694+
const successResponse = await dbp.getSuccessResponse();
695+
696+
expect(successResponse).toHaveProperty('actions');
697+
expect(Array.isArray(successResponse.actions)).toBe(true);
698+
expect(successResponse.actions.length).toBe(0);
699+
});
700+
701+
test('a failing condition returns error', async ({ page }, workerInfo) => {
702+
const dbp = BrokerProtectionPage.create(page, workerInfo.project.use);
703+
await dbp.enabled();
704+
await dbp.navigatesTo('form.html');
705+
await dbp.receivesAction('condition-fail.json');
706+
const response = await dbp.collector.waitForMessage('actionCompleted');
707+
dbp.isErrorMessage(response);
708+
});
709+
});
667710
});
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"state": {
3+
"action": {
4+
"actionType": "condition",
5+
"retry": {
6+
"environment": "web",
7+
"interval": { "ms": 1000 },
8+
"maxAttempts": 1
9+
},
10+
"expectations": [
11+
{
12+
"type": "element",
13+
"selector": "form.fakeForm",
14+
"failSilently": true
15+
}
16+
],
17+
"actions": [
18+
{
19+
"actionType": "click",
20+
"elements": [
21+
{
22+
"type": "button",
23+
"selector": ".btn-sbmt"
24+
}
25+
]
26+
}
27+
]
28+
}
29+
}
30+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"state": {
3+
"action": {
4+
"actionType": "condition",
5+
"retry": {
6+
"environment": "web",
7+
"interval": { "ms": 1000 },
8+
"maxAttempts": 1
9+
},
10+
"expectations": [
11+
{
12+
"type": "element",
13+
"selector": "form.fakeForm"
14+
}
15+
],
16+
"actions": [
17+
{
18+
"actionType": "click",
19+
"elements": [
20+
{
21+
"type": "button",
22+
"selector": ".btn-sbmt"
23+
}
24+
]
25+
}
26+
]
27+
}
28+
}
29+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"state": {
3+
"action": {
4+
"actionType": "condition",
5+
"expectations": [
6+
{
7+
"type": "element",
8+
"selector": "form.ahm"
9+
}
10+
],
11+
"actions": [
12+
{
13+
"actionType": "click",
14+
"elements": [
15+
{
16+
"type": "button",
17+
"selector": ".btn-sbmt"
18+
}
19+
]
20+
}
21+
]
22+
}
23+
}
24+
}

injected/src/features/broker-protection.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,9 @@ export default class BrokerProtection extends ContentFeature {
100100
};
101101
}
102102
/**
103-
* Special case for when expectation contains a check for an element, retry it
103+
* Special case for when expectation or condition contains a check for an element, retry it
104104
*/
105-
if (!retryConfig && action.actionType === 'expectation') {
105+
if (!retryConfig && (action.actionType === 'expectation' || action.actionType === 'condition')) {
106106
if (action.expectations.some((x) => x.type === 'element')) {
107107
return {
108108
interval: { ms: 1000 },

0 commit comments

Comments
 (0)