From 0ec282e8d65fcc32fb9e03ebd14875968f0fb141 Mon Sep 17 00:00:00 2001
From: yurkovychv <vasyl.yurkovych@percona.com>
Date: Wed, 18 Dec 2024 13:42:14 +0200
Subject: [PATCH 1/7] PMM-13620 add test for restarting mongo node

---
 tests/custom_steps.js                         |  3 ++
 .../pmm_psmdb_integration_test.js             | 44 +++++++++++++++++++
 2 files changed, 47 insertions(+)

diff --git a/tests/custom_steps.js b/tests/custom_steps.js
index 632a021e0..57fd2d77c 100644
--- a/tests/custom_steps.js
+++ b/tests/custom_steps.js
@@ -209,6 +209,9 @@ module.exports = () => actor({
         case 'cluster':
           queryParams['var-cluster'] = value;
           break;
+        case 'replica_set':
+          queryParams['var-replset'] = value;
+          break;
         case 'service_name':
           queryParams['var-service_name'] = value;
           break;
diff --git a/tests/qa-integration/pmm_psmdb_integration_test.js b/tests/qa-integration/pmm_psmdb_integration_test.js
index 40a4a30a9..6f4efaa2f 100644
--- a/tests/qa-integration/pmm_psmdb_integration_test.js
+++ b/tests/qa-integration/pmm_psmdb_integration_test.js
@@ -225,3 +225,47 @@ Scenario('PMM-T1889 Verify Mongo replication lag graph shows correct info @pmm-p
 
   I.assertFalse(/min|hour|day|week|month|year/.test(maxValue), `Max replication value should be in seconds. Value is: ${maxValue}`);
 });
+
+Scenario('PMM-T1956 Verify Node States metrics when one node is down @pmm-psmdb-replica-integration', async ({
+  I, dashboardPage, grafanaAPI, inventoryAPI,
+}) => {
+  I.amOnPage(I.buildUrlWithParams(dashboardPage.mongodbReplicaSetSummaryDashboard.cleanUrl, { from: 'now-5m', refresh: '10s', replica_set: 'rs' }));
+  dashboardPage.waitForDashboardOpened();
+
+  const { service_name: rs101ServiceName } = await inventoryAPI.apiGetNodeInfoByServiceName(SERVICE_TYPE.MONGODB, 'rs101');
+  const { service_name: rs102ServiceName } = await inventoryAPI.apiGetNodeInfoByServiceName(SERVICE_TYPE.MONGODB, 'rs102');
+  const { service_name: rs103ServiceName } = await inventoryAPI.apiGetNodeInfoByServiceName(SERVICE_TYPE.MONGODB, 'rs103');
+  const expression = `max by (service_name) (mongodb_mongod_replset_my_state{environment=~".*", cluster=~"replicaset", set=~"rs", service_name=~"(${rs101ServiceName}|${rs102ServiceName}|${rs103ServiceName})"})`;
+
+  const initialMetrics = await grafanaAPI.getMetric(expression, null);
+  const initialFrames = initialMetrics.data.results.A.frames;
+
+  assert.ok(initialFrames.length === 3, 'There should be 3 frames in the response');
+
+  await I.verifyCommand('docker stop rs102');
+  let frames;
+
+  await I.asyncWaitFor(async () => {
+    const resp = await grafanaAPI.getMetric(expression, null);
+
+    frames = resp.data.results.A.frames;
+
+    return frames.length === 2;
+  }, 120);
+
+  assert.ok(frames.length === 2, 'There should be 2 frames in the response');
+  const serviceNames = frames.map((frame) => frame.schema.fields[1].labels.service_name);
+
+  assert.ok(serviceNames.includes(rs101ServiceName), 'rs101 service name should be in the list');
+  assert.ok(serviceNames.includes(rs103ServiceName), 'rs103 service name should be in the list');
+
+  await I.verifyCommand('docker start rs102');
+
+  await I.asyncWaitFor(async () => {
+    const resp = await grafanaAPI.getMetric(expression, null);
+
+    frames = resp.data.results.A.frames;
+
+    return frames.length === 3;
+  }, 120);
+});

From 771539cf38c8cfaedecb3801efc3e8b0228a375a Mon Sep 17 00:00:00 2001
From: yurkovychv <vasyl.yurkovych@percona.com>
Date: Wed, 18 Dec 2024 15:01:44 +0200
Subject: [PATCH 2/7] PMM-13620 add test for restarting mongo node

---
 tests/qa-integration/pmm_psmdb_integration_test.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/qa-integration/pmm_psmdb_integration_test.js b/tests/qa-integration/pmm_psmdb_integration_test.js
index 6f4efaa2f..3252ee273 100644
--- a/tests/qa-integration/pmm_psmdb_integration_test.js
+++ b/tests/qa-integration/pmm_psmdb_integration_test.js
@@ -251,7 +251,7 @@ Scenario('PMM-T1956 Verify Node States metrics when one node is down @pmm-psmdb-
     frames = resp.data.results.A.frames;
 
     return frames.length === 2;
-  }, 120);
+  }, 180);
 
   assert.ok(frames.length === 2, 'There should be 2 frames in the response');
   const serviceNames = frames.map((frame) => frame.schema.fields[1].labels.service_name);

