From feca2480e5f7eac79403ff2c8ccf5a84f41042ca Mon Sep 17 00:00:00 2001 From: Miki-Session Date: Tue, 12 Nov 2024 15:55:51 +1100 Subject: [PATCH 01/21] feat: compareColors function --- package.json | 4 +- run/test/specs/utils/check_colour.ts | 26 +++ yarn.lock | 247 ++++++++++++++++++++++++++- 3 files changed, 269 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 7658e066..cd9a2a18 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,6 @@ "test-parallel": "_TESTING=1 npx playwright test ./run/test/**/*.spec.ts --grep ios", "test-high-risk-android": "_TESTING=1 npx playwright test --timeout 300000 ./run/test/**/*.spec.ts --grep 'android @high-risk'", "test-high-risk-ios": "_TESTING=1 npx playwright test --timeout 300000 ./run/test/**/*.spec.ts --grep 'ios @high-risk'" - }, "devDependencies": { "@appium/execute-driver-plugin": "^3.0.1", @@ -47,7 +46,8 @@ "appium": "^2.4.1", "appium-uiautomator2-driver": "patch:appium-uiautomator2-driver@npm%3A3.7.3#~/patches/appium-uiautomator2-driver-npm-3.7.3-24e944f6c5.patch", "appium-xcuitest-driver": "^7.26.0", - "dotenv": "^16.4.5" + "dotenv": "^16.4.5", + "looks-same": "^9.0.1" }, "packageManager": "yarn@4.0.2", "resolutions": { diff --git a/run/test/specs/utils/check_colour.ts b/run/test/specs/utils/check_colour.ts index e0669c3d..537e8f87 100644 --- a/run/test/specs/utils/check_colour.ts +++ b/run/test/specs/utils/check_colour.ts @@ -1,4 +1,5 @@ import PNG from 'png-js'; +import { colors } from 'looks-same'; export async function parseDataImage(base64: string) { const buffer = Buffer.from(base64, 'base64'); @@ -23,3 +24,28 @@ export async function parseDataImage(base64: string) { // console.info("Middle x:", middleX, "middleY:", middleY, "width:", width); return pixelColor; } + +// Function to compare two colors within a specified CIEDE2000 tolerance +export async function compareColors( + hex1: string, + hex2: string, + tolerance: number = 2.3 // looks-same default value which is "enough for most cases" +): Promise { + // looks-same expects colors as RGB objects but parseDataImage outputs hex + function hexToRgbObject(hex: string): { R: number; G: number; B: number } { + const bigint = parseInt(hex.replace('#', ''), 16); + return { + R: (bigint >> 16) & 255, + G: (bigint >> 8) & 255, + B: bigint & 255, + }; + } + // RGB-HEX conversion + const rgb1 = hexToRgbObject(hex1); + const rgb2 = hexToRgbObject(hex2); + + // Compare whether colors are within tolerance + const isSameColor = colors(rgb1, rgb2, { tolerance }); + + return isSameColor +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 040a4459..f7470f2f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2643,6 +2643,13 @@ __metadata: languageName: node linkType: hard +"chownr@npm:^1.1.1": + version: 1.1.4 + resolution: "chownr@npm:1.1.4" + checksum: ed57952a84cc0c802af900cf7136de643d3aba2eecb59d29344bc2f3f9bf703a301b9d84cdc71f82c3ffc9ccde831b0d92f5b45f91727d6c9da62f23aef9d9db + languageName: node + linkType: hard + "chownr@npm:^2.0.0": version: 2.0.0 resolution: "chownr@npm:2.0.0" @@ -2720,6 +2727,20 @@ __metadata: languageName: node linkType: hard +"color-convert@npm:~0.5.0": + version: 0.5.3 + resolution: "color-convert@npm:0.5.3" + checksum: 324b863446bab6c5f88cb0010c3a16a6ca6bf6709eb7b7b3482d3e9ca6cfcfa690c25c1151bd2dc6279a0f4e2c593630486a2b9caae3c3eb96b82f5408e23e54 + languageName: node + linkType: hard + +"color-diff@npm:^1.1.0": + version: 1.4.0 + resolution: "color-diff@npm:1.4.0" + checksum: c52eeef1d0b0a60482fb7a16070b86db2b15d1730fbfca0876deb1e21eebf4769473fdb90982bcba9a38d53c45b83cc3a2467e530d219a64053cd849b96351cb + languageName: node + linkType: hard + "color-name@npm:1.1.3": version: 1.1.3 resolution: "color-name@npm:1.1.3" @@ -3098,6 +3119,13 @@ __metadata: languageName: node linkType: hard +"deep-extend@npm:^0.6.0": + version: 0.6.0 + resolution: "deep-extend@npm:0.6.0" + checksum: 1c6b0abcdb901e13a44c7d699116d3d4279fdb261983122a3783e7273844d5f2537dc2e1c454a23fcf645917f93fbf8d07101c1d03c015a87faa662755212566 + languageName: node + linkType: hard + "deep-is@npm:^0.1.3": version: 0.1.4 resolution: "deep-is@npm:0.1.4" @@ -3178,7 +3206,7 @@ __metadata: languageName: node linkType: hard -"detect-libc@npm:^2.0.3": +"detect-libc@npm:^2.0.0, detect-libc@npm:^2.0.2, detect-libc@npm:^2.0.3": version: 2.0.3 resolution: "detect-libc@npm:2.0.3" checksum: 88095bda8f90220c95f162bf92cad70bd0e424913e655c20578600e35b91edc261af27531cf160a331e185c0ced93944bc7e09939143225f56312d7fd800fdb7 @@ -3596,6 +3624,13 @@ __metadata: languageName: node linkType: hard +"expand-template@npm:^2.0.3": + version: 2.0.3 + resolution: "expand-template@npm:2.0.3" + checksum: 1c9e7afe9acadf9d373301d27f6a47b34e89b3391b1ef38b7471d381812537ef2457e620ae7f819d2642ce9c43b189b3583813ec395e2938319abe356a9b2f51 + languageName: node + linkType: hard + "exponential-backoff@npm:^3.1.1": version: 3.1.1 resolution: "exponential-backoff@npm:3.1.1" @@ -4019,6 +4054,17 @@ __metadata: languageName: node linkType: hard +"fs-extra@npm:^8.1.0": + version: 8.1.0 + resolution: "fs-extra@npm:8.1.0" + dependencies: + graceful-fs: "npm:^4.2.0" + jsonfile: "npm:^4.0.0" + universalify: "npm:^0.1.0" + checksum: 259f7b814d9e50d686899550c4f9ded85c46c643f7fe19be69504888e007fcbc08f306fae8ec495b8b998635e997c9e3e175ff2eeed230524ef1c1684cc96423 + languageName: node + linkType: hard + "fs-minipass@npm:^2.0.0": version: 2.1.0 resolution: "fs-minipass@npm:2.1.0" @@ -4161,6 +4207,13 @@ __metadata: languageName: node linkType: hard +"github-from-package@npm:0.0.0": + version: 0.0.0 + resolution: "github-from-package@npm:0.0.0" + checksum: 737ee3f52d0a27e26332cde85b533c21fcdc0b09fb716c3f8e522cfaa9c600d4a631dec9fcde179ec9d47cca89017b7848ed4d6ae6b6b78f936c06825b1fcc12 + languageName: node + linkType: hard + "glob-parent@npm:^5.1.2": version: 5.1.2 resolution: "glob-parent@npm:5.1.2" @@ -4575,6 +4628,13 @@ __metadata: languageName: node linkType: hard +"ini@npm:~1.3.0": + version: 1.3.8 + resolution: "ini@npm:1.3.8" + checksum: ec93838d2328b619532e4f1ff05df7909760b6f66d9c9e2ded11e5c1897d6f2f9980c54dd638f88654b00919ce31e827040631eab0a3969e4d1abefa0719516a + languageName: node + linkType: hard + "io.appium.settings@npm:^5.12.0": version: 5.12.6 resolution: "io.appium.settings@npm:5.12.6" @@ -4766,6 +4826,15 @@ __metadata: languageName: node linkType: hard +"js-graph-algorithms@npm:1.0.18": + version: 1.0.18 + resolution: "js-graph-algorithms@npm:1.0.18" + bin: + js-graphs: ./src/jsgraphs.js + checksum: d5ee2b39d4c57776847b38f9194d55429ffbd6b5b41d7bae821abb8d6f27ed0e03516944ddb17cfa351dff5f083678c6400d24aeb7deb4b71075a3ec5372833b + languageName: node + linkType: hard + "js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" @@ -4877,6 +4946,18 @@ __metadata: languageName: node linkType: hard +"jsonfile@npm:^4.0.0": + version: 4.0.0 + resolution: "jsonfile@npm:4.0.0" + dependencies: + graceful-fs: "npm:^4.1.6" + dependenciesMeta: + graceful-fs: + optional: true + checksum: 7dc94b628d57a66b71fb1b79510d460d662eb975b5f876d723f81549c2e9cd316d58a2ddf742b2b93a4fa6b17b2accaf1a738a0e2ea114bdfb13a32e5377e480 + languageName: node + linkType: hard + "jsonfile@npm:^6.0.1": version: 6.1.0 resolution: "jsonfile@npm:6.1.0" @@ -5085,7 +5166,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:4.17.21, lodash@npm:^4.0.0, lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.21, lodash@npm:^4.17.4, lodash@npm:^4.2.1": +"lodash@npm:4.17.21, lodash@npm:^4.0.0, lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.21, lodash@npm:^4.17.3, lodash@npm:^4.17.4, lodash@npm:^4.2.1": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c @@ -5130,6 +5211,21 @@ __metadata: languageName: node linkType: hard +"looks-same@npm:^9.0.1": + version: 9.0.1 + resolution: "looks-same@npm:9.0.1" + dependencies: + color-diff: "npm:^1.1.0" + fs-extra: "npm:^8.1.0" + js-graph-algorithms: "npm:1.0.18" + lodash: "npm:^4.17.3" + nested-error-stacks: "npm:^2.1.0" + parse-color: "npm:^1.0.0" + sharp: "npm:0.32.6" + checksum: 31453ed27b130ff8798f13dab0aac6305acf545d5770d2d18f7a35bc0e7e00b1bf03033c40c3230d86a8e6dfcf0fd73411390d2e1b4bdc3b128cec4b44543d52 + languageName: node + linkType: hard + "lowercase-keys@npm:^3.0.0": version: 3.0.0 resolution: "lowercase-keys@npm:3.0.0" @@ -5322,7 +5418,7 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.2.6": +"minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.6": version: 1.2.8 resolution: "minimist@npm:1.2.8" checksum: 19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6 @@ -5420,7 +5516,7 @@ __metadata: languageName: node linkType: hard -"mkdirp-classic@npm:^0.5.2": +"mkdirp-classic@npm:^0.5.2, mkdirp-classic@npm:^0.5.3": version: 0.5.3 resolution: "mkdirp-classic@npm:0.5.3" checksum: 95371d831d196960ddc3833cc6907e6b8f67ac5501a6582f47dfae5eb0f092e9f8ce88e0d83afcae95d6e2b61a01741ba03714eeafb6f7a6e9dcc158ac85b168 @@ -5515,6 +5611,13 @@ __metadata: languageName: node linkType: hard +"napi-build-utils@npm:^1.0.1": + version: 1.0.2 + resolution: "napi-build-utils@npm:1.0.2" + checksum: 37fd2cd0ff2ad20073ce78d83fd718a740d568b225924e753ae51cb69d68f330c80544d487e5e5bd18e28702ed2ca469c2424ad948becd1862c1b0209542b2e9 + languageName: node + linkType: hard + "natural-compare-lite@npm:^1.4.0": version: 1.4.0 resolution: "natural-compare-lite@npm:1.4.0" @@ -5552,6 +5655,13 @@ __metadata: languageName: node linkType: hard +"nested-error-stacks@npm:^2.1.0": + version: 2.1.1 + resolution: "nested-error-stacks@npm:2.1.1" + checksum: feec00417e4778661cfbbe657e6add6ca9918dcc026cd697ac330b4a56a79e4882b36dde8abc138167566b1ce4c5baa17d2d4df727a96f8b96aebace1c3ffca7 + languageName: node + linkType: hard + "netmask@npm:^2.0.2": version: 2.0.2 resolution: "netmask@npm:2.0.2" @@ -5559,6 +5669,24 @@ __metadata: languageName: node linkType: hard +"node-abi@npm:^3.3.0": + version: 3.71.0 + resolution: "node-abi@npm:3.71.0" + dependencies: + semver: "npm:^7.3.5" + checksum: dbd0792ea729329cd9d099f28a5681ff9e8a6db48cf64e1437bf6a7fd669009d1e758a784619a1c4cc8bfd1ed17162f042c787654edf19a1f64b5018457c9c1f + languageName: node + linkType: hard + +"node-addon-api@npm:^6.1.0": + version: 6.1.0 + resolution: "node-addon-api@npm:6.1.0" + dependencies: + node-gyp: "npm:latest" + checksum: d2699c4ad15740fd31482a3b6fca789af7723ab9d393adc6ac45250faaee72edad8f0b10b2b9d087df0de93f1bdc16d97afdd179b26b9ebc9ed68b569faa4bac + languageName: node + linkType: hard + "node-domexception@npm:^1.0.0": version: 1.0.0 resolution: "node-domexception@npm:1.0.0" @@ -5871,6 +5999,15 @@ __metadata: languageName: node linkType: hard +"parse-color@npm:^1.0.0": + version: 1.0.0 + resolution: "parse-color@npm:1.0.0" + dependencies: + color-convert: "npm:~0.5.0" + checksum: 53b864bd91f9e3134e8d05b834c42c9ece76c6c3426fe979c36fc0452cfd9c8cbe8c7497cd7ddd8436a5878cd43af982a5eaf85908f69a6de0fe3daf122b65f7 + languageName: node + linkType: hard + "parse-json@npm:^5.0.0": version: 5.2.0 resolution: "parse-json@npm:5.2.0" @@ -6059,6 +6196,28 @@ __metadata: languageName: node linkType: hard +"prebuild-install@npm:^7.1.1": + version: 7.1.2 + resolution: "prebuild-install@npm:7.1.2" + dependencies: + detect-libc: "npm:^2.0.0" + expand-template: "npm:^2.0.3" + github-from-package: "npm:0.0.0" + minimist: "npm:^1.2.3" + mkdirp-classic: "npm:^0.5.3" + napi-build-utils: "npm:^1.0.1" + node-abi: "npm:^3.3.0" + pump: "npm:^3.0.0" + rc: "npm:^1.2.7" + simple-get: "npm:^4.0.0" + tar-fs: "npm:^2.0.0" + tunnel-agent: "npm:^0.6.0" + bin: + prebuild-install: bin.js + checksum: e64868ba9ef2068fd7264f5b03e5298a901e02a450acdb1f56258d88c09dea601eefdb3d1dfdff8513fdd230a92961712be0676192626a3b4d01ba154d48bdd3 + languageName: node + linkType: hard + "prelude-ls@npm:^1.2.1": version: 1.2.1 resolution: "prelude-ls@npm:1.2.1" @@ -6291,6 +6450,20 @@ __metadata: languageName: node linkType: hard +"rc@npm:^1.2.7": + version: 1.2.8 + resolution: "rc@npm:1.2.8" + dependencies: + deep-extend: "npm:^0.6.0" + ini: "npm:~1.3.0" + minimist: "npm:^1.2.0" + strip-json-comments: "npm:~2.0.1" + bin: + rc: ./cli.js + checksum: 24a07653150f0d9ac7168e52943cc3cb4b7a22c0e43c7dff3219977c2fdca5a2760a304a029c20811a0e79d351f57d46c9bde216193a0f73978496afc2b85b15 + languageName: node + linkType: hard + "read-pkg@npm:5.2.0": version: 5.2.0 resolution: "read-pkg@npm:5.2.0" @@ -6734,6 +6907,7 @@ __metadata: dotenv: "npm:^16.4.5" eslint: "npm:^8.33.0" lodash: "npm:^4.17.21" + looks-same: "npm:^9.0.1" png-js: "npm:^1.0.0" prettier: "npm:^3.3.3" ts-node: "npm:^10.9.1" @@ -6778,6 +6952,23 @@ __metadata: languageName: node linkType: hard +"sharp@npm:0.32.6": + version: 0.32.6 + resolution: "sharp@npm:0.32.6" + dependencies: + color: "npm:^4.2.3" + detect-libc: "npm:^2.0.2" + node-addon-api: "npm:^6.1.0" + node-gyp: "npm:latest" + prebuild-install: "npm:^7.1.1" + semver: "npm:^7.5.4" + simple-get: "npm:^4.0.1" + tar-fs: "npm:^3.0.4" + tunnel-agent: "npm:^0.6.0" + checksum: f6a756fec5051ef2f9341e0543cde1da4e822982dd5398010baad92e2262bd177e08b753eb19b2fbee30f2fcb0e8756f24088fafc48293a364e9a8f8dc65a300 + languageName: node + linkType: hard + "sharp@npm:0.33.4": version: 0.33.4 resolution: "sharp@npm:0.33.4" @@ -6896,6 +7087,24 @@ __metadata: languageName: node linkType: hard +"simple-concat@npm:^1.0.0": + version: 1.0.1 + resolution: "simple-concat@npm:1.0.1" + checksum: 62f7508e674414008910b5397c1811941d457dfa0db4fd5aa7fa0409eb02c3609608dfcd7508cace75b3a0bf67a2a77990711e32cd213d2c76f4fd12ee86d776 + languageName: node + linkType: hard + +"simple-get@npm:^4.0.0, simple-get@npm:^4.0.1": + version: 4.0.1 + resolution: "simple-get@npm:4.0.1" + dependencies: + decompress-response: "npm:^6.0.0" + once: "npm:^1.3.1" + simple-concat: "npm:^1.0.0" + checksum: b0649a581dbca741babb960423248899203165769747142033479a7dc5e77d7b0fced0253c731cd57cf21e31e4d77c9157c3069f4448d558ebc96cf9e1eebcf0 + languageName: node + linkType: hard + "simple-swizzle@npm:^0.2.2": version: 0.2.2 resolution: "simple-swizzle@npm:0.2.2" @@ -7209,6 +7418,13 @@ __metadata: languageName: node linkType: hard +"strip-json-comments@npm:~2.0.1": + version: 2.0.1 + resolution: "strip-json-comments@npm:2.0.1" + checksum: b509231cbdee45064ff4f9fd73609e2bcc4e84a4d508e9dd0f31f70356473fde18abfb5838c17d56fb236f5a06b102ef115438de0600b749e818a35fbbc48c43 + languageName: node + linkType: hard + "supports-color@npm:8.1.1": version: 8.1.1 resolution: "supports-color@npm:8.1.1" @@ -7254,7 +7470,19 @@ __metadata: languageName: node linkType: hard -"tar-fs@npm:^3.0.6": +"tar-fs@npm:^2.0.0": + version: 2.1.1 + resolution: "tar-fs@npm:2.1.1" + dependencies: + chownr: "npm:^1.1.1" + mkdirp-classic: "npm:^0.5.2" + pump: "npm:^3.0.0" + tar-stream: "npm:^2.1.4" + checksum: 871d26a934bfb7beeae4c4d8a09689f530b565f79bd0cf489823ff0efa3705da01278160da10bb006d1a793fa0425cf316cec029b32a9159eacbeaff4965fb6d + languageName: node + linkType: hard + +"tar-fs@npm:^3.0.4, tar-fs@npm:^3.0.6": version: 3.0.6 resolution: "tar-fs@npm:3.0.6" dependencies: @@ -7271,7 +7499,7 @@ __metadata: languageName: node linkType: hard -"tar-stream@npm:^2.1.0": +"tar-stream@npm:^2.1.0, tar-stream@npm:^2.1.4": version: 2.2.0 resolution: "tar-stream@npm:2.2.0" dependencies: @@ -7650,6 +7878,13 @@ __metadata: languageName: node linkType: hard +"universalify@npm:^0.1.0": + version: 0.1.2 + resolution: "universalify@npm:0.1.2" + checksum: e70e0339f6b36f34c9816f6bf9662372bd241714dc77508d231d08386d94f2c4aa1ba1318614f92015f40d45aae1b9075cd30bd490efbe39387b60a76ca3f045 + languageName: node + linkType: hard + "universalify@npm:^2.0.0": version: 2.0.1 resolution: "universalify@npm:2.0.1" From 79589323c8cf52afade2dc966ddc87e7bf115c0e Mon Sep 17 00:00:00 2001 From: Miki-Session Date: Tue, 12 Nov 2024 15:56:09 +1100 Subject: [PATCH 02/21] feat: check avatar color test spec --- run/test/specs/check_avatar_color.spec.ts | 47 +++++++++++++++++++++++ run/test/specs/locators/conversation.ts | 19 +++++++++ run/test/specs/locators/home.ts | 10 +++++ run/types/testing.ts | 6 +-- 4 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 run/test/specs/check_avatar_color.spec.ts diff --git a/run/test/specs/check_avatar_color.spec.ts b/run/test/specs/check_avatar_color.spec.ts new file mode 100644 index 00000000..bd441d61 --- /dev/null +++ b/run/test/specs/check_avatar_color.spec.ts @@ -0,0 +1,47 @@ +import { bothPlatformsIt } from '../../types/sessionIt'; +import { USERNAME } from '../../types/testing'; +import { newUser } from './utils/create_account'; +import { newContact } from './utils/create_contact'; +import { SupportedPlatformsType, closeApp, openAppTwoDevices } from './utils/open_app'; +import { compareColors, parseDataImage } from './utils/check_colour'; +import { UserSettings } from './locators/settings'; +import { ConversationItem } from './locators/home'; +import { ConversationAvatar, ConversationSettings } from './locators/conversation'; + +bothPlatformsIt('Avatar color', 'medium', avatarColor); + +async function avatarColor(platform: SupportedPlatformsType) { + const result = compareColors("6fd0fa", "ffffff") + console.log(result) + const { device1, device2 } = await openAppTwoDevices(platform); + const [userA, userB] = await Promise.all([ + newUser(device1, USERNAME.ALICE, platform), + newUser(device2, USERNAME.BOB, platform), + ]); + await newContact(platform, device1, userA, device2, userB); + await device1.navigateBack(); + await device2.navigateBack(); + // Get Alice's avatar color on device 1 and turn it into a hex value + const device1Avatar = await device1.waitForTextElementToBePresent(new UserSettings(device1)); + const device1Base64 = await device1.getElementScreenshot(device1Avatar.ELEMENT); + const device1PixelColor = await parseDataImage(device1Base64); + await device2.clickOnElementAll(new ConversationItem(device2)) + // Get Alice's avatar color on device 2 and turn it into a hex value + let device2Avatar; + if (platform === 'ios') { + device2Avatar = await device2.waitForTextElementToBePresent(new ConversationSettings(device2)); + } else { + device2Avatar = await device2.waitForTextElementToBePresent(new ConversationAvatar(device2)); + } + const device2Base64 = await device2.getElementScreenshot(device2Avatar.ELEMENT); + const device2PixelColor = await parseDataImage(device2Base64) + // Color comparison of devices 1 and 2 + console.log(`The colors are ${device1PixelColor} and ${device2PixelColor}`) + const colorCompare = await compareColors(device1PixelColor, device2PixelColor) + if (!colorCompare) { + throw new Error (`The avatar color of ${userA.userName} does not match across devices. The colors are ${device1PixelColor} and ${device2PixelColor}`) + } else { + console.log(`The default avatar color of ${userA.userName} is within tolerance across devices.`) + } + await closeApp(device1, device2); +} diff --git a/run/test/specs/locators/conversation.ts b/run/test/specs/locators/conversation.ts index a3d2c888..be429f97 100644 --- a/run/test/specs/locators/conversation.ts +++ b/run/test/specs/locators/conversation.ts @@ -7,4 +7,23 @@ export class MessageInput extends LocatorsInterface { selector: 'Message input box', } as const; } +} + +export class ConversationSettings extends LocatorsInterface { + public build() { + return { + strategy: 'accessibility id', + selector: 'More options' + } as const; + } +} + +// android-only locator for the avatar +export class ConversationAvatar extends LocatorsInterface { + public build() { + return { + strategy: 'id', + selector: 'network.loki.messenger:id/singleModeImageView' + } as const + } } \ No newline at end of file diff --git a/run/test/specs/locators/home.ts b/run/test/specs/locators/home.ts index 8b2c9fb4..574a2a07 100644 --- a/run/test/specs/locators/home.ts +++ b/run/test/specs/locators/home.ts @@ -1,6 +1,16 @@ import { StrategyExtractionObj } from '../../../types/testing'; import { LocatorsInterface } from './index'; +export class ConversationItem extends LocatorsInterface { + public build(text?: string) { + return { + strategy: 'accessibility id', + selector: 'Conversation list item', + text: text + } as const; + } +} + export class PlusButton extends LocatorsInterface { public build() { return { diff --git a/run/types/testing.ts b/run/types/testing.ts index 71898daf..4b75b789 100644 --- a/run/types/testing.ts +++ b/run/types/testing.ts @@ -360,9 +360,9 @@ export type Id = | 'network.loki.messenger:id/action_apply' | 'Save' | 'android:id/content_preview_text' - | 'network.loki.messenger:id/search_result_title'; - | 'Error message'; - | 'network.loki.messenger:id/action_apply'; + | 'network.loki.messenger:id/search_result_title' + | 'network.loki.messenger:id/action_apply' + | 'network.loki.messenger:id/singleModeImageView'; export type testRisk = | 'high' From d48f22057d87ab980b53f5fbdb68a8215a40ba8a Mon Sep 17 00:00:00 2001 From: Miki-Session Date: Tue, 12 Nov 2024 16:43:35 +1100 Subject: [PATCH 03/21] remove logging --- run/test/specs/check_avatar_color.spec.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/run/test/specs/check_avatar_color.spec.ts b/run/test/specs/check_avatar_color.spec.ts index bd441d61..27fdcfa4 100644 --- a/run/test/specs/check_avatar_color.spec.ts +++ b/run/test/specs/check_avatar_color.spec.ts @@ -11,8 +11,6 @@ import { ConversationAvatar, ConversationSettings } from './locators/conversatio bothPlatformsIt('Avatar color', 'medium', avatarColor); async function avatarColor(platform: SupportedPlatformsType) { - const result = compareColors("6fd0fa", "ffffff") - console.log(result) const { device1, device2 } = await openAppTwoDevices(platform); const [userA, userB] = await Promise.all([ newUser(device1, USERNAME.ALICE, platform), @@ -36,7 +34,6 @@ async function avatarColor(platform: SupportedPlatformsType) { const device2Base64 = await device2.getElementScreenshot(device2Avatar.ELEMENT); const device2PixelColor = await parseDataImage(device2Base64) // Color comparison of devices 1 and 2 - console.log(`The colors are ${device1PixelColor} and ${device2PixelColor}`) const colorCompare = await compareColors(device1PixelColor, device2PixelColor) if (!colorCompare) { throw new Error (`The avatar color of ${userA.userName} does not match across devices. The colors are ${device1PixelColor} and ${device2PixelColor}`) From 95da703111561f53593b845d7d8548efdbcacd93 Mon Sep 17 00:00:00 2001 From: Miki-Session Date: Tue, 12 Nov 2024 16:43:51 +1100 Subject: [PATCH 04/21] add separate linked device spec --- .../specs/linked_device_avatar_color.spec.ts | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 run/test/specs/linked_device_avatar_color.spec.ts diff --git a/run/test/specs/linked_device_avatar_color.spec.ts b/run/test/specs/linked_device_avatar_color.spec.ts new file mode 100644 index 00000000..387e9830 --- /dev/null +++ b/run/test/specs/linked_device_avatar_color.spec.ts @@ -0,0 +1,30 @@ +import { bothPlatformsIt } from '../../types/sessionIt'; +import { USERNAME } from '../../types/testing'; +import { linkedDevice } from './utils/link_device'; +import { SupportedPlatformsType, closeApp, openAppTwoDevices } from './utils/open_app'; +import { compareColors, parseDataImage } from './utils/check_colour'; +import { UserSettings } from './locators/settings'; + +bothPlatformsIt('Avatar color linked device', 'medium', avatarColorLinkedDevice); + +async function avatarColorLinkedDevice(platform: SupportedPlatformsType) { + const { device1, device2 } = await openAppTwoDevices(platform); + const userA = await linkedDevice(device1, device2, USERNAME.ALICE, platform); + // Get Alice's avatar color on device 1 and turn it into a hex value + const device1Avatar = await device1.waitForTextElementToBePresent(new UserSettings(device1)); + const device1Base64 = await device1.getElementScreenshot(device1Avatar.ELEMENT); + const device1PixelColor = await parseDataImage(device1Base64); + // Get Alice's avatar color on the linked device and turn it into a hex value + const device2Avatar = await device2.waitForTextElementToBePresent(new UserSettings(device2)); + const device2Base64 = await device2.getElementScreenshot(device2Avatar.ELEMENT); + const device2PixelColor = await parseDataImage(device2Base64) + // Color comparison of devices 1 and 2 + console.log(`The colors are ${device1PixelColor} and ${device2PixelColor}`) + const colorCompare = await compareColors(device1PixelColor, device2PixelColor) + if (!colorCompare) { + throw new Error (`The avatar color of ${userA.userName} does not match across devices. The colors are ${device1PixelColor} and ${device2PixelColor}`) + } else { + console.log(`The default avatar color of ${userA.userName} is within tolerance across devices.`) + } + await closeApp(device1, device2); +} From 573260f04d3443f633cbe5ee0f2b01e4ce0cdb87 Mon Sep 17 00:00:00 2001 From: Miki-Session Date: Wed, 13 Nov 2024 11:29:45 +1100 Subject: [PATCH 05/21] compareColors doesn't need to be async --- run/test/specs/check_avatar_color.spec.ts | 4 ++-- run/test/specs/linked_device_avatar_color.spec.ts | 3 +-- run/test/specs/utils/check_colour.ts | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/run/test/specs/check_avatar_color.spec.ts b/run/test/specs/check_avatar_color.spec.ts index 27fdcfa4..fb80e16f 100644 --- a/run/test/specs/check_avatar_color.spec.ts +++ b/run/test/specs/check_avatar_color.spec.ts @@ -23,8 +23,8 @@ async function avatarColor(platform: SupportedPlatformsType) { const device1Avatar = await device1.waitForTextElementToBePresent(new UserSettings(device1)); const device1Base64 = await device1.getElementScreenshot(device1Avatar.ELEMENT); const device1PixelColor = await parseDataImage(device1Base64); - await device2.clickOnElementAll(new ConversationItem(device2)) // Get Alice's avatar color on device 2 and turn it into a hex value + await device2.clickOnElementAll(new ConversationItem(device2)) let device2Avatar; if (platform === 'ios') { device2Avatar = await device2.waitForTextElementToBePresent(new ConversationSettings(device2)); @@ -34,7 +34,7 @@ async function avatarColor(platform: SupportedPlatformsType) { const device2Base64 = await device2.getElementScreenshot(device2Avatar.ELEMENT); const device2PixelColor = await parseDataImage(device2Base64) // Color comparison of devices 1 and 2 - const colorCompare = await compareColors(device1PixelColor, device2PixelColor) + const colorCompare = compareColors(device1PixelColor, device2PixelColor) if (!colorCompare) { throw new Error (`The avatar color of ${userA.userName} does not match across devices. The colors are ${device1PixelColor} and ${device2PixelColor}`) } else { diff --git a/run/test/specs/linked_device_avatar_color.spec.ts b/run/test/specs/linked_device_avatar_color.spec.ts index 387e9830..c81ea718 100644 --- a/run/test/specs/linked_device_avatar_color.spec.ts +++ b/run/test/specs/linked_device_avatar_color.spec.ts @@ -19,8 +19,7 @@ async function avatarColorLinkedDevice(platform: SupportedPlatformsType) { const device2Base64 = await device2.getElementScreenshot(device2Avatar.ELEMENT); const device2PixelColor = await parseDataImage(device2Base64) // Color comparison of devices 1 and 2 - console.log(`The colors are ${device1PixelColor} and ${device2PixelColor}`) - const colorCompare = await compareColors(device1PixelColor, device2PixelColor) + const colorCompare = compareColors(device1PixelColor, device2PixelColor) if (!colorCompare) { throw new Error (`The avatar color of ${userA.userName} does not match across devices. The colors are ${device1PixelColor} and ${device2PixelColor}`) } else { diff --git a/run/test/specs/utils/check_colour.ts b/run/test/specs/utils/check_colour.ts index 537e8f87..88a29126 100644 --- a/run/test/specs/utils/check_colour.ts +++ b/run/test/specs/utils/check_colour.ts @@ -26,11 +26,11 @@ export async function parseDataImage(base64: string) { } // Function to compare two colors within a specified CIEDE2000 tolerance -export async function compareColors( +export function compareColors( hex1: string, hex2: string, tolerance: number = 2.3 // looks-same default value which is "enough for most cases" -): Promise { +) { // looks-same expects colors as RGB objects but parseDataImage outputs hex function hexToRgbObject(hex: string): { R: number; G: number; B: number } { const bigint = parseInt(hex.replace('#', ''), 16); From 43edb394ff585794314782608eb4189eebaeb661 Mon Sep 17 00:00:00 2001 From: Miki-Session Date: Wed, 13 Nov 2024 15:30:48 +1100 Subject: [PATCH 06/21] fix: explicitly type isSameColor --- run/test/specs/utils/check_colour.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/run/test/specs/utils/check_colour.ts b/run/test/specs/utils/check_colour.ts index 88a29126..da20f61f 100644 --- a/run/test/specs/utils/check_colour.ts +++ b/run/test/specs/utils/check_colour.ts @@ -30,7 +30,7 @@ export function compareColors( hex1: string, hex2: string, tolerance: number = 2.3 // looks-same default value which is "enough for most cases" -) { +): boolean { // looks-same expects colors as RGB objects but parseDataImage outputs hex function hexToRgbObject(hex: string): { R: number; G: number; B: number } { const bigint = parseInt(hex.replace('#', ''), 16); @@ -45,7 +45,7 @@ export function compareColors( const rgb2 = hexToRgbObject(hex2); // Compare whether colors are within tolerance - const isSameColor = colors(rgb1, rgb2, { tolerance }); + const isSameColor: boolean = colors(rgb1, rgb2, { tolerance }); return isSameColor } \ No newline at end of file From 11fc2adf225f503fa0fd9546e85e0782d9723927 Mon Sep 17 00:00:00 2001 From: Miki-Session Date: Wed, 13 Nov 2024 15:31:12 +1100 Subject: [PATCH 07/21] chore: eslint errors --- run/test/specs/user_actions_set_nickname.spec.ts | 2 +- run/test/specs/utils/sleep_for.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/run/test/specs/user_actions_set_nickname.spec.ts b/run/test/specs/user_actions_set_nickname.spec.ts index e37da207..ea962d29 100644 --- a/run/test/specs/user_actions_set_nickname.spec.ts +++ b/run/test/specs/user_actions_set_nickname.spec.ts @@ -1,4 +1,4 @@ -import { androidIt, bothPlatformsIt, iosIt } from '../../types/sessionIt'; +import { androidIt, iosIt } from '../../types/sessionIt'; import { USERNAME } from '../../types/testing'; import { sleepFor } from './utils'; import { newUser } from './utils/create_account'; diff --git a/run/test/specs/utils/sleep_for.ts b/run/test/specs/utils/sleep_for.ts index f7372ca2..4be5afc9 100644 --- a/run/test/specs/utils/sleep_for.ts +++ b/run/test/specs/utils/sleep_for.ts @@ -1,6 +1,6 @@ export function sleepFor(ms: number) { return new Promise(resolve => { setTimeout(resolve, ms); - console.log('Sleeping for ' + ms + ' milliseconds'); + console.log(`Sleeping for ${ms} milliseconds'`); }); } From 0705585cfa9d5285d5979f21bf05557241b486a6 Mon Sep 17 00:00:00 2001 From: Miki-Session Date: Wed, 13 Nov 2024 15:31:31 +1100 Subject: [PATCH 08/21] fix: looks-same is a devdependency not a dependency --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index cd9a2a18..38ac3d1f 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "@wdio/types": "^8.1.2", "eslint": "^8.33.0", "lodash": "^4.17.21", + "looks-same": "^9.0.1", "png-js": "^1.0.0", "prettier": "^3.3.3", "ts-node": "^10.9.1", @@ -46,8 +47,7 @@ "appium": "^2.4.1", "appium-uiautomator2-driver": "patch:appium-uiautomator2-driver@npm%3A3.7.3#~/patches/appium-uiautomator2-driver-npm-3.7.3-24e944f6c5.patch", "appium-xcuitest-driver": "^7.26.0", - "dotenv": "^16.4.5", - "looks-same": "^9.0.1" + "dotenv": "^16.4.5" }, "packageManager": "yarn@4.0.2", "resolutions": { From 76038d74c79c17cc8525e6fce9a14f31222e25f5 Mon Sep 17 00:00:00 2001 From: Miki-Session Date: Mon, 18 Nov 2024 15:43:45 +1100 Subject: [PATCH 09/21] fix: ConversationAvatar locator class iOS case --- run/test/specs/locators/conversation.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/run/test/specs/locators/conversation.ts b/run/test/specs/locators/conversation.ts index 54e443f7..032feee9 100644 --- a/run/test/specs/locators/conversation.ts +++ b/run/test/specs/locators/conversation.ts @@ -20,10 +20,15 @@ export class ConversationSettings extends LocatorsInterface { // android-only locator for the avatar export class ConversationAvatar extends LocatorsInterface { - public build() { + public build() { + switch (this.platform) { + case 'android': return { strategy: 'id', selector: 'network.loki.messenger:id/singleModeImageView' } as const + case 'ios': + throw new Error('Unsupported platform'); } + } } \ No newline at end of file From 3ef171038606b42d74dba403cdc9fc84366a6116 Mon Sep 17 00:00:00 2001 From: Miki-Session Date: Mon, 18 Nov 2024 15:45:43 +1100 Subject: [PATCH 10/21] chore: yarn lint --- run/test/specs/check_avatar_color.spec.ts | 20 ++++++++++------- .../specs/linked_device_avatar_color.spec.ts | 18 +++++++++------ run/test/specs/locators/conversation.ts | 22 +++++++++---------- run/test/specs/locators/home.ts | 2 +- run/test/specs/utils/check_colour.ts | 8 +++---- 5 files changed, 39 insertions(+), 31 deletions(-) diff --git a/run/test/specs/check_avatar_color.spec.ts b/run/test/specs/check_avatar_color.spec.ts index fb80e16f..b8d018ce 100644 --- a/run/test/specs/check_avatar_color.spec.ts +++ b/run/test/specs/check_avatar_color.spec.ts @@ -19,12 +19,12 @@ async function avatarColor(platform: SupportedPlatformsType) { await newContact(platform, device1, userA, device2, userB); await device1.navigateBack(); await device2.navigateBack(); - // Get Alice's avatar color on device 1 and turn it into a hex value + // Get Alice's avatar color on device 1 and turn it into a hex value const device1Avatar = await device1.waitForTextElementToBePresent(new UserSettings(device1)); const device1Base64 = await device1.getElementScreenshot(device1Avatar.ELEMENT); const device1PixelColor = await parseDataImage(device1Base64); - // Get Alice's avatar color on device 2 and turn it into a hex value - await device2.clickOnElementAll(new ConversationItem(device2)) + // Get Alice's avatar color on device 2 and turn it into a hex value + await device2.clickOnElementAll(new ConversationItem(device2)); let device2Avatar; if (platform === 'ios') { device2Avatar = await device2.waitForTextElementToBePresent(new ConversationSettings(device2)); @@ -32,13 +32,17 @@ async function avatarColor(platform: SupportedPlatformsType) { device2Avatar = await device2.waitForTextElementToBePresent(new ConversationAvatar(device2)); } const device2Base64 = await device2.getElementScreenshot(device2Avatar.ELEMENT); - const device2PixelColor = await parseDataImage(device2Base64) - // Color comparison of devices 1 and 2 - const colorCompare = compareColors(device1PixelColor, device2PixelColor) + const device2PixelColor = await parseDataImage(device2Base64); + // Color comparison of devices 1 and 2 + const colorCompare = compareColors(device1PixelColor, device2PixelColor); if (!colorCompare) { - throw new Error (`The avatar color of ${userA.userName} does not match across devices. The colors are ${device1PixelColor} and ${device2PixelColor}`) + throw new Error( + `The avatar color of ${userA.userName} does not match across devices. The colors are ${device1PixelColor} and ${device2PixelColor}` + ); } else { - console.log(`The default avatar color of ${userA.userName} is within tolerance across devices.`) + console.log( + `The default avatar color of ${userA.userName} is within tolerance across devices.` + ); } await closeApp(device1, device2); } diff --git a/run/test/specs/linked_device_avatar_color.spec.ts b/run/test/specs/linked_device_avatar_color.spec.ts index c81ea718..bc160d83 100644 --- a/run/test/specs/linked_device_avatar_color.spec.ts +++ b/run/test/specs/linked_device_avatar_color.spec.ts @@ -10,20 +10,24 @@ bothPlatformsIt('Avatar color linked device', 'medium', avatarColorLinkedDevice) async function avatarColorLinkedDevice(platform: SupportedPlatformsType) { const { device1, device2 } = await openAppTwoDevices(platform); const userA = await linkedDevice(device1, device2, USERNAME.ALICE, platform); - // Get Alice's avatar color on device 1 and turn it into a hex value + // Get Alice's avatar color on device 1 and turn it into a hex value const device1Avatar = await device1.waitForTextElementToBePresent(new UserSettings(device1)); const device1Base64 = await device1.getElementScreenshot(device1Avatar.ELEMENT); const device1PixelColor = await parseDataImage(device1Base64); - // Get Alice's avatar color on the linked device and turn it into a hex value + // Get Alice's avatar color on the linked device and turn it into a hex value const device2Avatar = await device2.waitForTextElementToBePresent(new UserSettings(device2)); const device2Base64 = await device2.getElementScreenshot(device2Avatar.ELEMENT); - const device2PixelColor = await parseDataImage(device2Base64) - // Color comparison of devices 1 and 2 - const colorCompare = compareColors(device1PixelColor, device2PixelColor) + const device2PixelColor = await parseDataImage(device2Base64); + // Color comparison of devices 1 and 2 + const colorCompare = compareColors(device1PixelColor, device2PixelColor); if (!colorCompare) { - throw new Error (`The avatar color of ${userA.userName} does not match across devices. The colors are ${device1PixelColor} and ${device2PixelColor}`) + throw new Error( + `The avatar color of ${userA.userName} does not match across devices. The colors are ${device1PixelColor} and ${device2PixelColor}` + ); } else { - console.log(`The default avatar color of ${userA.userName} is within tolerance across devices.`) + console.log( + `The default avatar color of ${userA.userName} is within tolerance across devices.` + ); } await closeApp(device1, device2); } diff --git a/run/test/specs/locators/conversation.ts b/run/test/specs/locators/conversation.ts index 032feee9..44b7fb38 100644 --- a/run/test/specs/locators/conversation.ts +++ b/run/test/specs/locators/conversation.ts @@ -10,25 +10,25 @@ export class MessageInput extends LocatorsInterface { } export class ConversationSettings extends LocatorsInterface { - public build() { - return { - strategy: 'accessibility id', - selector: 'More options' - } as const; - } + public build() { + return { + strategy: 'accessibility id', + selector: 'More options', + } as const; + } } -// android-only locator for the avatar +// android-only locator for the avatar export class ConversationAvatar extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { - strategy: 'id', - selector: 'network.loki.messenger:id/singleModeImageView' - } as const + strategy: 'id', + selector: 'network.loki.messenger:id/singleModeImageView', + } as const; case 'ios': throw new Error('Unsupported platform'); } } -} \ No newline at end of file +} diff --git a/run/test/specs/locators/home.ts b/run/test/specs/locators/home.ts index 4f29eb36..13d512dd 100644 --- a/run/test/specs/locators/home.ts +++ b/run/test/specs/locators/home.ts @@ -6,7 +6,7 @@ export class ConversationItem extends LocatorsInterface { return { strategy: 'accessibility id', selector: 'Conversation list item', - text: text + text: text, } as const; } } diff --git a/run/test/specs/utils/check_colour.ts b/run/test/specs/utils/check_colour.ts index da20f61f..f4618659 100644 --- a/run/test/specs/utils/check_colour.ts +++ b/run/test/specs/utils/check_colour.ts @@ -31,7 +31,7 @@ export function compareColors( hex2: string, tolerance: number = 2.3 // looks-same default value which is "enough for most cases" ): boolean { - // looks-same expects colors as RGB objects but parseDataImage outputs hex + // looks-same expects colors as RGB objects but parseDataImage outputs hex function hexToRgbObject(hex: string): { R: number; G: number; B: number } { const bigint = parseInt(hex.replace('#', ''), 16); return { @@ -44,8 +44,8 @@ export function compareColors( const rgb1 = hexToRgbObject(hex1); const rgb2 = hexToRgbObject(hex2); - // Compare whether colors are within tolerance + // Compare whether colors are within tolerance const isSameColor: boolean = colors(rgb1, rgb2, { tolerance }); - return isSameColor -} \ No newline at end of file + return isSameColor; +} From 273f6ed98f00985570dff499ca20dbe35e5cc5e2 Mon Sep 17 00:00:00 2001 From: Miki-Session Date: Tue, 10 Dec 2024 12:09:32 +1100 Subject: [PATCH 11/21] chore: bump typescript-eslint to 8.15.0 --- package.json | 2 +- yarn.lock | 204 +++++++++++++++++++++++++++------------------------ 2 files changed, 111 insertions(+), 95 deletions(-) diff --git a/package.json b/package.json index 9f78a751..c565d2d0 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "sinon": "^19.0.2", "ts-node": "^10.9.1", "typescript": "^5.6.3", - "typescript-eslint": "^8.14.0", + "typescript-eslint": "^8.15.0", "wd": "^1.14.0", "wdio-wait-for": "^2.2.6" }, diff --git a/yarn.lock b/yarn.lock index 89031827..a3284cd5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -409,20 +409,22 @@ __metadata: linkType: hard "@eslint/config-array@npm:^0.19.0": - version: 0.19.0 - resolution: "@eslint/config-array@npm:0.19.0" + version: 0.19.1 + resolution: "@eslint/config-array@npm:0.19.1" dependencies: - "@eslint/object-schema": "npm:^2.1.4" + "@eslint/object-schema": "npm:^2.1.5" debug: "npm:^4.3.1" minimatch: "npm:^3.1.2" - checksum: def23c6c67a8f98dc88f1b87e17a5668e5028f5ab9459661aabfe08e08f2acd557474bbaf9ba227be0921ae4db232c62773dbb7739815f8415678eb8f592dbf5 + checksum: 43b01f596ddad404473beae5cf95c013d29301c72778d0f5bf8a6699939c8a9a5663dbd723b53c5f476b88b0c694f76ea145d1aa9652230d140fe1161e4a4b49 languageName: node linkType: hard "@eslint/core@npm:^0.9.0": - version: 0.9.0 - resolution: "@eslint/core@npm:0.9.0" - checksum: 6d8e8e0991cef12314c49425d8d2d9394f5fb1a36753ff82df7c03185a4646cb7c8736cf26638a4a714782cedf4b23cfc17667d282d3e5965b3920a0e7ce20d4 + version: 0.9.1 + resolution: "@eslint/core@npm:0.9.1" + dependencies: + "@types/json-schema": "npm:^7.0.15" + checksum: 638104b1b5833a9bbf2329f0c0ddf322e4d6c0410b149477e02cd2b78c04722be90c14b91b8ccdef0d63a2404dff72a17b6b412ce489ea429ae6a8fcb8abff28 languageName: node linkType: hard @@ -443,26 +445,33 @@ __metadata: languageName: node linkType: hard -"@eslint/js@npm:9.15.0, @eslint/js@npm:^9.14.0": +"@eslint/js@npm:9.16.0": + version: 9.16.0 + resolution: "@eslint/js@npm:9.16.0" + checksum: a55846a4ddade720662d36682f3eaaf38eac06eeee12c83bb837bba2b7d550dadcb3445b104219f0bc1da2e09b4fe5fb5ba123b8338c8c787bcfbd540878df75 + languageName: node + linkType: hard + +"@eslint/js@npm:^9.14.0": version: 9.15.0 resolution: "@eslint/js@npm:9.15.0" checksum: 56552966ab1aa95332f70d0e006db5746b511c5f8b5e0c6a9b2d6764ff6d964e0b2622731877cbc4e3f0e74c5b39191290d5f48147be19175292575130d499ab languageName: node linkType: hard -"@eslint/object-schema@npm:^2.1.4": - version: 2.1.4 - resolution: "@eslint/object-schema@npm:2.1.4" - checksum: e9885532ea70e483fb007bf1275968b05bb15ebaa506d98560c41a41220d33d342e19023d5f2939fed6eb59676c1bda5c847c284b4b55fce521d282004da4dda +"@eslint/object-schema@npm:^2.1.5": + version: 2.1.5 + resolution: "@eslint/object-schema@npm:2.1.5" + checksum: 5320691ed41ecd09a55aff40ce8e56596b4eb81f3d4d6fe530c50fdd6552d88102d1c1a29d970ae798ce30849752a708772de38ded07a6f25b3da32ebea081d8 languageName: node linkType: hard "@eslint/plugin-kit@npm:^0.2.3": - version: 0.2.3 - resolution: "@eslint/plugin-kit@npm:0.2.3" + version: 0.2.4 + resolution: "@eslint/plugin-kit@npm:0.2.4" dependencies: levn: "npm:^0.4.1" - checksum: 89a8035976bb1780e3fa8ffe682df013bd25f7d102d991cecd3b7c297f4ce8c1a1b6805e76dd16465b5353455b670b545eff2b4ec3133e0eab81a5f9e99bd90f + checksum: 1bcfc0a30b1df891047c1d8b3707833bded12a057ba01757a2a8591fdc8d8fe0dbb8d51d4b0b61b2af4ca1d363057abd7d2fb4799f1706b105734f4d3fa0dbf1 languageName: node linkType: hard @@ -1509,15 +1518,15 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:8.14.0": - version: 8.14.0 - resolution: "@typescript-eslint/eslint-plugin@npm:8.14.0" +"@typescript-eslint/eslint-plugin@npm:8.18.0": + version: 8.18.0 + resolution: "@typescript-eslint/eslint-plugin@npm:8.18.0" dependencies: "@eslint-community/regexpp": "npm:^4.10.0" - "@typescript-eslint/scope-manager": "npm:8.14.0" - "@typescript-eslint/type-utils": "npm:8.14.0" - "@typescript-eslint/utils": "npm:8.14.0" - "@typescript-eslint/visitor-keys": "npm:8.14.0" + "@typescript-eslint/scope-manager": "npm:8.18.0" + "@typescript-eslint/type-utils": "npm:8.18.0" + "@typescript-eslint/utils": "npm:8.18.0" + "@typescript-eslint/visitor-keys": "npm:8.18.0" graphemer: "npm:^1.4.0" ignore: "npm:^5.3.1" natural-compare: "npm:^1.4.0" @@ -1525,10 +1534,8 @@ __metadata: peerDependencies: "@typescript-eslint/parser": ^8.0.0 || ^8.0.0-alpha.0 eslint: ^8.57.0 || ^9.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 46c82eb45be82ffec0ab04728a5180691b1d17002c669864861a3044b6d2105a75ca23cc80d18721b40b5e7dff1eff4ed68a43d726e25d55f3e466a9fbeeb873 + typescript: ">=4.8.4 <5.8.0" + checksum: c338da1b96c41d7b94401a6711659d0fef3acb691eff7a958f9d3aa0442a858830daad67e3575288a4f4669572e2b690517a513519b404a465ad68fe0a82d3ec languageName: node linkType: hard @@ -1556,21 +1563,19 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/parser@npm:8.14.0": - version: 8.14.0 - resolution: "@typescript-eslint/parser@npm:8.14.0" +"@typescript-eslint/parser@npm:8.18.0": + version: 8.18.0 + resolution: "@typescript-eslint/parser@npm:8.18.0" dependencies: - "@typescript-eslint/scope-manager": "npm:8.14.0" - "@typescript-eslint/types": "npm:8.14.0" - "@typescript-eslint/typescript-estree": "npm:8.14.0" - "@typescript-eslint/visitor-keys": "npm:8.14.0" + "@typescript-eslint/scope-manager": "npm:8.18.0" + "@typescript-eslint/types": "npm:8.18.0" + "@typescript-eslint/typescript-estree": "npm:8.18.0" + "@typescript-eslint/visitor-keys": "npm:8.18.0" debug: "npm:^4.3.4" peerDependencies: eslint: ^8.57.0 || ^9.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 522b7afd25cd302c0510cc71985ba55ff92ecc5dbe3fc74a76fefea0169252fdd4b8cad6291fef05f63dfc173951af450dca20859c7f23e387b2e7410e8b97b1 + typescript: ">=4.8.4 <5.8.0" + checksum: d3a062511c24dfcf522a645db1153022d49aa3bb05e288c22474cf04dc1d836f877eb9d2733947e448981ffb16e4de50d4ebe7570a268733a641f228ca6c4849 languageName: node linkType: hard @@ -1601,13 +1606,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:8.14.0": - version: 8.14.0 - resolution: "@typescript-eslint/scope-manager@npm:8.14.0" +"@typescript-eslint/scope-manager@npm:8.18.0": + version: 8.18.0 + resolution: "@typescript-eslint/scope-manager@npm:8.18.0" dependencies: - "@typescript-eslint/types": "npm:8.14.0" - "@typescript-eslint/visitor-keys": "npm:8.14.0" - checksum: 1e1295c6f9febadf63559aad328b23d960510ce6b4c9f74e10d881c3858fa7f1db767cd1af5272d2fe7c9c5c7daebee71854e6f841e413e5d70af282f6616e26 + "@typescript-eslint/types": "npm:8.18.0" + "@typescript-eslint/visitor-keys": "npm:8.18.0" + checksum: 6bf6532fd43f2b55b9b47fa8b0217c5b5a03f022e869a6a21228fc3ae04c0ac6c5ae5d6026866d189ba424d2f98cc6fbd2a34f909d241c9b86c031afd808f90c languageName: node linkType: hard @@ -1628,18 +1633,18 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:8.14.0": - version: 8.14.0 - resolution: "@typescript-eslint/type-utils@npm:8.14.0" +"@typescript-eslint/type-utils@npm:8.18.0": + version: 8.18.0 + resolution: "@typescript-eslint/type-utils@npm:8.18.0" dependencies: - "@typescript-eslint/typescript-estree": "npm:8.14.0" - "@typescript-eslint/utils": "npm:8.14.0" + "@typescript-eslint/typescript-estree": "npm:8.18.0" + "@typescript-eslint/utils": "npm:8.18.0" debug: "npm:^4.3.4" ts-api-utils: "npm:^1.3.0" - peerDependenciesMeta: - typescript: - optional: true - checksum: 42616a664b38ca418e13504247e5e1bad6ae85c045b48e5735ffab977d4bd58cc86fb9d2292bbb314fa408d78d4b0454c3a27dbf9f881f9921917a942825c806 + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <5.8.0" + checksum: c0fcf201c3b53f9374c0571198a639c81536170141caa08fd0f47094a596b1f82f839a849eac5832f954345c567dccb45b2ee1c0872c513331165f7bcb812396 languageName: node linkType: hard @@ -1650,10 +1655,10 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:8.14.0": - version: 8.14.0 - resolution: "@typescript-eslint/types@npm:8.14.0" - checksum: 7707f900e24e60e6780c5705f69627b7c0ef912cb3b095dfc8f4a0c84e866c66b1c4c10278cf99724560dc66985ec640750c4192786a09b853f9bb4c3ca5a7ce +"@typescript-eslint/types@npm:8.18.0": + version: 8.18.0 + resolution: "@typescript-eslint/types@npm:8.18.0" + checksum: 2dd7468c3f1c305545268b72c3a333488e6ab1b628c5f65081d895866422b9376c21634a7aac437805f84b22e352b6a8fc4dcf925ef4a8fd7d1898b8359f71be languageName: node linkType: hard @@ -1675,22 +1680,21 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:8.14.0": - version: 8.14.0 - resolution: "@typescript-eslint/typescript-estree@npm:8.14.0" +"@typescript-eslint/typescript-estree@npm:8.18.0": + version: 8.18.0 + resolution: "@typescript-eslint/typescript-estree@npm:8.18.0" dependencies: - "@typescript-eslint/types": "npm:8.14.0" - "@typescript-eslint/visitor-keys": "npm:8.14.0" + "@typescript-eslint/types": "npm:8.18.0" + "@typescript-eslint/visitor-keys": "npm:8.18.0" debug: "npm:^4.3.4" fast-glob: "npm:^3.3.2" is-glob: "npm:^4.0.3" minimatch: "npm:^9.0.4" semver: "npm:^7.6.0" ts-api-utils: "npm:^1.3.0" - peerDependenciesMeta: - typescript: - optional: true - checksum: 5e890d22bd067095f871cf144907a8c302db5b5f014c58906ad58d7f23569951cba805042eac6844744e5abb0d3648c9cc221a91b0703da0a8d6345dc1f83e74 + peerDependencies: + typescript: ">=4.8.4 <5.8.0" + checksum: 87b432b190b627314f007b17b2371898db78baaa3df67a0d9a94d080d88a7a307906b54a735084cacef37f6421e2b9c3320040617e73fe54eac2bf22c610f1ec languageName: node linkType: hard @@ -1712,17 +1716,18 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:8.14.0": - version: 8.14.0 - resolution: "@typescript-eslint/utils@npm:8.14.0" +"@typescript-eslint/utils@npm:8.18.0": + version: 8.18.0 + resolution: "@typescript-eslint/utils@npm:8.18.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.4.0" - "@typescript-eslint/scope-manager": "npm:8.14.0" - "@typescript-eslint/types": "npm:8.14.0" - "@typescript-eslint/typescript-estree": "npm:8.14.0" + "@typescript-eslint/scope-manager": "npm:8.18.0" + "@typescript-eslint/types": "npm:8.18.0" + "@typescript-eslint/typescript-estree": "npm:8.18.0" peerDependencies: eslint: ^8.57.0 || ^9.0.0 - checksum: 1fcc2651d870832a799a5d1c85fc9421853508a006d6a6073c8316b012489dda77e123d13aea8f53eb9030a2da2c0eb273a6946a9941caa2519b99b33e89b720 + typescript: ">=4.8.4 <5.8.0" + checksum: 58a2fc1e404d1f905c2a958d995824eb4abc6e73836b186717550677f8b1d17954acc369feddb83277350915388bc3d8b721423c37777b8b8017fc29c89ec6ee languageName: node linkType: hard @@ -1736,13 +1741,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:8.14.0": - version: 8.14.0 - resolution: "@typescript-eslint/visitor-keys@npm:8.14.0" +"@typescript-eslint/visitor-keys@npm:8.18.0": + version: 8.18.0 + resolution: "@typescript-eslint/visitor-keys@npm:8.18.0" dependencies: - "@typescript-eslint/types": "npm:8.14.0" - eslint-visitor-keys: "npm:^3.4.3" - checksum: d0faf70ed9ecff5e36694bbb161a90bea6db59e0e79a7d4f264d67d565c12b13733d664b736b2730935f013c87ce3155cea954a533d28e99987681bc5f6259c3 + "@typescript-eslint/types": "npm:8.18.0" + eslint-visitor-keys: "npm:^4.2.0" + checksum: d4cdc2adab553098b5be7117fb7df76fb66cfd380528881a0a8c2a9eee03bf8baddda07d15ca0bd3ed8b35c379b3f449292183df18e3e81898dbcadafcb708b8 languageName: node linkType: hard @@ -3155,7 +3160,7 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.1, cross-spawn@npm:^7.0.5": +"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.1": version: 7.0.5 resolution: "cross-spawn@npm:7.0.5" dependencies: @@ -3166,6 +3171,17 @@ __metadata: languageName: node linkType: hard +"cross-spawn@npm:^7.0.5": + version: 7.0.6 + resolution: "cross-spawn@npm:7.0.6" + dependencies: + path-key: "npm:^3.1.0" + shebang-command: "npm:^2.0.0" + which: "npm:^2.0.1" + checksum: 053ea8b2135caff68a9e81470e845613e374e7309a47731e81639de3eaeb90c3d01af0e0b44d2ab9d50b43467223b88567dfeb3262db942dc063b9976718ffc1 + languageName: node + linkType: hard + "css-selector-parser@npm:^3.0.0": version: 3.0.5 resolution: "css-selector-parser@npm:3.0.5" @@ -3639,15 +3655,15 @@ __metadata: linkType: hard "eslint@npm:^9.14.0": - version: 9.15.0 - resolution: "eslint@npm:9.15.0" + version: 9.16.0 + resolution: "eslint@npm:9.16.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.2.0" "@eslint-community/regexpp": "npm:^4.12.1" "@eslint/config-array": "npm:^0.19.0" "@eslint/core": "npm:^0.9.0" "@eslint/eslintrc": "npm:^3.2.0" - "@eslint/js": "npm:9.15.0" + "@eslint/js": "npm:9.16.0" "@eslint/plugin-kit": "npm:^0.2.3" "@humanfs/node": "npm:^0.16.6" "@humanwhocodes/module-importer": "npm:^1.0.1" @@ -3683,7 +3699,7 @@ __metadata: optional: true bin: eslint: bin/eslint.js - checksum: d0d7606f36bfcccb1c3703d0a24df32067b207a616f17efe5fb1765a91d13f085afffc4fc97ecde4ab9c9f4edd64d9b4ce750e13ff7937a25074b24bee15b20f + checksum: f36d12652c6f20bab8a77375b8ad29a6af030c3840deb0a5f9dd4cee49d68a2d68d7dc73b0c25918df59d83cd686dd5712e11387e696e1f3842e8dde15cd3255 languageName: node linkType: hard @@ -6915,7 +6931,7 @@ __metadata: sinon: "npm:^19.0.2" ts-node: "npm:^10.9.1" typescript: "npm:^5.6.3" - typescript-eslint: "npm:^8.14.0" + typescript-eslint: "npm:^8.15.0" wd: "npm:^1.14.0" wdio-wait-for: "npm:^2.2.6" languageName: unknown @@ -7873,17 +7889,17 @@ __metadata: languageName: node linkType: hard -"typescript-eslint@npm:^8.14.0": - version: 8.14.0 - resolution: "typescript-eslint@npm:8.14.0" +"typescript-eslint@npm:^8.15.0": + version: 8.18.0 + resolution: "typescript-eslint@npm:8.18.0" dependencies: - "@typescript-eslint/eslint-plugin": "npm:8.14.0" - "@typescript-eslint/parser": "npm:8.14.0" - "@typescript-eslint/utils": "npm:8.14.0" - peerDependenciesMeta: - typescript: - optional: true - checksum: b9c2f32139d3df52057bfb80d4663fd5e440ccd0da75d92fe91582fe5216213e7012ef691e7d91c75e402e373b9aded6b128b005aaeeae32d7b9d7b39732bcc7 + "@typescript-eslint/eslint-plugin": "npm:8.18.0" + "@typescript-eslint/parser": "npm:8.18.0" + "@typescript-eslint/utils": "npm:8.18.0" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <5.8.0" + checksum: dda882cbfc1ebad6903864571bc69bfd7e32e17fec67d98fdfab2bd652348d425c6a1c3697734d59cd5dd15d26d496db3c3808c1de5840fa29b9e76184fa1865 languageName: node linkType: hard From e2f514988d8c315347b3c756e75ca29a1d637863 Mon Sep 17 00:00:00 2001 From: Miki-Session Date: Tue, 7 Jan 2025 16:11:11 +1100 Subject: [PATCH 12/21] fix: address test spec feedback --- run/test/specs/check_avatar_color.spec.ts | 8 ++------ run/test/specs/linked_device_avatar_color.spec.ts | 8 ++------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/run/test/specs/check_avatar_color.spec.ts b/run/test/specs/check_avatar_color.spec.ts index b8d018ce..25f3b1dc 100644 --- a/run/test/specs/check_avatar_color.spec.ts +++ b/run/test/specs/check_avatar_color.spec.ts @@ -34,15 +34,11 @@ async function avatarColor(platform: SupportedPlatformsType) { const device2Base64 = await device2.getElementScreenshot(device2Avatar.ELEMENT); const device2PixelColor = await parseDataImage(device2Base64); // Color comparison of devices 1 and 2 - const colorCompare = compareColors(device1PixelColor, device2PixelColor); - if (!colorCompare) { + const colorMatch = compareColors(device1PixelColor, device2PixelColor); + if (!colorMatch) { throw new Error( `The avatar color of ${userA.userName} does not match across devices. The colors are ${device1PixelColor} and ${device2PixelColor}` ); - } else { - console.log( - `The default avatar color of ${userA.userName} is within tolerance across devices.` - ); } await closeApp(device1, device2); } diff --git a/run/test/specs/linked_device_avatar_color.spec.ts b/run/test/specs/linked_device_avatar_color.spec.ts index bc160d83..69d1cb26 100644 --- a/run/test/specs/linked_device_avatar_color.spec.ts +++ b/run/test/specs/linked_device_avatar_color.spec.ts @@ -19,15 +19,11 @@ async function avatarColorLinkedDevice(platform: SupportedPlatformsType) { const device2Base64 = await device2.getElementScreenshot(device2Avatar.ELEMENT); const device2PixelColor = await parseDataImage(device2Base64); // Color comparison of devices 1 and 2 - const colorCompare = compareColors(device1PixelColor, device2PixelColor); - if (!colorCompare) { + const colorMatch = compareColors(device1PixelColor, device2PixelColor); + if (!colorMatch) { throw new Error( `The avatar color of ${userA.userName} does not match across devices. The colors are ${device1PixelColor} and ${device2PixelColor}` ); - } else { - console.log( - `The default avatar color of ${userA.userName} is within tolerance across devices.` - ); } await closeApp(device1, device2); } From 4fecfda5409571bd6bdf1f2af8612d8c4a509fde Mon Sep 17 00:00:00 2001 From: Miki-Session Date: Tue, 7 Jan 2025 16:16:25 +1100 Subject: [PATCH 13/21] fix: begin simplifying the compareColors function --- run/test/specs/utils/check_colour.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/run/test/specs/utils/check_colour.ts b/run/test/specs/utils/check_colour.ts index f4618659..d05e3101 100644 --- a/run/test/specs/utils/check_colour.ts +++ b/run/test/specs/utils/check_colour.ts @@ -26,11 +26,7 @@ export async function parseDataImage(base64: string) { } // Function to compare two colors within a specified CIEDE2000 tolerance -export function compareColors( - hex1: string, - hex2: string, - tolerance: number = 2.3 // looks-same default value which is "enough for most cases" -): boolean { +export function compareColors(hex1: string, hex2: string) { // looks-same expects colors as RGB objects but parseDataImage outputs hex function hexToRgbObject(hex: string): { R: number; G: number; B: number } { const bigint = parseInt(hex.replace('#', ''), 16); @@ -45,7 +41,7 @@ export function compareColors( const rgb2 = hexToRgbObject(hex2); // Compare whether colors are within tolerance - const isSameColor: boolean = colors(rgb1, rgb2, { tolerance }); + const isSameColor: boolean = colors(rgb1, rgb2); return isSameColor; } From 0c6b567cbe39377edff849ef07c02a459dda8514 Mon Sep 17 00:00:00 2001 From: Miki-Session Date: Tue, 7 Jan 2025 16:25:10 +1100 Subject: [PATCH 14/21] fix: remove platform from newUser and linkedDevice --- run/test/specs/check_avatar_color.spec.ts | 4 ++-- run/test/specs/linked_device_avatar_color.spec.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/run/test/specs/check_avatar_color.spec.ts b/run/test/specs/check_avatar_color.spec.ts index 25f3b1dc..af774995 100644 --- a/run/test/specs/check_avatar_color.spec.ts +++ b/run/test/specs/check_avatar_color.spec.ts @@ -13,8 +13,8 @@ bothPlatformsIt('Avatar color', 'medium', avatarColor); async function avatarColor(platform: SupportedPlatformsType) { const { device1, device2 } = await openAppTwoDevices(platform); const [userA, userB] = await Promise.all([ - newUser(device1, USERNAME.ALICE, platform), - newUser(device2, USERNAME.BOB, platform), + newUser(device1, USERNAME.ALICE), + newUser(device2, USERNAME.BOB), ]); await newContact(platform, device1, userA, device2, userB); await device1.navigateBack(); diff --git a/run/test/specs/linked_device_avatar_color.spec.ts b/run/test/specs/linked_device_avatar_color.spec.ts index 69d1cb26..fc7e57cc 100644 --- a/run/test/specs/linked_device_avatar_color.spec.ts +++ b/run/test/specs/linked_device_avatar_color.spec.ts @@ -9,7 +9,7 @@ bothPlatformsIt('Avatar color linked device', 'medium', avatarColorLinkedDevice) async function avatarColorLinkedDevice(platform: SupportedPlatformsType) { const { device1, device2 } = await openAppTwoDevices(platform); - const userA = await linkedDevice(device1, device2, USERNAME.ALICE, platform); + const userA = await linkedDevice(device1, device2, USERNAME.ALICE); // Get Alice's avatar color on device 1 and turn it into a hex value const device1Avatar = await device1.waitForTextElementToBePresent(new UserSettings(device1)); const device1Base64 = await device1.getElementScreenshot(device1Avatar.ELEMENT); From 359b4852a6613742fc5d225713cbd487026c542b Mon Sep 17 00:00:00 2001 From: Miki-Session Date: Wed, 8 Jan 2025 16:10:21 +1100 Subject: [PATCH 15/21] fix: move hexToRgbObject to utilities.ts, rename compareColors function to isSameColor --- run/test/specs/check_avatar_color.spec.ts | 6 +++--- .../specs/linked_device_avatar_color.spec.ts | 6 +++--- run/test/specs/utils/check_colour.ts | 20 +++++-------------- run/test/specs/utils/utilities.ts | 13 ++++++++++++ 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/run/test/specs/check_avatar_color.spec.ts b/run/test/specs/check_avatar_color.spec.ts index af774995..ca11454d 100644 --- a/run/test/specs/check_avatar_color.spec.ts +++ b/run/test/specs/check_avatar_color.spec.ts @@ -3,7 +3,7 @@ import { USERNAME } from '../../types/testing'; import { newUser } from './utils/create_account'; import { newContact } from './utils/create_contact'; import { SupportedPlatformsType, closeApp, openAppTwoDevices } from './utils/open_app'; -import { compareColors, parseDataImage } from './utils/check_colour'; +import { isSameColor, parseDataImage } from './utils/check_colour'; import { UserSettings } from './locators/settings'; import { ConversationItem } from './locators/home'; import { ConversationAvatar, ConversationSettings } from './locators/conversation'; @@ -33,8 +33,8 @@ async function avatarColor(platform: SupportedPlatformsType) { } const device2Base64 = await device2.getElementScreenshot(device2Avatar.ELEMENT); const device2PixelColor = await parseDataImage(device2Base64); - // Color comparison of devices 1 and 2 - const colorMatch = compareColors(device1PixelColor, device2PixelColor); + // Color matching devices 1 and 2 + const colorMatch = isSameColor(device1PixelColor, device2PixelColor); if (!colorMatch) { throw new Error( `The avatar color of ${userA.userName} does not match across devices. The colors are ${device1PixelColor} and ${device2PixelColor}` diff --git a/run/test/specs/linked_device_avatar_color.spec.ts b/run/test/specs/linked_device_avatar_color.spec.ts index fc7e57cc..fe5f6044 100644 --- a/run/test/specs/linked_device_avatar_color.spec.ts +++ b/run/test/specs/linked_device_avatar_color.spec.ts @@ -2,7 +2,7 @@ import { bothPlatformsIt } from '../../types/sessionIt'; import { USERNAME } from '../../types/testing'; import { linkedDevice } from './utils/link_device'; import { SupportedPlatformsType, closeApp, openAppTwoDevices } from './utils/open_app'; -import { compareColors, parseDataImage } from './utils/check_colour'; +import { isSameColor, parseDataImage } from './utils/check_colour'; import { UserSettings } from './locators/settings'; bothPlatformsIt('Avatar color linked device', 'medium', avatarColorLinkedDevice); @@ -18,8 +18,8 @@ async function avatarColorLinkedDevice(platform: SupportedPlatformsType) { const device2Avatar = await device2.waitForTextElementToBePresent(new UserSettings(device2)); const device2Base64 = await device2.getElementScreenshot(device2Avatar.ELEMENT); const device2PixelColor = await parseDataImage(device2Base64); - // Color comparison of devices 1 and 2 - const colorMatch = compareColors(device1PixelColor, device2PixelColor); + // Color matching devices 1 and 2 + const colorMatch = isSameColor(device1PixelColor, device2PixelColor); if (!colorMatch) { throw new Error( `The avatar color of ${userA.userName} does not match across devices. The colors are ${device1PixelColor} and ${device2PixelColor}` diff --git a/run/test/specs/utils/check_colour.ts b/run/test/specs/utils/check_colour.ts index d05e3101..0f19541c 100644 --- a/run/test/specs/utils/check_colour.ts +++ b/run/test/specs/utils/check_colour.ts @@ -1,5 +1,6 @@ import PNG from 'png-js'; import { colors } from 'looks-same'; +import { hexToRgbObject } from './utilities'; export async function parseDataImage(base64: string) { const buffer = Buffer.from(base64, 'base64'); @@ -25,23 +26,12 @@ export async function parseDataImage(base64: string) { return pixelColor; } -// Function to compare two colors within a specified CIEDE2000 tolerance -export function compareColors(hex1: string, hex2: string) { - // looks-same expects colors as RGB objects but parseDataImage outputs hex - function hexToRgbObject(hex: string): { R: number; G: number; B: number } { - const bigint = parseInt(hex.replace('#', ''), 16); - return { - R: (bigint >> 16) & 255, - G: (bigint >> 8) & 255, - B: bigint & 255, - }; - } - // RGB-HEX conversion +// Determines if two colors look "the same" for humans even if they are not an exact match +export function isSameColor(hex1: string, hex2: string) { + // Convert the hex strings to RGB objects const rgb1 = hexToRgbObject(hex1); const rgb2 = hexToRgbObject(hex2); - - // Compare whether colors are within tolerance + // Perform the color comparison using the looks-same library const isSameColor: boolean = colors(rgb1, rgb2); - return isSameColor; } diff --git a/run/test/specs/utils/utilities.ts b/run/test/specs/utils/utilities.ts index 487e0284..02bfe4b0 100644 --- a/run/test/specs/utils/utilities.ts +++ b/run/test/specs/utils/utilities.ts @@ -45,3 +45,16 @@ export const isDeviceAndroid = (device: unknown) => !isDeviceIOS(device); export const isCI = () => { return process.env.NODE_CONFIG_ENV === 'ci'; }; + +// Converts a hexadecimal color string to an RGB object +export function hexToRgbObject(hex: string): { R: number; G: number; B: number } { + // Parse the hexadecimal string into a decimal number + // Removes the # prefix if present and converts the remaining string to base-10 + const decimalValue = parseInt(hex.replace('#', ''), 16); + // Extract the red, green, and blue components using bitwise operations + return { + R: (decimalValue >> 16) & 255, + G: (decimalValue >> 8) & 255, + B: decimalValue & 255, + }; +} From 2fc28323649ae169ae9e509267239a6991dc7c78 Mon Sep 17 00:00:00 2001 From: Miki-Session Date: Wed, 8 Jan 2025 16:29:25 +1100 Subject: [PATCH 16/21] fix: remove explicit typing for isSameColor --- run/test/specs/utils/check_colour.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run/test/specs/utils/check_colour.ts b/run/test/specs/utils/check_colour.ts index 0f19541c..6609608d 100644 --- a/run/test/specs/utils/check_colour.ts +++ b/run/test/specs/utils/check_colour.ts @@ -32,6 +32,6 @@ export function isSameColor(hex1: string, hex2: string) { const rgb1 = hexToRgbObject(hex1); const rgb2 = hexToRgbObject(hex2); // Perform the color comparison using the looks-same library - const isSameColor: boolean = colors(rgb1, rgb2); + const isSameColor = colors(rgb1, rgb2); return isSameColor; } From d5a50a982e14f9d271469e2378933e57b7f02abe Mon Sep 17 00:00:00 2001 From: Miki-Session Date: Mon, 13 Jan 2025 16:19:56 +1100 Subject: [PATCH 17/21] fix: wrap device1 and device2.navigateBack in await Promise.all --- run/test/specs/check_avatar_color.spec.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/run/test/specs/check_avatar_color.spec.ts b/run/test/specs/check_avatar_color.spec.ts index ca11454d..7540a3e6 100644 --- a/run/test/specs/check_avatar_color.spec.ts +++ b/run/test/specs/check_avatar_color.spec.ts @@ -17,8 +17,10 @@ async function avatarColor(platform: SupportedPlatformsType) { newUser(device2, USERNAME.BOB), ]); await newContact(platform, device1, userA, device2, userB); - await device1.navigateBack(); - await device2.navigateBack(); + await Promise.all([ + device1.navigateBack(), + device2.navigateBack() + ]); // Get Alice's avatar color on device 1 and turn it into a hex value const device1Avatar = await device1.waitForTextElementToBePresent(new UserSettings(device1)); const device1Base64 = await device1.getElementScreenshot(device1Avatar.ELEMENT); From 1eaee50cc69bf348379b013e88eb18027937d4c9 Mon Sep 17 00:00:00 2001 From: Miki-Session Date: Mon, 13 Jan 2025 16:25:12 +1100 Subject: [PATCH 18/21] chore: comment about conversation avatars per platform --- run/test/specs/check_avatar_color.spec.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/run/test/specs/check_avatar_color.spec.ts b/run/test/specs/check_avatar_color.spec.ts index 7540a3e6..d428c54c 100644 --- a/run/test/specs/check_avatar_color.spec.ts +++ b/run/test/specs/check_avatar_color.spec.ts @@ -28,6 +28,9 @@ async function avatarColor(platform: SupportedPlatformsType) { // Get Alice's avatar color on device 2 and turn it into a hex value await device2.clickOnElementAll(new ConversationItem(device2)); let device2Avatar; + // The conversation screen looks slightly different per platform: + // On iOS the avatar doubles as the Conversation Settings button + // On Android, the avatar is a separate, non-interactable element (and the settings has the 3-dot icon) if (platform === 'ios') { device2Avatar = await device2.waitForTextElementToBePresent(new ConversationSettings(device2)); } else { From 1852c5baa3fadb729fac06c271066a94e8d70d2c Mon Sep 17 00:00:00 2001 From: Miki-Session Date: Mon, 13 Jan 2025 17:02:31 +1100 Subject: [PATCH 19/21] chore: explain which elements are being compared --- run/test/specs/check_avatar_color.spec.ts | 2 +- run/test/specs/linked_device_avatar_color.spec.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/run/test/specs/check_avatar_color.spec.ts b/run/test/specs/check_avatar_color.spec.ts index d428c54c..1b301b83 100644 --- a/run/test/specs/check_avatar_color.spec.ts +++ b/run/test/specs/check_avatar_color.spec.ts @@ -21,7 +21,7 @@ async function avatarColor(platform: SupportedPlatformsType) { device1.navigateBack(), device2.navigateBack() ]); - // Get Alice's avatar color on device 1 and turn it into a hex value + // Get Alice's avatar color on device 1 (Home Screen avatar) and turn it into a hex value const device1Avatar = await device1.waitForTextElementToBePresent(new UserSettings(device1)); const device1Base64 = await device1.getElementScreenshot(device1Avatar.ELEMENT); const device1PixelColor = await parseDataImage(device1Base64); diff --git a/run/test/specs/linked_device_avatar_color.spec.ts b/run/test/specs/linked_device_avatar_color.spec.ts index fe5f6044..499c2c67 100644 --- a/run/test/specs/linked_device_avatar_color.spec.ts +++ b/run/test/specs/linked_device_avatar_color.spec.ts @@ -10,11 +10,11 @@ bothPlatformsIt('Avatar color linked device', 'medium', avatarColorLinkedDevice) async function avatarColorLinkedDevice(platform: SupportedPlatformsType) { const { device1, device2 } = await openAppTwoDevices(platform); const userA = await linkedDevice(device1, device2, USERNAME.ALICE); - // Get Alice's avatar color on device 1 and turn it into a hex value + // Get Alice's avatar color on device 1 (Home Screen avatar) and turn it into a hex value const device1Avatar = await device1.waitForTextElementToBePresent(new UserSettings(device1)); const device1Base64 = await device1.getElementScreenshot(device1Avatar.ELEMENT); const device1PixelColor = await parseDataImage(device1Base64); - // Get Alice's avatar color on the linked device and turn it into a hex value + // Get Alice's avatar color on the linked device (Home Screen avatar) and turn it into a hex value const device2Avatar = await device2.waitForTextElementToBePresent(new UserSettings(device2)); const device2Base64 = await device2.getElementScreenshot(device2Avatar.ELEMENT); const device2PixelColor = await parseDataImage(device2Base64); From 3d34a4ce697c6c8d384c1abd0fa42bdd6d0fae17 Mon Sep 17 00:00:00 2001 From: Miki-Session Date: Mon, 13 Jan 2025 17:03:35 +1100 Subject: [PATCH 20/21] chore: yarn lint --- run/test/specs/check_avatar_color.spec.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/run/test/specs/check_avatar_color.spec.ts b/run/test/specs/check_avatar_color.spec.ts index 1b301b83..5a244bc1 100644 --- a/run/test/specs/check_avatar_color.spec.ts +++ b/run/test/specs/check_avatar_color.spec.ts @@ -17,10 +17,7 @@ async function avatarColor(platform: SupportedPlatformsType) { newUser(device2, USERNAME.BOB), ]); await newContact(platform, device1, userA, device2, userB); - await Promise.all([ - device1.navigateBack(), - device2.navigateBack() - ]); + await Promise.all([device1.navigateBack(), device2.navigateBack()]); // Get Alice's avatar color on device 1 (Home Screen avatar) and turn it into a hex value const device1Avatar = await device1.waitForTextElementToBePresent(new UserSettings(device1)); const device1Base64 = await device1.getElementScreenshot(device1Avatar.ELEMENT); From 312cc67826ba137a54afbd48c4b26d2dbaf8d432 Mon Sep 17 00:00:00 2001 From: Miki-Session Date: Wed, 15 Jan 2025 17:06:02 +1100 Subject: [PATCH 21/21] feat: add getElementPixelColor function --- run/test/specs/check_avatar_color.spec.ts | 20 ++++++++----------- .../specs/linked_device_avatar_color.spec.ts | 10 +++------- run/types/DeviceWrapper.ts | 15 ++++++++++++++ 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/run/test/specs/check_avatar_color.spec.ts b/run/test/specs/check_avatar_color.spec.ts index 5a244bc1..23cd4852 100644 --- a/run/test/specs/check_avatar_color.spec.ts +++ b/run/test/specs/check_avatar_color.spec.ts @@ -3,7 +3,7 @@ import { USERNAME } from '../../types/testing'; import { newUser } from './utils/create_account'; import { newContact } from './utils/create_contact'; import { SupportedPlatformsType, closeApp, openAppTwoDevices } from './utils/open_app'; -import { isSameColor, parseDataImage } from './utils/check_colour'; +import { isSameColor } from './utils/check_colour'; import { UserSettings } from './locators/settings'; import { ConversationItem } from './locators/home'; import { ConversationAvatar, ConversationSettings } from './locators/conversation'; @@ -19,22 +19,18 @@ async function avatarColor(platform: SupportedPlatformsType) { await newContact(platform, device1, userA, device2, userB); await Promise.all([device1.navigateBack(), device2.navigateBack()]); // Get Alice's avatar color on device 1 (Home Screen avatar) and turn it into a hex value - const device1Avatar = await device1.waitForTextElementToBePresent(new UserSettings(device1)); - const device1Base64 = await device1.getElementScreenshot(device1Avatar.ELEMENT); - const device1PixelColor = await parseDataImage(device1Base64); + const device1PixelColor = await device1.getElementPixelColor(new UserSettings(device1)); // Get Alice's avatar color on device 2 and turn it into a hex value await device2.clickOnElementAll(new ConversationItem(device2)); - let device2Avatar; - // The conversation screen looks slightly different per platform: - // On iOS the avatar doubles as the Conversation Settings button - // On Android, the avatar is a separate, non-interactable element (and the settings has the 3-dot icon) + let device2PixelColor; + // The conversation screen looks slightly different per platform so we're grabbing the avatar from different locators + // On iOS the avatar doubles as the Conversation Settings button on the right + // On Android, the avatar is a separate, non-interactable element on the left (and the settings has the 3-dot icon) if (platform === 'ios') { - device2Avatar = await device2.waitForTextElementToBePresent(new ConversationSettings(device2)); + device2PixelColor = await device2.getElementPixelColor(new ConversationSettings(device2)); } else { - device2Avatar = await device2.waitForTextElementToBePresent(new ConversationAvatar(device2)); + device2PixelColor = await device2.getElementPixelColor(new ConversationAvatar(device2)); } - const device2Base64 = await device2.getElementScreenshot(device2Avatar.ELEMENT); - const device2PixelColor = await parseDataImage(device2Base64); // Color matching devices 1 and 2 const colorMatch = isSameColor(device1PixelColor, device2PixelColor); if (!colorMatch) { diff --git a/run/test/specs/linked_device_avatar_color.spec.ts b/run/test/specs/linked_device_avatar_color.spec.ts index 499c2c67..0ed5384e 100644 --- a/run/test/specs/linked_device_avatar_color.spec.ts +++ b/run/test/specs/linked_device_avatar_color.spec.ts @@ -2,7 +2,7 @@ import { bothPlatformsIt } from '../../types/sessionIt'; import { USERNAME } from '../../types/testing'; import { linkedDevice } from './utils/link_device'; import { SupportedPlatformsType, closeApp, openAppTwoDevices } from './utils/open_app'; -import { isSameColor, parseDataImage } from './utils/check_colour'; +import { isSameColor } from './utils/check_colour'; import { UserSettings } from './locators/settings'; bothPlatformsIt('Avatar color linked device', 'medium', avatarColorLinkedDevice); @@ -11,13 +11,9 @@ async function avatarColorLinkedDevice(platform: SupportedPlatformsType) { const { device1, device2 } = await openAppTwoDevices(platform); const userA = await linkedDevice(device1, device2, USERNAME.ALICE); // Get Alice's avatar color on device 1 (Home Screen avatar) and turn it into a hex value - const device1Avatar = await device1.waitForTextElementToBePresent(new UserSettings(device1)); - const device1Base64 = await device1.getElementScreenshot(device1Avatar.ELEMENT); - const device1PixelColor = await parseDataImage(device1Base64); + const device1PixelColor = await device1.getElementPixelColor(new UserSettings(device1)); // Get Alice's avatar color on the linked device (Home Screen avatar) and turn it into a hex value - const device2Avatar = await device2.waitForTextElementToBePresent(new UserSettings(device2)); - const device2Base64 = await device2.getElementScreenshot(device2Avatar.ELEMENT); - const device2PixelColor = await parseDataImage(device2Base64); + const device2PixelColor = await device2.getElementPixelColor(new UserSettings(device2)); // Color matching devices 1 and 2 const colorMatch = isSameColor(device1PixelColor, device2PixelColor); if (!colorMatch) { diff --git a/run/types/DeviceWrapper.ts b/run/types/DeviceWrapper.ts index ffd58a11..3fd462f9 100644 --- a/run/types/DeviceWrapper.ts +++ b/run/types/DeviceWrapper.ts @@ -30,6 +30,7 @@ import { User, XPath, } from './testing'; +import { parseDataImage } from '../test/specs/utils/check_colour'; export type Coordinates = { x: number; @@ -1787,6 +1788,20 @@ export class DeviceWrapper { } } + public async getElementPixelColor( + args: { + text?: string; + maxWait?: number; + } & (StrategyExtractionObj | LocatorsInterface) + ): Promise { + // Wait for the element to be present + const element = await this.waitForTextElementToBePresent(args); + // Take a screenshot and return a hex color value + const base64image = await this.getElementScreenshot(element.ELEMENT); + const pixelColor = await parseDataImage(base64image); + return pixelColor; + } + /* === all the utilities function === */ public isIOS(): boolean { return isDeviceIOS(this.device);