Bug 1903838 - Fix change-to-language telemetry edge case a=RyanVM

Fixes an edge case in the SelectTranslationsPanel where,
on Windows and Linux, if both the from-language and to-language
are changed via keyboard before triggering re-translation, then
only the change-from-language event is logged to telemetry.

Original Revision: https://phabricator.services.mozilla.com/D214419

Differential Revision: https://phabricator.services.mozilla.com/D214429
This commit is contained in:
Erik Nordin 2024-06-21 00:57:08 +00:00
parent 8043a755f3
commit 64ea984262
5 changed files with 718 additions and 1 deletions

View file

@ -2262,7 +2262,8 @@ var SelectTranslationsPanel = new (class {
currentLangTag: selectedFromLanguage,
docLangTag,
});
} else if (selectedToLanguage !== previousToLanguage) {
}
if (selectedToLanguage !== previousToLanguage) {
TranslationsParent.telemetry()
.selectTranslationsPanel()
.onChangeToLanguage(selectedToLanguage);

View file

@ -165,6 +165,10 @@ skip-if = ["os == 'linux' && !debug"] # Bug 1863227
["browser_translations_select_panel_unsupported_language.js"]
["browser_translations_select_telemetry_change_both_languages_together.js"]
["browser_translations_select_telemetry_change_languages_multiple_times.js"]
["browser_translations_select_telemetry_init_failure_ui_then_cancel.js"]
["browser_translations_select_telemetry_init_failure_ui_then_succeed.js"]

View file

@ -0,0 +1,329 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* This test case tests the edge-case scenario where, through keyboard navigation, a user is technically
* able to change both the from-language and the to-language value before triggering a re-translation.
* We want to make sure in this situation that both telemetry events for a changed from-language and
* for a changed to-language fire.
*
* The test covers all three methods of triggering the translation:
* - Pressing the Enter key with the from-menulist focused.
* - Pressing the Enter key with the to-menulist focused.
* - Tabbing to focus the textarea after a language has been changed.
*/
add_task(
async function test_select_translations_panel_change_from_and_to_languages_before_retranslation() {
const { cleanup, runInPage, resolveDownloads } = await loadTestPage({
page: SELECT_TEST_PAGE_URL,
languagePairs: [
{ fromLang: "es", toLang: "en" },
{ fromLang: "en", toLang: "es" },
{ fromLang: "fa", toLang: "en" },
{ fromLang: "en", toLang: "fa" },
{ fromLang: "fi", toLang: "en" },
{ fromLang: "en", toLang: "fi" },
{ fromLang: "fr", toLang: "en" },
{ fromLang: "en", toLang: "fr" },
{ fromLang: "sl", toLang: "en" },
{ fromLang: "en", toLang: "sl" },
{ fromLang: "uk", toLang: "en" },
{ fromLang: "en", toLang: "uk" },
],
prefs: [["browser.translations.select.enable", true]],
});
await SelectTranslationsTestUtils.openPanel(runInPage, {
selectSpanishSentence: true,
openAtSpanishSentence: true,
expectedFromLanguage: "es",
expectedToLanguage: "en",
downloadHandler: resolveDownloads,
onOpenPanel: SelectTranslationsTestUtils.assertPanelViewTranslated,
});
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.open,
{
expectedEventCount: 1,
expectNewFlowId: true,
assertForMostRecentEvent: {
document_language: "es",
from_language: "es",
to_language: "en",
top_preferred_language: "en",
text_source: "selection",
},
}
);
await TestTranslationsTelemetry.assertLabeledCounter(
Glean.translations.requestCount,
[
["full_page", 0],
["select", 1],
]
);
await TestTranslationsTelemetry.assertEvent(
Glean.translations.translationRequest,
{
expectedEventCount: 1,
assertForMostRecentEvent: {
document_language: "es",
from_language: "es",
to_language: "en",
top_preferred_language: "en",
request_target: "select",
auto_translate: false,
source_text_code_units: 165,
source_text_word_count: 28,
},
}
);
const { fromMenuList, toMenuList } = SelectTranslationsPanel.elements;
info(
"Changing both the from-language and to-language before triggering translation."
);
fromMenuList.value = "fr";
toMenuList.value = "uk";
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeFromLanguage,
{
expectedEventCount: 0,
}
);
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeToLanguage,
{
expectedEventCount: 0,
}
);
{
info(
"Triggering a single translation with both updated languages via Enter key on from-menulist."
);
const translatablePhasePromise =
SelectTranslationsTestUtils.waitForPanelState("translatable");
focusElementAndSynthesizeKey(fromMenuList, "KEY_Enter");
await translatablePhasePromise;
await SelectTranslationsTestUtils.handleDownloads({
pivotTranslation: true,
downloadHandler: resolveDownloads,
});
await SelectTranslationsTestUtils.assertPanelViewTranslated();
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeFromLanguage,
{
expectedEventCount: 1,
assertForMostRecentEvent: {
language: "fr",
previous_language: "es",
document_language: "es",
},
}
);
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeToLanguage,
{
expectedEventCount: 1,
assertForMostRecentEvent: {
language: "uk",
},
}
);
await TestTranslationsTelemetry.assertLabeledCounter(
Glean.translations.requestCount,
[
["full_page", 0],
["select", 2],
]
);
await TestTranslationsTelemetry.assertEvent(
Glean.translations.translationRequest,
{
expectedEventCount: 2,
assertForMostRecentEvent: {
document_language: "es",
from_language: "fr",
to_language: "uk",
top_preferred_language: "en",
request_target: "select",
auto_translate: false,
},
}
);
}
{
info(
"Changing both the from-language and to-language before triggering translation."
);
fromMenuList.value = "fa";
toMenuList.value = "en";
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeFromLanguage,
{
expectedEventCount: 1,
}
);
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeToLanguage,
{
expectedEventCount: 1,
}
);
info(
"Triggering a single translation with both updated languages via Enter key on to-menulist."
);
const translatablePhasePromise =
SelectTranslationsTestUtils.waitForPanelState("translatable");
focusElementAndSynthesizeKey(toMenuList, "KEY_Enter");
await translatablePhasePromise;
await SelectTranslationsTestUtils.handleDownloads({
downloadHandler: resolveDownloads,
});
await SelectTranslationsTestUtils.assertPanelViewTranslated();
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeFromLanguage,
{
expectedEventCount: 2,
assertForMostRecentEvent: {
language: "fa",
previous_language: "fr",
document_language: "es",
},
}
);
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeToLanguage,
{
expectedEventCount: 2,
assertForMostRecentEvent: {
language: "en",
},
}
);
await TestTranslationsTelemetry.assertLabeledCounter(
Glean.translations.requestCount,
[
["full_page", 0],
["select", 3],
]
);
await TestTranslationsTelemetry.assertEvent(
Glean.translations.translationRequest,
{
expectedEventCount: 3,
assertForMostRecentEvent: {
document_language: "es",
from_language: "fa",
to_language: "en",
top_preferred_language: "en",
request_target: "select",
auto_translate: false,
},
}
);
}
{
info(
"Changing both the from-language and to-language before triggering translation."
);
fromMenuList.value = "sl";
toMenuList.value = "fi";
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeFromLanguage,
{
expectedEventCount: 2,
}
);
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeToLanguage,
{
expectedEventCount: 2,
}
);
info(
"Triggering a single translation with both updated languages via Tab key on to-menulist."
);
const translatablePhasePromise =
SelectTranslationsTestUtils.waitForPanelState("translatable");
focusElementAndSynthesizeKey(toMenuList, "KEY_Tab");
await translatablePhasePromise;
await SelectTranslationsTestUtils.handleDownloads({
pivotTranslation: true,
downloadHandler: resolveDownloads,
});
await SelectTranslationsTestUtils.assertPanelViewTranslated();
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeFromLanguage,
{
expectedEventCount: 3,
assertForMostRecentEvent: {
language: "sl",
previous_language: "fa",
document_language: "es",
},
}
);
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeToLanguage,
{
expectedEventCount: 3,
assertForMostRecentEvent: {
language: "fi",
},
}
);
await TestTranslationsTelemetry.assertLabeledCounter(
Glean.translations.requestCount,
[
["full_page", 0],
["select", 4],
]
);
await TestTranslationsTelemetry.assertEvent(
Glean.translations.translationRequest,
{
expectedEventCount: 4,
assertForMostRecentEvent: {
document_language: "es",
from_language: "sl",
to_language: "fi",
top_preferred_language: "en",
request_target: "select",
auto_translate: false,
},
}
);
}
await SelectTranslationsTestUtils.clickDoneButton();
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.doneButton,
{
expectedEventCount: 1,
}
);
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.close,
{
expectedEventCount: 1,
}
);
await cleanup();
}
);

