Skip to content

Commit

Permalink
Add support for conditional clicking (#3623)
Browse files Browse the repository at this point in the history
Task/Issue URL:
https://app.asana.com/0/1199230911884351/1208647902506360/f
Tech Design URL:
CC:

**Description**:

Adds support for conditional clicking of elements by adding “choices”
and “default” keys to the click action.

**Optional E2E tests**:
- [x] Run PIR E2E tests
Check this to run the Personal Information Removal end to end tests. If
updating CCF, or any PIR related code, tick this.

**Steps to test this PR**:
The easiest way to test whether the decoding is working is to setup one
of the test files from the C-S-S integration tests as a fake broker:

1. Download [this
file](https://github.com/duckduckgo/content-scope-scripts/blob/main/injected/integration-test/test-pages/broker-protection/pages/expectation-actions.html)
on your local machine. Open it to copy the file path, should start with
`file://`
2. Download [this
JSON](https://gist.github.com/brianhall/969d81b04b8d4fff4e21c9c6b48164b9)
and update the url to the file path you copied in 1.
3. Save the JSON file in the macos-browser repo under
`LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Resources/JSON`
4. Build the browser (no need for any special dependencies, just build
`main`), then open the debug version of PIR: Debug Menu -> Personal
Information Removal -> Run Personal Information Removal in Debug Mode.
5. In Birth Year enter `1965`, then select **Test Broker** in the list
of brokers and click the Run button.
6. After about 30 seconds, right click the webview and Inspect Element,
then click the console tab and type `window.location.href` and hit
enter. You should see a url that ends with `#1`, which means that the
user was older than 45.
7. Do steps 5-6 again, but for birth year enter `1990`, when you do
`window.location.href` you should get a url that ends with `#2` instead,
indicating that the user is < 45.
8. Edit the mybrokertest.com.json file, copy/paste the contents of [this
gist](https://gist.github.com/brianhall/ebac912c56c5e904ec86c05e3fa3ab30)
in and save. This just sets the default case at the bottom to `null`.
_Now re-build the browser to load the updated JSON._
9. Run steps 5-7 again, this time `window.location.href` should return a
url with `#1` for step 5, and a url with no `#` at the end for step 7,
meaning that nothing was clicked and no error was triggered.
10. Edit the mybrokertest.com.json file again and remove line 45 (and
the comma above on line 44) and then rebuild the browser to update the
JSON. Finally steps 5-7 again - step 5 should return no errors (and have
a `#1` hash at the end of the url), and step 7 should not return an
error, but also not have any hash (e.g. `#1`) at the end of the url.

**Definition of Done**:

* [ ] Does this PR satisfy our [Definition of
Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)?

—
###### Internal references:
[Pull Request Review
Checklist](https://app.asana.com/0/1202500774821704/1203764234894239/f)
[Software Engineering
Expectations](https://app.asana.com/0/59792373528535/199064865822552)
[Technical Design
Template](https://app.asana.com/0/59792373528535/184709971311943)
[Pull Request
Documentation](https://app.asana.com/0/1202500774821704/1204012835277482/f)
  • Loading branch information
brianhall authored Jan 14, 2025
1 parent 0fd512d commit 3cedd46
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,73 @@

import Foundation

struct Condition: Codable, Sendable {
let left: String
let operation: String
let right: String
}

struct Choice: Codable, Sendable {
let condition: Condition
let elements: [PageElement]
}

struct ClickAction: Action {
let id: String
let actionType: ActionType
let elements: [PageElement]
let elements: [PageElement]?
let dataSource: DataSource?
let choices: [Choice]?
let `default`: Default?

let hasDefault: Bool

struct Default: Codable {
let elements: [PageElement]?
}

init(id: String, actionType: ActionType, elements: [PageElement]? = nil, dataSource: DataSource? = nil, choices: [Choice]? = nil, `default`: Default? = nil, hasDefault: Bool = false) {
self.id = id
self.actionType = actionType
self.elements = elements
self.dataSource = dataSource
self.choices = choices
self.default = `default`
self.hasDefault = `default` != nil
}

init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.id = try container.decode(String.self, forKey: .id)
self.actionType = try container.decode(ActionType.self, forKey: .actionType)
self.elements = try container.decodeIfPresent([PageElement].self, forKey: .elements)
self.dataSource = try container.decodeIfPresent(DataSource.self, forKey: .dataSource)
self.choices = try container.decodeIfPresent([Choice].self, forKey: .choices)
self.default = try container.decodeIfPresent(Default.self, forKey: .default)
self.hasDefault = container.contains(.default)
}

enum CodingKeys: String, CodingKey {
case id
case actionType
case elements
case dataSource
case choices
case `default`
}

func encode(to encoder: any Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.id, forKey: .id)
try container.encode(self.actionType, forKey: .actionType)
try container.encodeIfPresent(self.elements, forKey: .elements)
try container.encodeIfPresent(self.dataSource, forKey: .dataSource)
try container.encodeIfPresent(self.choices, forKey: .choices)

if self.hasDefault {
try container.encode(self.default, forKey: .default)
} else {
try container.encodeNil(forKey: .default)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ final class DataBrokerOperationActionTests: XCTestCase {

func testWhenClickActionRuns_thenStageIsSetToSubmit() async {
let mockStageCalculator = MockStageDurationCalculator()
let clickAction = ClickAction(id: "1", actionType: .click, elements: [PageElement](), dataSource: nil)
let clickAction = ClickAction(id: "1", actionType: .click, elements: [PageElement](), dataSource: nil, choices: nil, default: nil, hasDefault: false)
let sut = OptOutJob(
privacyConfig: PrivacyConfigurationManagingMock(),
prefs: ContentScopeProperties.mock,
Expand Down

0 comments on commit 3cedd46

Please sign in to comment.