From cffbe715abc90e6d2c221f6ba531bb985d98cc14 Mon Sep 17 00:00:00 2001
From: yurkovychv <vasyl.yurkovych@percona.com>
Date: Wed, 18 Dec 2024 15:05:32 +0200
Subject: [PATCH 3/7] PMM-13620 add timerange value to getMetric method

---
 tests/pages/api/grafanaAPI.js                      | 4 ++--
 tests/qa-integration/pmm_psmdb_integration_test.js | 6 +++---
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/tests/pages/api/grafanaAPI.js b/tests/pages/api/grafanaAPI.js
index 92a44c023..e01d3151a 100644
--- a/tests/pages/api/grafanaAPI.js
+++ b/tests/pages/api/grafanaAPI.js
@@ -358,7 +358,7 @@ module.exports = {
   },
 
   // Refactored function for new Grafana Explore UI format
-  async getMetric(metricName, refineBy) {
+  async getMetric(metricName, refineBy, lastMinutes = 5) {
     const uid = await this.getDataSourceUidByName();
     const currentTime = Date.now();
     let refineByString = '';
@@ -421,7 +421,7 @@ module.exports = {
           maxDataPoints: 757,
         },
       ],
-      from: (currentTime - 5 * 60 * 1000).toString(),
+      from: (currentTime - lastMinutes * 60 * 1000).toString(),
       to: currentTime.toString(),
     };
 
diff --git a/tests/qa-integration/pmm_psmdb_integration_test.js b/tests/qa-integration/pmm_psmdb_integration_test.js
index 3252ee273..809cca9c8 100644
--- a/tests/qa-integration/pmm_psmdb_integration_test.js
+++ b/tests/qa-integration/pmm_psmdb_integration_test.js
@@ -246,12 +246,12 @@ Scenario('PMM-T1956 Verify Node States metrics when one node is down @pmm-psmdb-
   let frames;
 
   await I.asyncWaitFor(async () => {
-    const resp = await grafanaAPI.getMetric(expression, null);
+    const resp = await grafanaAPI.getMetric(expression, null, 1);
 
     frames = resp.data.results.A.frames;
 
     return frames.length === 2;
-  }, 180);
+  }, 120);
 
   assert.ok(frames.length === 2, 'There should be 2 frames in the response');
   const serviceNames = frames.map((frame) => frame.schema.fields[1].labels.service_name);