View file

@ -0,0 +1,366 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* This test case verifies the data associated the change-from-language and change-to-language
* telemetry events when changing selected the from-language menu item multiple times in different ways.
*/
add_task(
async function test_select_translations_panel_change_from_language_multiple_times() {
const { cleanup, runInPage, resolveDownloads } = await loadTestPage({
page: SELECT_TEST_PAGE_URL,
languagePairs: [
{ fromLang: "es", toLang: "en" },
{ fromLang: "en", toLang: "es" },
{ fromLang: "fa", toLang: "en" },
{ fromLang: "en", toLang: "fa" },
{ fromLang: "fi", toLang: "en" },
{ fromLang: "en", toLang: "fi" },
{ fromLang: "fr", toLang: "en" },
{ fromLang: "en", toLang: "fr" },
{ fromLang: "sl", toLang: "en" },
{ fromLang: "en", toLang: "sl" },
{ fromLang: "uk", toLang: "en" },
{ fromLang: "en", toLang: "uk" },
],
prefs: [["browser.translations.select.enable", true]],
});
await SelectTranslationsTestUtils.openPanel(runInPage, {
selectSpanishSentence: true,
openAtSpanishSentence: true,
expectedFromLanguage: "es",
expectedToLanguage: "en",
downloadHandler: resolveDownloads,
onOpenPanel: SelectTranslationsTestUtils.assertPanelViewTranslated,
});
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.open,
{
expectedEventCount: 1,
expectNewFlowId: true,
assertForMostRecentEvent: {
document_language: "es",
from_language: "es",
to_language: "en",
top_preferred_language: "en",
text_source: "selection",
},
}
);
await TestTranslationsTelemetry.assertLabeledCounter(
Glean.translations.requestCount,
[
["full_page", 0],
["select", 1],
]
);
await TestTranslationsTelemetry.assertEvent(
Glean.translations.translationRequest,
{
expectedEventCount: 1,
assertForMostRecentEvent: {
document_language: "es",
from_language: "es",
to_language: "en",
top_preferred_language: "en",
request_target: "select",
auto_translate: false,
source_text_code_units: 165,
source_text_word_count: 28,
},
}
);
await SelectTranslationsTestUtils.changeSelectedFromLanguage(
["fi", "fr", "sl"],
{
openDropdownMenu: false,
downloadHandler: resolveDownloads,
onChangeLanguage: SelectTranslationsTestUtils.assertPanelViewTranslated,
}
);
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeFromLanguage,
{
expectedEventCount: 1,
assertForMostRecentEvent: {
language: "sl",
previous_language: "es",
document_language: "es",
},
}
);
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeToLanguage,
{
expectedEventCount: 0,
}
);
await TestTranslationsTelemetry.assertLabeledCounter(
Glean.translations.requestCount,
[
["full_page", 0],
["select", 2],
]
);
await TestTranslationsTelemetry.assertEvent(
Glean.translations.translationRequest,
{
expectedEventCount: 2,
assertForMostRecentEvent: {
document_language: "es",
from_language: "sl",
to_language: "en",
top_preferred_language: "en",
request_target: "select",
auto_translate: false,
},
}
);
await SelectTranslationsTestUtils.changeSelectedFromLanguage(["uk", "fa"], {
openDropdownMenu: true,
downloadHandler: resolveDownloads,
onChangeLanguage: SelectTranslationsTestUtils.assertPanelViewTranslated,
});
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeFromLanguage,
{
expectedEventCount: 3,
assertForMostRecentEvent: {
language: "fa",
previous_language: "uk",
document_language: "es",
},
}
);
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeToLanguage,
{
expectedEventCount: 0,
}
);
await TestTranslationsTelemetry.assertLabeledCounter(
Glean.translations.requestCount,
[
["full_page", 0],
["select", 4],
]
);
await TestTranslationsTelemetry.assertEvent(
Glean.translations.translationRequest,
{
expectedEventCount: 4,
assertForMostRecentEvent: {
document_language: "es",
from_language: "fa",
to_language: "en",
top_preferred_language: "en",
request_target: "select",
auto_translate: false,
},
}
);
await SelectTranslationsTestUtils.clickDoneButton();
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.doneButton,
{
expectedEventCount: 1,
}
);
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.close,
{
expectedEventCount: 1,
}
);
await cleanup();
}
);
/**
* This test case verifies the data associated the change-from-language and change-to-language
* telemetry events when changing the selected to-language menu item multiple times in different ways.
*/
add_task(
async function test_select_translations_panel_change_to_language_multiple_times() {
const { cleanup, runInPage, resolveDownloads } = await loadTestPage({
page: SELECT_TEST_PAGE_URL,
languagePairs: [
{ fromLang: "es", toLang: "en" },
{ fromLang: "en", toLang: "es" },
{ fromLang: "fa", toLang: "en" },
{ fromLang: "en", toLang: "fa" },
{ fromLang: "fi", toLang: "en" },
{ fromLang: "en", toLang: "fi" },
{ fromLang: "fr", toLang: "en" },
{ fromLang: "en", toLang: "fr" },
{ fromLang: "sl", toLang: "en" },
{ fromLang: "en", toLang: "sl" },
{ fromLang: "uk", toLang: "en" },
{ fromLang: "en", toLang: "uk" },
],
prefs: [["browser.translations.select.enable", true]],
});
await SelectTranslationsTestUtils.openPanel(runInPage, {
selectSpanishSentence: true,
openAtSpanishSentence: true,
expectedFromLanguage: "es",
expectedToLanguage: "en",
downloadHandler: resolveDownloads,
onOpenPanel: SelectTranslationsTestUtils.assertPanelViewTranslated,
});
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.open,
{
expectedEventCount: 1,
expectNewFlowId: true,
assertForMostRecentEvent: {
document_language: "es",
from_language: "es",
to_language: "en",
top_preferred_language: "en",
text_source: "selection",
},
}
);
await TestTranslationsTelemetry.assertLabeledCounter(
Glean.translations.requestCount,
[
["full_page", 0],
["select", 1],
]
);
await TestTranslationsTelemetry.assertEvent(
Glean.translations.translationRequest,
{
expectedEventCount: 1,
assertForMostRecentEvent: {
document_language: "es",
from_language: "es",
to_language: "en",
top_preferred_language: "en",
request_target: "select",
auto_translate: false,
source_text_code_units: 165,
source_text_word_count: 28,
},
}
);
await SelectTranslationsTestUtils.changeSelectedToLanguage(
["sl", "fi", "fa"],
{
openDropdownMenu: false,
pivotTranslation: true,
downloadHandler: resolveDownloads,
onChangeLanguage: SelectTranslationsTestUtils.assertPanelViewTranslated,
}
);
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeFromLanguage,
{
expectedEventCount: 0,
}
);
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeToLanguage,
{
expectedEventCount: 1,
assertForMostRecentEvent: {
language: "fa",
},
}
);
await TestTranslationsTelemetry.assertLabeledCounter(
Glean.translations.requestCount,
[
["full_page", 0],
["select", 2],
]
);
await TestTranslationsTelemetry.assertEvent(
Glean.translations.translationRequest,
{
expectedEventCount: 2,
assertForMostRecentEvent: {
document_language: "es",
from_language: "es",
to_language: "fa",
top_preferred_language: "en",
request_target: "select",
auto_translate: false,
source_text_code_units: 165,
source_text_word_count: 28,
},
}
);
await SelectTranslationsTestUtils.changeSelectedToLanguage(["fr", "uk"], {
openDropdownMenu: true,
pivotTranslation: true,
downloadHandler: resolveDownloads,
onChangeLanguage: SelectTranslationsTestUtils.assertPanelViewTranslated,
});
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeFromLanguage,
{
expectedEventCount: 0,
}
);
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeToLanguage,
{
expectedEventCount: 3,
assertForMostRecentEvent: {
language: "uk",
},
}
);
await TestTranslationsTelemetry.assertLabeledCounter(
Glean.translations.requestCount,
[
["full_page", 0],
["select", 4],
]
);
await TestTranslationsTelemetry.assertEvent(
Glean.translations.translationRequest,
{
expectedEventCount: 4,
assertForMostRecentEvent: {
document_language: "es",
from_language: "es",
to_language: "uk",
top_preferred_language: "en",
request_target: "select",
auto_translate: false,
source_text_code_units: 165,
source_text_word_count: 28,
},
}
);
await SelectTranslationsTestUtils.clickDoneButton();
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.doneButton,
{
expectedEventCount: 1,
}
);
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.close,
{
expectedEventCount: 1,
}
);
await cleanup();
}
);

View file

@ -98,6 +98,12 @@ add_task(
},
}
);
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeToLanguage,
{
expectedEventCount: 0,
}
);
await TestTranslationsTelemetry.assertLabeledCounter(
Glean.translations.requestCount,
[
@ -196,6 +202,17 @@ add_task(
downloadHandler: resolveDownloads,
onChangeLanguage: SelectTranslationsTestUtils.assertPanelViewTranslated,
});
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeFromLanguage,
{
expectedEventCount: 1,
assertForMostRecentEvent: {
language: "fi",
previous_language: "es",
document_language: "es",
},
}
);
await TestTranslationsTelemetry.assertEvent(
Glean.translationsSelectTranslationsPanel.changeToLanguage,
{