diff --git a/ci/Jenkinsfile.tests-e2e.windows b/ci/Jenkinsfile.tests-e2e.windows
new file mode 100644
index 00000000000..2a3fb4ad8a7
--- /dev/null
+++ b/ci/Jenkinsfile.tests-e2e.windows
@@ -0,0 +1,287 @@
+#!/usr/bin/env groovy
+library 'status-jenkins-lib@v1.9.28'
+
+pipeline {
+
+ agent {
+ label 'windows && x86_64 && qt-6.9.2 && windows-e2e'
+ }
+
+ parameters {
+ gitParameter(
+ name: 'GIT_REF',
+ description: 'Git branch to checkout.',
+ branchFilter: 'origin/(.*)',
+ branch: '',
+ defaultValue: 'master',
+ quickFilterEnabled: false,
+ selectedValue: 'DEFAULT',
+ sortMode: 'ASCENDING_SMART',
+ tagFilter: '*',
+ type: 'PT_BRANCH'
+ )
+ string(
+ name: 'BUILD_SOURCE',
+ description: 'URL to tar.gz file OR path to Jenkins build.',
+ defaultValue: getDefaultBuildSource()
+ )
+ string(
+ name: 'TEST_NAME',
+ description: 'Paste test name/part of test name to run specific test.',
+ defaultValue: ''
+ )
+ string(
+ name: 'TEST_SCOPE_FLAG',
+ description: 'Paste a known mark to run tests labeled with this mark',
+ defaultValue: getDefaultTestScopeFlag()
+ )
+ string(
+ name: 'TESTRAIL_RUN_NAME',
+ description: 'Test run name in Test Rail.',
+ defaultValue: ''
+ )
+ choice(
+ name: 'LOG_LEVEL',
+ description: 'Log level for pytest.',
+ choices: ['INFO', 'DEBUG', 'TRACE', 'WARNING', 'CRITICAL']
+ )
+ }
+
+ options {
+ timestamps()
+ /* Prevent Jenkins jobs from running forever */
+ timeout(time: 120, unit: 'MINUTES')
+ /* manage how many builds we keep */
+ buildDiscarder(logRotator(
+ daysToKeepStr: '60',
+ numToKeepStr: '50',
+ artifactNumToKeepStr: '50',
+ ))
+ disableRestartFromStage()
+ }
+
+ environment {
+ PLATFORM = 'tests/e2e'
+
+ SQUISH_DIR = 'C:\\squish-runner-9.0.1-qt-6.9'
+ PYTHONPATH = "${SQUISH_DIR}\\lib;${SQUISH_DIR}\\bin;${SQUISH_DIR}\\lib\\python;${PYTHONPATH}"
+
+ /* To stop e2e tests using port 8545 */
+ STATUS_RUNTIME_HTTP_API = 'False'
+ STATUS_RUNTIME_WS_API = 'False'
+
+ /* Avoid race conditions with other builds using virtualenv. */
+ VIRTUAL_ENV = "${WORKSPACE_TMP}\\venv"
+ PATH = "${VIRTUAL_ENV}\\bin;C:\\Qt\\6.9.2\\msvc2022_64\\bin;${PATH}"
+
+ /* To store user configuratiin files in temp dir */
+ XDG_CONFIG_HOME = "${WORKSPACE_TMP}/config"
+
+ TESTRAIL_URL = 'https://ethstatus.testrail.net'
+ TESTRAIL_PROJECT_ID = 18
+ /* Override QT xcb plugin with linux to avoid errors like:
+ * "Could not load the Qt platform plugin "xcb" in "" even though it was found."
+ QT_QPA_PLATFORM = "linuxfb"*/
+
+ /* Runtime flag to make testing of the app easier. Switched off: unpredictable app behavior under new tests */
+ STATUS_RUNTIME_TEST_MODE = 1
+
+ /* Logging rules let you enable or disable logging for categories */
+ /* QT_LOGGING_RULES = '*.warning=true' */
+
+ /* Set to a non-zero value to make Qt print out diagnostic information about the each (C++) plugin it tries to load. */
+ /* QT_DEBUG_PLUGINS = 0 */
+
+ /* Hack fix for params not being set in job on first run */
+ BUILD_SOURCE = "${params.BUILD_SOURCE}"
+ TEST_NAME = "${params.TEST_NAME}"
+ TEST_SCOPE_FLAG = "${params.TEST_SCOPE_FLAG}"
+ TESTRAIL_RUN_NAME = "${params.TESTRAIL_RUN_NAME}"
+ LOG_LEVEL = "${params.LOG_LEVEL}"
+
+ /* Forces QT to use OpenGL for rendering instead of default Direct3D 11 */
+ QSG_RHI_BACKEND = 'opengl'
+ }
+
+ stages {
+ stage('Cleanup Workspace') {
+ steps {
+ sh './scripts/clean-git.sh'
+ }
+ }
+ stage('Prep') {
+ steps { script {
+ setNewBuildName()
+ updateGitHubStatus()
+ } }
+ }
+
+ stage('Deps') {
+ steps { script { dir('test/e2e') {
+ bat """
+ python310 -m venv ${VIRTUAL_ENV}
+ python310 -m pip install --upgrade pip
+ python310 -m pip install -r requirements.txt
+ """
+ } } }
+ }
+
+ stage('Download') {
+ when { expression { params.BUILD_SOURCE.startsWith('http') } }
+ steps { timeout(5) { script { dir('test/e2e') {
+ sh 'mkdir -p ./pkg/'
+ setBuildDescFromFile(params.BUILD_SOURCE)
+ fileOperations([
+ fileDownloadOperation(
+ url: params.BUILD_SOURCE,
+ targetFileName: 'StatusIm-Desktop.7z',
+ targetLocation: './pkg/',
+ userName: '',
+ password: '',
+ )
+ ])
+ } } } }
+ }
+
+ stage('Copy') {
+ when { expression { ! params.BUILD_SOURCE.startsWith('http') } }
+ steps { timeout(5) { script { dir('test/e2e') {
+ copyArtifacts(
+ projectName: params.BUILD_SOURCE,
+ filter: 'pkg/*-x86_64.7z',
+ selector: lastWithArtifacts(),
+ target: './'
+ )
+ setBuildDescFromFile(utils.findFile('pkg/*7z'))
+ } } } }
+ }
+
+ stage('Unpack') {
+ steps { timeout(5) { script { dir('test/e2e') {
+ sh 'mkdir aut'
+ sh "7z x '${utils.findFile('pkg/*.7z')}' -o'./aut'"
+ env.AUT_PATH = utils.findFile('aut/Status/bin/Status.exe').replace('\\','/')
+ } } } }
+ }
+
+ stage('Test') {
+ steps {
+ timeout(time: getTestStageTimeout()) {
+ dir('test/e2e') {
+ /* Lock the agent so we run only one e2e build at a time */
+ lock(resource: "e2e-windows-${env.NODE_NAME}", quantity: 1) {
+ script {
+ def flags = []
+ if (params.TEST_NAME) { flags.add("-k=${params.TEST_NAME}") }
+ if (params.TEST_SCOPE_FLAG) { flags.add(params.TEST_SCOPE_FLAG) }
+ if (params.LOG_LEVEL) { flags.addAll(["--log-level=${params.LOG_LEVEL}", "--log-cli-level=${params.LOG_LEVEL}"]) }
+ def flagStr = flags.join(' ')
+
+ withCredentials([
+ usernamePassword(credentialsId: 'test-rail-api-devops', usernameVariable: 'TESTRAIL_USR', passwordVariable: 'TESTRAIL_PSW'),
+ string(credentialsId: 'wallet-test-user-seed', variable: 'WALLET_TEST_USER_SEED')
+ ]) {
+ sh"""
+ pushd configs
+ ln -sf _local.ci.py _local.py || cp _local.ci.py _local.py
+ popd
+
+ """
+ bat"""
+ python310 -m pytest -m "not keycard" -v --reruns=1 --timeout=300 ${flagStr} --disable-warnings --alluredir=./allure-results -o timeout_func_only=true
+ """
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ post {
+ always { script { dir('test/e2e') {
+ archiveArtifacts('aut/Status/bin/*.log')
+
+ /* Needed to categorize types of errors and add environment section in allure report. */
+ sh 'cp ext/allure_files/categories.json allure-results'
+ sh 'cp ext/allure_files/environment.properties allure-results'
+
+ allure([
+ results: [[path: 'allure-results']],
+ reportBuildPolicy: 'ALWAYS',
+ properties: [],
+ jdk: '',
+ ])
+ /* Link for Jenkins Builds GitHub comment. */
+ env.PKG_URL = "${env.BUILD_URL}allure/"
+ updateGitHubStatus()
+ } } }
+ success { script {
+ github.notifyPR(true)
+ } }
+ failure { script {
+ github.notifyPR(false)
+ discord.send(
+ header: '**Desktop E2E test failure!**',
+ cred: 'discord-status-desktop-e2e-webhook',
+ )
+ } }
+ cleanup { cleanWs(disableDeferredWipeout: true) }
+ }
+}
+
+def setNewBuildName() {
+ if (currentBuild.upstreamBuilds) {
+ def parent = utils.parentOrCurrentBuild()
+ currentBuild.displayName = parent.getFullDisplayName().minus('status-desktop ยป ')
+ }
+}
+
+def setBuildDescFromFile(fileNameOrPath) {
+ def tokens = utils.parseFilename(utils.baseName(fileNameOrPath))
+ if (tokens == null) { /* Fallback for regex fail. */
+ currentBuild.description = utils.baseName(fileNameOrPath)
+ return
+ }
+ if (tokens.build && tokens.build.startsWith('pr')) {
+ currentBuild.displayName = tokens.build.replace(/^pr/, 'PR-')
+ }
+ currentBuild.description = formatMap([
+ Node: NODE_NAME,
+ Build: tokens.build,
+ Commit: tokens.commit,
+ Version: (tokens.tstamp ?: tokens.version),
+ ])
+}
+
+def updateGitHubStatus() {
+ /* For PR builds update check status. */
+ if (params.BUILD_SOURCE ==~ /.*\/PR-[0-9]+\/?$/) {
+ github.statusUpdate(
+ context: 'jenkins/prs/tests/e2e-new.windows',
+ commit: jenkins.getJobCommitByPath(params.BUILD_SOURCE),
+ repo_url: 'https://github.com/status-im/status-desktop'
+ )
+ }
+}
+
+def formatMap(Map data=[:]) {
+ def text = ''
+ data.each { key, val -> text += "${key}: ${val}
\n" }
+ return text
+}
+
+def getDefaultBuildSource() {
+ return ''
+}
+
+def getDefaultTestScopeFlag() {
+ if (JOB_NAME == "status-desktop/systems/windows/x86_64/tests-e2e") {
+ return ''
+ } else {
+ return '-m=critical'
+ }
+}
+
+def getTestStageTimeout() { params.TEST_SCOPE_FLAG == '-m=critical' ? 30 : 120 }
diff --git a/ci/Jenkinsfile.windows b/ci/Jenkinsfile.windows
index 8e770cc2050..50b0c3959e3 100644
--- a/ci/Jenkinsfile.windows
+++ b/ci/Jenkinsfile.windows
@@ -73,7 +73,7 @@ pipeline {
QTDIR = "/c/Qt/6.9.2/msvc2022_64"
PATH = "${env.QTDIR}/bin:${goPath()}/bin:${env.PATH}"
/* Avoid weird bugs caused by stale cache. */
- QML_DISABLE_DISK_CACHE = "true"
+ QML_DISABLE_DISK_CACHE = 1
/* Control output the filename */
VERSION = sh(script: "./scripts/version.sh", returnStdout: true).trim()
STATUS_CLIENT_EXE = "pkg/${utils.pkgFilename(ext: 'exe', arch: getArch(), version: env.VERSION)}"
@@ -149,6 +149,21 @@ pipeline {
jenkins.setBuildDesc(Zip: zip_url, Exe: exe_url)
} }
}
+
+
+ stage('E2E') {
+ when { expression { utils.isPRBuild() } }
+ steps { script {
+ build(
+ job: 'status-desktop/e2e/prs-windows',
+ wait: false,
+ parameters: jenkins.mapToParams([
+ GIT_REF: env.GIT_COMMIT,
+ BUILD_SOURCE: env.JOB_NAME,
+ ]),
+ )
+ } }
+ }
}
post {
success { script { github.notifyPR(true) } }
diff --git a/test/e2e/configs/__init__.py b/test/e2e/configs/__init__.py
index d1257cf2f5c..e97569a7ea2 100644
--- a/test/e2e/configs/__init__.py
+++ b/test/e2e/configs/__init__.py
@@ -19,8 +19,8 @@
if AUT_PATH is None:
exit('Please add "AUT_PATH" in ./configs/_local.py')
-if get_platform() == "Windows" and 'bin' not in AUT_PATH:
- exit('Please use launcher from "bin" folder in "AUT_PATH"')
+if get_platform() == "Windows" and 'Status' not in AUT_PATH:
+ exit('Please use launcher from "Status" folder in "AUT_PATH"')
AUT_PATH = SystemPath(AUT_PATH)
WALLET_SEED = os.getenv('WALLET_TEST_USER_SEED')
diff --git a/test/e2e/conftest.py b/test/e2e/conftest.py
index a4fc17f85c6..2d627e0cf8a 100644
--- a/test/e2e/conftest.py
+++ b/test/e2e/conftest.py
@@ -4,6 +4,7 @@
import allure
import pytest
import shortuuid
+import sys
from tests import test_data
from PIL import ImageGrab
@@ -12,6 +13,9 @@
from scripts.utils.system_path import SystemPath
# Send logs to pytest.log as well
+# Ensure log directory exists
+log_dir = os.path.dirname(configs.PYTEST_LOG)
+os.makedirs(log_dir, exist_ok=True)
handler = logging.FileHandler(filename=configs.PYTEST_LOG)
logging.basicConfig(
level=os.getenv('LOG_LEVEL', 'INFO'),
@@ -28,9 +32,31 @@
]
+@pytest.fixture(scope='session', autouse=True)
+def generate_allure_environment():
+ """Generate allure environment.properties with dynamic platform information"""
+ env_dir = configs.testpath.ROOT / 'ext' / 'allure_files'
+ env_file = env_dir / 'environment.properties'
+
+ # Ensure directory exists
+ env_dir.mkdir(parents=True, exist_ok=True)
+
+ platform_name = get_platform()
+ python_version = f"Python {sys.version_info.major}.{sys.version_info.minor}"
+
+ content = f"""os_platform = {platform_name}
+python_version = {python_version}
+"""
+
+ env_file.write_text(content)
+ LOG.info(f'Generated allure environment.properties with platform={platform_name}, python={python_version}')
+ yield
+
+
@pytest.fixture(scope='session', autouse=True)
def setup_session_scope(
# init_testrail_api, TODO: https://github.com/status-im/status-desktop/issues/18288
+ generate_allure_environment,
prepare_test_directory,
start_squish_server
):
diff --git a/test/e2e/tests/crtitical_tests_prs/test_create_edit_join_community_pin_unpin_message.py b/test/e2e/tests/crtitical_tests_prs/test_create_edit_join_community_pin_unpin_message.py
index c376e5f02ec..6dc0ef1b3b3 100644
--- a/test/e2e/tests/crtitical_tests_prs/test_create_edit_join_community_pin_unpin_message.py
+++ b/test/e2e/tests/crtitical_tests_prs/test_create_edit_join_community_pin_unpin_message.py
@@ -3,6 +3,7 @@
from allure_commons._allure import step
import driver
+from configs import get_platform
from constants.community import Channel
from gui.main_window import MainWindow
from helpers.multiple_instances_helper import (
@@ -26,6 +27,7 @@
@pytest.mark.communities
@pytest.mark.smoke
@pytest.mark.critical
+@pytest.mark.skipif(get_platform() == 'Windows', reason="https://github.com/status-im/status-desktop/issues/18994")
def test_create_edit_join_community_pin_unpin_message(multiple_instances):
user_one: UserAccount = RandomUser()
user_two: UserAccount = RandomUser()
diff --git a/test/e2e/tests/crtitical_tests_prs/test_messaging_1x1_chat.py b/test/e2e/tests/crtitical_tests_prs/test_messaging_1x1_chat.py
index 8d48c871118..bb28bc877f1 100644
--- a/test/e2e/tests/crtitical_tests_prs/test_messaging_1x1_chat.py
+++ b/test/e2e/tests/crtitical_tests_prs/test_messaging_1x1_chat.py
@@ -7,6 +7,9 @@
from allure_commons._allure import step
import driver
+from configs import get_platform
+from constants.images_paths import HEART_EMOJI_PATH, ANGRY_EMOJI_PATH, THUMBSUP_EMOJI_PATH, THUMBSDOWN_EMOJI_PATH, \
+ LAUGHING_EMOJI_PATH, SAD_EMOJI_PATH
from constants.messaging import Messaging
from constants.wallet import WalletAddress
from ext.test_files.base64_images import BASE_64_IMAGE_JPEG
@@ -25,6 +28,7 @@
@allure.testcase('https://ethstatus.testrail.net/index.php?/cases/view/703087', '1-1 Chat')
@pytest.mark.case(703087, 738732, 738734, 738742, 738744, 738745)
@pytest.mark.critical
+@pytest.mark.skipif(get_platform() == 'Windows', reason="https://github.com/status-im/status-desktop/issues/18994")
@pytest.mark.smoke
def test_1x1_chat_add_contact_in_settings(multiple_instances):
user_one: UserAccount = RandomUser()
diff --git a/test/e2e/tests/crtitical_tests_prs/test_messaging_group_chat.py b/test/e2e/tests/crtitical_tests_prs/test_messaging_group_chat.py
index dc412d4a8d9..640677aef32 100644
--- a/test/e2e/tests/crtitical_tests_prs/test_messaging_group_chat.py
+++ b/test/e2e/tests/crtitical_tests_prs/test_messaging_group_chat.py
@@ -6,6 +6,7 @@
from allure_commons._allure import step
import driver
+from configs import get_platform
from constants.links import external_link, link_to_status_community
import configs.testpath
@@ -23,6 +24,7 @@
@allure.testcase('https://ethstatus.testrail.net/index.php?/cases/view/703014', 'Create a group and send messages')
@pytest.mark.case(703014, 738735, 738736, 738739, 738740)
@pytest.mark.critical
+@pytest.mark.skipif(get_platform() == 'Windows', reason="https://github.com/status-im/status-desktop/issues/18994")
@pytest.mark.smoke
@pytest.mark.parametrize('community_name, domain_link, domain_link_2',
[pytest.param('Status', 'status.app', 'github.com')
diff --git a/test/e2e/tests/crtitical_tests_prs/test_onboarding_sync_with_code.py b/test/e2e/tests/crtitical_tests_prs/test_onboarding_sync_with_code.py
index abfee556c5b..cd40725f900 100644
--- a/test/e2e/tests/crtitical_tests_prs/test_onboarding_sync_with_code.py
+++ b/test/e2e/tests/crtitical_tests_prs/test_onboarding_sync_with_code.py
@@ -7,6 +7,7 @@
import configs.testpath
import driver
+from configs import get_platform
from configs.timeouts import APP_LOAD_TIMEOUT_MSEC
from constants import UserAccount, RandomUser
from constants.syncing import SyncingSettings
@@ -19,6 +20,7 @@
@allure.testcase('https://ethstatus.testrail.net/index.php?/cases/view/703592', 'Sync device during onboarding')
@pytest.mark.case(703592, 738760)
@pytest.mark.critical
+@pytest.mark.skipif(get_platform() == 'Windows', reason="https://github.com/status-im/status-desktop/issues/18846 on Windows")
@pytest.mark.smoke
def test_sync_devices_during_onboarding_change_settings_unpair(multiple_instances):
user: UserAccount = RandomUser()