Skip to content

Commit

Permalink
AG-20302 Add ability to click element if cookie/localStorage item doe…
Browse files Browse the repository at this point in the history
…sn't exist. #298

Squashed commit of the following:

commit 19d09f4
Author: Adam Wróblewski <adam@adguard.com>
Date:   Tue Mar 28 13:10:20 2023 +0200

    Do not reassign function parameters

commit 2b6fef7
Author: Adam Wróblewski <adam@adguard.com>
Date:   Mon Mar 27 14:15:24 2023 +0200

    Fix typo in description

commit eaf048a
Author: Adam Wróblewski <adam@adguard.com>
Date:   Mon Mar 27 11:56:13 2023 +0200

    Use parseMatchArg helper
    Use native startsWith in parseMatchArg helper
    Return string in parseMatchArg helper
    Add test with cookie value
    Set isInvertedMatchCookie and isInvertedMatchLocalStorage to false instead of null
    Rever test for abort-on-stack-trace
    Fix typo in description

commit df78bc3
Author: Adam Wróblewski <adam@adguard.com>
Date:   Tue Mar 21 20:17:52 2023 +0100

    Add ability to click element if cookie/localStorage item doesn't exist
  • Loading branch information
AdamWr committed Mar 28, 2023
1 parent ce23fa9 commit 32102f6
Show file tree
Hide file tree
Showing 5 changed files with 307 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- ability for `trusted-click-element` scriptlet to click element if `cookie`/`localStorage` item doesn't exist [#298](https://github.com/AdguardTeam/Scriptlets/issues/298)
- static delay between multiple clicks in `trusted-click-element` [#284](https://github.com/AdguardTeam/Scriptlets/issues/284)

### Fixed
Expand Down
5 changes: 3 additions & 2 deletions src/helpers/string-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,10 +238,11 @@ export const isValidMatchNumber = (match) => {
*/
export const parseMatchArg = (match) => {
const INVERT_MARKER = '!';
const isInvertedMatch = startsWith(match, INVERT_MARKER);
// In case if "match" is "undefined" return "false"
const isInvertedMatch = match ? match.startsWith(INVERT_MARKER) : false;
const matchValue = isInvertedMatch ? match.slice(1) : match;
const matchRegexp = toRegExp(matchValue);
return { isInvertedMatch, matchRegexp };
return { isInvertedMatch, matchRegexp, matchValue };
};

/**
Expand Down
32 changes: 27 additions & 5 deletions src/scriptlets/trusted-click-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
parseCookieString,
throttle,
logMessage,
parseMatchArg,
} from '../helpers/index';

/* eslint-disable max-len */
Expand All @@ -20,6 +21,7 @@ import {
*
* - `selectors` — required, string with query selectors delimited by comma
* - `extraMatch` — optional, extra condition to check on a page; allows to match `cookie` and `localStorage`; can be set as `name:key[=value]` where `value` is optional.
* If `cookie`/`localStorage` starts with `!` then the element will only be clicked if specified cookie/localStorage item does not exist.
* Multiple conditions are allowed inside one `extraMatch` but they should be delimited by comma and each of them should match the syntax. Possible `name`s:
* - `cookie` - test string or regex against cookies on a page
* - `localStorage` - check if localStorage item is present
Expand Down Expand Up @@ -60,6 +62,16 @@ import {
* ```
* example.com#%#//scriptlet('trusted-click-element', 'button[name="agree"], input[type="submit"][value="akkoord"]', 'cookie:cmpconsent, localStorage:promo', '250')
* ```
*
* 8. Click element only if cookie with name `cmpconsent` does not exist
* ```
* example.com#%#//scriptlet('trusted-click-element', 'button[name="agree"]', '!cookie:cmpconsent')
* ```
*
* 9. Click element only if specified cookie string and localStorage item does not exist
* ```
* example.com#%#//scriptlet('trusted-click-element', 'button[name="agree"]', '!cookie:cmpconsent, !localStorage:promo')
* ```
*/
/* eslint-enable max-len */
export function trustedClickElement(source, selectors, extraMatch = '', delay = NaN) {
Expand All @@ -75,7 +87,7 @@ export function trustedClickElement(source, selectors, extraMatch = '', delay =
const SELECTORS_DELIMITER = ',';
const COOKIE_STRING_DELIMITER = ';';
// Regex to split match pairs by commas, avoiding the ones included in regexes
const EXTRA_MATCH_DELIMITER = /(,\s*){1}(?=cookie:|localStorage:)/;
const EXTRA_MATCH_DELIMITER = /(,\s*){1}(?=!?cookie:|!?localStorage:)/;

const sleep = (delayMs) => new Promise((resolve) => setTimeout(resolve, delayMs));

Expand All @@ -95,6 +107,8 @@ export function trustedClickElement(source, selectors, extraMatch = '', delay =

const cookieMatches = [];
const localStorageMatches = [];
let isInvertedMatchCookie = false;
let isInvertedMatchLocalStorage = false;

if (extraMatch) {
// Get all match marker:value pairs from argument
Expand All @@ -105,11 +119,15 @@ export function trustedClickElement(source, selectors, extraMatch = '', delay =
// Filter match pairs by marker
parsedExtraMatch.forEach((matchStr) => {
if (matchStr.indexOf(COOKIE_MATCH_MARKER) > -1) {
const cookieMatch = matchStr.replace(COOKIE_MATCH_MARKER, '');
const { isInvertedMatch, matchValue } = parseMatchArg(matchStr);
isInvertedMatchCookie = isInvertedMatch;
const cookieMatch = matchValue.replace(COOKIE_MATCH_MARKER, '');
cookieMatches.push(cookieMatch);
}
if (matchStr.indexOf(LOCAL_STORAGE_MATCH_MARKER) > -1) {
const localStorageMatch = matchStr.replace(LOCAL_STORAGE_MATCH_MARKER, '');
const { isInvertedMatch, matchValue } = parseMatchArg(matchStr);
isInvertedMatchLocalStorage = isInvertedMatch;
const localStorageMatch = matchValue.replace(LOCAL_STORAGE_MATCH_MARKER, '');
localStorageMatches.push(localStorageMatch);
}
});
Expand Down Expand Up @@ -145,7 +163,8 @@ export function trustedClickElement(source, selectors, extraMatch = '', delay =
});
});

if (!cookiesMatched) {
const shouldRun = cookiesMatched !== isInvertedMatchCookie;
if (!shouldRun) {
return;
}
}
Expand All @@ -156,7 +175,9 @@ export function trustedClickElement(source, selectors, extraMatch = '', delay =
const itemValue = window.localStorage.getItem(str);
return itemValue || itemValue === '';
});
if (!localStorageMatched) {

const shouldRun = localStorageMatched !== isInvertedMatchLocalStorage;
if (!shouldRun) {
return;
}
}
Expand Down Expand Up @@ -287,4 +308,5 @@ trustedClickElement.injections = [
parseCookieString,
throttle,
logMessage,
parseMatchArg,
];
2 changes: 1 addition & 1 deletion tests/scriptlets/abort-on-stack-trace.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ test('do NOT abort Math.round, test for injected script', (assert) => {
// eslint-disable-next-line no-console
console.log('Something went wrong', error);
}
assert.strictEqual(testPassed, true, 'testPassed set to true, script has been aborted');
assert.strictEqual(testPassed, true, 'testPassed set to true, script has not been aborted');
assert.strictEqual(window.hit, undefined, 'hit should NOT fire');
});

Expand Down

0 comments on commit 32102f6

Please sign in to comment.