From c9fac1b944e516ffdc6de6f193162e97b74d2ac7 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Wed, 13 Dec 2023 15:34:43 +0100 Subject: [PATCH 1/2] chore(web): Add unit tests for `pageContextAttachment` --- package-lock.json | 443 +++++++++++++++++- web/build.sh | 48 +- web/common.inc.sh | 33 +- web/package.json | 3 +- web/src/engine/attachment/.c8rc.json | 10 + web/src/engine/attachment/build.sh | 8 +- web/src/test/auto/.mocharc.json | 9 + .../attachment/pageContextAttachment.tests.ts | 108 +++++ web/src/test/auto/tsconfig.json | 12 + web/test.sh | 2 +- 10 files changed, 638 insertions(+), 38 deletions(-) create mode 100644 web/src/engine/attachment/.c8rc.json create mode 100644 web/src/test/auto/.mocharc.json create mode 100644 web/src/test/auto/headless/engine/attachment/pageContextAttachment.tests.ts create mode 100644 web/src/test/auto/tsconfig.json diff --git a/package-lock.json b/package-lock.json index 750b36a8bc0..2be28a317b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4613,6 +4613,12 @@ "node": "*" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, "node_modules/atob-lite": { "version": "2.0.0", "license": "MIT" @@ -5185,6 +5191,18 @@ "node": ">=0.10.0" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", @@ -5355,11 +5373,70 @@ "node": ">= 8" } }, + "node_modules/cssstyle": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", + "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", + "dev": true, + "dependencies": { + "rrweb-cssom": "^0.6.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/custom-event": { "version": "1.0.1", "dev": true, "license": "MIT" }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls/node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dev": true, + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "dev": true, + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/date-format": { "version": "4.0.6", "dev": true, @@ -5391,6 +5468,12 @@ "node": ">=0.10.0" } }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true + }, "node_modules/decompress-response": { "version": "6.0.0", "license": "MIT", @@ -5461,6 +5544,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/delegates": { "version": "1.0.0", "devOptional": true, @@ -7062,6 +7154,20 @@ "node": ">=8.0.0" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "license": "MIT", @@ -7621,6 +7727,18 @@ "license": "MIT", "optional": true }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/html-escaper": { "version": "2.0.2", "dev": true, @@ -8024,6 +8142,12 @@ "node": ">=0.10.0" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -8219,6 +8343,135 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsdom": { + "version": "23.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-23.0.1.tgz", + "integrity": "sha512-2i27vgvlUsGEBO9+/kJQRbtqtm+191b5zAZrU/UezVmnC2dlDAFLgDYJvAEi94T4kjsRKkezEtLQTgsNEsW2lQ==", + "dev": true, + "dependencies": { + "cssstyle": "^3.0.0", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.7", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.6.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.3", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.14.2", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/jsdom/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/jsdom/node_modules/https-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", + "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/jsdom/node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dev": true, + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/jsdom/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/jsdom/node_modules/whatwg-url": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "dev": true, + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "license": "MIT" @@ -9702,6 +9955,12 @@ "node": ">=0.10.0" } }, + "node_modules/nwsapi": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", + "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", + "dev": true + }, "node_modules/object-assign": { "version": "4.1.1", "license": "MIT", @@ -9907,6 +10166,30 @@ "node": ">=6" } }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/parseurl": { "version": "1.3.3", "license": "MIT", @@ -10061,6 +10344,12 @@ "node": ">= 0.10" } }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, "node_modules/pump": { "version": "3.0.0", "license": "MIT", @@ -10070,9 +10359,9 @@ } }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" @@ -10105,6 +10394,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -10342,6 +10637,12 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "dev": true + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -10405,6 +10706,18 @@ "version": "1.2.4", "license": "ISC" }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/semver": { "version": "7.5.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", @@ -10963,6 +11276,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, "node_modules/tar": { "version": "6.1.13", "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", @@ -11085,6 +11404,30 @@ "node": ">=0.6" } }, + "node_modules/tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/tr46": { "version": "0.0.3", "license": "MIT" @@ -11344,6 +11687,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/unique-filename": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", @@ -11403,6 +11752,16 @@ "punycode": "^2.1.0" } }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "license": "MIT" @@ -11463,10 +11822,55 @@ "node": ">=0.10.0" } }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "license": "BSD-2-Clause" }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "dev": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "engines": { + "node": ">=18" + } + }, "node_modules/whatwg-url": { "version": "5.0.0", "license": "MIT", @@ -11621,9 +12025,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "version": "8.15.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.15.1.tgz", + "integrity": "sha512-W5OZiCjXEmk0yZ66ZN82beM5Sz7l7coYxpRkzS+p9PP+ToQry8szKh+61eNktr7EA9DOwvFGhfC605jDHbP6QQ==", "engines": { "node": ">=10.0.0" }, @@ -11640,6 +12044,15 @@ } } }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "engines": { + "node": ">=18" + } + }, "node_modules/xml2js": { "version": "0.4.23", "resolved": "git+ssh://git@github.com/keymanapp/dependency-node-xml2js.git#535fe732dc408d697e0f847c944cc45f0baf0829", @@ -11660,6 +12073,12 @@ "node": ">=4.0" } }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, "node_modules/xtend": { "version": "4.0.2", "license": "MIT", @@ -11940,7 +12359,6 @@ "@keymanapp/recorder-core": "*", "@keymanapp/tslib": "*", "@keymanapp/web-utils": "*", - "@types/node": "^11.9.4", "eventemitter3": "^4.0.0", "tslib": "^2.5.2" }, @@ -11948,8 +12366,10 @@ "@keymanapp/resources-gosh": "*", "@keymanapp/web-sentry-manager": "*", "@sentry/cli": "2.2.0", + "@types/node": "^18.19.3", "c8": "^7.12.0", "chai": "^4.3.4", + "jsdom": "^23.0.1", "karma": "^6.4.1", "karma-browserstack-launcher": "^1.6.0", "karma-chai": "^0.1.0", @@ -11969,6 +12389,15 @@ "ts-node": "^10.9.1", "typescript": "^4.9.5" } + }, + "web/node_modules/@types/node": { + "version": "18.19.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.3.tgz", + "integrity": "sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } } } } diff --git a/web/build.sh b/web/build.sh index 8e7c1ac0b07..c97dec4b079 100755 --- a/web/build.sh +++ b/web/build.sh @@ -65,6 +65,28 @@ builder_run_child_actions configure ## Build actions +build_action() { + tsc --project "${KEYMAN_ROOT}/web/src/test/auto/tsconfig.json" +} + +test_action() { + TEST_OPTS= + if builder_has_option --ci; then + TEST_OPTS=--ci + fi + ./test.sh "${TEST_OPTS}" +} + +coverage_action() { + builder_echo "Creating coverage report..." + cd "$KEYMAN_ROOT" + mkdir -p web/build/coverage/tmp + find . -type f -name coverage-\*.json -print0 | xargs -0 cp -t web/build/coverage/tmp + c8 report --config web/.c8rc.json ---reporter html --clean=false --reports-dir=web/build/coverage + rm -rf web/build/coverage/tmp + cd web +} + builder_run_child_actions build:engine/device-detect builder_run_child_actions build:engine/dom-utils builder_run_child_actions build:engine/element-wrappers @@ -103,26 +125,12 @@ builder_run_child_actions build:tools # Some test pages refer to KMW tools. builder_run_child_actions build:test-pages -builder_run_child_actions test +# Build tests +builder_run_action build build_action -if builder_start_action test; then - TEST_OPTS= - if builder_has_option --ci; then - TEST_OPTS=--ci - fi - ./test.sh $TEST_OPTS - - builder_finish_action success test -fi - -coverage_action() { - builder_echo "Creating coverage report..." - cd "$KEYMAN_ROOT" - mkdir -p web/build/coverage/tmp - find . -type f -name coverage-\*.json -print0 | xargs -0 cp -t web/build/coverage/tmp - c8 report --config web/.c8rc.json ---reporter html --clean=false --reports-dir=web/build/coverage - rm -rf web/build/coverage/tmp - cd web -} +# Run tests +builder_run_child_actions test +builder_run_action test test_action +# Create coverage report builder_run_action coverage coverage_action diff --git a/web/common.inc.sh b/web/common.inc.sh index e1594c911c2..0cb6773a86b 100644 --- a/web/common.inc.sh +++ b/web/common.inc.sh @@ -77,24 +77,47 @@ function prepare() { # # * 1: `product` the folder under src/test/auto/headless containing the # child project's tests +# * 2: `base_dir` the base directory containing the `product` folder. +# Optional. Default: ${KEYMAN_ROOT}/web/src/test/auto/headless/ # # ### Example # # ```bash # # from engine/osk -# test-headless osk +# test-headless engine/osk # ``` function test-headless() { TEST_FOLDER=$1 + TEST_BASE=${2:-${KEYMAN_ROOT}/web/src/test/auto/headless/} TEST_OPTS= if builder_has_option --ci; then TEST_OPTS="--reporter mocha-teamcity-reporter" fi - if [ -e .c8rc.json ]; then - c8 mocha --recursive "${KEYMAN_ROOT}/web/src/test/auto/headless/$TEST_FOLDER" $TEST_OPTS + if [[ -e .c8rc.json ]]; then + c8 mocha --recursive "${TEST_BASE}/${TEST_FOLDER}" $TEST_OPTS else - mocha --recursive "${KEYMAN_ROOT}/web/src/test/auto/headless/$TEST_FOLDER" $TEST_OPTS + mocha --recursive "${TEST_BASE}/${TEST_FOLDER}" $TEST_OPTS fi -} \ No newline at end of file +} + +# Runs all headless tests (written in typescript) corresponding to the +# specified target. +# This should be called from the working directory of a child project's +# build script. +# +# ### Parameters +# +# * 1: `product` the folder under src/test/auto/headless containing the +# child project's tests +# +# ### Example +# +# ```bash +# # from engine/osk +# test-headless-typescript engine/osk +# ``` +function test-headless-typescript() { + test-headless "$1" "${KEYMAN_ROOT}/web/build/test/headless" +} diff --git a/web/package.json b/web/package.json index 06640cdca86..6f659c5b088 100644 --- a/web/package.json +++ b/web/package.json @@ -73,6 +73,7 @@ "@sentry/cli": "2.2.0", "c8": "^7.12.0", "chai": "^4.3.4", + "jsdom": "^23.0.1", "karma": "^6.4.1", "karma-browserstack-launcher": "^1.6.0", "karma-chai": "^0.1.0", @@ -104,7 +105,7 @@ "@keymanapp/recorder-core": "*", "@keymanapp/tslib": "*", "@keymanapp/web-utils": "*", - "@types/node": "^11.9.4", + "@types/node": "^18.19.3", "eventemitter3": "^4.0.0", "tslib": "^2.5.2" }, diff --git a/web/src/engine/attachment/.c8rc.json b/web/src/engine/attachment/.c8rc.json new file mode 100644 index 00000000000..c789716cd50 --- /dev/null +++ b/web/src/engine/attachment/.c8rc.json @@ -0,0 +1,10 @@ +{ + "check-coverage": false, + "clean": true, + "exclude-after-remap": true, + "reporter": ["text", "text-summary"], + "reports-dir": "build/coverage", + "src": [ + "src/" + ] +} \ No newline at end of file diff --git a/web/src/engine/attachment/build.sh b/web/src/engine/attachment/build.sh index d7c78e740ce..c86708f4d0c 100755 --- a/web/src/engine/attachment/build.sh +++ b/web/src/engine/attachment/build.sh @@ -36,7 +36,7 @@ builder_parse "$@" #### Build action definitions #### -builder_run_action configure verify_npm_setup -builder_run_action clean rm -rf "$KEYMAN_ROOT/web/build/$SUBPROJECT_NAME" -builder_run_action build compile $SUBPROJECT_NAME -builder_run_action test # No headless tests +builder_run_action configure verify_npm_setup +builder_run_action clean rm -rf "${KEYMAN_ROOT}/web/build/${SUBPROJECT_NAME}" +builder_run_action build compile "${SUBPROJECT_NAME}" +builder_run_action test test-headless-typescript "${SUBPROJECT_NAME}" diff --git a/web/src/test/auto/.mocharc.json b/web/src/test/auto/.mocharc.json new file mode 100644 index 00000000000..2e96416c49a --- /dev/null +++ b/web/src/test/auto/.mocharc.json @@ -0,0 +1,9 @@ +{ + "extensions": ["ts"], + "spec": ["**/*.tests.*"], + "node-option": [ + "experimental-specifier-resolution=node", + "loader=ts-node/esm" + ], + "global": "window" +} \ No newline at end of file diff --git a/web/src/test/auto/headless/engine/attachment/pageContextAttachment.tests.ts b/web/src/test/auto/headless/engine/attachment/pageContextAttachment.tests.ts new file mode 100644 index 00000000000..01520f083bd --- /dev/null +++ b/web/src/test/auto/headless/engine/attachment/pageContextAttachment.tests.ts @@ -0,0 +1,108 @@ +import { assert } from 'chai'; +import { JSDOM } from 'jsdom'; +import { PageContextAttachment } from 'keyman/engine/attachment'; + +declare global { + namespace NodeJS { + interface Global { + document: Document; + window: Window; + navigator: Navigator; + } + } +} + +describe('PageContextAttachment', () => { + function createDocument(content: string): Document { + const jsdom = new JSDOM(content); + // JSDOM does not support Element.contentEditable + // https://github.com/jsdom/jsdom/issues/1670 + Object.defineProperty(jsdom.window.HTMLElement.prototype, 'contentEditable', { + get: function() { + return this.getAttribute('contenteditable') + } + }); + const { window } = new JSDOM(content); + global.document = window.document; + global.window = global.document.defaultView; + return global.document; + } + + describe('listInputs', () => { + it('empty doc has no elements', () => { + const doc = createDocument(''); + const sut = new PageContextAttachment(doc, null); + sut.listInputs(); + + assert.isEmpty(sut.sortedInputs); + }); + + it('supported input types', () => { + const doc = createDocument(' '); + const sut = new PageContextAttachment(doc, null); + sut.listInputs(); + + const expected = ['email', 'search', 'text', 'url', 'textarea']; + const types = sut.sortedInputs.map((e: HTMLInputElement) => (e.type)); + assert.equal(types.length, expected.length); + assert.deepEqual(types, expected, `Actual [${types}]`); + }); + + it('ignores disabled', () => { + const doc = createDocument(' '); + const sut = new PageContextAttachment(doc, null); + sut.listInputs(); + + const expected = ['1', '3']; + const types = sut.sortedInputs.map((e: HTMLInputElement) => (e.id)); + assert.equal(types.length, expected.length); + assert.deepEqual(types, expected, `Actual [${types}]`); + }); + }); + + describe('isKMWInput', () => { + + it('supported input types', () => { + ['email', 'search', 'text', 'url'].forEach(function (elementType) { + const doc = createDocument(``); + const sut = new PageContextAttachment(doc, null); + const elem = doc.getElementById('1'); + + const result = sut.isKMWInput(elem); + assert.isTrue(result, `${elementType} should be treated as input element`); + }); + }); + + it('unsupported input types', () => { + [ 'button', 'date', 'file', 'hidden', 'image', 'month', 'number', + 'password', 'radio', 'range', 'reset', 'submit', 'tel', 'time', + 'week'].forEach(function (elementType) { + const doc = createDocument(``); + const sut = new PageContextAttachment(doc, null); + const elem = doc.getElementById('1'); + + const result = sut.isKMWInput(elem); + assert.isFalse(result, `${elementType} should not be treated as input element`); + }); + }); + + it('text area is input', () => { + const doc = createDocument(''); + const sut = new PageContextAttachment(doc, null); + const elem = doc.getElementById('1'); + + const result = sut.isKMWInput(elem); + assert.isTrue(result); + }); + + // Can't test contenteditable because JSDOM doesn't support that attribute. + // See https://github.com/jsdom/jsdom/issues/1670 + + // missing tests: + // - iframe without content window -> false + // - iframe with touch and designmode -> false + // - iframe with touch and no designmode -> true + // - iframe with _kmwAttachment -> true + + }); +}); diff --git a/web/src/test/auto/tsconfig.json b/web/src/test/auto/tsconfig.json new file mode 100644 index 00000000000..be849ee0a9d --- /dev/null +++ b/web/src/test/auto/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.dom.json", + + "compilerOptions": { + "baseUrl": "./", + "outDir": "../../../build/test", + "tsBuildInfoFile": "../../../build/test/tsconfig.tsbuildinfo", + "rootDir": "." + }, + + "include": [ "**/*.ts" ] +} diff --git a/web/test.sh b/web/test.sh index 18ad1164b9c..a1aa3638605 100755 --- a/web/test.sh +++ b/web/test.sh @@ -100,7 +100,7 @@ fi # End common configs. -builder_run_action test:dom karma start $KARMA_FLAGS "${KEYMAN_ROOT}/web/src/test/auto/dom/$CONFIG" +builder_run_action test:dom karma start ${KARMA_FLAGS} "${KEYMAN_ROOT}/web/src/test/auto/dom/${CONFIG}" # The multi-browser test suite, which uses BrowserStack when run by our CI. if builder_start_action test:integrated; then From f3d244844ca30c606d4b6b2128d05d464595f193 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Thu, 14 Dec 2023 18:37:18 +0100 Subject: [PATCH 2/2] chore(web): Address code review comments --- .../attachment/pageContextAttachment.tests.ts | 51 ++++++++++++++++--- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/web/src/test/auto/headless/engine/attachment/pageContextAttachment.tests.ts b/web/src/test/auto/headless/engine/attachment/pageContextAttachment.tests.ts index 01520f083bd..1f56a60e234 100644 --- a/web/src/test/auto/headless/engine/attachment/pageContextAttachment.tests.ts +++ b/web/src/test/auto/headless/engine/attachment/pageContextAttachment.tests.ts @@ -38,7 +38,32 @@ describe('PageContextAttachment', () => { }); it('supported input types', () => { - const doc = createDocument(' '); + const doc = createDocument( + ` + + + + + + + + + + + + + + + + + + + + + + + + `); const sut = new PageContextAttachment(doc, null); sut.listInputs(); @@ -49,7 +74,13 @@ describe('PageContextAttachment', () => { }); it('ignores disabled', () => { - const doc = createDocument(' '); + const doc = createDocument( + ` + + + + + `); const sut = new PageContextAttachment(doc, null); sut.listInputs(); @@ -61,10 +92,12 @@ describe('PageContextAttachment', () => { }); describe('isKMWInput', () => { - it('supported input types', () => { ['email', 'search', 'text', 'url'].forEach(function (elementType) { - const doc = createDocument(``); + const doc = createDocument( + ` + + `); const sut = new PageContextAttachment(doc, null); const elem = doc.getElementById('1'); @@ -77,7 +110,10 @@ describe('PageContextAttachment', () => { [ 'button', 'date', 'file', 'hidden', 'image', 'month', 'number', 'password', 'radio', 'range', 'reset', 'submit', 'tel', 'time', 'week'].forEach(function (elementType) { - const doc = createDocument(``); + const doc = createDocument( + ` + + `); const sut = new PageContextAttachment(doc, null); const elem = doc.getElementById('1'); @@ -87,7 +123,10 @@ describe('PageContextAttachment', () => { }); it('text area is input', () => { - const doc = createDocument(''); + const doc = createDocument( + ` + + `); const sut = new PageContextAttachment(doc, null); const elem = doc.getElementById('1');