From 710dc5fdfd2dcbaa533766b4bf57c8909e36c7b1 Mon Sep 17 00:00:00 2001 From: Matt Lichtenstein Date: Thu, 25 Jan 2024 17:31:25 -0500 Subject: [PATCH] VPN-6124: Help sheet improvements (#8985) --- nebula/ui/components/MZBottomSheet.qml | 54 +- nebula/ui/components/MZHelpSheet.qml | 278 +++--- nebula/ui/themes/main/theme.js | 5 + src/ui/screens/devices/ViewDevices.qml | 34 +- src/ui/screens/home/ViewServers.qml | 30 +- src/ui/screens/settings/ViewDNSSettings.qml | 31 +- .../appPermissions/ViewAppPermissions.qml | 43 +- .../screens/settings/privacy/ViewPrivacy.qml | 31 +- tests/functional/queries.js | 58 +- tests/functional/testAppExclusions.js | 88 +- tests/functional/testDevices.js | 28 + tests/functional/testServers.js | 17 + tests/functional/testSettings.js | 932 +++++++++--------- 13 files changed, 893 insertions(+), 736 deletions(-) diff --git a/nebula/ui/components/MZBottomSheet.qml b/nebula/ui/components/MZBottomSheet.qml index ea275a88b8..4efbfc4c36 100644 --- a/nebula/ui/components/MZBottomSheet.qml +++ b/nebula/ui/components/MZBottomSheet.qml @@ -26,32 +26,48 @@ import Mozilla.Shared 1.0 } */ -Drawer { - id: drawer +Loader { + id: root - readonly property int maxHeight: (Qt.platform.os === "ios" ? window.safeContentHeight : window.height) - MZTheme.theme.sheetTopMargin + readonly property int maxSheetHeight: (Qt.platform.os === "ios" ? window.safeContentHeight : window.height) - MZTheme.theme.sheetTopMargin + required default property var contentItem + property bool sizeToContent: false + property bool opened: active ? item.opened : null - implicitWidth: window.width - implicitHeight: maxHeight + signal close - topPadding: 0 + active: false - dragMargin: 0 - edge: Qt.BottomEdge - background: Rectangle { + onClose: item.close() - radius: 8 - color: MZTheme.theme.bgColor + sourceComponent: Drawer { + implicitWidth: window.width + implicitHeight: root.sizeToContent ? Math.min(contentItem.implicitHeight, maxSheetHeight) : maxSheetHeight - Rectangle { - color: parent.color - anchors.bottom: parent.bottom - width: parent.width - height: parent.radius + topPadding: 0 + + dragMargin: 0 + edge: Qt.BottomEdge + contentItem: root.contentItem + + onClosed: root.active = false + + background: Rectangle { + + radius: 8 + color: MZTheme.theme.bgColor + + Rectangle { + color: parent.color + anchors.bottom: parent.bottom + width: parent.width + height: parent.radius + } } - } - Overlay.modal: Rectangle { - color: MZTheme.theme.overlayBackground + Overlay.modal: Rectangle { + color: MZTheme.theme.overlayBackground + } } } + diff --git a/nebula/ui/components/MZHelpSheet.qml b/nebula/ui/components/MZHelpSheet.qml index 7719ad6931..20424dc904 100644 --- a/nebula/ui/components/MZHelpSheet.qml +++ b/nebula/ui/components/MZHelpSheet.qml @@ -38,7 +38,7 @@ import Mozilla.Shared 1.0 MZBottomSheet { id: bottomSheet - property alias title: title.text + property string title required property var model enum BlockType { @@ -48,201 +48,207 @@ MZBottomSheet { LinkButton } - implicitHeight: Math.min(contentItem.implicitHeight, maxHeight) + sizeToContent: true - contentItem: ColumnLayout { + //Only load the content if the drawer itself is loaded + contentItem: Loader { - spacing: 0 + active: bottomSheet.active + sourceComponent: ColumnLayout { - Accessible.role: Accessible.Grouping - Accessible.name: bottomSheet.title + spacing: 0 - Component.onCompleted: forceActiveFocus() + Accessible.role: Accessible.Grouping + Accessible.name: bottomSheet.title - ColumnLayout { - id: headerLayout + Component.onCompleted: forceActiveFocus() - Layout.topMargin: 8 - Layout.preferredWidth: parent.width + ColumnLayout { + id: headerLayout - spacing: 0 + Layout.topMargin: 8 + Layout.preferredWidth: parent.width - RowLayout { spacing: 0 - Item { - Layout.topMargin: MZTheme.theme.windowMargin / 2 - Layout.leftMargin: MZTheme.theme.windowMargin - Layout.preferredHeight: MZTheme.theme.iconSize * 1.5 - Layout.preferredWidth: MZTheme.theme.iconSize * 1.5 - Layout.alignment: Qt.AlignTop + RowLayout { + spacing: 0 + + Item { + Layout.topMargin: MZTheme.theme.windowMargin / 2 + Layout.leftMargin: MZTheme.theme.windowMargin + Layout.preferredHeight: MZTheme.theme.iconSize * 1.5 + Layout.preferredWidth: MZTheme.theme.iconSize * 1.5 + Layout.alignment: Qt.AlignTop - Image { - id: icon - anchors.centerIn: parent + Image { + anchors.centerIn: parent - source: "qrc:/nebula/resources/tip-filled.svg" - sourceSize.width: MZTheme.theme.iconSize * 1.5 + source: "qrc:/nebula/resources/tip-filled.svg" + sourceSize.width: MZTheme.theme.iconSize * 1.5 - mirror: MZLocalizer.isRightToLeft - fillMode: Image.PreserveAspectFit + mirror: MZLocalizer.isRightToLeft + fillMode: Image.PreserveAspectFit + } } - } - MZBoldLabel { - id: title + MZBoldLabel { + id: title - Layout.topMargin: MZTheme.theme.windowMargin / 2 - Layout.leftMargin: 8 - Layout.alignment: Qt.AlignTop - Layout.fillWidth: true + Layout.topMargin: MZTheme.theme.windowMargin / 2 + Layout.leftMargin: 8 + Layout.alignment: Qt.AlignTop + Layout.fillWidth: true - verticalAlignment: Text.AlignVCenter - lineHeightMode: Text.FixedHeight - lineHeight: 24 - elide: Text.ElideRight - } + text: bottomSheet.title + verticalAlignment: Text.AlignVCenter + lineHeightMode: Text.FixedHeight + lineHeight: 24 + elide: Text.ElideRight + } - Item { - Layout.fillWidth: true - } + Item { + Layout.fillWidth: true + } - MZIconButton { - Layout.rightMargin: MZTheme.theme.windowMargin / 2 + MZIconButton { + objectName: bottomSheet.objectName + "-closeButton" - Layout.preferredHeight: MZTheme.theme.rowHeight - Layout.preferredWidth: MZTheme.theme.rowHeight + Layout.rightMargin: MZTheme.theme.windowMargin / 2 - //Hacky workaround because for some reason, when opening a sheet via - //the right menu button in MZMenu, this close button is in a - //"Hovered" state, even though it wasn't hovered - //Likely something to do with both icon buttons being in the same position - //Relative to their parent (top right corner) - mouseArea.hoverEnabled: bottomSheet.opened + Layout.preferredHeight: MZTheme.theme.rowHeight + Layout.preferredWidth: MZTheme.theme.rowHeight - onClicked: bottomSheet.close() + onClicked: bottomSheet.close() - accessibleName: MZI18n.GlobalClose + accessibleName: MZI18n.GlobalClose - Image { - anchors.centerIn: parent + Image { + anchors.centerIn: parent - sourceSize.height: MZTheme.theme.iconSize - sourceSize.width: MZTheme.theme.iconSize + sourceSize.height: MZTheme.theme.iconSize + sourceSize.width: MZTheme.theme.iconSize - source: "qrc:/nebula/resources/close-dark.svg" - fillMode: Image.PreserveAspectFit + source: "qrc:/nebula/resources/close-dark.svg" + fillMode: Image.PreserveAspectFit + } } } + + Rectangle { + Layout.topMargin: 8 + Layout.preferredHeight: MZTheme.theme.dividerHeight + Layout.fillWidth: true + + color: MZTheme.colors.grey10 + } } - Rectangle { - Layout.topMargin: 8 - Layout.preferredHeight: MZTheme.theme.dividerHeight + MZFlickable { + id: flickable + + readonly property int maxheight: bottomSheet.maxSheetHeight - headerLayout.implicitHeight - headerLayout.Layout.topMargin + Layout.fillWidth: true + Layout.preferredHeight: Math.min(layout.implicitHeight + layout.anchors.topMargin + layout.anchors.bottomMargin, maxheight) - color: MZTheme.colors.grey10 - } - } + flickContentHeight: layout.implicitHeight + layout.anchors.topMargin + layout.anchors.bottomMargin - MZFlickable { - id: flickable + addNavbarHeightOffset: false - readonly property int maxheight: bottomSheet.maxHeight - headerLayout.implicitHeight - headerLayout.Layout.topMargin + ColumnLayout { + id: layout - Layout.fillWidth: true - Layout.preferredHeight: Math.min(layout.implicitHeight + layout.anchors.topMargin + layout.anchors.bottomMargin, maxheight) + anchors.fill: parent + anchors.margins: MZTheme.theme.windowMargin * 1.5 - flickContentHeight: layout.implicitHeight + layout.anchors.topMargin + layout.anchors.bottomMargin + Repeater { + model: bottomSheet.model + delegate: Loader { + id: loader + objectName: "helpSheetContentLoader" - addNavbarHeightOffset: false + property var composerBlock: bottomSheet.model[index] - ColumnLayout { - id: layout - anchors.fill: parent - anchors.margins: MZTheme.theme.windowMargin * 1.5 - - Repeater { - model: bottomSheet.model - delegate: Loader { - id: loader - - property var composerBlock: bottomSheet.model[index] - - function getSourceComponent() { - switch (composerBlock.type) { - case MZHelpSheet.BlockType.Title: - return titleBlock - case MZHelpSheet.BlockType.Text: - return textBlock - case MZHelpSheet.BlockType.PrimaryButton: - return buttonBlock - case MZHelpSheet.BlockType.LinkButton: - return linkButtonBlock - default: - return console.error("Unable to create view for composer block of type: " + modelData) - } + function getSourceComponent() { + switch (composerBlock.type) { + case MZHelpSheet.BlockType.Title: + return titleBlock + case MZHelpSheet.BlockType.Text: + return textBlock + case MZHelpSheet.BlockType.PrimaryButton: + return buttonBlock + case MZHelpSheet.BlockType.LinkButton: + return linkButtonBlock + default: + return console.error("Unable to create view for composer block of type: " + modelData) + } - } + } - Layout.fillWidth: true - Layout.preferredHeight: item.implicitHeight - Layout.topMargin: composerBlock.margin + Layout.fillWidth: true + Layout.preferredHeight: item.implicitHeight + Layout.topMargin: composerBlock.margin - sourceComponent: getSourceComponent() + sourceComponent: getSourceComponent() - Component { - id: titleBlock + Component { + id: titleBlock - MZBoldInterLabel { - Layout.fillWidth: true + MZBoldInterLabel { + Layout.fillWidth: true - text: loader.composerBlock.text - font.pixelSize: MZTheme.theme.fontSize - lineHeight: 24 - verticalAlignment: Text.AlignVCenter + text: loader.composerBlock.text + font.pixelSize: MZTheme.theme.fontSize + lineHeight: 24 + verticalAlignment: Text.AlignVCenter + } } - } - Component { - id: textBlock + Component { + id: textBlock - MZInterLabel { + MZInterLabel { - text: loader.composerBlock.text - font.pixelSize: MZTheme.theme.fontSizeSmall - color: MZTheme.theme.fontColor - lineHeight: 21 - horizontalAlignment: Text.AlignLeft + text: loader.composerBlock.text + font.pixelSize: MZTheme.theme.fontSizeSmall + color: MZTheme.theme.fontColor + lineHeight: 21 + horizontalAlignment: Text.AlignLeft + } } - } - Component { - id: buttonBlock + Component { + id: buttonBlock + + MZButton { + objectName: typeof loader.composerBlock.objectName !== "undefined" ? loader.composerBlock.objectName : null - MZButton { - anchors.left: parent.left - anchors.right: parent.right + anchors.left: parent.left + anchors.right: parent.right - implicitHeight: MZTheme.theme.rowHeight + implicitHeight: MZTheme.theme.rowHeight - text: loader.composerBlock.text + text: loader.composerBlock.text - onClicked: loader.composerBlock.action() + onClicked: loader.composerBlock.action() + } } - } - Component { - id: linkButtonBlock + Component { + id: linkButtonBlock + + MZLinkButton { + objectName: typeof loader.composerBlock.objectName !== "undefined" ? loader.composerBlock.objectName : null - MZLinkButton { - anchors.left: parent.left - anchors.right: parent.right + anchors.left: parent.left + anchors.right: parent.right - labelText: loader.composerBlock.text + labelText: loader.composerBlock.text - onClicked: loader.composerBlock.action() + onClicked: loader.composerBlock.action() + } } } } diff --git a/nebula/ui/themes/main/theme.js b/nebula/ui/themes/main/theme.js index cda5b849e3..53de94a049 100644 --- a/nebula/ui/themes/main/theme.js +++ b/nebula/ui/themes/main/theme.js @@ -87,6 +87,11 @@ theme.dividerHeight = 1 theme.guideCardHeight = 172 +theme.helpSheetTitleBodySpacing = 8 +theme.helpSheetBodySpacing = 16 +theme.helpSheetBodyButtonSpacing = 16 +theme.helpSheetSecondaryButtonSpacing = 8 + theme.navBarHeight = 64; theme.navBarMaxWidth = 608; theme.navBarTopMargin = 48; diff --git a/src/ui/screens/devices/ViewDevices.qml b/src/ui/screens/devices/ViewDevices.qml index efa894afbf..499eabf151 100644 --- a/src/ui/screens/devices/ViewDevices.qml +++ b/src/ui/screens/devices/ViewDevices.qml @@ -12,6 +12,8 @@ import components 0.1 MZViewBase { id: vpnFlickable + objectName: "devicesSettingsView" + property var isModalDialogOpened: removePopup.visible property var wasmView property string deviceCountLabelText: "" @@ -60,7 +62,9 @@ MZViewBase { id: helpIconButtonLoader active: MZFeatureList.get("helpSheets").isSupported sourceComponent: MZIconButton { - onClicked: helpSheetLoader.active = true + objectName: "devicesHelpButton" + + onClicked: helpSheet.active = true accessibleName: MZI18n.GetHelpLinkTitle @@ -99,27 +103,23 @@ MZViewBase { } } - Loader { - id: helpSheetLoader - - active: false - - onActiveChanged: if (active) item.open() + MZHelpSheet { + id: helpSheet + objectName: "devicesHelpSheet" - sourceComponent: MZHelpSheet { - title: MZI18n.HelpSheetsDevicesTitle + title: MZI18n.HelpSheetsDevicesTitle - model: [ - {type: MZHelpSheet.BlockType.Title, text: MZI18n.HelpSheetsDevicesHeader}, - {type: MZHelpSheet.BlockType.Text, text: MZI18n.HelpSheetsDevicesBody1, margin: 8}, - {type: MZHelpSheet.BlockType.Text, text:MZI18n.HelpSheetsDevicesBody2, margin: 16}, - {type: MZHelpSheet.BlockType.LinkButton, text: MZI18n.GlobalLearnMore, margin: 16, action: () => { MZUrlOpener.openUrlLabel("sumoDevices") } }, - ] + model: [ + {type: MZHelpSheet.BlockType.Title, text: MZI18n.HelpSheetsDevicesHeader}, + {type: MZHelpSheet.BlockType.Text, text: MZI18n.HelpSheetsDevicesBody1, margin: MZTheme.theme.helpSheetTitleBodySpacing}, + {type: MZHelpSheet.BlockType.Text, text: MZI18n.HelpSheetsDevicesBody2, margin: MZTheme.theme.helpSheetBodySpacing}, + {type: MZHelpSheet.BlockType.LinkButton, text: MZI18n.GlobalLearnMore, margin: MZTheme.theme.helpSheetBodyButtonSpacing, action: () => { MZUrlOpener.openUrlLabel("sumoDevices") }, objectName: "learnMoreLink"}, + ] - onClosed: helpSheetLoader.active = false - } + onActiveChanged: if (active) item.open() } + Connections { target: deviceList function onIsEditing(isEditing) { diff --git a/src/ui/screens/home/ViewServers.qml b/src/ui/screens/home/ViewServers.qml index 5ebb5705d6..b88b5c099c 100644 --- a/src/ui/screens/home/ViewServers.qml +++ b/src/ui/screens/home/ViewServers.qml @@ -32,7 +32,9 @@ Item { Loader { active: MZFeatureList.get("helpSheets").isSupported sourceComponent: MZIconButton { - onClicked: helpSheetLoader.active = true + objectName: "serverHelpButton" + + onClicked: helpSheet.active = true accessibleName: MZI18n.GetHelpLinkTitle @@ -149,25 +151,21 @@ Item { } } - Loader { - id: helpSheetLoader - - active: false - onActiveChanged: if (active) item.open() + MZHelpSheet { + id: helpSheet + objectName: "serverHelpSheet" - sourceComponent: MZHelpSheet { - title: MZI18n.HelpSheetsLocationTitle + title: MZI18n.HelpSheetsLocationTitle - model: [ - {type: MZHelpSheet.BlockType.Title, text: MZI18n.HelpSheetsLocationHeader}, - {type: MZHelpSheet.BlockType.Text, text: MZI18n.HelpSheetsLocationBody1, margin: 8}, - {type: MZHelpSheet.BlockType.Text, text:MZI18n.HelpSheetsLocationBody2, margin: 16}, - {type: MZHelpSheet.BlockType.LinkButton, text: MZI18n.GlobalLearnMore, margin: 16, action: () => { MZUrlOpener.openUrlLabel("sumoMultihop") } }, - ] + model: [ + {type: MZHelpSheet.BlockType.Title, text: MZI18n.HelpSheetsLocationHeader}, + {type: MZHelpSheet.BlockType.Text, text: MZI18n.HelpSheetsLocationBody1, margin: MZTheme.theme.helpSheetTitleBodySpacing}, + {type: MZHelpSheet.BlockType.Text, text: MZI18n.HelpSheetsLocationBody2, margin: MZTheme.theme.helpSheetBodySpacing}, + {type: MZHelpSheet.BlockType.LinkButton, text: MZI18n.GlobalLearnMore, margin: MZTheme.theme.helpSheetBodyButtonSpacing, action: () => { MZUrlOpener.openUrlLabel("sumoMultihop") }, objectName: "learnMoreLink"}, + ] - onClosed: helpSheetLoader.active = false - } + onActiveChanged: if (active) item.open() } Component.onCompleted: { diff --git a/src/ui/screens/settings/ViewDNSSettings.qml b/src/ui/screens/settings/ViewDNSSettings.qml index 72219d3410..7a636e69e5 100644 --- a/src/ui/screens/settings/ViewDNSSettings.qml +++ b/src/ui/screens/settings/ViewDNSSettings.qml @@ -25,7 +25,9 @@ MZViewBase { Loader { active: MZFeatureList.get("helpSheets").isSupported sourceComponent: MZIconButton { - onClicked: helpSheetLoader.active = true + objectName: "dnsHelpButton" + + onClicked: helpSheet.active = true accessibleName: MZI18n.GetHelpLinkTitle @@ -334,25 +336,20 @@ MZViewBase { onActiveChanged: if (active) { item.open() } } - Loader { - id: helpSheetLoader + MZHelpSheet { + id: helpSheet + objectName: "dnsHelpSheet" - active: false - - onActiveChanged: if (active) item.open() + title: MZI18n.HelpSheetsDnsTitle - sourceComponent: MZHelpSheet { - title: MZI18n.HelpSheetsDnsTitle + model: [ + {type: MZHelpSheet.BlockType.Title, text: MZI18n.HelpSheetsDnsHeader}, + {type: MZHelpSheet.BlockType.Text, text: MZI18n.HelpSheetsDnsBody1, margin: MZTheme.theme.helpSheetTitleBodySpacing}, + {type: MZHelpSheet.BlockType.Text, text: MZI18n.HelpSheetsDnsBody2, margin: MZTheme.theme.helpSheetBodySpacing}, + {type: MZHelpSheet.BlockType.LinkButton, text: MZI18n.GlobalLearnMore, margin: MZTheme.theme.helpSheetBodyButtonSpacing, action: () => { MZUrlOpener.openUrlLabel("sumoDns") }, objectName: "learnMoreLink"}, + ] - model: [ - {type: MZHelpSheet.BlockType.Title, text: MZI18n.HelpSheetsDnsHeader}, - {type: MZHelpSheet.BlockType.Text, text: MZI18n.HelpSheetsDnsBody1, margin: 8}, - {type: MZHelpSheet.BlockType.Text, text:MZI18n.HelpSheetsDnsBody2, margin: 16}, - {type: MZHelpSheet.BlockType.LinkButton, text: MZI18n.GlobalLearnMore, margin: 16, action: () => { MZUrlOpener.openUrlLabel("sumoDns") } }, - ] - - onClosed: helpSheetLoader.active = false - } + onActiveChanged: if (active) item.open() } } diff --git a/src/ui/screens/settings/appPermissions/ViewAppPermissions.qml b/src/ui/screens/settings/appPermissions/ViewAppPermissions.qml index fe969bb6b1..d8500f2b9d 100644 --- a/src/ui/screens/settings/appPermissions/ViewAppPermissions.qml +++ b/src/ui/screens/settings/appPermissions/ViewAppPermissions.qml @@ -27,7 +27,9 @@ MZViewBase { Loader { active: MZFeatureList.get("helpSheets").isSupported sourceComponent: MZIconButton { - onClicked: helpSheetLoader.active = true + objectName: "excludedAppsHelpButton" + + onClicked: helpSheet.active = true accessibleName: MZI18n.GetHelpLinkTitle @@ -82,30 +84,26 @@ MZViewBase { } } - Loader { - id: helpSheetLoader - active: false + MZHelpSheet { + id: helpSheet + objectName: "excludedAppsHelpSheet" - onActiveChanged: if (active) item.open() + title: MZI18n.HelpSheetsExcludedAppsTitle - sourceComponent: MZHelpSheet { - title: MZI18n.HelpSheetsExcludedAppsTitle - - model: [ - {type: MZHelpSheet.BlockType.Title, text: MZI18n.HelpSheetsExcludedAppsHeader}, - {type: MZHelpSheet.BlockType.Text, text: MZI18n.HelpSheetsExcludedAppsBody1, margin: 8}, - {type: MZHelpSheet.BlockType.Text, text: MZI18n.HelpSheetsExcludedAppsBody2, margin: 16}, - {type: MZHelpSheet.BlockType.Text, text: MZI18n.HelpSheetsExcludedAppsBody3, margin: 16}, - {type: MZHelpSheet.BlockType.PrimaryButton, text: MZI18n.HelpSheetsExcludedAppsCTA, margin: 16, action: () => { - close() - getStack().push("qrc:/ui/screens/settings/privacy/ViewPrivacy.qml") - }}, - {type: MZHelpSheet.BlockType.LinkButton, text: MZI18n.GlobalLearnMore, margin: 8, action: () => { MZUrlOpener.openUrlLabel("sumoExcludedApps") } }, - ] - - onClosed: helpSheetLoader.active = false - } + model: [ + {type: MZHelpSheet.BlockType.Title, text: MZI18n.HelpSheetsExcludedAppsHeader}, + {type: MZHelpSheet.BlockType.Text, text: MZI18n.HelpSheetsExcludedAppsBody1, margin: MZTheme.theme.helpSheetTitleBodySpacing}, + {type: MZHelpSheet.BlockType.Text, text: MZI18n.HelpSheetsExcludedAppsBody2, margin: MZTheme.theme.helpSheetBodySpacing}, + {type: MZHelpSheet.BlockType.Text, text: MZI18n.HelpSheetsExcludedAppsBody3, margin: MZTheme.theme.helpSheetBodySpacing}, + {type: MZHelpSheet.BlockType.PrimaryButton, text: MZI18n.HelpSheetsExcludedAppsCTA, margin: MZTheme.theme.helpSheetBodyButtonSpacing, action: () => { + close() + getStack().push("qrc:/ui/screens/settings/privacy/ViewPrivacy.qml") + }, objectName: "openPrivacyFeaturesButton"}, + {type: MZHelpSheet.BlockType.LinkButton, text: MZI18n.GlobalLearnMore, margin: MZTheme.theme.helpSheetSecondaryButtonSpacing, action: () => { MZUrlOpener.openUrlLabel("sumoExcludedApps") }, objectName: "learnMoreLink"}, + ] + + onActiveChanged: if (active) item.open() } Component.onCompleted: { @@ -113,5 +111,4 @@ MZViewBase { VPNAppPermissions.requestApplist(); Glean.sample.appPermissionsViewOpened.record(); } - } diff --git a/src/ui/screens/settings/privacy/ViewPrivacy.qml b/src/ui/screens/settings/privacy/ViewPrivacy.qml index e536fa57ae..4ae963890f 100644 --- a/src/ui/screens/settings/privacy/ViewPrivacy.qml +++ b/src/ui/screens/settings/privacy/ViewPrivacy.qml @@ -20,7 +20,9 @@ MZViewBase { Loader { active: MZFeatureList.get("helpSheets").isSupported sourceComponent: MZIconButton { - onClicked: helpSheetLoader.active = true + objectName: "privacyHelpButton" + + onClicked: helpSheet.active = true accessibleName: MZI18n.GetHelpLinkTitle @@ -125,25 +127,20 @@ MZViewBase { onActiveChanged: if (active) { item.open() } } - Loader { - id: helpSheetLoader + MZHelpSheet { + id: helpSheet + objectName: "privacyHelpSheet" - active: false - - onActiveChanged: if (active) item.open() + title: MZI18n.HelpSheetsPrivacyTitle - sourceComponent: MZHelpSheet { - title: MZI18n.HelpSheetsPrivacyTitle + model: [ + {type: MZHelpSheet.BlockType.Title, text: MZI18n.HelpSheetsPrivacyHeader}, + {type: MZHelpSheet.BlockType.Text, text: MZI18n.HelpSheetsPrivacyBody1, margin: MZTheme.theme.helpSheetTitleBodySpacing}, + {type: MZHelpSheet.BlockType.Text, text: MZI18n.HelpSheetsPrivacyBody2, margin: MZTheme.theme.helpSheetBodySpacing}, + {type: MZHelpSheet.BlockType.LinkButton, text: MZI18n.GlobalLearnMore, margin: MZTheme.theme.helpSheetBodyButtonSpacing, action: () => { MZUrlOpener.openUrlLabel("sumoPrivacy") }, objectName: "learnMoreLink"}, + ] - model: [ - {type: MZHelpSheet.BlockType.Title, text: MZI18n.HelpSheetsPrivacyHeader}, - {type: MZHelpSheet.BlockType.Text, text: MZI18n.HelpSheetsPrivacyBody1, margin: 8}, - {type: MZHelpSheet.BlockType.Text, text:MZI18n.HelpSheetsPrivacyBody2, margin: 16}, - {type: MZHelpSheet.BlockType.LinkButton, text: MZI18n.GlobalLearnMore, margin: 16, action: () => { MZUrlOpener.openUrlLabel("sumoPrivacy") } }, - ] - - onClosed: helpSheetLoader.active = false - } + onActiveChanged: if (active) item.open() } } diff --git a/tests/functional/queries.js b/tests/functional/queries.js index 302fec1e08..11adbecd7f 100644 --- a/tests/functional/queries.js +++ b/tests/functional/queries.js @@ -54,6 +54,15 @@ class QmlQueryComposer { return this.prop('busy', false); } + opened() { + return this.prop('opened', true); + } + + closed() { + return this.prop('opened', false); + } + + prop(propName, propValue = undefined) { if (propValue === undefined) { return new QmlQueryComposer(`${this.path}{${propName}}`); @@ -100,6 +109,10 @@ const screenHome = { }, BACK_BUTTON: new QmlQueryComposer('//serverListBackButton'), + HELP_BUTTON: new QmlQueryComposer('//serverHelpButton'), + HELP_SHEET: new QmlQueryComposer('//serverHelpSheet'), + HELP_SHEET_CLOSE_BUTTON: new QmlQueryComposer('//serverHelpSheet-closeButton'), + HELP_SHEET_LEARN_MORE_BUTTON: new QmlQueryComposer('//helpSheetContentLoader/learnMoreLink'), COUNTRY_VIEW: new QmlQueryComposer('//serverCountryView'), ENTRY_BUTTON: new QmlQueryComposer('//buttonSelectEntry'), EXIT_BUTTON: new QmlQueryComposer('//buttonSelectExit'), @@ -256,16 +269,6 @@ const screenDeveloperMenu = { RESET_AND_QUIT_BUTTON: new QmlQueryComposer('//resetAndQuitButton'), }; -const appExclusionsView = { - ADD_APPLICATION_BUTTON: new QmlQueryComposer('//addApplication'), - APP_LIST: new QmlQueryComposer('//appList'), - APP_ROW1: new QmlQueryComposer('//app-0'), - CHECKBOX1: new QmlQueryComposer('//app-0/checkbox'), - CHECKBOX2: new QmlQueryComposer('//app-1/checkbox'), - CLEAR_ALL: new QmlQueryComposer('//clearAll'), - SCREEN: new QmlQueryComposer('//appPermissions') -}; - const screenSettings = { ABOUT_US: new QmlQueryComposer('//settingsAboutUs'), BACK: new QmlQueryComposer('//settings-back'), @@ -286,6 +289,7 @@ const screenSettings = { new QmlQueryComposer('//settingsUserProfile-emailAddress'), privacyView: { + VIEW: new QmlQueryComposer('//privacySettingsView'), BLOCK_ADS: new QmlQueryComposer('//blockAds'), BLOCK_ADS_CHECKBOX: new QmlQueryComposer('//blockAds//checkbox'), BLOCK_TRACKERS: new QmlQueryComposer('//blockTrackers'), @@ -304,10 +308,32 @@ const screenSettings = { MODAL_SECONDARY_BUTTON: new QmlQueryComposer('//privacyOverwritePopupGoBackButton'), - VIEW_PRIVACY_WARNING: new QmlQueryComposer('//viewPrivacyWarning') + VIEW_PRIVACY_WARNING: new QmlQueryComposer('//viewPrivacyWarning'), + + HELP_BUTTON: new QmlQueryComposer('//privacyHelpButton'), + HELP_SHEET: new QmlQueryComposer('//privacyHelpSheet'), + HELP_SHEET_CLOSE_BUTTON: new QmlQueryComposer('//privacyHelpSheet-closeButton'), + HELP_SHEET_LEARN_MORE_BUTTON: new QmlQueryComposer('//helpSheetContentLoader/learnMoreLink'), + }, + + appExclusionsView: { + ADD_APPLICATION_BUTTON: new QmlQueryComposer('//addApplication'), + APP_LIST: new QmlQueryComposer('//appList'), + APP_ROW1: new QmlQueryComposer('//app-0'), + CHECKBOX1: new QmlQueryComposer('//app-0/checkbox'), + CHECKBOX2: new QmlQueryComposer('//app-1/checkbox'), + CLEAR_ALL: new QmlQueryComposer('//clearAll'), + SCREEN: new QmlQueryComposer('//appPermissions'), + + HELP_BUTTON: new QmlQueryComposer('//excludedAppsHelpButton'), + HELP_SHEET: new QmlQueryComposer('//excludedAppsHelpSheet'), + HELP_SHEET_CLOSE_BUTTON: new QmlQueryComposer('//excludedAppsHelpSheet-closeButton'), + HELP_SHEET_LEARN_MORE_BUTTON: new QmlQueryComposer('//helpSheetContentLoader/learnMoreLink'), + HELP_SHEET_OPEN_PRIVACY_FEATURES_BUTTON: new QmlQueryComposer('//helpSheetContentLoader/openPrivacyFeaturesButton'), }, myDevicesView: { + DEVICES_VIEW: new QmlQueryComposer('//devicesSettingsView'), BACK: new QmlQueryComposer('//deviceList-back'), CONFIRM_REMOVAL_BUTTON: new QmlQueryComposer('//confirmRemoveDeviceButton'), DEVICE_LIST: new QmlQueryComposer('//deviceList'), @@ -315,6 +341,10 @@ const screenSettings = { REMOVE_DEVICE_BUTTON: new QmlQueryComposer( '//deviceList/deviceListLayout/device-device_1/swipeActionLoader/swipeActionDelete'), + HELP_BUTTON: new QmlQueryComposer('//devicesHelpButton'), + HELP_SHEET: new QmlQueryComposer('//devicesHelpSheet'), + HELP_SHEET_CLOSE_BUTTON: new QmlQueryComposer('//devicesHelpSheet-closeButton'), + HELP_SHEET_LEARN_MORE_BUTTON: new QmlQueryComposer('//helpSheetContentLoader/learnMoreLink'), }, tipsAndTricksView: { @@ -346,6 +376,11 @@ const screenSettings = { new QmlQueryComposer('//dnsOverwritePopupDiscoverNowButton'), MODAL_SECONDARY_BUTTON: new QmlQueryComposer('//dnsOverwritePopupGoBackButton'), + + HELP_BUTTON: new QmlQueryComposer('//dnsHelpButton'), + HELP_SHEET: new QmlQueryComposer('//dnsHelpSheet'), + HELP_SHEET_CLOSE_BUTTON: new QmlQueryComposer('//dnsHelpSheet-closeButton'), + HELP_SHEET_LEARN_MORE_BUTTON: new QmlQueryComposer('//helpSheetContentLoader/learnMoreLink'), }, languageSettingsView: { @@ -519,7 +554,6 @@ const global = { }; module.exports = { - appExclusionsView, screenHome, screenInitialize, screenPostAuthentication, diff --git a/tests/functional/testAppExclusions.js b/tests/functional/testAppExclusions.js index 3cd677d7c3..5cfc1d58b4 100644 --- a/tests/functional/testAppExclusions.js +++ b/tests/functional/testAppExclusions.js @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ const assert = require('assert'); -const {appExclusionsView, navBar, screenSettings} = require('./queries.js'); +const queries = require('./queries.js'); const vpn = require('./helper.js'); const {appendFile} = require('fs'); @@ -12,10 +12,10 @@ describe('Settings', function() { this.ctx.authenticationNeeded = true; beforeEach(async () => { - await vpn.waitForQueryAndClick(navBar.SETTINGS.visible()); - await vpn.waitForQuery(screenSettings.STACKVIEW.ready()); - await vpn.waitForQueryAndClick(screenSettings.APP_EXCLUSIONS.visible()); - await vpn.waitForQuery(screenSettings.STACKVIEW.ready()); + await vpn.waitForQueryAndClick(queries.navBar.SETTINGS.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); + await vpn.waitForQueryAndClick(queries.screenSettings.APP_EXCLUSIONS.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); }); const getNumDisabledApps = @@ -28,15 +28,15 @@ describe('Settings', function() { async () => { // Clear all button is correctly disabled when there are no disabled apps await vpn.waitForQuery( - appExclusionsView.CLEAR_ALL.visible().prop('enabled', 'false')); - await vpn.waitForQuery(screenSettings.STACKVIEW.ready()); - await vpn.waitForQueryAndClick(appExclusionsView.CHECKBOX1.visible()); - await vpn.waitForQuery(screenSettings.STACKVIEW.ready()); + queries.screenSettings.appExclusionsView.CLEAR_ALL.visible().prop('enabled', 'false')); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); + await vpn.waitForQueryAndClick(queries.screenSettings.appExclusionsView.CHECKBOX1.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); // Clear all button is enabled when disabledAppsList.length > 0 await vpn.waitForQuery( - appExclusionsView.CLEAR_ALL.visible().prop('enabled', 'true')); - await vpn.waitForQueryAndClick(appExclusionsView.CHECKBOX1); + queries.screenSettings.appExclusionsView.CLEAR_ALL.visible().prop('enabled', 'true')); + await vpn.waitForQueryAndClick(queries.screenSettings.appExclusionsView.CHECKBOX1); assert(await getNumDisabledApps() == '0'); }); @@ -46,14 +46,14 @@ describe('Settings', function() { return; } - await vpn.waitForQueryAndClick(appExclusionsView.CHECKBOX1.visible()); - await vpn.waitForQueryAndClick(appExclusionsView.CHECKBOX2.visible()); - await vpn.waitForQuery(screenSettings.STACKVIEW.ready()); + await vpn.waitForQueryAndClick(queries.screenSettings.appExclusionsView.CHECKBOX1.visible()); + await vpn.waitForQueryAndClick(queries.screenSettings.appExclusionsView.CHECKBOX2.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); assert(await getNumDisabledApps() == '2'); - await vpn.waitForQueryAndClick(appExclusionsView.CLEAR_ALL.visible()); - await vpn.waitForQuery(screenSettings.STACKVIEW.ready()); + await vpn.waitForQueryAndClick(queries.screenSettings.appExclusionsView.CLEAR_ALL.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); assert(await getNumDisabledApps() == '0'); // Check that we collect telemetry @@ -64,21 +64,51 @@ describe('Settings', function() { }); it('Excluded apps are at the top of the list on initial load', async () => { - await vpn.waitForQueryAndClick(appExclusionsView.CHECKBOX2); - await vpn.waitForQueryAndClick(screenSettings.BACK.visible()); - await vpn.waitForQuery(screenSettings.STACKVIEW.ready()); + await vpn.waitForQueryAndClick(queries.screenSettings.appExclusionsView.CHECKBOX2); + await vpn.waitForQueryAndClick(queries.screenSettings.BACK.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); - await vpn.waitForQueryAndClick(screenSettings.APP_EXCLUSIONS.visible()); - await vpn.waitForQuery(screenSettings.STACKVIEW.ready()); + await vpn.waitForQueryAndClick(queries.screenSettings.APP_EXCLUSIONS.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); - await vpn.waitForQuery(appExclusionsView.APP_ROW1.visible().prop( + await vpn.waitForQuery(queries.screenSettings.appExclusionsView.APP_ROW1.visible().prop( 'appIdForFunctionalTests', 'com.example.two')); }); it('Back button works', async () => { - await vpn.waitForQueryAndClick(screenSettings.BACK.visible()); - await vpn.waitForQuery(screenSettings.STACKVIEW.ready()); - await vpn.waitForQueryAndClick(screenSettings.APP_EXCLUSIONS.visible()); + await vpn.waitForQueryAndClick(queries.screenSettings.BACK.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); + await vpn.waitForQueryAndClick(queries.screenSettings.APP_EXCLUSIONS.visible()); + }); + + it('Checking the excluded apps help sheet', async () => { + if (!(await vpn.isFeatureFlippedOn('helpSheets'))) { + await vpn.flipFeatureOn('helpSheets'); + } + + //Test the "Open privacy features" button + await vpn.waitForQueryAndClick(queries.screenSettings.appExclusionsView.HELP_BUTTON.visible()); + await vpn.waitForQuery(queries.screenSettings.appExclusionsView.HELP_SHEET.visible()); + await vpn.waitForQuery(queries.screenSettings.appExclusionsView.HELP_SHEET.opened()); + await vpn.waitForQueryAndClick(queries.screenSettings.appExclusionsView.HELP_SHEET_OPEN_PRIVACY_FEATURES_BUTTON.visible()); + await vpn.waitForQuery(queries.screenSettings.appExclusionsView.HELP_SHEET.closed()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); + await vpn.waitForQuery(queries.screenSettings.privacyView.VIEW.visible()); + + //Go back to the app exclusions view + await vpn.waitForQueryAndClick(queries.screenSettings.BACK.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); + + //Test the "Learn more" link + await vpn.waitForQueryAndClick(queries.screenSettings.appExclusionsView.HELP_BUTTON.visible()); + await vpn.waitForQuery(queries.screenSettings.appExclusionsView.HELP_SHEET.visible()); + await vpn.waitForQuery(queries.screenSettings.appExclusionsView.HELP_SHEET.opened()); + await vpn.waitForQueryAndClick(queries.screenSettings.appExclusionsView.HELP_SHEET_LEARN_MORE_BUTTON.visible()); + await vpn.waitForCondition(async () => { + const url = await vpn.getLastUrl(); + return url === 'https://support.mozilla.org/kb/split-tunneling-app-permissions'; + }); + await vpn.waitForQueryAndClick(queries.screenSettings.appExclusionsView.HELP_SHEET_CLOSE_BUTTON.visible()); }); // Dummy VPN does not have the Add Application button so we cannot currently test this. @@ -98,10 +128,10 @@ describe('Settings', function() { // This test cannot run in wasm return; } - await vpn.waitForQueryAndClick(navBar.SETTINGS.visible()); - await vpn.waitForQuery(screenSettings.STACKVIEW.ready()); - await vpn.waitForQueryAndClick(screenSettings.APP_EXCLUSIONS.visible()); - await vpn.waitForQuery(screenSettings.STACKVIEW.ready()); + await vpn.waitForQueryAndClick(queries.navBar.SETTINGS.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); + await vpn.waitForQueryAndClick(queries.screenSettings.APP_EXCLUSIONS.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); // Check that we collect telemetry const events = await vpn.gleanTestGetValue("interaction", "appExclusionsSelected", "main"); diff --git a/tests/functional/testDevices.js b/tests/functional/testDevices.js index 1c1f05ca8b..b07c94d9eb 100644 --- a/tests/functional/testDevices.js +++ b/tests/functional/testDevices.js @@ -7,6 +7,34 @@ const vpn = require('./helper.js'); const guardianEndpoints = require('./servers/guardian_endpoints.js') describe('Devices', function() { + describe('My devices tests', function() { + this.ctx.authenticationNeeded = true; + + beforeEach(async () => { + await vpn.waitForQueryAndClick(queries.navBar.SETTINGS.visible()); + await vpn.waitForQueryAndClick(queries.screenSettings.MY_DEVICES.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); + await vpn.waitForQuery(queries.screenSettings.myDevicesView.DEVICES_VIEW.visible()); + }); + + it('Checking the devices help sheet', async () => { + if (!(await vpn.isFeatureFlippedOn('helpSheets'))) { + await vpn.flipFeatureOn('helpSheets'); + } + + await vpn.waitForQueryAndClick(queries.screenSettings.myDevicesView.HELP_BUTTON.visible()); + await vpn.waitForQuery(queries.screenSettings.myDevicesView.HELP_SHEET.visible()); + await vpn.waitForQuery(queries.screenSettings.myDevicesView.HELP_SHEET.opened()); + await vpn.waitForQueryAndClick(queries.screenSettings.myDevicesView.HELP_SHEET_LEARN_MORE_BUTTON.visible()); + await vpn.waitForCondition(async () => { + const url = await vpn.getLastUrl(); + return url === 'https://support.mozilla.org/kb/how-add-devices-your-mozilla-vpn-subscription'; + }); + await vpn.waitForQueryAndClick(queries.screenSettings.myDevicesView.HELP_SHEET_CLOSE_BUTTON.visible()); + await vpn.waitForQuery(queries.screenSettings.myDevicesView.HELP_SHEET.closed()); + }); + }); + describe('Device limit', function() { this.ctx.authenticationNeeded = true; diff --git a/tests/functional/testServers.js b/tests/functional/testServers.js index 00697184e8..81ef616548 100644 --- a/tests/functional/testServers.js +++ b/tests/functional/testServers.js @@ -267,6 +267,23 @@ describe('Server list', function() { queries.screenHome.serverListView.SEARCH_BAR_ERROR.hidden()); }); + it('check the help sheet', async () => { + if (!(await vpn.isFeatureFlippedOn('helpSheets'))) { + await vpn.flipFeatureOn('helpSheets'); + } + + await vpn.waitForQueryAndClick(queries.screenHome.serverListView.HELP_BUTTON.visible()); + await vpn.waitForQuery(queries.screenHome.serverListView.HELP_SHEET.visible()); + await vpn.waitForQuery(queries.screenHome.serverListView.HELP_SHEET.opened()); + await vpn.waitForQueryAndClick(queries.screenHome.serverListView.HELP_SHEET_LEARN_MORE_BUTTON.visible()); + await vpn.waitForCondition(async () => { + const url = await vpn.getLastUrl(); + return url === 'https://support.mozilla.org/kb/multi-hop-encrypt-your-data-twice-enhanced-security'; + }); + await vpn.waitForQueryAndClick(queries.screenHome.serverListView.HELP_SHEET_CLOSE_BUTTON.visible()); + await vpn.waitForQuery(queries.screenHome.serverListView.HELP_SHEET.closed()); + }); + // TODO: server list disabled when reached the device limit }); diff --git a/tests/functional/testSettings.js b/tests/functional/testSettings.js index 4e71fb92b9..73adf0506f 100644 --- a/tests/functional/testSettings.js +++ b/tests/functional/testSettings.js @@ -103,463 +103,495 @@ describe('Settings', function() { await vpn.waitForQuery(queries.screenSettings.USER_PROFILE.visible()); }); - it('Checking the privacy settings', async () => { - await vpn.waitForQuery(queries.screenSettings.PRIVACY.visible()); - - await vpn.scrollToQuery( - queries.screenSettings.SCREEN, queries.screenSettings.PRIVACY); - - await vpn.clickOnQuery(queries.screenSettings.PRIVACY.visible()); - await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); - - // Checking that the `These changes may affect...` warning is visible - await vpn.waitForQuery( - queries.screenSettings.privacyView.INFORMATION_CARD.visible()); - - // Checking if the checkboxes are correctly set based on the settings prop - await vpn.setSetting('dnsProviderFlags', 0); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_ADS.visible().prop( - 'isChecked', false)); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_TRACKERS.visible().prop( - 'isChecked', false)); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_MALWARE.visible().prop( - 'isChecked', false)); - - await vpn.setSetting('dnsProviderFlags', 2); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_ADS.visible().prop( - 'isChecked', true)); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_TRACKERS.visible().prop( - 'isChecked', false)); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_MALWARE.visible().prop( - 'isChecked', false)); - - await vpn.setSetting('dnsProviderFlags', 4); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_ADS.visible().prop( - 'isChecked', false)); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_TRACKERS.visible().prop( - 'isChecked', true)); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_MALWARE.visible().prop( - 'isChecked', false)); - - await vpn.setSetting('dnsProviderFlags', 6); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_ADS.visible().prop( - 'isChecked', true)); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_TRACKERS.visible().prop( - 'isChecked', true)); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_MALWARE.visible().prop( - 'isChecked', false)); - - await vpn.setSetting('dnsProviderFlags', 8); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_ADS.visible().prop( - 'isChecked', false)); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_TRACKERS.visible().prop( - 'isChecked', false)); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_MALWARE.visible().prop( - 'isChecked', true)); - - await vpn.setSetting('dnsProviderFlags', 10); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_ADS.visible().prop( - 'isChecked', true)); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_TRACKERS.visible().prop( - 'isChecked', false)); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_MALWARE.visible().prop( - 'isChecked', true)); - - await vpn.setSetting('dnsProviderFlags', 12); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_ADS.visible().prop( - 'isChecked', false)); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_TRACKERS.visible().prop( - 'isChecked', true)); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_MALWARE.visible().prop( - 'isChecked', true)); - - await vpn.setSetting('dnsProviderFlags', 14); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_ADS.visible().prop( - 'isChecked', true)); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_TRACKERS.visible().prop( - 'isChecked', true)); - await vpn.waitForQuery( - queries.screenSettings.privacyView.BLOCK_MALWARE.visible().prop( - 'isChecked', true)); - - // Tests the clicks - await vpn.setSetting('dnsProviderFlags', 0); - await vpn.waitForQueryAndClick( - queries.screenSettings.privacyView.BLOCK_ADS_CHECKBOX.visible()); - assert.equal(await vpn.getSetting('dnsProviderFlags'), 2); - - await vpn.setSetting('dnsProviderFlags', 0); - await vpn.waitForQueryAndClick( - queries.screenSettings.privacyView.BLOCK_TRACKERS_CHECKBOX.visible()); - assert.equal(await vpn.getSetting('dnsProviderFlags'), 4); - - await vpn.setSetting('dnsProviderFlags', 0); - await vpn.waitForQueryAndClick( - queries.screenSettings.privacyView.BLOCK_MALWARE_CHECKBOX.visible()); - assert.equal(await vpn.getSetting('dnsProviderFlags'), 8); - - // Let's test the modal - await vpn.setSetting('dnsProviderFlags', 1); - await vpn.waitForQueryAndClick( - queries.screenSettings.privacyView.BLOCK_ADS_CHECKBOX.visible()); - assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); - await vpn.waitForQueryAndClick( - queries.screenSettings.privacyView.MODAL_SECONDARY_BUTTON.visible()); - await vpn.waitForQuery( - queries.screenSettings.privacyView.MODAL_LOADER.prop('active', false)); - assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); - await vpn.waitForQueryAndClick( - queries.screenSettings.privacyView.BLOCK_ADS_CHECKBOX.visible()); - assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); - await vpn.waitForQueryAndClick( - queries.screenSettings.privacyView.MODAL_CLOSE_BUTTON.visible()); - await vpn.waitForQuery( - queries.screenSettings.privacyView.MODAL_LOADER.prop('active', false)); - assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); - await vpn.waitForQueryAndClick( - queries.screenSettings.privacyView.BLOCK_ADS_CHECKBOX.visible()); - assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); - await vpn.waitForQueryAndClick( - queries.screenSettings.privacyView.MODAL_PRIMARY_BUTTON.visible()); - await vpn.waitForQuery( - queries.screenSettings.privacyView.MODAL_LOADER.prop('active', false)); - assert.equal(await vpn.getSetting('dnsProviderFlags'), 2); - - await vpn.setSetting('dnsProviderFlags', 1); - await vpn.waitForQueryAndClick( - queries.screenSettings.privacyView.BLOCK_TRACKERS_CHECKBOX.visible()); - assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); - await vpn.waitForQueryAndClick( - queries.screenSettings.privacyView.MODAL_SECONDARY_BUTTON.visible()); - await vpn.waitForQuery( - queries.screenSettings.privacyView.MODAL_LOADER.prop('active', false)); - assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); - await vpn.waitForQueryAndClick( - queries.screenSettings.privacyView.BLOCK_TRACKERS_CHECKBOX.visible()); - assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); - await vpn.waitForQueryAndClick( - queries.screenSettings.privacyView.MODAL_CLOSE_BUTTON.visible()); - await vpn.waitForQuery( - queries.screenSettings.privacyView.MODAL_LOADER.prop('active', false)); - assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); - await vpn.waitForQueryAndClick( - queries.screenSettings.privacyView.BLOCK_TRACKERS_CHECKBOX.visible()); - assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); - await vpn.waitForQueryAndClick( - queries.screenSettings.privacyView.MODAL_PRIMARY_BUTTON.visible()); - await vpn.waitForQuery( - queries.screenSettings.privacyView.MODAL_LOADER.prop('active', false)); - assert.equal(await vpn.getSetting('dnsProviderFlags'), 4); - - await vpn.setSetting('dnsProviderFlags', 1); - await vpn.waitForQueryAndClick( - queries.screenSettings.privacyView.BLOCK_MALWARE_CHECKBOX.visible()); - assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); - await vpn.waitForQueryAndClick( - queries.screenSettings.privacyView.MODAL_SECONDARY_BUTTON.visible()); - await vpn.waitForQuery( - queries.screenSettings.privacyView.MODAL_LOADER.prop('active', false)); - assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); - await vpn.waitForQueryAndClick( - queries.screenSettings.privacyView.BLOCK_MALWARE_CHECKBOX.visible()); - assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); - await vpn.waitForQueryAndClick( - queries.screenSettings.privacyView.MODAL_CLOSE_BUTTON.visible()); - await vpn.waitForQuery( - queries.screenSettings.privacyView.MODAL_LOADER.prop('active', false)); - assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); - await vpn.waitForQueryAndClick( - queries.screenSettings.privacyView.BLOCK_MALWARE_CHECKBOX.visible()); - assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); - await vpn.waitForQueryAndClick( - queries.screenSettings.privacyView.MODAL_PRIMARY_BUTTON.visible()); - await vpn.waitForQuery( - queries.screenSettings.privacyView.MODAL_LOADER.prop('active', false)); - assert.equal(await vpn.getSetting('dnsProviderFlags'), 8); - - // Let's go back - await vpn.waitForQueryAndClick(queries.screenSettings.BACK.visible()); - await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); - - await vpn.waitForQuery(queries.screenSettings.USER_PROFILE.visible()); - - // Reset - await vpn.setSetting('dnsProviderFlags', 0); + describe('Privacy settings tests', function () { + beforeEach(async () => { + await vpn.waitForQuery(queries.screenSettings.PRIVACY.visible()); + + await vpn.scrollToQuery( + queries.screenSettings.SCREEN, queries.screenSettings.PRIVACY); + + await vpn.clickOnQuery(queries.screenSettings.PRIVACY.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); }); - - it('Checking the DNS settings', async () => { - await vpn.setSetting('userDNS', ''); - await vpn.setSetting('dnsProviderFlags', 0); - - await vpn.waitForQueryAndClick( - queries.screenSettings.APP_PREFERENCES.visible()); - await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); - - await vpn.waitForQueryAndClick( - queries.screenSettings.appPreferencesView.DNS_SETTINGS.visible()); - await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); - - // Checking if the checkboxes are correctly set based on the settings prop - await vpn.waitForQuery( - queries.screenSettings.appPreferencesView.dnsSettingsView.STANDARD_DNS - .visible() - .prop('checked', true)); - await vpn.waitForQuery( - queries.screenSettings.appPreferencesView.dnsSettingsView.CUSTOM_DNS - .visible() - .prop('checked', false)); - - await vpn.waitForQueryAndClick(queries.navBar.HOME.visible()); - await vpn.waitForQuery(queries.global.SCREEN_LOADER.ready()); - - await vpn.setSetting('dnsProviderFlags', 1); - - await vpn.waitForQueryAndClick(queries.navBar.SETTINGS.visible()); - await vpn.waitForQuery(queries.global.SCREEN_LOADER.ready()); - - await vpn.waitForQuery( - queries.screenSettings.appPreferencesView.dnsSettingsView.STANDARD_DNS - .visible() - .prop('checked', false)); - await vpn.waitForQuery( - queries.screenSettings.appPreferencesView.dnsSettingsView.CUSTOM_DNS - .visible() - .prop('checked', true)); - await vpn.waitForQuery(queries.screenSettings.appPreferencesView - .dnsSettingsView.CUSTOM_DNS_INPUT.visible() - .prop('hasError', false)); - await vpn.setQueryProperty( - queries.screenSettings.appPreferencesView.dnsSettingsView - .CUSTOM_DNS_INPUT.visible(), - 'text', 'wow'); - await vpn.waitForQuery(queries.screenSettings.appPreferencesView - .dnsSettingsView.CUSTOM_DNS_INPUT.visible() - .prop('hasError', true)); - await vpn.setQueryProperty( - queries.screenSettings.appPreferencesView.dnsSettingsView - .CUSTOM_DNS_INPUT.visible(), - 'text', '1.2.3.4'); - await vpn.waitForQuery(queries.screenSettings.appPreferencesView - .dnsSettingsView.CUSTOM_DNS_INPUT.visible() - .prop('hasError', false)); - - // Check the warning message - assert.equal( - await vpn.getQueryProperty( - queries.screenSettings.appPreferencesView.dnsSettingsView - .INFORMATION_CARD_LOADER, - 'active'), 'false'); - - // Check the click - await vpn.waitForQueryAndClick( - queries.screenSettings.appPreferencesView.dnsSettingsView.STANDARD_DNS - .visible() - .prop('checked', false)); - - await vpn.waitForQueryAndClick(queries.navBar.HOME.visible()); - await vpn.waitForQuery(queries.global.SCREEN_LOADER.ready()); - - assert.equal(await vpn.getSetting('dnsProviderFlags'), 0); - - await vpn.waitForQueryAndClick(queries.navBar.SETTINGS.visible()); - await vpn.waitForQuery(queries.global.SCREEN_LOADER.ready()); - - await vpn.waitForQueryAndClick( - queries.screenSettings.appPreferencesView.dnsSettingsView.CUSTOM_DNS - .visible() - .prop('checked', false)); - - await vpn.waitForQueryAndClick(queries.navBar.HOME.visible()); - await vpn.waitForQuery(queries.global.SCREEN_LOADER.ready()); - - assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); - - // Check the modal - await vpn.setSetting('dnsProviderFlags', 2); - - await vpn.waitForQueryAndClick(queries.navBar.SETTINGS.visible()); - await vpn.waitForQuery(queries.global.SCREEN_LOADER.ready()); - - await vpn.waitForQuery( - queries.screenSettings.appPreferencesView.dnsSettingsView.STANDARD_DNS - .visible() - .prop('checked', true)); - - await vpn.waitForQueryAndClick( - queries.screenSettings.appPreferencesView.dnsSettingsView.CUSTOM_DNS - .visible() - .prop('checked', false)); - - await vpn.waitForQueryAndClick( - queries.screenSettings.appPreferencesView.dnsSettingsView - .MODAL_SECONDARY_BUTTON.visible()); - await vpn.waitForQuery( - queries.screenSettings.appPreferencesView.dnsSettingsView - .MODAL_LOADER.prop('active', false)); - - await vpn.waitForQueryAndClick(queries.screenSettings.appPreferencesView - .dnsSettingsView.CUSTOM_DNS.visible()); - - await vpn.waitForQueryAndClick( - queries.screenSettings.appPreferencesView.dnsSettingsView - .MODAL_CLOSE_BUTTON.visible()); - await vpn.waitForQuery( - queries.screenSettings.appPreferencesView.dnsSettingsView - .MODAL_LOADER.prop('active', false)); - - await vpn.waitForQueryAndClick(queries.screenSettings.appPreferencesView - .dnsSettingsView.CUSTOM_DNS.visible()); - - await vpn.waitForQueryAndClick( - queries.screenSettings.appPreferencesView.dnsSettingsView - .MODAL_PRIMARY_BUTTON.visible()); - await vpn.waitForQuery( - queries.screenSettings.appPreferencesView.dnsSettingsView - .MODAL_LOADER.prop('active', false)); - - await vpn.setQueryProperty( - queries.screenSettings.appPreferencesView.dnsSettingsView - .CUSTOM_DNS_INPUT.visible(), - 'text', '1.2.3.4'); - - await vpn.waitForQueryAndClick(queries.screenSettings.BACK.visible()); - await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); - - assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); - - await vpn.waitForQueryAndClick(queries.screenSettings.BACK.visible()); - await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); - - await vpn.waitForQuery(queries.screenSettings.USER_PROFILE.visible()); + + it('Checking the privacy settings', async () => { + // Checking that the `These changes may affect...` warning is visible + await vpn.waitForQuery( + queries.screenSettings.privacyView.INFORMATION_CARD.visible()); + + // Checking if the checkboxes are correctly set based on the settings prop + await vpn.setSetting('dnsProviderFlags', 0); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_ADS.visible().prop( + 'isChecked', false)); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_TRACKERS.visible().prop( + 'isChecked', false)); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_MALWARE.visible().prop( + 'isChecked', false)); + + await vpn.setSetting('dnsProviderFlags', 2); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_ADS.visible().prop( + 'isChecked', true)); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_TRACKERS.visible().prop( + 'isChecked', false)); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_MALWARE.visible().prop( + 'isChecked', false)); + + await vpn.setSetting('dnsProviderFlags', 4); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_ADS.visible().prop( + 'isChecked', false)); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_TRACKERS.visible().prop( + 'isChecked', true)); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_MALWARE.visible().prop( + 'isChecked', false)); + + await vpn.setSetting('dnsProviderFlags', 6); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_ADS.visible().prop( + 'isChecked', true)); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_TRACKERS.visible().prop( + 'isChecked', true)); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_MALWARE.visible().prop( + 'isChecked', false)); + + await vpn.setSetting('dnsProviderFlags', 8); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_ADS.visible().prop( + 'isChecked', false)); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_TRACKERS.visible().prop( + 'isChecked', false)); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_MALWARE.visible().prop( + 'isChecked', true)); + + await vpn.setSetting('dnsProviderFlags', 10); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_ADS.visible().prop( + 'isChecked', true)); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_TRACKERS.visible().prop( + 'isChecked', false)); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_MALWARE.visible().prop( + 'isChecked', true)); + + await vpn.setSetting('dnsProviderFlags', 12); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_ADS.visible().prop( + 'isChecked', false)); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_TRACKERS.visible().prop( + 'isChecked', true)); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_MALWARE.visible().prop( + 'isChecked', true)); + + await vpn.setSetting('dnsProviderFlags', 14); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_ADS.visible().prop( + 'isChecked', true)); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_TRACKERS.visible().prop( + 'isChecked', true)); + await vpn.waitForQuery( + queries.screenSettings.privacyView.BLOCK_MALWARE.visible().prop( + 'isChecked', true)); + + // Tests the clicks + await vpn.setSetting('dnsProviderFlags', 0); + await vpn.waitForQueryAndClick( + queries.screenSettings.privacyView.BLOCK_ADS_CHECKBOX.visible()); + assert.equal(await vpn.getSetting('dnsProviderFlags'), 2); + + await vpn.setSetting('dnsProviderFlags', 0); + await vpn.waitForQueryAndClick( + queries.screenSettings.privacyView.BLOCK_TRACKERS_CHECKBOX.visible()); + assert.equal(await vpn.getSetting('dnsProviderFlags'), 4); + + await vpn.setSetting('dnsProviderFlags', 0); + await vpn.waitForQueryAndClick( + queries.screenSettings.privacyView.BLOCK_MALWARE_CHECKBOX.visible()); + assert.equal(await vpn.getSetting('dnsProviderFlags'), 8); + + // Let's test the modal + await vpn.setSetting('dnsProviderFlags', 1); + await vpn.waitForQueryAndClick( + queries.screenSettings.privacyView.BLOCK_ADS_CHECKBOX.visible()); + assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); + await vpn.waitForQueryAndClick( + queries.screenSettings.privacyView.MODAL_SECONDARY_BUTTON.visible()); + await vpn.waitForQuery( + queries.screenSettings.privacyView.MODAL_LOADER.prop('active', false)); + assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); + await vpn.waitForQueryAndClick( + queries.screenSettings.privacyView.BLOCK_ADS_CHECKBOX.visible()); + assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); + await vpn.waitForQueryAndClick( + queries.screenSettings.privacyView.MODAL_CLOSE_BUTTON.visible()); + await vpn.waitForQuery( + queries.screenSettings.privacyView.MODAL_LOADER.prop('active', false)); + assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); + await vpn.waitForQueryAndClick( + queries.screenSettings.privacyView.BLOCK_ADS_CHECKBOX.visible()); + assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); + await vpn.waitForQueryAndClick( + queries.screenSettings.privacyView.MODAL_PRIMARY_BUTTON.visible()); + await vpn.waitForQuery( + queries.screenSettings.privacyView.MODAL_LOADER.prop('active', false)); + assert.equal(await vpn.getSetting('dnsProviderFlags'), 2); + + await vpn.setSetting('dnsProviderFlags', 1); + await vpn.waitForQueryAndClick( + queries.screenSettings.privacyView.BLOCK_TRACKERS_CHECKBOX.visible()); + assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); + await vpn.waitForQueryAndClick( + queries.screenSettings.privacyView.MODAL_SECONDARY_BUTTON.visible()); + await vpn.waitForQuery( + queries.screenSettings.privacyView.MODAL_LOADER.prop('active', false)); + assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); + await vpn.waitForQueryAndClick( + queries.screenSettings.privacyView.BLOCK_TRACKERS_CHECKBOX.visible()); + assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); + await vpn.waitForQueryAndClick( + queries.screenSettings.privacyView.MODAL_CLOSE_BUTTON.visible()); + await vpn.waitForQuery( + queries.screenSettings.privacyView.MODAL_LOADER.prop('active', false)); + assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); + await vpn.waitForQueryAndClick( + queries.screenSettings.privacyView.BLOCK_TRACKERS_CHECKBOX.visible()); + assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); + await vpn.waitForQueryAndClick( + queries.screenSettings.privacyView.MODAL_PRIMARY_BUTTON.visible()); + await vpn.waitForQuery( + queries.screenSettings.privacyView.MODAL_LOADER.prop('active', false)); + assert.equal(await vpn.getSetting('dnsProviderFlags'), 4); + + await vpn.setSetting('dnsProviderFlags', 1); + await vpn.waitForQueryAndClick( + queries.screenSettings.privacyView.BLOCK_MALWARE_CHECKBOX.visible()); + assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); + await vpn.waitForQueryAndClick( + queries.screenSettings.privacyView.MODAL_SECONDARY_BUTTON.visible()); + await vpn.waitForQuery( + queries.screenSettings.privacyView.MODAL_LOADER.prop('active', false)); + assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); + await vpn.waitForQueryAndClick( + queries.screenSettings.privacyView.BLOCK_MALWARE_CHECKBOX.visible()); + assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); + await vpn.waitForQueryAndClick( + queries.screenSettings.privacyView.MODAL_CLOSE_BUTTON.visible()); + await vpn.waitForQuery( + queries.screenSettings.privacyView.MODAL_LOADER.prop('active', false)); + assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); + await vpn.waitForQueryAndClick( + queries.screenSettings.privacyView.BLOCK_MALWARE_CHECKBOX.visible()); + assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); + await vpn.waitForQueryAndClick( + queries.screenSettings.privacyView.MODAL_PRIMARY_BUTTON.visible()); + await vpn.waitForQuery( + queries.screenSettings.privacyView.MODAL_LOADER.prop('active', false)); + assert.equal(await vpn.getSetting('dnsProviderFlags'), 8); + + // Let's go back + await vpn.waitForQueryAndClick(queries.screenSettings.BACK.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); + + await vpn.waitForQuery(queries.screenSettings.USER_PROFILE.visible()); + + // Reset + await vpn.setSetting('dnsProviderFlags', 0); + }); + + it('Checking the privacy help sheet', async () => { + if (!(await vpn.isFeatureFlippedOn('helpSheets'))) { + await vpn.flipFeatureOn('helpSheets'); + } + + await vpn.waitForQueryAndClick(queries.screenSettings.privacyView.HELP_BUTTON.visible()); + await vpn.waitForQuery(queries.screenSettings.privacyView.HELP_SHEET.visible()); + await vpn.waitForQuery(queries.screenSettings.privacyView.HELP_SHEET.opened()); + await vpn.waitForQueryAndClick(queries.screenSettings.privacyView.HELP_SHEET_LEARN_MORE_BUTTON.visible()); + await vpn.waitForCondition(async () => { + const url = await vpn.getLastUrl(); + return url === 'https://support.mozilla.org/kb/how-do-i-change-my-privacy-features'; + }); + await vpn.waitForQueryAndClick(queries.screenSettings.privacyView.HELP_SHEET_CLOSE_BUTTON.visible()); + await vpn.waitForQuery(queries.screenSettings.privacyView.HELP_SHEET.closed()); + }); }); - it('Checking the DNS settings reset', async () => { - await vpn.setSetting('dnsProviderFlags', 0); - await vpn.setSetting('userDNS', ''); - - await vpn.waitForQueryAndClick( - queries.screenSettings.APP_PREFERENCES.visible()); - await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); - - await vpn.waitForQueryAndClick( - queries.screenSettings.appPreferencesView.DNS_SETTINGS.visible()); - await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); - - // Checking if the checkboxes are correctly set based on the settings prop - await vpn.waitForQuery( - queries.screenSettings.appPreferencesView.dnsSettingsView.STANDARD_DNS - .visible() - .prop('checked', true)); - await vpn.waitForQuery( - queries.screenSettings.appPreferencesView.dnsSettingsView.CUSTOM_DNS - .visible() - .prop('checked', false)); - - // Click on "Custom DNS" but leaving the input field empty. - await vpn.waitForQueryAndClick( - queries.screenSettings.appPreferencesView.dnsSettingsView.CUSTOM_DNS - .visible() - .prop('checked', false)); - - await vpn.setQueryProperty( - queries.screenSettings.appPreferencesView.dnsSettingsView - .CUSTOM_DNS_INPUT.visible(), - 'text', ''); - - // Going back... - await vpn.waitForQueryAndClick(queries.screenSettings.BACK.visible()); - await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); - - // .. the DNS setting is reset to the default value. - assert.equal(await vpn.getSetting('dnsProviderFlags'), 0); - - // Same test as before... - await vpn.waitForQueryAndClick( - queries.screenSettings.appPreferencesView.DNS_SETTINGS.visible()); - await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); - - await vpn.waitForQuery( - queries.screenSettings.appPreferencesView.dnsSettingsView.STANDARD_DNS - .visible() - .prop('checked', true)); - await vpn.waitForQuery( - queries.screenSettings.appPreferencesView.dnsSettingsView.CUSTOM_DNS - .visible() - .prop('checked', false)); - - await vpn.waitForQueryAndClick( - queries.screenSettings.appPreferencesView.dnsSettingsView.CUSTOM_DNS - .visible() - .prop('checked', false)); - - // But with a valid DNS value... - await vpn.setQueryProperty( - queries.screenSettings.appPreferencesView.dnsSettingsView - .CUSTOM_DNS_INPUT.visible(), - 'text', '1.2.3.4'); - - await vpn.waitForQueryAndClick(queries.screenSettings.BACK.visible()); - await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); - - // We keep the custom DNS. - assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); - - // Write something invalid... - await vpn.waitForQueryAndClick( - queries.screenSettings.appPreferencesView.DNS_SETTINGS.visible()); - await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); - - await vpn.waitForQuery( - queries.screenSettings.appPreferencesView.dnsSettingsView.STANDARD_DNS - .visible() - .prop('checked', false)); - await vpn.waitForQuery( - queries.screenSettings.appPreferencesView.dnsSettingsView.CUSTOM_DNS - .visible() - .prop('checked', true)); - - assert.equal( - await vpn.getQueryProperty( - queries.screenSettings.appPreferencesView.dnsSettingsView - .CUSTOM_DNS_INPUT.visible(), - 'text'), - '1.2.3.4'); - - await vpn.setQueryProperty( - queries.screenSettings.appPreferencesView.dnsSettingsView - .CUSTOM_DNS_INPUT.visible(), - 'text', '1.2.3.4aabbcc'); + describe('DNS settings tests', function () { + beforeEach(async () => { + await vpn.setSetting('userDNS', ''); + await vpn.setSetting('dnsProviderFlags', 0); + + await vpn.waitForQueryAndClick( + queries.screenSettings.APP_PREFERENCES.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); + + await vpn.waitForQueryAndClick( + queries.screenSettings.appPreferencesView.DNS_SETTINGS.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); + }); - await vpn.waitForQueryAndClick(queries.screenSettings.BACK.visible()); - await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); + it('Checking the DNS settings', async () => { + // Checking if the checkboxes are correctly set based on the settings prop + await vpn.waitForQuery( + queries.screenSettings.appPreferencesView.dnsSettingsView.STANDARD_DNS + .visible() + .prop('checked', true)); + await vpn.waitForQuery( + queries.screenSettings.appPreferencesView.dnsSettingsView.CUSTOM_DNS + .visible() + .prop('checked', false)); + + await vpn.waitForQueryAndClick(queries.navBar.HOME.visible()); + await vpn.waitForQuery(queries.global.SCREEN_LOADER.ready()); + + await vpn.setSetting('dnsProviderFlags', 1); + + await vpn.waitForQueryAndClick(queries.navBar.SETTINGS.visible()); + await vpn.waitForQuery(queries.global.SCREEN_LOADER.ready()); + + await vpn.waitForQuery( + queries.screenSettings.appPreferencesView.dnsSettingsView.STANDARD_DNS + .visible() + .prop('checked', false)); + await vpn.waitForQuery( + queries.screenSettings.appPreferencesView.dnsSettingsView.CUSTOM_DNS + .visible() + .prop('checked', true)); + await vpn.waitForQuery(queries.screenSettings.appPreferencesView + .dnsSettingsView.CUSTOM_DNS_INPUT.visible() + .prop('hasError', false)); + await vpn.setQueryProperty( + queries.screenSettings.appPreferencesView.dnsSettingsView + .CUSTOM_DNS_INPUT.visible(), + 'text', 'wow'); + await vpn.waitForQuery(queries.screenSettings.appPreferencesView + .dnsSettingsView.CUSTOM_DNS_INPUT.visible() + .prop('hasError', true)); + await vpn.setQueryProperty( + queries.screenSettings.appPreferencesView.dnsSettingsView + .CUSTOM_DNS_INPUT.visible(), + 'text', '1.2.3.4'); + await vpn.waitForQuery(queries.screenSettings.appPreferencesView + .dnsSettingsView.CUSTOM_DNS_INPUT.visible() + .prop('hasError', false)); + + // Check the warning message + assert.equal( + await vpn.getQueryProperty( + queries.screenSettings.appPreferencesView.dnsSettingsView + .INFORMATION_CARD_LOADER, + 'active'), 'false'); + + // Check the click + await vpn.waitForQueryAndClick( + queries.screenSettings.appPreferencesView.dnsSettingsView.STANDARD_DNS + .visible() + .prop('checked', false)); + + await vpn.waitForQueryAndClick(queries.navBar.HOME.visible()); + await vpn.waitForQuery(queries.global.SCREEN_LOADER.ready()); + + assert.equal(await vpn.getSetting('dnsProviderFlags'), 0); + + await vpn.waitForQueryAndClick(queries.navBar.SETTINGS.visible()); + await vpn.waitForQuery(queries.global.SCREEN_LOADER.ready()); + + await vpn.waitForQueryAndClick( + queries.screenSettings.appPreferencesView.dnsSettingsView.CUSTOM_DNS + .visible() + .prop('checked', false)); + + await vpn.waitForQueryAndClick(queries.navBar.HOME.visible()); + await vpn.waitForQuery(queries.global.SCREEN_LOADER.ready()); + + assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); + + // Check the modal + await vpn.setSetting('dnsProviderFlags', 2); + + await vpn.waitForQueryAndClick(queries.navBar.SETTINGS.visible()); + await vpn.waitForQuery(queries.global.SCREEN_LOADER.ready()); + + await vpn.waitForQuery( + queries.screenSettings.appPreferencesView.dnsSettingsView.STANDARD_DNS + .visible() + .prop('checked', true)); + + await vpn.waitForQueryAndClick( + queries.screenSettings.appPreferencesView.dnsSettingsView.CUSTOM_DNS + .visible() + .prop('checked', false)); + + await vpn.waitForQueryAndClick( + queries.screenSettings.appPreferencesView.dnsSettingsView + .MODAL_SECONDARY_BUTTON.visible()); + await vpn.waitForQuery( + queries.screenSettings.appPreferencesView.dnsSettingsView + .MODAL_LOADER.prop('active', false)); + + await vpn.waitForQueryAndClick(queries.screenSettings.appPreferencesView + .dnsSettingsView.CUSTOM_DNS.visible()); + + await vpn.waitForQueryAndClick( + queries.screenSettings.appPreferencesView.dnsSettingsView + .MODAL_CLOSE_BUTTON.visible()); + await vpn.waitForQuery( + queries.screenSettings.appPreferencesView.dnsSettingsView + .MODAL_LOADER.prop('active', false)); + + await vpn.waitForQueryAndClick(queries.screenSettings.appPreferencesView + .dnsSettingsView.CUSTOM_DNS.visible()); + + await vpn.waitForQueryAndClick( + queries.screenSettings.appPreferencesView.dnsSettingsView + .MODAL_PRIMARY_BUTTON.visible()); + await vpn.waitForQuery( + queries.screenSettings.appPreferencesView.dnsSettingsView + .MODAL_LOADER.prop('active', false)); + + await vpn.setQueryProperty( + queries.screenSettings.appPreferencesView.dnsSettingsView + .CUSTOM_DNS_INPUT.visible(), + 'text', '1.2.3.4'); + + await vpn.waitForQueryAndClick(queries.screenSettings.BACK.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); + + assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); + + await vpn.waitForQueryAndClick(queries.screenSettings.BACK.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); + + await vpn.waitForQuery(queries.screenSettings.USER_PROFILE.visible()); + }); + + it('Checking the DNS settings reset', async () => { + // Checking if the checkboxes are correctly set based on the settings prop + await vpn.waitForQuery( + queries.screenSettings.appPreferencesView.dnsSettingsView.STANDARD_DNS + .visible() + .prop('checked', true)); + await vpn.waitForQuery( + queries.screenSettings.appPreferencesView.dnsSettingsView.CUSTOM_DNS + .visible() + .prop('checked', false)); + + // Click on "Custom DNS" but leaving the input field empty. + await vpn.waitForQueryAndClick( + queries.screenSettings.appPreferencesView.dnsSettingsView.CUSTOM_DNS + .visible() + .prop('checked', false)); + + await vpn.setQueryProperty( + queries.screenSettings.appPreferencesView.dnsSettingsView + .CUSTOM_DNS_INPUT.visible(), + 'text', ''); + + // Going back... + await vpn.waitForQueryAndClick(queries.screenSettings.BACK.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); + + // .. the DNS setting is reset to the default value. + assert.equal(await vpn.getSetting('dnsProviderFlags'), 0); + + // Same test as before... + await vpn.waitForQueryAndClick( + queries.screenSettings.appPreferencesView.DNS_SETTINGS.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); + + await vpn.waitForQuery( + queries.screenSettings.appPreferencesView.dnsSettingsView.STANDARD_DNS + .visible() + .prop('checked', true)); + await vpn.waitForQuery( + queries.screenSettings.appPreferencesView.dnsSettingsView.CUSTOM_DNS + .visible() + .prop('checked', false)); + + await vpn.waitForQueryAndClick( + queries.screenSettings.appPreferencesView.dnsSettingsView.CUSTOM_DNS + .visible() + .prop('checked', false)); + + // But with a valid DNS value... + await vpn.setQueryProperty( + queries.screenSettings.appPreferencesView.dnsSettingsView + .CUSTOM_DNS_INPUT.visible(), + 'text', '1.2.3.4'); + + await vpn.waitForQueryAndClick(queries.screenSettings.BACK.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); + + // We keep the custom DNS. + assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); + + // Write something invalid... + await vpn.waitForQueryAndClick( + queries.screenSettings.appPreferencesView.DNS_SETTINGS.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); + + await vpn.waitForQuery( + queries.screenSettings.appPreferencesView.dnsSettingsView.STANDARD_DNS + .visible() + .prop('checked', false)); + await vpn.waitForQuery( + queries.screenSettings.appPreferencesView.dnsSettingsView.CUSTOM_DNS + .visible() + .prop('checked', true)); + + assert.equal( + await vpn.getQueryProperty( + queries.screenSettings.appPreferencesView.dnsSettingsView + .CUSTOM_DNS_INPUT.visible(), + 'text'), + '1.2.3.4'); + + await vpn.setQueryProperty( + queries.screenSettings.appPreferencesView.dnsSettingsView + .CUSTOM_DNS_INPUT.visible(), + 'text', '1.2.3.4aabbcc'); + + await vpn.waitForQueryAndClick(queries.screenSettings.BACK.visible()); + await vpn.waitForQuery(queries.screenSettings.STACKVIEW.ready()); + + // We keep the custom DNS. + assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); + }); - // We keep the custom DNS. - assert.equal(await vpn.getSetting('dnsProviderFlags'), 1); + it('Checking the dns help sheet', async () => { + if (!(await vpn.isFeatureFlippedOn('helpSheets'))) { + await vpn.flipFeatureOn('helpSheets'); + } + + await vpn.waitForQueryAndClick(queries.screenSettings.appPreferencesView.dnsSettingsView.HELP_BUTTON.visible()); + await vpn.waitForQuery(queries.screenSettings.appPreferencesView.dnsSettingsView.HELP_SHEET.visible()); + await vpn.waitForQuery(queries.screenSettings.appPreferencesView.dnsSettingsView.HELP_SHEET.opened()); + await vpn.waitForQueryAndClick(queries.screenSettings.appPreferencesView.dnsSettingsView.HELP_SHEET_LEARN_MORE_BUTTON.visible()); + await vpn.waitForCondition(async () => { + const url = await vpn.getLastUrl(); + return url === 'https://support.mozilla.org/kb/how-do-i-change-my-dns-settings'; + }); + await vpn.waitForQueryAndClick(queries.screenSettings.appPreferencesView.dnsSettingsView.HELP_SHEET_CLOSE_BUTTON.visible()); + await vpn.waitForQuery(queries.screenSettings.appPreferencesView.dnsSettingsView.HELP_SHEET.closed()); + }); }); + it('Checking the languages settings', async () => { await vpn.setSetting('languageCode', '');