@opentermsarchive/engine 15.0.0 → 15.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/archivist/extract/exposedFilters.js +47 -1
- package/src/archivist/extract/exposedFilters.test.js +69 -1
- package/src/archivist/fetcher/fullDomFetcher.test.js +1 -1
- package/src/archivist/index.test.js +1 -1
- package/src/archivist/services/index.js +1 -1
- package/src/archivist/services/index.test.js +15 -3
package/package.json
CHANGED
|
@@ -1,4 +1,35 @@
|
|
|
1
|
-
|
|
1
|
+
const DEFAULT_TRACKING_QUERY_PARAMS = Object.freeze([
|
|
2
|
+
'utm_source', // Campaign parameters, see https://en.wikipedia.org/wiki/UTM_parameters
|
|
3
|
+
'utm_medium',
|
|
4
|
+
'utm_campaign',
|
|
5
|
+
'utm_term',
|
|
6
|
+
'utm_content',
|
|
7
|
+
'fbclid', // Click and user identifiers, see https://github.com/privacytests/privacytests/blob/dda473a462e5c37f9f2c8b2367fbc5f834796be4/live/results.js#L31-L65
|
|
8
|
+
'gclid',
|
|
9
|
+
'msclkid',
|
|
10
|
+
'mc_eid',
|
|
11
|
+
'dclid',
|
|
12
|
+
'oly_anon_id',
|
|
13
|
+
'oly_enc_id',
|
|
14
|
+
'_openstat',
|
|
15
|
+
'vero_conv',
|
|
16
|
+
'vero_id',
|
|
17
|
+
'wickedid',
|
|
18
|
+
'yclid',
|
|
19
|
+
'__s',
|
|
20
|
+
'rb_clickid',
|
|
21
|
+
's_cid',
|
|
22
|
+
'ml_subscriber',
|
|
23
|
+
'ml_subscriber_hash',
|
|
24
|
+
'_hsenc',
|
|
25
|
+
'__hssc',
|
|
26
|
+
'__hstc',
|
|
27
|
+
'__hsfp',
|
|
28
|
+
'hsCtaTracking',
|
|
29
|
+
'mkt_tok',
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
export function removeQueryParams(webPageDOM, paramsToRemove = DEFAULT_TRACKING_QUERY_PARAMS) {
|
|
2
33
|
const normalizedParams = Array.isArray(paramsToRemove) ? paramsToRemove : [paramsToRemove];
|
|
3
34
|
|
|
4
35
|
if (!normalizedParams.length) {
|
|
@@ -26,3 +57,18 @@ export function removeQueryParams(webPageDOM, paramsToRemove = []) {
|
|
|
26
57
|
}
|
|
27
58
|
}
|
|
28
59
|
}
|
|
60
|
+
|
|
61
|
+
const SPACE_SEPARATORS = /\p{Zs}/gu;
|
|
62
|
+
|
|
63
|
+
export function convertSpacesToStandard(webPageDOM) {
|
|
64
|
+
const walker = webPageDOM.createTreeWalker(webPageDOM.body, webPageDOM.defaultView.NodeFilter.SHOW_TEXT);
|
|
65
|
+
|
|
66
|
+
for (let node = walker.nextNode(); node; node = walker.nextNode()) {
|
|
67
|
+
const original = node.nodeValue;
|
|
68
|
+
const normalized = original.replace(SPACE_SEPARATORS, ' ');
|
|
69
|
+
|
|
70
|
+
if (normalized !== original) {
|
|
71
|
+
node.nodeValue = normalized;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { expect } from 'chai';
|
|
2
2
|
|
|
3
3
|
import createWebPageDOM from './dom.js';
|
|
4
|
-
import { removeQueryParams } from './exposedFilters.js';
|
|
4
|
+
import { convertSpacesToStandard, removeQueryParams } from './exposedFilters.js';
|
|
5
5
|
|
|
6
6
|
describe('exposedFilters', () => {
|
|
7
7
|
let webPageDOM;
|
|
@@ -51,6 +51,26 @@ describe('exposedFilters', () => {
|
|
|
51
51
|
});
|
|
52
52
|
});
|
|
53
53
|
|
|
54
|
+
describe('without parameters', () => {
|
|
55
|
+
let link;
|
|
56
|
+
|
|
57
|
+
before(() => {
|
|
58
|
+
link = webPageDOM.createElement('a');
|
|
59
|
+
link.setAttribute('href', 'https://example.com/page?utm_source=newsletter&utm_campaign=spring&fbclid=abc&gclid=def&mkt_tok=ghi&keep=value');
|
|
60
|
+
webPageDOM.body.appendChild(link);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
after(() => {
|
|
64
|
+
link.remove();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('removes well-known tracking parameters', () => {
|
|
68
|
+
removeQueryParams(webPageDOM);
|
|
69
|
+
|
|
70
|
+
expect(link.getAttribute('href')).to.equal('https://example.com/page?keep=value');
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
54
74
|
describe('with string parameter', () => {
|
|
55
75
|
let link;
|
|
56
76
|
|
|
@@ -265,4 +285,52 @@ fetch(trackingUrl);
|
|
|
265
285
|
});
|
|
266
286
|
});
|
|
267
287
|
});
|
|
288
|
+
|
|
289
|
+
describe('#convertSpacesToStandard', () => {
|
|
290
|
+
describe('with Unicode space separators in text', () => {
|
|
291
|
+
let element;
|
|
292
|
+
|
|
293
|
+
before(() => {
|
|
294
|
+
element = webPageDOM.createElement('p');
|
|
295
|
+
element.textContent = 'a\u00A0b\u202Fc\u2009d\u3000e';
|
|
296
|
+
webPageDOM.body.appendChild(element);
|
|
297
|
+
|
|
298
|
+
convertSpacesToStandard(webPageDOM);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
after(() => {
|
|
302
|
+
element.remove();
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it('replaces them with a regular space', () => {
|
|
306
|
+
expect(element.textContent).to.equal('a b c d e');
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
describe('with Unicode space separators in an attribute', () => {
|
|
311
|
+
let element;
|
|
312
|
+
const className = 'label\u00A0primary';
|
|
313
|
+
|
|
314
|
+
before(() => {
|
|
315
|
+
element = webPageDOM.createElement('a');
|
|
316
|
+
element.setAttribute('class', className);
|
|
317
|
+
element.textContent = 'read\u00A0the\u00A0policy';
|
|
318
|
+
webPageDOM.body.appendChild(element);
|
|
319
|
+
|
|
320
|
+
convertSpacesToStandard(webPageDOM);
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
after(() => {
|
|
324
|
+
element.remove();
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
it('leaves attribute values untouched', () => {
|
|
328
|
+
expect(element.getAttribute('class')).to.equal(className);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
it('replaces them in the text content', () => {
|
|
332
|
+
expect(element.textContent).to.equal('read the policy');
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
});
|
|
268
336
|
});
|
|
@@ -79,7 +79,7 @@ describe('Full DOM Fetcher', function () {
|
|
|
79
79
|
});
|
|
80
80
|
|
|
81
81
|
describe('#fetch', () => {
|
|
82
|
-
const config = { navigationTimeout:
|
|
82
|
+
const config = { navigationTimeout: 5000, waitForElementsTimeout: 5000, language: 'en' };
|
|
83
83
|
|
|
84
84
|
it('waits for dynamically injected elements to appear in the DOM', async () => {
|
|
85
85
|
const result = await fetch(`http://127.0.0.1:${SERVER_PORT}/dynamic`, ['.dynamic'], config);
|
|
@@ -106,7 +106,7 @@ function createWrappedFilter(baseFunction, filterName, filterParams) {
|
|
|
106
106
|
return;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
if (filterParams) {
|
|
109
|
+
if (filterParams || exposedFilters[filterName]) { // Built-in filters always receive their parameters before the context, even when none are declared
|
|
110
110
|
const wrappedFilter = (webPageDOM, context) => baseFunction(webPageDOM, filterParams, context);
|
|
111
111
|
|
|
112
112
|
Object.defineProperty(wrappedFilter, 'name', { value: filterName });
|
|
@@ -6,6 +6,7 @@ import sinon from 'sinon';
|
|
|
6
6
|
import sinonChai from 'sinon-chai';
|
|
7
7
|
|
|
8
8
|
import expectedServices from '../../../test/fixtures/services.js';
|
|
9
|
+
import createWebPageDOM from '../extract/dom.js';
|
|
9
10
|
import * as exposedFilters from '../extract/exposedFilters.js';
|
|
10
11
|
|
|
11
12
|
import Service from './service.js';
|
|
@@ -272,7 +273,18 @@ describe('Services', () => {
|
|
|
272
273
|
const filterName = filterNames[0];
|
|
273
274
|
const result = getServiceFilters({}, [filterName]);
|
|
274
275
|
|
|
275
|
-
expect(result).to.
|
|
276
|
+
expect(result).to.have.length(1);
|
|
277
|
+
expect(result[0]).to.be.a('function');
|
|
278
|
+
expect(result[0].name).to.equal(filterName);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('calls exposedFilters with their default parameters when declared by string name', () => {
|
|
282
|
+
const webPageDOM = createWebPageDOM('<!DOCTYPE html><html><body><a href="https://example.com/page?fbclid=abc&keep=value"></a></body></html>', 'https://example.com');
|
|
283
|
+
const [removeQueryParams] = getServiceFilters({}, ['removeQueryParams']);
|
|
284
|
+
|
|
285
|
+
removeQueryParams(webPageDOM, { fetch: 'https://example.com', select: [], remove: [], filter: ['removeQueryParams'] });
|
|
286
|
+
|
|
287
|
+
expect(webPageDOM.querySelector('a').getAttribute('href')).to.equal('https://example.com/page?keep=value');
|
|
276
288
|
});
|
|
277
289
|
|
|
278
290
|
it('returns filters from serviceFilters by string name', () => {
|
|
@@ -371,7 +383,7 @@ describe('Services', () => {
|
|
|
371
383
|
expect(sourceDocument.filters).to.be.an('array');
|
|
372
384
|
expect(sourceDocument.filters).to.have.length(2);
|
|
373
385
|
expect(sourceDocument.filters[0]).to.be.a('function');
|
|
374
|
-
expect(sourceDocument.filters[0]).to.equal(
|
|
386
|
+
expect(sourceDocument.filters[0].name).to.equal(realFilterNames[0]);
|
|
375
387
|
expect(sourceDocument.filters[1]).to.be.a('function');
|
|
376
388
|
expect(sourceDocument.filters[1].name).to.equal('removePrintButton');
|
|
377
389
|
});
|
|
@@ -431,7 +443,7 @@ describe('Services', () => {
|
|
|
431
443
|
expect(secondSourceDocument.filters).to.be.an('array');
|
|
432
444
|
expect(secondSourceDocument.filters).to.have.length(2);
|
|
433
445
|
expect(secondSourceDocument.filters[0]).to.be.a('function');
|
|
434
|
-
expect(secondSourceDocument.filters[0].name).to.equal(
|
|
446
|
+
expect(secondSourceDocument.filters[0].name).to.equal(realFilterNames[0]);
|
|
435
447
|
expect(secondSourceDocument.filters[1]).to.be.a('function');
|
|
436
448
|
expect(secondSourceDocument.filters[1].name).to.equal('removePrintButton');
|
|
437
449
|
});
|