Skip to content

Commit d926037

Browse files
Add preview conditionalChanges support (#2032)
1 parent c2ed781 commit d926037

File tree

4 files changed

+218
-2
lines changed

4 files changed

+218
-2
lines changed

injected/docs/platform-integration.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,9 @@ The following placeholders are replaced during the build process:
6666
- **`$USER_PREFERENCES$`** - An object containing:
6767
- `platform`:
6868
- `name`: '<ios | macos | extension | android | windows>',
69-
- `internal`: <boolean>
70-
- `version`: <string | number>
69+
- `internal`: `<boolean>`
70+
- `preview`: `<boolean>`
71+
- `version`: `<string | number>`
7172
- `debug`: boolean
7273
- `globalPrivacyControlValue`: boolean
7374
- `sessionKey`: `<CSRNG UUID 4 string>` (used for fingerprinting) - this should regenerate on browser close or every 24 hours

injected/src/config-feature.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ export default class ConfigFeature {
135135
* @property {boolean} [context.top] - true if the condition applies to the top frame
136136
* @property {string} [injectName] - the inject name to match against (e.g., "apple-isolated")
137137
* @property {boolean} [internal] - true if the condition applies to internal builds
138+
* @property {boolean} [preview] - true if the condition applies to preview builds
138139
*/
139140

140141
/**
@@ -167,6 +168,7 @@ export default class ConfigFeature {
167168
maxSupportedVersion: this._matchMaxSupportedVersion,
168169
injectName: this._matchInjectNameConditional,
169170
internal: this._matchInternalConditional,
171+
preview: this._matchPreviewConditional,
170172
};
171173

172174
for (const key in conditionBlock) {
@@ -302,6 +304,18 @@ export default class ConfigFeature {
302304
return Boolean(conditionBlock.internal) === Boolean(isInternal);
303305
}
304306

307+
/**
308+
* Takes a condition block and returns true if the preview state matches the condition.
309+
* @param {ConditionBlock} conditionBlock
310+
* @returns {boolean}
311+
*/
312+
_matchPreviewConditional(conditionBlock) {
313+
if (conditionBlock.preview === undefined) return false;
314+
const isPreview = this.#args?.platform?.preview;
315+
if (isPreview === undefined) return false;
316+
return Boolean(conditionBlock.preview) === Boolean(isPreview);
317+
}
318+
305319
/**
306320
* Takes a condition block and returns true if the platform version satisfies the `minSupportedFeature`
307321
* @param {ConditionBlock} conditionBlock

injected/src/utils.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,7 @@ export function isUnprotectedDomain(topLevelHostname, featureList) {
562562
* @property {'ios' | 'macos' | 'extension' | 'android' | 'windows'} name
563563
* @property {string | number } [version]
564564
* @property {boolean} [internal] - Internal build flag
565+
* @property {boolean} [preview] - Preview build flag
565566
*/
566567

567568
/**

injected/unit-test/content-feature.js

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,4 +990,204 @@ describe('ContentFeature class', () => {
990990
expect(result).toBe(true);
991991
});
992992
});
993+
994+
describe('preview condition', () => {
995+
it('should match when preview is true and condition is true', () => {
996+
class MyTestFeature extends ContentFeature {
997+
testMatchPreviewConditional(conditionBlock) {
998+
return this._matchPreviewConditional(conditionBlock);
999+
}
1000+
}
1001+
1002+
const args = {
1003+
site: {
1004+
domain: 'example.com',
1005+
url: 'http://example.com',
1006+
},
1007+
platform: {
1008+
name: 'test',
1009+
preview: true,
1010+
},
1011+
};
1012+
1013+
const feature = new MyTestFeature('test', {}, args);
1014+
const result = feature.testMatchPreviewConditional({
1015+
preview: true,
1016+
});
1017+
expect(result).toBe(true);
1018+
});
1019+
1020+
it('should match when preview is false and condition is false', () => {
1021+
class MyTestFeature extends ContentFeature {
1022+
testMatchPreviewConditional(conditionBlock) {
1023+
return this._matchPreviewConditional(conditionBlock);
1024+
}
1025+
}
1026+
1027+
const args = {
1028+
site: {
1029+
domain: 'example.com',
1030+
url: 'http://example.com',
1031+
},
1032+
platform: {
1033+
name: 'test',
1034+
preview: false,
1035+
},
1036+
};
1037+
1038+
const feature = new MyTestFeature('test', {}, args);
1039+
const result = feature.testMatchPreviewConditional({
1040+
preview: false,
1041+
});
1042+
expect(result).toBe(true);
1043+
});
1044+
1045+
it('should not match when preview is true but condition is false', () => {
1046+
class MyTestFeature extends ContentFeature {
1047+
testMatchPreviewConditional(conditionBlock) {
1048+
return this._matchPreviewConditional(conditionBlock);
1049+
}
1050+
}
1051+
1052+
const args = {
1053+
site: {
1054+
domain: 'example.com',
1055+
url: 'http://example.com',
1056+
},
1057+
platform: {
1058+
name: 'test',
1059+
preview: true,
1060+
},
1061+
};
1062+
1063+
const feature = new MyTestFeature('test', {}, args);
1064+
const result = feature.testMatchPreviewConditional({
1065+
preview: false,
1066+
});
1067+
expect(result).toBe(false);
1068+
});
1069+
1070+
it('should not match when preview is false but condition is true', () => {
1071+
class MyTestFeature extends ContentFeature {
1072+
testMatchPreviewConditional(conditionBlock) {
1073+
return this._matchPreviewConditional(conditionBlock);
1074+
}
1075+
}
1076+
1077+
const args = {
1078+
site: {
1079+
domain: 'example.com',
1080+
url: 'http://example.com',
1081+
},
1082+
platform: {
1083+
name: 'test',
1084+
preview: false,
1085+
},
1086+
};
1087+
1088+
const feature = new MyTestFeature('test', {}, args);
1089+
const result = feature.testMatchPreviewConditional({
1090+
preview: true,
1091+
});
1092+
expect(result).toBe(false);
1093+
});
1094+
1095+
it('should handle undefined preview state gracefully', () => {
1096+
class MyTestFeature extends ContentFeature {
1097+
testMatchPreviewConditional(conditionBlock) {
1098+
return this._matchPreviewConditional(conditionBlock);
1099+
}
1100+
}
1101+
1102+
const args = {
1103+
site: {
1104+
domain: 'example.com',
1105+
url: 'http://example.com',
1106+
},
1107+
platform: {
1108+
name: 'test',
1109+
// preview not set
1110+
},
1111+
};
1112+
1113+
const feature = new MyTestFeature('test', {}, args);
1114+
const result = feature.testMatchPreviewConditional({
1115+
preview: true,
1116+
});
1117+
expect(result).toBe(false);
1118+
});
1119+
1120+
it('should handle missing preview condition', () => {
1121+
class MyTestFeature extends ContentFeature {
1122+
testMatchPreviewConditional(conditionBlock) {
1123+
return this._matchPreviewConditional(conditionBlock);
1124+
}
1125+
}
1126+
1127+
const args = {
1128+
site: {
1129+
domain: 'example.com',
1130+
url: 'http://example.com',
1131+
},
1132+
platform: {
1133+
name: 'test',
1134+
preview: true,
1135+
},
1136+
};
1137+
1138+
const feature = new MyTestFeature('test', {}, args);
1139+
const result = feature.testMatchPreviewConditional({});
1140+
expect(result).toBe(false);
1141+
});
1142+
1143+
it('should handle truthy values for preview condition', () => {
1144+
class MyTestFeature extends ContentFeature {
1145+
testMatchPreviewConditional(conditionBlock) {
1146+
return this._matchPreviewConditional(conditionBlock);
1147+
}
1148+
}
1149+
1150+
const args = {
1151+
site: {
1152+
domain: 'example.com',
1153+
url: 'http://example.com',
1154+
},
1155+
platform: {
1156+
name: 'test',
1157+
preview: 1, // truthy value
1158+
},
1159+
};
1160+
1161+
const feature = new MyTestFeature('test', {}, args);
1162+
const result = feature.testMatchPreviewConditional({
1163+
preview: true,
1164+
});
1165+
expect(result).toBe(true);
1166+
});
1167+
1168+
it('should handle falsy values for preview condition', () => {
1169+
class MyTestFeature extends ContentFeature {
1170+
testMatchPreviewConditional(conditionBlock) {
1171+
return this._matchPreviewConditional(conditionBlock);
1172+
}
1173+
}
1174+
1175+
const args = {
1176+
site: {
1177+
domain: 'example.com',
1178+
url: 'http://example.com',
1179+
},
1180+
platform: {
1181+
name: 'test',
1182+
preview: 0, // falsy value
1183+
},
1184+
};
1185+
1186+
const feature = new MyTestFeature('test', {}, args);
1187+
const result = feature.testMatchPreviewConditional({
1188+
preview: false,
1189+
});
1190+
expect(result).toBe(true);
1191+
});
1192+
});
9931193
});

0 commit comments

Comments
 (0)