@@ -262,7 +262,7 @@ Scenario('PMM-T1956 Verify Node States metrics when one node is down @pmm-psmdb-
   await I.verifyCommand('docker start rs102');
 
   await I.asyncWaitFor(async () => {
-    const resp = await grafanaAPI.getMetric(expression, null);
+    const resp = await grafanaAPI.getMetric(expression, null, 1);
 
     frames = resp.data.results.A.frames;
 

From afaf3c80bcefd4ac0234451ea9104823ab95e411 Mon Sep 17 00:00:00 2001
From: yurkovychv <vasyl.yurkovych@percona.com>
Date: Thu, 19 Dec 2024 17:37:23 +0200
Subject: [PATCH 4/7] PMM-13620 add visual comparison for the panel

---
 .github/workflows/ci.yml                      |   3 +-
 package-lock.json                             | 596 +++++++++++++++++-
 package.json                                  |   1 +
 tests/pages/dashboardPage.js                  |   2 +-
 .../pmm_psmdb_integration_test.js             |  44 +-
 .../base/Mongo_down_nodes_states.png          | Bin 0 -> 4618 bytes
 6 files changed, 590 insertions(+), 56 deletions(-)
 create mode 100644 tests/screenshots/base/Mongo_down_nodes_states.png

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5686dd702..c74212f2c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -29,6 +29,7 @@ jobs:
       sha: 'null'
       pmm_ui_tests_branch: ${{ github.head_ref }}
       pmm_qa_branch: 'v3'
-      pmm_server_image: 'perconalab/pmm-server:3-dev-latest'
+      pmm_server_image: 'perconalab/pmm-server-fb:PR-3761-646d9cc'
+#      pmm_server_image: 'perconalab/pmm-server:3-dev-latest'
       pmm_client_image: 'perconalab/pmm-client:3-dev-latest'
       pmm_client_version: '3-dev-latest'
diff --git a/package-lock.json b/package-lock.json
index 08eae8439..97fbbe849 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -23,6 +23,7 @@
         "codeceptjs-dbhelper": "^1.2.2",
         "codeceptjs-mailosaurhelper": "^1.0.5",
         "codeceptjs-postgresqlhelper": "^1.0.0",
+        "codeceptjs-resemblehelper": "^1.9.7",
         "faker": "^5.5.3",
         "form-data": "^4.0.0",
         "generate-password": "^1.7.1",
@@ -2774,6 +2775,103 @@
         "@jridgewell/sourcemap-codec": "^1.4.14"
       }
     },
+    "node_modules/@mapbox/node-pre-gyp": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz",
+      "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==",
+      "dependencies": {
+        "detect-libc": "^2.0.0",
+        "https-proxy-agent": "^5.0.0",
+        "make-dir": "^3.1.0",
+        "node-fetch": "^2.6.7",
+        "nopt": "^5.0.0",
+        "npmlog": "^5.0.1",
+        "rimraf": "^3.0.2",
+        "semver": "^7.3.5",
+        "tar": "^6.1.11"
+      },
+      "bin": {
+        "node-pre-gyp": "bin/node-pre-gyp"
+      }
+    },
+    "node_modules/@mapbox/node-pre-gyp/node_modules/abbrev": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+      "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+    },
+    "node_modules/@mapbox/node-pre-gyp/node_modules/chownr": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+      "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+      "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+      "dependencies": {
+        "semver": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@mapbox/node-pre-gyp/node_modules/minipass": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
+      "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@mapbox/node-pre-gyp/node_modules/nopt": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
+      "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
+      "dependencies": {
+        "abbrev": "1"
+      },
+      "bin": {
+        "nopt": "bin/nopt.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@mapbox/node-pre-gyp/node_modules/tar": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
+      "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
+      "dependencies": {
+        "chownr": "^2.0.0",
+        "fs-minipass": "^2.0.0",
+        "minipass": "^5.0.0",
+        "minizlib": "^2.1.1",
+        "mkdirp": "^1.0.3",
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@mapbox/node-pre-gyp/node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+    },
     "node_modules/@nodelib/fs.scandir": {
       "version": "2.1.5",
       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -4319,6 +4417,11 @@
         "url": "https://github.com/chalk/ansi-styles?sponsor=1"
       }
     },
+    "node_modules/any-promise": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+      "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="
+    },
     "node_modules/anymatch": {
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
@@ -4337,6 +4440,37 @@
       "integrity": "sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==",
       "optional": true
     },
+    "node_modules/aproba": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
+      "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ=="
+    },
+    "node_modules/are-we-there-yet": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz",
+      "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==",
+      "deprecated": "This package is no longer supported.",
+      "dependencies": {
+        "delegates": "^1.0.0",
+        "readable-stream": "^3.6.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/are-we-there-yet/node_modules/readable-stream": {
+      "version": "3.6.2",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+      "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
     "node_modules/argparse": {
       "version": "1.0.10",
       "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@@ -4521,6 +4655,15 @@
         "safer-buffer": "~2.1.0"
       }
     },
+    "node_modules/assert": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.1.tgz",
+      "integrity": "sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==",
+      "dependencies": {
+        "object.assign": "^4.1.4",
+        "util": "^0.10.4"
+      }
+    },
     "node_modules/assert-plus": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
@@ -4595,6 +4738,49 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/aws-sdk": {
+      "version": "2.1027.0",
+      "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1027.0.tgz",
+      "integrity": "sha512-j3UjPV9hzyCvkmfcbhRscMggdmrPqlhvo8QzkXCGFfPXjZMh1OJd4HkCEH2NaunzLOyF2Y3QzxKrGOLMT7sNzg==",
+      "dependencies": {
+        "buffer": "4.9.2",
+        "events": "1.1.1",
+        "ieee754": "1.1.13",
+        "jmespath": "0.15.0",
+        "querystring": "0.2.0",
+        "sax": "1.2.1",
+        "url": "0.10.3",
+        "uuid": "3.3.2",
+        "xml2js": "0.4.19"
+      },
+      "engines": {
+        "node": ">= 10.0.0"
+      }
+    },
+    "node_modules/aws-sdk/node_modules/buffer": {
+      "version": "4.9.2",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
+      "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==",
+      "dependencies": {
+        "base64-js": "^1.0.2",
+        "ieee754": "^1.1.4",
+        "isarray": "^1.0.0"
+      }
+    },
+    "node_modules/aws-sdk/node_modules/ieee754": {
+      "version": "1.1.13",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
+      "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
+    },
+    "node_modules/aws-sdk/node_modules/uuid": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
+      "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==",
+      "deprecated": "Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.",
+      "bin": {
+        "uuid": "bin/uuid"
+      }
+    },
     "node_modules/aws-sign2": {
       "version": "0.7.0",
       "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
@@ -5059,7 +5245,6 @@
       "version": "1.0.7",
       "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
       "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
-      "dev": true,
       "dependencies": {
         "es-define-property": "^1.0.0",
         "es-errors": "^1.3.0",
@@ -5161,6 +5346,20 @@
       ],
       "optional": true
     },
