Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

/* Any copyright is dedicated to the Public Domain.
"use strict";
const AI_CONTROL_DEFAULT_PREF = "browser.ai.control.default";
const AI_CONTROL_TRANSLATIONS_PREF = "browser.ai.control.translations";
const TRANSLATIONS_ENABLE_PREF = "browser.translations.enable";
/**
* This test case ensures that the Translations feature contains the proper id.
*/
add_task(async function test_ai_feature_id() {
is(
TranslationsParent.AIFeature.id,
"translations",
"AIFeature exposes the translations id"
);
});
/**
* This test case ensures that the Translations feature availability is correct
* for all combinations of the prefs that control its enabled state.
*/
add_task(async function test_ai_feature_state_combinations() {
await SpecialPowers.pushPrefEnv({
set: [
[AI_CONTROL_DEFAULT_PREF, "available"],
[AI_CONTROL_TRANSLATIONS_PREF, "default"],
[TRANSLATIONS_ENABLE_PREF, false],
],
});
const feature = TranslationsParent.AIFeature;
const cases = [
{
defaultPref: "available",
translationsPref: "blocked",
enabledPref: false,
expectEnabled: false,
},
{
defaultPref: "available",
translationsPref: "blocked",
enabledPref: true,
expectEnabled: true,
},
{
defaultPref: "available",
translationsPref: "enabled",
enabledPref: false,
expectEnabled: false,
},
{
defaultPref: "available",
translationsPref: "enabled",
enabledPref: true,
expectEnabled: true,
},
{
defaultPref: "available",
translationsPref: "default",
enabledPref: false,
expectEnabled: false,
},
{
defaultPref: "available",
translationsPref: "default",
enabledPref: true,
expectEnabled: true,
},
{
defaultPref: "available",
translationsPref: "invalid",
enabledPref: false,
expectEnabled: false,
},
{
defaultPref: "available",
translationsPref: "invalid",
enabledPref: true,
expectEnabled: true,
},
{
defaultPref: "blocked",
translationsPref: "blocked",
enabledPref: false,
expectEnabled: false,
},
{
defaultPref: "blocked",
translationsPref: "blocked",
enabledPref: true,
expectEnabled: true,
},
{
defaultPref: "blocked",
translationsPref: "enabled",
enabledPref: false,
expectEnabled: false,
},
{
defaultPref: "blocked",
translationsPref: "enabled",
enabledPref: true,
expectEnabled: true,
},
{
defaultPref: "blocked",
translationsPref: "default",
enabledPref: false,
expectEnabled: false,
},
{
defaultPref: "blocked",
translationsPref: "default",
enabledPref: true,
expectEnabled: true,
},
{
defaultPref: "blocked",
translationsPref: "invalid",
enabledPref: false,
expectEnabled: false,
},
{
defaultPref: "blocked",
translationsPref: "invalid",
enabledPref: true,
expectEnabled: true,
},
{
defaultPref: "invalid",
translationsPref: "blocked",
enabledPref: false,
expectEnabled: false,
},
{
defaultPref: "invalid",
translationsPref: "blocked",
enabledPref: true,
expectEnabled: true,
},
{
defaultPref: "invalid",
translationsPref: "enabled",
enabledPref: false,
expectEnabled: false,
},
{
defaultPref: "invalid",
translationsPref: "enabled",
enabledPref: true,
expectEnabled: true,
},
{
defaultPref: "invalid",
translationsPref: "default",
enabledPref: false,
expectEnabled: false,
},
{
defaultPref: "invalid",
translationsPref: "default",
enabledPref: true,
expectEnabled: true,
},
{
defaultPref: "invalid",
translationsPref: "invalid",
enabledPref: false,
expectEnabled: false,
},
{
defaultPref: "invalid",
translationsPref: "invalid",
enabledPref: true,
expectEnabled: true,
},
];
is(cases.length, 24, "Covers all combinations");
for (const {
translationsPref,
defaultPref,
enabledPref,
expectEnabled,
} of cases) {
const description = `default=${defaultPref} translations=${translationsPref} enabled=${enabledPref}`;
info(`Translations feature state: ${description}`);
Services.prefs.setStringPref(AI_CONTROL_DEFAULT_PREF, defaultPref);
Services.prefs.setStringPref(
AI_CONTROL_TRANSLATIONS_PREF,
translationsPref
);
Services.prefs.setBoolPref(TRANSLATIONS_ENABLE_PREF, enabledPref);
is(feature.isAllowed, true, `${description} (allowed state)`);
is(feature.isBlocked, !expectEnabled, `${description} (blocked state)`);
is(feature.isEnabled, expectEnabled, `${description} (enabled state)`);
}
await SpecialPowers.popPrefEnv();
});
/**
* This test case ensures that enabling the Translations feature updates prefs without deleting artifacts.
*/
add_task(async function test_ai_feature_enable() {
await SpecialPowers.pushPrefEnv({
set: [
[AI_CONTROL_DEFAULT_PREF, "available"],
[AI_CONTROL_TRANSLATIONS_PREF, "default"],
[TRANSLATIONS_ENABLE_PREF, false],
],
});
const feature = TranslationsParent.AIFeature;
const originalDeleteAllLanguageFiles =
TranslationsUtils.deleteAllLanguageFiles;
let deleteCalls = 0;
TranslationsUtils.deleteAllLanguageFiles = async () => {
deleteCalls += 1;
return [];
};
try {
await feature.enable();
is(
Services.prefs.getStringPref(AI_CONTROL_TRANSLATIONS_PREF),
"enabled",
"Enable sets the AI control pref"
);
is(
Services.prefs.getBoolPref(TRANSLATIONS_ENABLE_PREF),
true,
"Enable turns on translations"
);
is(deleteCalls, 0, "Enable does not delete artifacts");
await TestTranslationsTelemetry.assertEvent(
Glean.translationsFeature.enable,
{
expectedEventCount: 1,
}
);
} finally {
TranslationsUtils.deleteAllLanguageFiles = originalDeleteAllLanguageFiles;
await SpecialPowers.popPrefEnv();
TestTranslationsTelemetry.cleanup();
}
});
/**
* This test case ensures that disabling the Translations feature updates prefs and deletes artifacts.
*/
add_task(async function test_ai_feature_disable() {
await SpecialPowers.pushPrefEnv({
set: [
[AI_CONTROL_DEFAULT_PREF, "available"],
[AI_CONTROL_TRANSLATIONS_PREF, "enabled"],
[TRANSLATIONS_ENABLE_PREF, true],
],
});
const feature = TranslationsParent.AIFeature;
const originalDeleteAllLanguageFiles =
TranslationsUtils.deleteAllLanguageFiles;
let deleteCalls = 0;
let shouldThrow = false;
TranslationsUtils.deleteAllLanguageFiles = async () => {
deleteCalls += 1;
if (shouldThrow) {
throw new Error("Delete failed");
}
return [];
};
try {
shouldThrow = true;
await feature.disable();
is(
Services.prefs.getStringPref(AI_CONTROL_TRANSLATIONS_PREF),
"blocked",
"Disable sets the AI control pref"
);
is(
Services.prefs.getBoolPref(TRANSLATIONS_ENABLE_PREF),
false,
"Disable turns off translations"
);
is(deleteCalls, 1, "Disable deletes artifacts");
await TestTranslationsTelemetry.assertEvent(
Glean.translationsFeature.disable,
{
expectedEventCount: 1,
}
);
} finally {
TranslationsUtils.deleteAllLanguageFiles = originalDeleteAllLanguageFiles;
await SpecialPowers.popPrefEnv();
TestTranslationsTelemetry.cleanup();
}
});
/**
* This test case ensures that resetting the Translations feature clears prefs and deletes artifacts.
*/
add_task(async function test_ai_feature_reset() {
await SpecialPowers.pushPrefEnv({
set: [
[AI_CONTROL_DEFAULT_PREF, "available"],
[AI_CONTROL_TRANSLATIONS_PREF, "enabled"],
[TRANSLATIONS_ENABLE_PREF, true],
],
});
const feature = TranslationsParent.AIFeature;
const originalDeleteAllLanguageFiles =
TranslationsUtils.deleteAllLanguageFiles;
let deleteCalls = 0;
TranslationsUtils.deleteAllLanguageFiles = async () => {
deleteCalls += 1;
return [];
};
try {
await feature.reset();
ok(
!Services.prefs.prefHasUserValue(AI_CONTROL_TRANSLATIONS_PREF),
"Reset clears the AI control pref"
);
ok(
!Services.prefs.prefHasUserValue(TRANSLATIONS_ENABLE_PREF),
"Reset clears the translations enabled pref"
);
is(deleteCalls, 1, "Reset deletes artifacts");
await TestTranslationsTelemetry.assertEvent(
Glean.translationsFeature.reset,
{
expectedEventCount: 1,
}
);
} finally {
TranslationsUtils.deleteAllLanguageFiles = originalDeleteAllLanguageFiles;
await SpecialPowers.popPrefEnv();
TestTranslationsTelemetry.cleanup();
}
});
/**
* This test case ensures that policy-managed translations enable pref rejects Translations feature changes.
*/
add_task(async function test_ai_feature_policy_lock_enable_pref() {
await SpecialPowers.pushPrefEnv({
set: [
[AI_CONTROL_DEFAULT_PREF, "available"],
[AI_CONTROL_TRANSLATIONS_PREF, "default"],
[TRANSLATIONS_ENABLE_PREF, false],
],
});
const feature = TranslationsParent.AIFeature;
ok(!feature.isManagedByPolicy, "Policy managed state starts off");
Services.prefs.lockPref(TRANSLATIONS_ENABLE_PREF);
try {
ok(
feature.isManagedByPolicy,
"Policy managed state reflects translations pref management"
);
let threw = false;
try {
await feature.enable();
} catch (error) {
threw = true;
}
ok(threw, "Enable rejects when prefs are managed by policy");
threw = false;
try {
await feature.disable();
} catch (error) {
threw = true;
}
ok(threw, "Disable rejects when prefs are managed by policy");
threw = false;
try {
await feature.reset();
} catch (error) {
threw = true;
}
ok(threw, "Reset rejects when prefs are managed by policy");
} finally {
Services.prefs.unlockPref(TRANSLATIONS_ENABLE_PREF);
ok(
!feature.isManagedByPolicy,
"Policy managed state clears when prefs are unlocked"
);
await SpecialPowers.popPrefEnv();
}
});
/**
* This test case ensures that policy-managed AI control pref rejects Translations feature changes.
*/
add_task(async function test_ai_feature_policy_lock_ai_control_pref() {
await SpecialPowers.pushPrefEnv({
set: [
[AI_CONTROL_DEFAULT_PREF, "available"],
[AI_CONTROL_TRANSLATIONS_PREF, "default"],
[TRANSLATIONS_ENABLE_PREF, false],
],
});
const feature = TranslationsParent.AIFeature;
ok(!feature.isManagedByPolicy, "Policy managed state starts off");
Services.prefs.lockPref(AI_CONTROL_TRANSLATIONS_PREF);
try {
ok(
feature.isManagedByPolicy,
"Policy managed state reflects AI control pref management"
);
let threw = false;
try {
await feature.enable();
} catch (error) {
threw = true;
}
ok(threw, "Enable rejects when AI control pref is managed by policy");
threw = false;
try {
await feature.disable();
} catch (error) {
threw = true;
}
ok(threw, "Disable rejects when AI control pref is managed by policy");
threw = false;
try {
await feature.reset();
} catch (error) {
threw = true;
}
ok(threw, "Reset rejects when AI control pref is managed by policy");
} finally {
Services.prefs.unlockPref(AI_CONTROL_TRANSLATIONS_PREF);
ok(
!feature.isManagedByPolicy,
"Policy managed state clears when prefs are unlocked"
);
await SpecialPowers.popPrefEnv();
}
});