+    "node_modules/canvas": {
+      "version": "2.11.2",
+      "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz",
+      "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==",
+      "hasInstallScript": true,
+      "dependencies": {
+        "@mapbox/node-pre-gyp": "^1.0.0",
+        "nan": "^2.17.0",
+        "simple-get": "^3.0.3"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/caseless": {
       "version": "0.12.0",
       "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
@@ -5759,6 +5958,35 @@
         "pg": "^8.7.3"
       }
     },
+    "node_modules/codeceptjs-resemblehelper": {
+      "version": "1.9.7",
+      "resolved": "https://registry.npmjs.org/codeceptjs-resemblehelper/-/codeceptjs-resemblehelper-1.9.7.tgz",
+      "integrity": "sha512-6UNK6jPo/lrb/IpSYrZFOfj7LQk+l8KRF1z7CkHkNM8M+Xp5lPuzuPFfRq+qCK4fm9ytIfPFuP+ZuLACGThSkw==",
+      "dependencies": {
+        "assert": "^1.5.0",
+        "aws-sdk": "2.1027.0",
+        "canvas": "^2.8.0",
+        "image-size": "1.0.0",
+        "mkdirp": "^1.0.4",
+        "mz": "2.7.0",
+        "path": "^0.12.7",
+        "resemblejs": "4.0.0"
+      }
+    },
+    "node_modules/codeceptjs-resemblehelper/node_modules/image-size": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.0.tgz",
+      "integrity": "sha512-JLJ6OwBfO1KcA+TvJT+v8gbE6iWbj24LyDNFgFEN0lzegn6cC6a/p3NIDaepMsJjQjlUWqIC7wJv8lBFxPNjcw==",
+      "dependencies": {
+        "queue": "6.0.2"
+      },
+      "bin": {
+        "image-size": "bin/image-size.js"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
     "node_modules/codeceptjs/node_modules/@cucumber/messages": {
       "version": "24.1.0",
       "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-24.1.0.tgz",
@@ -5875,6 +6103,14 @@
       "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
       "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
     },
+    "node_modules/color-support": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
+      "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
+      "bin": {
+        "color-support": "bin.js"
+      }
+    },
     "node_modules/colorette": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz",
@@ -6010,6 +6246,11 @@
       "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
       "optional": true
     },
+    "node_modules/console-control-strings": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+      "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ=="
+    },
     "node_modules/console-grid": {
       "version": "2.2.2",
       "resolved": "https://registry.npmjs.org/console-grid/-/console-grid-2.2.2.tgz",
@@ -6266,6 +6507,17 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/decompress-response": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
+      "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
+      "dependencies": {
+        "mimic-response": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/deep-eql": {
       "version": "5.0.2",
       "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
@@ -6325,7 +6577,6 @@
       "version": "1.1.4",
       "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
       "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
-      "dev": true,
       "dependencies": {
         "es-define-property": "^1.0.0",
         "es-errors": "^1.3.0",
@@ -6342,7 +6593,6 @@
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
       "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
-      "dev": true,
       "dependencies": {
         "define-data-property": "^1.0.1",
         "has-property-descriptors": "^1.0.0",
@@ -6376,6 +6626,11 @@
         "node": ">=0.4.0"
       }
     },
+    "node_modules/delegates": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+      "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="
+    },
     "node_modules/denodeify": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz",
@@ -6433,6 +6688,14 @@
         "npm": "1.2.8000 || >= 1.4.16"
       }
     },
+    "node_modules/detect-libc": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
+      "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/detox": {
       "version": "20.18.1",
       "resolved": "https://registry.npmjs.org/detox/-/detox-20.18.1.tgz",
@@ -7024,7 +7287,6 @@
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
       "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
-      "dev": true,
       "dependencies": {
         "get-intrinsic": "^1.2.4"
       },
@@ -7036,7 +7298,6 @@
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
       "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
-      "dev": true,
       "engines": {
         "node": ">= 0.4"
       }
@@ -7666,6 +7927,14 @@
         "node": ">=6"
       }
     },
+    "node_modules/events": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
+      "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==",
+      "engines": {
+        "node": ">=0.4.x"
+      }
+    },
     "node_modules/execa": {
       "version": "5.1.1",
       "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
@@ -8192,6 +8461,33 @@
         "node": ">=14.14"
       }
     },
+    "node_modules/fs-minipass": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
+      "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
+      "dependencies": {
+        "minipass": "^3.0.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/fs-minipass/node_modules/minipass": {
+      "version": "3.3.6",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
+      "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/fs-minipass/node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+    },
     "node_modules/fs.realpath": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -8309,6 +8605,52 @@
         "node": ">=8.3.0"
       }
     },
+    "node_modules/gauge": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
+      "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==",
+      "deprecated": "This package is no longer supported.",
+      "dependencies": {
+        "aproba": "^1.0.3 || ^2.0.0",
+        "color-support": "^1.1.2",
+        "console-control-strings": "^1.0.0",
+        "has-unicode": "^2.0.1",
+        "object-assign": "^4.1.1",
+        "signal-exit": "^3.0.0",
+        "string-width": "^4.2.3",
+        "strip-ansi": "^6.0.1",
+        "wide-align": "^1.1.2"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/gauge/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+    },
+    "node_modules/gauge/node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/gauge/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/geckodriver": {
       "version": "4.4.1",
       "resolved": "https://registry.npmjs.org/geckodriver/-/geckodriver-4.4.1.tgz",
@@ -8456,7 +8798,6 @@
       "version": "1.2.4",
       "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
       "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
-      "dev": true,
       "dependencies": {
         "es-errors": "^1.3.0",
         "function-bind": "^1.1.2",
@@ -8614,7 +8955,6 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
       "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
-      "dev": true,
       "dependencies": {
         "get-intrinsic": "^1.1.3"
       },
@@ -8688,7 +9028,6 @@
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
       "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
-      "dev": true,
       "dependencies": {
         "es-define-property": "^1.0.0"
       },
@@ -8700,7 +9039,6 @@
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
       "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
-      "dev": true,
       "engines": {
         "node": ">= 0.4"
       },
@@ -8733,6 +9071,11 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/has-unicode": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+      "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ=="
+    },
     "node_modules/hasown": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
@@ -9877,6 +10220,14 @@
         "url": "https://github.com/chalk/supports-color?sponsor=1"
       }
     },
+    "node_modules/jmespath": {
+      "version": "0.15.0",
+      "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz",
+      "integrity": "sha512-+kHj8HXArPfpPEKGLZ+kB5ONRTCiGQXo8RQYL0hH8t6pWXUBBK5KkkQmTNOwKK4LEsd0yTsgtjJVm4UBSZea4w==",
+      "engines": {
+        "node": ">= 0.6.0"
+      }
+    },
     "node_modules/joi": {
       "version": "17.13.0",
       "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.0.tgz",
@@ -11147,6 +11498,17 @@
         "node": ">=4"
       }
     },
+    "node_modules/mimic-response": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
+      "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/minimatch": {
       "version": "3.1.2",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -11171,6 +11533,34 @@
         "node": ">=16 || 14 >=14.17"
       }
     },
+    "node_modules/minizlib": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
+      "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
+      "dependencies": {
+        "minipass": "^3.0.0",
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/minizlib/node_modules/minipass": {
+      "version": "3.3.6",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
+      "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/minizlib/node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+    },
     "node_modules/mitt": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz",
@@ -11615,6 +12005,16 @@
         "node": ">= 0.6"
       }
     },
+    "node_modules/mz": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+      "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+      "dependencies": {
+        "any-promise": "^1.0.0",
+        "object-assign": "^4.0.1",
+        "thenify-all": "^1.0.0"
+      }
+    },
     "node_modules/named-placeholders": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz",
@@ -11637,8 +12037,7 @@
     "node_modules/nan": {
       "version": "2.19.0",
       "resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz",
-      "integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==",
-      "optional": true
+      "integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw=="
     },
     "node_modules/natural-compare": {
       "version": "1.4.0",
@@ -11838,6 +12237,18 @@
         "node": ">=8"
       }
     },
+    "node_modules/npmlog": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz",
+      "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==",
+      "deprecated": "This package is no longer supported.",
+      "dependencies": {
+        "are-we-there-yet": "^2.0.0",
+        "console-control-strings": "^1.1.0",
+        "gauge": "^3.0.0",
+        "set-blocking": "^2.0.0"
+      }
+    },
     "node_modules/nullthrows": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz",
@@ -11882,7 +12293,6 @@
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
       "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
-      "dev": true,
       "engines": {
         "node": ">= 0.4"
       }
@@ -11891,7 +12301,6 @@
       "version": "4.1.5",
       "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz",
       "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==",
-      "dev": true,
       "dependencies": {
         "call-bind": "^1.0.5",
         "define-properties": "^1.2.1",
@@ -12438,6 +12847,15 @@
       "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
       "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ=="
     },
+    "node_modules/path": {
+      "version": "0.12.7",
+      "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz",
+      "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==",
+      "dependencies": {
+        "process": "^0.11.1",
+        "util": "^0.10.3"
+      }
+    },
     "node_modules/path-exists": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -12880,6 +13298,14 @@
       "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
       "optional": true
     },
+    "node_modules/process": {
+      "version": "0.11.10",
+      "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+      "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+      "engines": {
+        "node": ">= 0.6.0"
+      }
+    },
     "node_modules/process-nextick-args": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -13233,11 +13659,19 @@
       "resolved": "https://registry.npmjs.org/query-selector-shadow-dom/-/query-selector-shadow-dom-1.0.1.tgz",
       "integrity": "sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw=="
     },
+    "node_modules/querystring": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
+      "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==",
+      "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.",
+      "engines": {
+        "node": ">=0.4.x"
+      }
+    },
     "node_modules/queue": {
       "version": "6.0.2",
       "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
       "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==",
-      "optional": true,
       "dependencies": {
         "inherits": "~2.0.3"
       }
@@ -13694,6 +14128,29 @@
       "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
       "optional": true
     },
+    "node_modules/resemblejs": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resemblejs/-/resemblejs-4.0.0.tgz",
+      "integrity": "sha512-vaGs/hFVx/941+RS4UJtd8DQvx5RuB61tPLOQCxPso3JpmjfDb6odH5HViT17S0d8DaZsexD01nRJI12giCz/A==",
+      "optionalDependencies": {
+        "canvas": "2.8.0"
+      }
+    },
+    "node_modules/resemblejs/node_modules/canvas": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.8.0.tgz",
+      "integrity": "sha512-gLTi17X8WY9Cf5GZ2Yns8T5lfBOcGgFehDFb+JQwDqdOoBOcECS9ZWMEAqMSVcMYwXD659J8NyzjRY/2aE+C2Q==",
+      "hasInstallScript": true,
+      "optional": true,
+      "dependencies": {
+        "@mapbox/node-pre-gyp": "^1.0.0",
+        "nan": "^2.14.0",
+        "simple-get": "^3.0.3"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/resolve": {
       "version": "1.22.8",
       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
@@ -13766,7 +14223,6 @@
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
       "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
-      "devOptional": true,
       "dependencies": {
         "glob": "^7.1.3"
       },
@@ -13781,7 +14237,6 @@
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
       "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
-      "devOptional": true,
       "dependencies": {
         "fs.realpath": "^1.0.0",
         "inflight": "^1.0.4",
@@ -13936,6 +14391,11 @@
         "node": ">=6"
       }
     },
+    "node_modules/sax": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz",
+      "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA=="
+    },
     "node_modules/scheduler": {
       "version": "0.24.0-canary-efb381bbf-20230505",
       "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.24.0-canary-efb381bbf-20230505.tgz",
@@ -14093,14 +14553,12 @@
     "node_modules/set-blocking": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
-      "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
-      "optional": true
+      "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
     },
     "node_modules/set-function-length": {
       "version": "1.2.2",
       "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
       "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
-      "dev": true,
       "dependencies": {
         "define-data-property": "^1.1.4",
         "es-errors": "^1.3.0",
@@ -14228,6 +14686,35 @@
       "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
       "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
     },
+    "node_modules/simple-concat": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
+      "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/simple-get": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
+      "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
+      "dependencies": {
+        "decompress-response": "^4.2.0",
+        "once": "^1.3.1",
+        "simple-concat": "^1.0.0"
+      }
+    },
     "node_modules/sisteransi": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
@@ -14911,6 +15398,25 @@
       "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
       "dev": true
     },
+    "node_modules/thenify": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+      "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+      "dependencies": {
+        "any-promise": "^1.0.0"
+      }
+    },
+    "node_modules/thenify-all": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+      "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
+      "dependencies": {
+        "thenify": ">= 3.1.0 < 4"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/throat": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz",
@@ -15348,6 +15854,20 @@
         "punycode": "^2.1.0"
       }
     },
+    "node_modules/url": {
+      "version": "0.10.3",
+      "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz",
+      "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==",
+      "dependencies": {
+        "punycode": "1.3.2",
+        "querystring": "0.2.0"
+      }
+    },
+    "node_modules/url/node_modules/punycode": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
+      "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw=="
+    },
     "node_modules/userhome": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/userhome/-/userhome-1.0.0.tgz",
@@ -15362,11 +15882,24 @@
       "integrity": "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==",
       "optional": true
     },
+    "node_modules/util": {
+      "version": "0.10.4",
+      "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
+      "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==",
+      "dependencies": {
+        "inherits": "2.0.3"
+      }
+    },
     "node_modules/util-deprecate": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
       "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
     },
+    "node_modules/util/node_modules/inherits": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+      "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw=="
+    },
     "node_modules/utils-merge": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
@@ -15545,6 +16078,14 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/wide-align": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
+      "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
+      "dependencies": {
+        "string-width": "^1.0.2 || 2 || 3 || 4"
+      }
+    },
     "node_modules/workerpool": {
       "version": "6.2.1",
       "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
@@ -15677,6 +16218,23 @@
       "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz",
       "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU="
     },
+    "node_modules/xml2js": {
+      "version": "0.4.19",
+      "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
+      "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
+      "dependencies": {
+        "sax": ">=0.6.0",
+        "xmlbuilder": "~9.0.1"
+      }
+    },
+    "node_modules/xmlbuilder": {
+      "version": "9.0.7",
+      "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
+      "integrity": "sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ==",
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
     "node_modules/xpath-builder": {
       "version": "0.0.7",
       "resolved": "https://registry.npmjs.org/xpath-builder/-/xpath-builder-0.0.7.tgz",
diff --git a/package.json b/package.json
index 24a8bf803..e830058df 100644
--- a/package.json
+++ b/package.json
@@ -29,6 +29,7 @@
     "codeceptjs-dbhelper": "^1.2.2",
     "codeceptjs-mailosaurhelper": "^1.0.5",
     "codeceptjs-postgresqlhelper": "^1.0.0",
+    "codeceptjs-resemblehelper": "^1.9.7",
     "faker": "^5.5.3",
     "form-data": "^4.0.0",
     "generate-password": "^1.7.1",
diff --git a/tests/pages/dashboardPage.js b/tests/pages/dashboardPage.js
index adca035a5..115adfcce 100644
--- a/tests/pages/dashboardPage.js
+++ b/tests/pages/dashboardPage.js
@@ -1307,7 +1307,7 @@ module.exports = {
   },
 
   panelByTitle(title) {
-    return I.useDataQA(`data-testid Panel header ${title}`);
+    return locate(I.useDataQA(`data-testid Panel header ${title}`));
   },
 
   panelDataByTitle(title) {
diff --git a/tests/qa-integration/pmm_psmdb_integration_test.js b/tests/qa-integration/pmm_psmdb_integration_test.js
index 809cca9c8..7e35cd963 100644
--- a/tests/qa-integration/pmm_psmdb_integration_test.js
+++ b/tests/qa-integration/pmm_psmdb_integration_test.js
@@ -226,46 +226,20 @@ Scenario('PMM-T1889 Verify Mongo replication lag graph shows correct info @pmm-p
   I.assertFalse(/min|hour|day|week|month|year/.test(maxValue), `Max replication value should be in seconds. Value is: ${maxValue}`);
 });
 
-Scenario('PMM-T1956 Verify Node States metrics when one node is down @pmm-psmdb-replica-integration', async ({
+Scenario('PMM-T1956 Verify Node States panel when one node is down @pmm-psmdb-replica-integration', async ({
   I, dashboardPage, grafanaAPI, inventoryAPI,
 }) => {
-  I.amOnPage(I.buildUrlWithParams(dashboardPage.mongodbReplicaSetSummaryDashboard.cleanUrl, { from: 'now-5m', refresh: '10s', replica_set: 'rs' }));
+  I.amOnPage(I.buildUrlWithParams(dashboardPage.mongodbReplicaSetSummaryDashboard.cleanUrl, {
+    from: 'now-15s',
+    refresh: '5s',
+    replica_set: 'rs',
+  }));
   dashboardPage.waitForDashboardOpened();
 
-  const { service_name: rs101ServiceName } = await inventoryAPI.apiGetNodeInfoByServiceName(SERVICE_TYPE.MONGODB, 'rs101');
-  const { service_name: rs102ServiceName } = await inventoryAPI.apiGetNodeInfoByServiceName(SERVICE_TYPE.MONGODB, 'rs102');
-  const { service_name: rs103ServiceName } = await inventoryAPI.apiGetNodeInfoByServiceName(SERVICE_TYPE.MONGODB, 'rs103');
-  const expression = `max by (service_name) (mongodb_mongod_replset_my_state{environment=~".*", cluster=~"replicaset", set=~"rs", service_name=~"(${rs101ServiceName}|${rs102ServiceName}|${rs103ServiceName})"})`;
-
-  const initialMetrics = await grafanaAPI.getMetric(expression, null);
-  const initialFrames = initialMetrics.data.results.A.frames;
-
-  assert.ok(initialFrames.length === 3, 'There should be 3 frames in the response');
-
   await I.verifyCommand('docker stop rs102');
-  let frames;
-
-  await I.asyncWaitFor(async () => {
-    const resp = await grafanaAPI.getMetric(expression, null, 1);
-
-    frames = resp.data.results.A.frames;
-
-    return frames.length === 2;
-  }, 120);
-
-  assert.ok(frames.length === 2, 'There should be 2 frames in the response');
-  const serviceNames = frames.map((frame) => frame.schema.fields[1].labels.service_name);
-
-  assert.ok(serviceNames.includes(rs101ServiceName), 'rs101 service name should be in the list');
-  assert.ok(serviceNames.includes(rs103ServiceName), 'rs103 service name should be in the list');
-
-  await I.verifyCommand('docker start rs102');
-
-  await I.asyncWaitFor(async () => {
-    const resp = await grafanaAPI.getMetric(expression, null, 1);
 
-    frames = resp.data.results.A.frames;
+  I.wait(30);
 
-    return frames.length === 3;
-  }, 120);
+  I.waitForElement(dashboardPage.panelByTitle('Node States').find('.u-over'), 15);
+  I.seeVisualDiffForElement(dashboardPage.panelByTitle('Node States').find('.u-over'), 'Mongo_down_nodes_states.png');
 });
diff --git a/tests/screenshots/base/Mongo_down_nodes_states.png b/tests/screenshots/base/Mongo_down_nodes_states.png
new file mode 100644
index 0000000000000000000000000000000000000000..b9830f38bdcf5abc59cd9a8bdcc65b4450d15efc
GIT binary patch
literal 4618
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
B_q+fA

literal 0
HcmV?d00001


From 3f821604d155996d782863a0a598369d8388e2a4 Mon Sep 17 00:00:00 2001
From: yurkovychv <vasyl.yurkovych@percona.com>
Date: Thu, 19 Dec 2024 17:38:55 +0200
Subject: [PATCH 5/7] PMM-13620 add visual comparison for the panel

---
 tests/qa-integration/pmm_psmdb_integration_test.js | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/tests/qa-integration/pmm_psmdb_integration_test.js b/tests/qa-integration/pmm_psmdb_integration_test.js
index 7e35cd963..2f48790b4 100644
--- a/tests/qa-integration/pmm_psmdb_integration_test.js
+++ b/tests/qa-integration/pmm_psmdb_integration_test.js
@@ -7,6 +7,10 @@ Before(async ({ I }) => {
   await I.Authorize();
 });
 
+After(async ({ I }) => {
+  await I.verifyCommand('docker start rs102');
+});
+
 const version = process.env.PSMDB_VERSION ? `${process.env.PSMDB_VERSION}` : '4.4';
 const replica_container_name = `psmdb_pmm_${version}_replica`;
 const regular_container_name = `psmdb_pmm_${version}_regular`;

From 078132ad9272034d6295feecffc47a47960ab8f2 Mon Sep 17 00:00:00 2001
From: yurkovychv <vasyl.yurkovych@percona.com>
Date: Fri, 20 Dec 2024 10:48:37 +0200
Subject: [PATCH 6/7] PMM-13620 include config changes

---
 pr.codecept.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/pr.codecept.js b/pr.codecept.js
index f21e28fca..b3047f2d7 100644
--- a/pr.codecept.js
+++ b/pr.codecept.js
@@ -92,6 +92,12 @@ exports.config = {
     ApiHelper: {
       require: './tests/helper/apiHelper.js',
     },
+    ResembleHelper: {
+      require: 'codeceptjs-resemblehelper',
+      baseFolder: './tests/screenshots/base/',
+      diffFolder: './tests/screenshots/diff/',
+      prepareBaseImage: true,
+    },
   },
   include: pageObjects,
   multiple: {

From faa85e86969515ad8a1c70bd6da7818e13ff9f3e Mon Sep 17 00:00:00 2001
From: yurkovychv <vasyl.yurkovych@percona.com>
Date: Fri, 20 Dec 2024 11:57:28 +0200
Subject: [PATCH 7/7] PMM-13620 fix test

---
 tests/qa-integration/pmm_psmdb_integration_test.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/tests/qa-integration/pmm_psmdb_integration_test.js b/tests/qa-integration/pmm_psmdb_integration_test.js
index 2f48790b4..c7f68fdcc 100644
--- a/tests/qa-integration/pmm_psmdb_integration_test.js
+++ b/tests/qa-integration/pmm_psmdb_integration_test.js
@@ -245,5 +245,6 @@ Scenario('PMM-T1956 Verify Node States panel when one node is down @pmm-psmdb-re
   I.wait(30);
 
   I.waitForElement(dashboardPage.panelByTitle('Node States').find('.u-over'), 15);
-  I.seeVisualDiffForElement(dashboardPage.panelByTitle('Node States').find('.u-over'), 'Mongo_down_nodes_states.png');
+  I.screenshotElement(dashboardPage.panelByTitle('Node States').find('.u-over'), 'Mongo_down_nodes_states');
+  I.seeVisualDiffForElement(dashboardPage.panelByTitle('Node States').find('.u-over'), 'Mongo_down_nodes_states.png', { prepareBaseImage: false });
 });