diff --git a/jest.config.cjs b/jest.config.cjs index f2ea1e0..1fbb81f 100644 --- a/jest.config.cjs +++ b/jest.config.cjs @@ -14,4 +14,7 @@ module.exports = { "^@/(.*)$": "/src/$1", }, transformIgnorePatterns: [], + setupFilesAfterEnv: [ + "./tests/setup-memfs.ts", + ], }; diff --git a/package-lock.json b/package-lock.json index 44ff3e9..301a941 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,22 +18,21 @@ }, "devDependencies": { "@babel/preset-env": "^7.23.8", + "@types/adm-zip": "^0.5.5", "@types/jest": "^29.5.11", - "@types/mock-fs": "^4.13.4", "@types/node": "^16.18.31", "@types/node-fetch": "^2.6.10", "@types/semver": "^7.5.6", - "@types/yazl": "^2.4.5", "@typescript-eslint/eslint-plugin": "^6.18.1", "@typescript-eslint/parser": "^6.18.1", "@vercel/ncc": "^0.38.1", + "adm-zip": "^0.5.16", "babel-jest": "^29.7.0", "eslint": "^8.56.0", "jest": "^29.7.0", - "mock-fs": "^5.2.0", + "memfs": "^4.13.0", "ts-jest": "^29.1.1", - "typescript": "^5.3.3", - "yazl": "^2.5.1" + "typescript": "^5.3.3" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -2656,6 +2655,63 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.1.0.tgz", + "integrity": "sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/base64": "^1.1.1", + "@jsonjoy.com/util": "^1.1.2", + "hyperdyperid": "^1.2.0", + "thingies": "^1.20.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.5.0.tgz", + "integrity": "sha512-ojoNsrIuPI9g6o8UxhraZQSyF2ByJanAY4cTFbc8Mf2AXEF4aQRGY1dJxyJpuyav8r9FGflEt/Ff3u5Nt6YMPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2712,6 +2768,16 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@types/adm-zip": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.5.tgz", + "integrity": "sha512-YCGstVMjc4LTY5uK9/obvxBya93axZOVOyf2GSUulADzmLhYE45u2nAssCs/fWBs1Ifq5Vat75JTPwd5XZoPJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -2802,15 +2868,6 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, - "node_modules/@types/mock-fs": { - "version": "4.13.4", - "resolved": "https://registry.npmjs.org/@types/mock-fs/-/mock-fs-4.13.4.tgz", - "integrity": "sha512-mXmM0o6lULPI8z3XNnQCpL0BGxPwx1Ul1wXYEPBGl4efShyxW2Rln0JOPEWGyZaYZMM6OVXM/15zUuFMY52ljg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/node": { "version": "16.18.70", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.70.tgz", @@ -2854,15 +2911,6 @@ "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true }, - "node_modules/@types/yazl": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/@types/yazl/-/yazl-2.4.5.tgz", - "integrity": "sha512-qpmPfx32HS7vlGJf7EsoM9qJnLZhXJBf1KH0hzfdc+D794rljQWh4H0I/UrZy+6Nhqn0l2jdBZXBGZtR1vnHqw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "6.18.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.1.tgz", @@ -3113,6 +3161,16 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/adm-zip": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz", + "integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -3491,15 +3549,6 @@ "node-int64": "^0.4.0" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -4666,6 +4715,16 @@ "node": ">=10.17.0" } }, + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.18" + } + }, "node_modules/ignore": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", @@ -6656,6 +6715,26 @@ "tmpl": "1.0.5" } }, + "node_modules/memfs": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.13.0.tgz", + "integrity": "sha512-dIs5KGy24fbdDhIAg0RxXpFqQp3RwL6wgSMRF9OSuphL/Uc9a4u2/SDJKPLj/zUgtOGKuHrRMrj563+IErj4Cg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/json-pack": "^1.0.3", + "@jsonjoy.com/util": "^1.3.0", + "tree-dump": "^1.0.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">= 4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -6724,15 +6803,6 @@ "node": "*" } }, - "node_modules/mock-fs": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-5.2.0.tgz", - "integrity": "sha512-2dF2R6YMSZbpip1V1WHKGLNjr/k48uQClqMVb5H3MOvwc9qhYis3/IWbj02qIg/Y8MDXKFF4c5v0rxx2o6xTZw==", - "dev": true, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -7529,6 +7599,19 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/thingies": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", + "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", + "dev": true, + "license": "Unlicense", + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "tslib": "^2" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -7560,6 +7643,23 @@ "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==" }, + "node_modules/tree-dump": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", + "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, "node_modules/ts-api-utils": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", @@ -7615,6 +7715,13 @@ } } }, + "node_modules/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "dev": true, + "license": "0BSD" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -7905,15 +8012,6 @@ "node": ">=12" } }, - "node_modules/yazl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", - "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -9794,6 +9892,32 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", + "dev": true, + "requires": {} + }, + "@jsonjoy.com/json-pack": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.1.0.tgz", + "integrity": "sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==", + "dev": true, + "requires": { + "@jsonjoy.com/base64": "^1.1.1", + "@jsonjoy.com/util": "^1.1.2", + "hyperdyperid": "^1.2.0", + "thingies": "^1.20.0" + } + }, + "@jsonjoy.com/util": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.5.0.tgz", + "integrity": "sha512-ojoNsrIuPI9g6o8UxhraZQSyF2ByJanAY4cTFbc8Mf2AXEF4aQRGY1dJxyJpuyav8r9FGflEt/Ff3u5Nt6YMPA==", + "dev": true, + "requires": {} + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -9841,6 +9965,15 @@ "@sinonjs/commons": "^3.0.0" } }, + "@types/adm-zip": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.5.tgz", + "integrity": "sha512-YCGstVMjc4LTY5uK9/obvxBya93axZOVOyf2GSUulADzmLhYE45u2nAssCs/fWBs1Ifq5Vat75JTPwd5XZoPJw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -9931,15 +10064,6 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, - "@types/mock-fs": { - "version": "4.13.4", - "resolved": "https://registry.npmjs.org/@types/mock-fs/-/mock-fs-4.13.4.tgz", - "integrity": "sha512-mXmM0o6lULPI8z3XNnQCpL0BGxPwx1Ul1wXYEPBGl4efShyxW2Rln0JOPEWGyZaYZMM6OVXM/15zUuFMY52ljg==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/node": { "version": "16.18.70", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.70.tgz", @@ -9983,15 +10107,6 @@ "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true }, - "@types/yazl": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/@types/yazl/-/yazl-2.4.5.tgz", - "integrity": "sha512-qpmPfx32HS7vlGJf7EsoM9qJnLZhXJBf1KH0hzfdc+D794rljQWh4H0I/UrZy+6Nhqn0l2jdBZXBGZtR1vnHqw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@typescript-eslint/eslint-plugin": { "version": "6.18.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.1.tgz", @@ -10138,6 +10253,12 @@ "dev": true, "requires": {} }, + "adm-zip": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz", + "integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==", + "dev": true + }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -10418,12 +10539,6 @@ "node-int64": "^0.4.0" } }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true - }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -11260,6 +11375,12 @@ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, + "hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "dev": true + }, "ignore": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", @@ -12748,6 +12869,18 @@ "tmpl": "1.0.5" } }, + "memfs": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.13.0.tgz", + "integrity": "sha512-dIs5KGy24fbdDhIAg0RxXpFqQp3RwL6wgSMRF9OSuphL/Uc9a4u2/SDJKPLj/zUgtOGKuHrRMrj563+IErj4Cg==", + "dev": true, + "requires": { + "@jsonjoy.com/json-pack": "^1.0.3", + "@jsonjoy.com/util": "^1.3.0", + "tree-dump": "^1.0.1", + "tslib": "^2.0.0" + } + }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -12798,12 +12931,6 @@ "brace-expansion": "^1.1.7" } }, - "mock-fs": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-5.2.0.tgz", - "integrity": "sha512-2dF2R6YMSZbpip1V1WHKGLNjr/k48uQClqMVb5H3MOvwc9qhYis3/IWbj02qIg/Y8MDXKFF4c5v0rxx2o6xTZw==", - "dev": true - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -13361,6 +13488,13 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "thingies": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", + "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", + "dev": true, + "requires": {} + }, "tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -13386,6 +13520,13 @@ "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==" }, + "tree-dump": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", + "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", + "dev": true, + "requires": {} + }, "ts-api-utils": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", @@ -13409,6 +13550,12 @@ "yargs-parser": "^21.0.1" } }, + "tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "dev": true + }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -13608,15 +13755,6 @@ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true }, - "yazl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", - "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", - "dev": true, - "requires": { - "buffer-crc32": "~0.2.3" - } - }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 2ddfe34..1cc7e2f 100644 --- a/package.json +++ b/package.json @@ -35,22 +35,21 @@ "homepage": "https://github.com/Kir-Antipov/mc-publish#readme", "devDependencies": { "@babel/preset-env": "^7.23.8", + "@types/adm-zip": "^0.5.5", "@types/jest": "^29.5.11", - "@types/mock-fs": "^4.13.4", "@types/node": "^16.18.31", "@types/node-fetch": "^2.6.10", "@types/semver": "^7.5.6", - "@types/yazl": "^2.4.5", "@typescript-eslint/eslint-plugin": "^6.18.1", "@typescript-eslint/parser": "^6.18.1", "@vercel/ncc": "^0.38.1", + "adm-zip": "^0.5.16", "babel-jest": "^29.7.0", "eslint": "^8.56.0", "jest": "^29.7.0", - "mock-fs": "^5.2.0", + "memfs": "^4.13.0", "ts-jest": "^29.1.1", - "typescript": "^5.3.3", - "yazl": "^2.5.1" + "typescript": "^5.3.3" }, "dependencies": { "fast-glob": "^3.3.2", diff --git a/tests/setup-memfs.ts b/tests/setup-memfs.ts new file mode 100644 index 0000000..a084127 --- /dev/null +++ b/tests/setup-memfs.ts @@ -0,0 +1,6 @@ +import { fs } from "memfs"; + +jest.mock("node:fs", () => fs); +jest.mock("node:fs/promises", () => fs.promises); +jest.mock("fs", () => fs); +jest.mock("fs/promises", () => fs.promises); diff --git a/tests/unit/games/minecraft/minecraft-version.spec.ts b/tests/unit/games/minecraft/minecraft-version.spec.ts index b631ecd..0dc0dc2 100644 --- a/tests/unit/games/minecraft/minecraft-version.spec.ts +++ b/tests/unit/games/minecraft/minecraft-version.spec.ts @@ -1,4 +1,4 @@ -import { readFileSync } from "node:fs"; +import { actualFs } from "@/../tests/utils/actual-fs"; import { resolve } from "node:path"; import { parseVersion } from "@/utils/versioning/version"; import { VersionType } from "@/utils/versioning/version-type"; @@ -87,7 +87,7 @@ describe("MinecraftVersion", () => { describe("getMinecraftVersionManifestEntries", () => { const manifest : MinecraftVersionManifest = JSON.parse( - readFileSync(resolve(__dirname, "../../../content/mojang/version_manifest_v2.json"), "utf8") + actualFs.readFileSync(resolve(__dirname, "../../../content/mojang/version_manifest_v2.json"), "utf8") ); test("returns correct number of entries", () => { diff --git a/tests/unit/loaders/fabric/fabric-metadata-reader.spec.ts b/tests/unit/loaders/fabric/fabric-metadata-reader.spec.ts index fe9ba28..47738b4 100644 --- a/tests/unit/loaders/fabric/fabric-metadata-reader.spec.ts +++ b/tests/unit/loaders/fabric/fabric-metadata-reader.spec.ts @@ -1,19 +1,15 @@ import { zipFile } from "@/../tests/utils/zip-utils"; -import mockFs from "mock-fs"; +import { vol } from "memfs"; import { FabricMetadata } from "@/loaders/fabric/fabric-metadata"; import { FabricMetadataReader } from "@/loaders/fabric/fabric-metadata-reader"; -beforeEach(async () => { - mockFs({ - "fabric.mod.jar": await zipFile([__dirname, "../../../content/fabric/fabric.mod.json"]), +beforeEach(() => { + vol.fromJSON({ + "fabric.mod.jar": zipFile([__dirname, "../../../content/fabric/fabric.mod.json"]), "text.txt": "", }); }); -afterEach(() => { - mockFs.restore(); -}); - describe("FabricMetadataReader", () => { test("successfully reads fabric.mod.json", async () => { const reader = new FabricMetadataReader(); diff --git a/tests/unit/loaders/fabric/fabric-metadata.spec.ts b/tests/unit/loaders/fabric/fabric-metadata.spec.ts index 0fdfaf3..9749a8d 100644 --- a/tests/unit/loaders/fabric/fabric-metadata.spec.ts +++ b/tests/unit/loaders/fabric/fabric-metadata.spec.ts @@ -1,4 +1,4 @@ -import { readFileSync } from "node:fs"; +import { actualFs } from "@/../tests/utils/actual-fs"; import { resolve as resolvePath } from "node:path"; import { DependencyType } from "@/dependencies/dependency-type"; import { PlatformType } from "@/platforms/platform-type"; @@ -6,7 +6,7 @@ import { RawFabricMetadata } from "@/loaders/fabric/raw-fabric-metadata"; import { FabricMetadata } from "@/loaders/fabric/fabric-metadata"; const RAW_METADATA: RawFabricMetadata = Object.freeze(JSON.parse( - readFileSync(resolvePath(__dirname, "../../../content/fabric/fabric.mod.json"), "utf8") + actualFs.readFileSync(resolvePath(__dirname, "../../../content/fabric/fabric.mod.json"), "utf8") )); describe("FabricMetadata", () => { diff --git a/tests/unit/loaders/forge/forge-metadata-reader.spec.ts b/tests/unit/loaders/forge/forge-metadata-reader.spec.ts index ad57214..6fcd1a1 100644 --- a/tests/unit/loaders/forge/forge-metadata-reader.spec.ts +++ b/tests/unit/loaders/forge/forge-metadata-reader.spec.ts @@ -1,19 +1,15 @@ import { zipFile } from "@/../tests/utils/zip-utils"; -import mockFs from "mock-fs"; +import { vol } from "memfs"; import { ForgeMetadata } from "@/loaders/forge/forge-metadata"; import { ForgeMetadataReader } from "@/loaders/forge/forge-metadata-reader"; -beforeEach(async () => { - mockFs({ - "forge.mod.jar": await zipFile([__dirname, "../../../content/forge/mods.toml"], "META-INF/mods.toml"), +beforeEach(() => { + vol.fromJSON({ + "forge.mod.jar": zipFile([__dirname, "../../../content/forge/mods.toml"], "META-INF/mods.toml"), "text.txt": "", }); }); -afterEach(() => { - mockFs.restore(); -}); - describe("ForgeMetadataReader", () => { test("successfully reads mods.toml", async () => { const reader = new ForgeMetadataReader(); diff --git a/tests/unit/loaders/forge/forge-metadata.spec.ts b/tests/unit/loaders/forge/forge-metadata.spec.ts index 9af87fa..b7af840 100644 --- a/tests/unit/loaders/forge/forge-metadata.spec.ts +++ b/tests/unit/loaders/forge/forge-metadata.spec.ts @@ -1,4 +1,4 @@ -import { readFileSync } from "node:fs"; +import { actualFs } from "@/../tests/utils/actual-fs"; import { resolve as resolvePath } from "node:path"; import { parse as parseToml } from "toml"; import { DependencyType } from "@/dependencies/dependency-type"; @@ -7,7 +7,7 @@ import { RawForgeMetadata } from "@/loaders/forge/raw-forge-metadata"; import { ForgeMetadata } from "@/loaders/forge/forge-metadata"; const RAW_METADATA: RawForgeMetadata = Object.freeze(parseToml( - readFileSync(resolvePath(__dirname, "../../../content/forge/mods.toml"), "utf8") + actualFs.readFileSync(resolvePath(__dirname, "../../../content/forge/mods.toml"), "utf8") )); describe("ForgeMetadata", () => { diff --git a/tests/unit/loaders/loader-metadata-reader.spec.ts b/tests/unit/loaders/loader-metadata-reader.spec.ts index f52e3c6..cd0682a 100644 --- a/tests/unit/loaders/loader-metadata-reader.spec.ts +++ b/tests/unit/loaders/loader-metadata-reader.spec.ts @@ -1,6 +1,6 @@ import { zipFile } from "@/../tests/utils/zip-utils"; import { LoaderType } from "@/loaders/loader-type"; -import mockFs from "mock-fs"; +import { vol } from "memfs"; import { LoaderMetadataReader, combineLoaderMetadataReaders, @@ -8,21 +8,17 @@ import { createDefaultLoaderMetadataReader, } from "@/loaders/loader-metadata-reader"; -beforeEach(async () => { - mockFs({ - "fabric.jar": await zipFile([__dirname, "../../content/fabric/fabric.mod.json"]), - "quilt.jar": await zipFile([__dirname, "../../content/quilt/quilt.mod.json"]), - "forge.jar": await zipFile([__dirname, "../../content/forge/mods.toml"], "META-INF/mods.toml"), - "neoforge.jar": await zipFile([__dirname, "../../content/neoforge/neoforge.mods.toml"], "META-INF/neoforge.mods.toml"), - "neoforge.legacy.jar": await zipFile([__dirname, "../../content/neoforge/neoforge.mods.toml"], "META-INF/mods.toml"), +beforeEach(() => { + vol.fromJSON({ + "fabric.jar": zipFile([__dirname, "../../content/fabric/fabric.mod.json"]), + "quilt.jar": zipFile([__dirname, "../../content/quilt/quilt.mod.json"]), + "forge.jar": zipFile([__dirname, "../../content/forge/mods.toml"], "META-INF/mods.toml"), + "neoforge.jar": zipFile([__dirname, "../../content/neoforge/neoforge.mods.toml"], "META-INF/neoforge.mods.toml"), + "neoforge.legacy.jar": zipFile([__dirname, "../../content/neoforge/neoforge.mods.toml"], "META-INF/mods.toml"), "text.txt": "", }); }); -afterEach(() => { - mockFs.restore(); -}); - describe("combineLoaderMetadataReaders", () => { test("combined reader returns metadata from the first underlying reader that successfully reads the metadata", async () => { const reader1 = { readMetadataFile: jest.fn().mockImplementation(x => x === "1" ? Promise.resolve({ id: "1" }) : Promise.reject(new Error("Unknown id"))) } as LoaderMetadataReader; diff --git a/tests/unit/loaders/neoforge/neoforge-metadata-reader.spec.ts b/tests/unit/loaders/neoforge/neoforge-metadata-reader.spec.ts index f884be2..0bdf8a4 100644 --- a/tests/unit/loaders/neoforge/neoforge-metadata-reader.spec.ts +++ b/tests/unit/loaders/neoforge/neoforge-metadata-reader.spec.ts @@ -1,19 +1,15 @@ import { zipFile } from "@/../tests/utils/zip-utils"; -import mockFs from "mock-fs"; +import { vol } from "memfs"; import { NeoForgeMetadata } from "@/loaders/neoforge/neoforge-metadata"; import { NeoForgeMetadataReader } from "@/loaders/neoforge/neoforge-metadata-reader"; -beforeEach(async () => { - mockFs({ - "neoforge.mod.jar": await zipFile([__dirname, "../../../content/neoforge/neoforge.mods.toml"], "META-INF/neoforge.mods.toml"), +beforeEach(() => { + vol.fromJSON({ + "neoforge.mod.jar": zipFile([__dirname, "../../../content/neoforge/neoforge.mods.toml"], "META-INF/neoforge.mods.toml"), "text.txt": "", }); }); -afterEach(() => { - mockFs.restore(); -}); - describe("NeoForgeMetadataReader", () => { test("successfully reads neoforge.mods.toml", async () => { const reader = new NeoForgeMetadataReader(); diff --git a/tests/unit/loaders/neoforge/neoforge-metadata.spec.ts b/tests/unit/loaders/neoforge/neoforge-metadata.spec.ts index 1633a73..50ea633 100644 --- a/tests/unit/loaders/neoforge/neoforge-metadata.spec.ts +++ b/tests/unit/loaders/neoforge/neoforge-metadata.spec.ts @@ -1,4 +1,4 @@ -import { readFileSync } from "node:fs"; +import { actualFs } from "@/../tests/utils/actual-fs"; import { resolve as resolvePath } from "node:path"; import { parse as parseToml } from "toml"; import { DependencyType } from "@/dependencies/dependency-type"; @@ -7,7 +7,7 @@ import { RawNeoForgeMetadata } from "@/loaders/neoforge/raw-neoforge-metadata"; import { NeoForgeMetadata } from "@/loaders/neoforge/neoforge-metadata"; const RAW_METADATA: RawNeoForgeMetadata = Object.freeze(parseToml( - readFileSync(resolvePath(__dirname, "../../../content/neoforge/neoforge.mods.toml"), "utf8") + actualFs.readFileSync(resolvePath(__dirname, "../../../content/neoforge/neoforge.mods.toml"), "utf8") )); describe("NeoForgeMetadata", () => { diff --git a/tests/unit/loaders/quilt/quilt-metadata-reader.spec.ts b/tests/unit/loaders/quilt/quilt-metadata-reader.spec.ts index bca50ae..0513324 100644 --- a/tests/unit/loaders/quilt/quilt-metadata-reader.spec.ts +++ b/tests/unit/loaders/quilt/quilt-metadata-reader.spec.ts @@ -1,19 +1,15 @@ import { zipFile } from "@/../tests/utils/zip-utils"; -import mockFs from "mock-fs"; +import { vol } from "memfs"; import { QuiltMetadata } from "@/loaders/quilt/quilt-metadata"; import { QuiltMetadataReader } from "@/loaders/quilt/quilt-metadata-reader"; -beforeEach(async () => { - mockFs({ - "quilt.mod.jar": await zipFile([__dirname, "../../../content/quilt/quilt.mod.json"]), +beforeEach(() => { + vol.fromJSON({ + "quilt.mod.jar": zipFile([__dirname, "../../../content/quilt/quilt.mod.json"]), "text.txt": "", }); }); -afterEach(() => { - mockFs.restore(); -}); - describe("QuiltMetadataReader", () => { test("successfully reads quilt.mod.json", async () => { const reader = new QuiltMetadataReader(); diff --git a/tests/unit/loaders/quilt/quilt-metadata.spec.ts b/tests/unit/loaders/quilt/quilt-metadata.spec.ts index 456177a..ce19f19 100644 --- a/tests/unit/loaders/quilt/quilt-metadata.spec.ts +++ b/tests/unit/loaders/quilt/quilt-metadata.spec.ts @@ -1,4 +1,4 @@ -import { readFileSync } from "node:fs"; +import { actualFs } from "@/../tests/utils/actual-fs"; import { resolve as resolvePath } from "node:path"; import { DependencyType } from "@/dependencies/dependency-type"; import { PlatformType } from "@/platforms/platform-type"; @@ -6,7 +6,7 @@ import { RawQuiltMetadata } from "@/loaders/quilt/raw-quilt-metadata"; import { QuiltMetadata } from "@/loaders/quilt/quilt-metadata"; const RAW_METADATA: RawQuiltMetadata = Object.freeze(JSON.parse( - readFileSync(resolvePath(__dirname, "../../../content/quilt/quilt.mod.json"), "utf8") + actualFs.readFileSync(resolvePath(__dirname, "../../../content/quilt/quilt.mod.json"), "utf8") )); describe("QuiltMetadata", () => { diff --git a/tests/unit/platforms/curseforge/curseforge-game-version-map.spec.ts b/tests/unit/platforms/curseforge/curseforge-game-version-map.spec.ts index 43b4812..0034df6 100644 --- a/tests/unit/platforms/curseforge/curseforge-game-version-map.spec.ts +++ b/tests/unit/platforms/curseforge/curseforge-game-version-map.spec.ts @@ -1,13 +1,13 @@ import { resolve } from "node:path"; -import { readFile } from "node:fs/promises"; +import { actualFsPromises } from "@/../tests/utils/actual-fs"; import { BUKKIT_GAME_VERSION_TYPE } from "@/platforms/curseforge/curseforge-game-version-type"; import { createCurseForgeGameVersionMap } from "@/platforms/curseforge/curseforge-game-version-map"; describe("createCurseForgeGameVersionMap", () => { test("organizes the provided versions into their respective buckets", async () => { const [versionsSource, versionTypesSource] = await Promise.all([ - readFile(resolve(__dirname, "../../../content/curseforge/versions.json"), "utf8"), - readFile(resolve(__dirname, "../../../content/curseforge/version-types.json"), "utf8"), + actualFsPromises.readFile(resolve(__dirname, "../../../content/curseforge/versions.json"), "utf8"), + actualFsPromises.readFile(resolve(__dirname, "../../../content/curseforge/version-types.json"), "utf8"), ]); const versions = JSON.parse(versionsSource); const versionTypes = [...JSON.parse(versionTypesSource), BUKKIT_GAME_VERSION_TYPE]; diff --git a/tests/unit/platforms/curseforge/curseforge-upload-api-client.spec.ts b/tests/unit/platforms/curseforge/curseforge-upload-api-client.spec.ts index c5b4b18..8789d5d 100644 --- a/tests/unit/platforms/curseforge/curseforge-upload-api-client.spec.ts +++ b/tests/unit/platforms/curseforge/curseforge-upload-api-client.spec.ts @@ -1,6 +1,6 @@ -import { readFileSync } from "node:fs"; +import { actualFs } from "@/../tests/utils/actual-fs"; import { resolve } from "node:path"; -import mockFs from "mock-fs"; +import { vol } from "memfs"; import { createFakeFetch } from "../../../utils/fetch-utils"; import { FormData } from "@/utils/net/form-data"; import { HttpResponse } from "@/utils/net/http-response"; @@ -16,11 +16,11 @@ const FILES = Object.freeze([ const DB = Object.freeze({ versionTypes: Object.freeze(JSON.parse( - readFileSync(resolve(__dirname, "../../../content/curseforge/version-types.json"), "utf8") + actualFs.readFileSync(resolve(__dirname, "../../../content/curseforge/version-types.json"), "utf8") )), versions: Object.freeze(JSON.parse( - readFileSync(resolve(__dirname, "../../../content/curseforge/versions.json"), "utf8") + actualFs.readFileSync(resolve(__dirname, "../../../content/curseforge/versions.json"), "utf8") )), projects: Object.freeze([ @@ -157,11 +157,7 @@ const CURSEFORGE_FETCH = createFakeFetch({ beforeEach(() => { const fakeFiles = FILES.reduce((a, b) => ({ ...a, [b]: "" }), {}); - mockFs(fakeFiles); -}); - -afterEach(() => { - mockFs.restore(); + vol.fromJSON(fakeFiles); }); describe("CurseForgeUploadApiClient", () => { diff --git a/tests/unit/platforms/curseforge/curseforge-uploader.spec.ts b/tests/unit/platforms/curseforge/curseforge-uploader.spec.ts index d3647d1..b3d8b22 100644 --- a/tests/unit/platforms/curseforge/curseforge-uploader.spec.ts +++ b/tests/unit/platforms/curseforge/curseforge-uploader.spec.ts @@ -1,6 +1,6 @@ -import { readFileSync } from "node:fs"; +import { actualFs } from "@/../tests/utils/actual-fs"; import { resolve } from "node:path"; -import mockFs from "mock-fs"; +import { vol } from "memfs"; import { createCombinedFetch, createFakeFetch } from "../../../utils/fetch-utils"; import { PlatformType } from "@/platforms/platform-type"; import { SecureString } from "@/utils/security/secure-string"; @@ -17,11 +17,11 @@ import { CurseForgeUploader } from "@/platforms/curseforge/curseforge-uploader"; const DB = Object.freeze({ versionTypes: Object.freeze(JSON.parse( - readFileSync(resolve(__dirname, "../../../content/curseforge/version-types.json"), "utf8") + actualFs.readFileSync(resolve(__dirname, "../../../content/curseforge/version-types.json"), "utf8") )), versions: Object.freeze(JSON.parse( - readFileSync(resolve(__dirname, "../../../content/curseforge/versions.json"), "utf8") + actualFs.readFileSync(resolve(__dirname, "../../../content/curseforge/versions.json"), "utf8") )), }); @@ -96,15 +96,11 @@ const CURSEFORGE_FETCH = createCombinedFetch( ); beforeEach(() => { - mockFs({ + vol.fromJSON({ "file.txt": "", }); }); -afterEach(() => { - mockFs.restore(); -}); - describe("CurseForgeUploader", () => { describe("platform", () => { test("returns `PlatformType.CURSEFORGE`", () => { diff --git a/tests/unit/platforms/github/github-api-client.spec.ts b/tests/unit/platforms/github/github-api-client.spec.ts index 81ef4eb..5b0b3da 100644 --- a/tests/unit/platforms/github/github-api-client.spec.ts +++ b/tests/unit/platforms/github/github-api-client.spec.ts @@ -1,6 +1,6 @@ -import { readFileSync } from "node:fs"; +import { actualFs } from "@/../tests/utils/actual-fs"; import { resolve } from "node:path"; -import mockFs from "mock-fs"; +import { vol } from "memfs"; import { createFakeFetch } from "../../../utils/fetch-utils"; import { HttpResponse } from "@/utils/net/http-response"; import { GitHubRelease, GitHubReleaseInit, GitHubReleasePatch } from "@/platforms/github/github-release"; @@ -8,7 +8,7 @@ import { GITHUB_API_URL, GitHubApiClient } from "@/platforms/github/github-api-c const DB = Object.freeze({ releases: Object.freeze(JSON.parse( - readFileSync(resolve(__dirname, "../../../content/github/releases.json"), "utf8") + actualFs.readFileSync(resolve(__dirname, "../../../content/github/releases.json"), "utf8") )) as GitHubRelease[], }); @@ -120,11 +120,7 @@ beforeEach(() => { const fileNames = DB.releases.flatMap(x => x.assets).map(x => x.name); const fakeFiles = fileNames.reduce((a, b) => ({ ...a, [b]: "" }), {}); - mockFs(fakeFiles); -}); - -afterEach(() => { - mockFs.restore(); + vol.fromJSON(fakeFiles); }); describe("GitHubApiClient", () => { diff --git a/tests/unit/platforms/github/github-context.spec.ts b/tests/unit/platforms/github/github-context.spec.ts index 97869b2..de55450 100644 --- a/tests/unit/platforms/github/github-context.spec.ts +++ b/tests/unit/platforms/github/github-context.spec.ts @@ -1,4 +1,4 @@ -import mockFs from "mock-fs"; +import { vol } from "memfs"; import { GitHubContext } from "@/platforms/github/github-context"; describe("GitHubContext", () => { @@ -74,15 +74,11 @@ describe("GitHubContext", () => { describe("payload", () => { beforeAll(() => { - mockFs({ + vol.fromJSON({ "payload.json": JSON.stringify({ release: { id: 42 } }), }); }); - afterAll(() => { - mockFs.restore(); - }); - test("returns payload when GITHUB_EVENT_PATH is set and file exists", () => { const context = new GitHubContext({ GITHUB_EVENT_PATH: "payload.json" }); diff --git a/tests/unit/platforms/github/github-uploader.spec.ts b/tests/unit/platforms/github/github-uploader.spec.ts index ccbfa33..3a54a8a 100644 --- a/tests/unit/platforms/github/github-uploader.spec.ts +++ b/tests/unit/platforms/github/github-uploader.spec.ts @@ -1,4 +1,4 @@ -import mockFs from "mock-fs"; +import { vol } from "memfs"; import { createFakeFetch } from "../../../utils/fetch-utils"; import { PlatformType } from "@/platforms/platform-type"; import { SecureString } from "@/utils/security/secure-string"; @@ -63,15 +63,11 @@ const CONTEXT = new GitHubContext({ }); beforeEach(() => { - mockFs({ + vol.fromJSON({ "file.txt": "", }); }); -afterEach(() => { - mockFs.restore(); -}); - describe("GitHubUploader", () => { describe("platform", () => { test("returns `PlatformType.GITHUB`", () => { diff --git a/tests/unit/platforms/modrinth/modrinth-api-client.spec.ts b/tests/unit/platforms/modrinth/modrinth-api-client.spec.ts index e4b3337..613cf2b 100644 --- a/tests/unit/platforms/modrinth/modrinth-api-client.spec.ts +++ b/tests/unit/platforms/modrinth/modrinth-api-client.spec.ts @@ -1,5 +1,5 @@ -import mockFs from "mock-fs"; -import { readFileSync } from "node:fs"; +import { vol } from "memfs"; +import { actualFs } from "@/../tests/utils/actual-fs"; import { resolve } from "node:path"; import { createFakeFetch } from "../../../utils/fetch-utils"; import { FormData } from "@/utils/net/form-data"; @@ -13,19 +13,19 @@ import { MODRINTH_API_URL, ModrinthApiClient } from "@/platforms/modrinth/modrin const DB = Object.freeze({ loaders: Object.freeze(JSON.parse( - readFileSync(resolve(__dirname, "../../../content/modrinth/loader.json"), "utf8") + actualFs.readFileSync(resolve(__dirname, "../../../content/modrinth/loader.json"), "utf8") )) as ModrinthLoader[], gameVersions: Object.freeze(JSON.parse( - readFileSync(resolve(__dirname, "../../../content/modrinth/game_version.json"), "utf8") + actualFs.readFileSync(resolve(__dirname, "../../../content/modrinth/game_version.json"), "utf8") )) as ModrinthGameVersion[], projects: Object.freeze(JSON.parse( - readFileSync(resolve(__dirname, "../../../content/modrinth/projects.json"), "utf8") + actualFs.readFileSync(resolve(__dirname, "../../../content/modrinth/projects.json"), "utf8") )) as ModrinthProject[], versions: Object.freeze(JSON.parse( - readFileSync(resolve(__dirname, "../../../content/modrinth/versions.json"), "utf8") + actualFs.readFileSync(resolve(__dirname, "../../../content/modrinth/versions.json"), "utf8") )) as ModrinthVersion[], }); @@ -196,11 +196,7 @@ beforeEach(() => { const fileNames = DB.versions.flatMap(x => x.files).map(x => x.filename); const fakeFiles = fileNames.reduce((a, b) => ({ ...a, [b]: "" }), {}); - mockFs(fakeFiles); -}); - -afterEach(() => { - mockFs.restore(); + vol.fromJSON(fakeFiles); }); describe("ModrinthApiClient", () => { diff --git a/tests/unit/platforms/modrinth/modrinth-uploader.spec.ts b/tests/unit/platforms/modrinth/modrinth-uploader.spec.ts index f0b8156..260b021 100644 --- a/tests/unit/platforms/modrinth/modrinth-uploader.spec.ts +++ b/tests/unit/platforms/modrinth/modrinth-uploader.spec.ts @@ -1,6 +1,6 @@ import { resolve } from "node:path"; -import { readFileSync } from "node:fs"; -import mockFs from "mock-fs"; +import { actualFs } from "@/../tests/utils/actual-fs"; +import { vol } from "memfs"; import { createFakeFetch } from "../../../utils/fetch-utils"; import { SecureString } from "@/utils/security/secure-string"; import { PlatformType } from "@/platforms/platform-type"; @@ -17,11 +17,11 @@ import { ModrinthUploader } from "@/platforms/modrinth/modrinth-uploader"; const DB = Object.freeze({ loaders: Object.freeze(JSON.parse( - readFileSync(resolve(__dirname, "../../../content/modrinth/loader.json"), "utf8") + actualFs.readFileSync(resolve(__dirname, "../../../content/modrinth/loader.json"), "utf8") )), gameVersions: Object.freeze(JSON.parse( - readFileSync(resolve(__dirname, "../../../content/modrinth/game_version.json"), "utf8") + actualFs.readFileSync(resolve(__dirname, "../../../content/modrinth/game_version.json"), "utf8") )), }); @@ -80,15 +80,11 @@ const MODRINTH_FETCH = createFakeFetch({ }); beforeEach(() => { - mockFs({ + vol.fromJSON({ "file.txt": "", }); }); -afterEach(() => { - mockFs.restore(); -}); - describe("ModrinthUploader", () => { describe("platform", () => { test("returns `PlatformType.MODRINTH`", () => { diff --git a/tests/unit/utils/actions/action-metadata.spec.ts b/tests/unit/utils/actions/action-metadata.spec.ts index e362d11..444df36 100644 --- a/tests/unit/utils/actions/action-metadata.spec.ts +++ b/tests/unit/utils/actions/action-metadata.spec.ts @@ -1,8 +1,8 @@ -import mockFs from "mock-fs"; +import { vol } from "memfs"; import { parseActionMetadataFromFile, parseActionMetadataFromString } from "@/utils/actions/action-metadata"; beforeEach(() => { - mockFs({ + vol.fromJSON({ "action.yml": ` name: Test Action description: This is a test action @@ -17,10 +17,6 @@ beforeEach(() => { }); }); -afterEach(() => { - mockFs.restore(); -}); - describe("parseActionMetadataFromString", () => { test("returns the parsed ActionMetadata object for valid YAML text", () => { const actionYamlText = ` diff --git a/tests/unit/utils/actions/action-output.spec.ts b/tests/unit/utils/actions/action-output.spec.ts index 950c850..606ac02 100644 --- a/tests/unit/utils/actions/action-output.spec.ts +++ b/tests/unit/utils/actions/action-output.spec.ts @@ -1,4 +1,4 @@ -import mockFs from "mock-fs"; +import { vol } from "memfs"; import { readFile } from "node:fs/promises"; import { ActionMetadata } from "@/utils/actions/action-metadata"; import { ActionParameterPathParser } from "@/utils/actions/action-parameter-path-parser"; @@ -9,15 +9,11 @@ const ENV = Object.freeze({ }); beforeEach(() => { - mockFs({ + vol.fromJSON({ "output.txt": "", }); }); -afterEach(() => { - mockFs.restore(); -}); - describe("setActionOutput", () => { test("writes the value of an output to a file", async () => { setActionOutput("output1", "value1", ENV); diff --git a/tests/unit/utils/errors/file-not-found-error.spec.ts b/tests/unit/utils/errors/file-not-found-error.spec.ts index 027866a..6578343 100644 --- a/tests/unit/utils/errors/file-not-found-error.spec.ts +++ b/tests/unit/utils/errors/file-not-found-error.spec.ts @@ -1,5 +1,5 @@ import { FileNotFoundError } from "@/utils/errors/file-not-found-error"; -import mockFs from "mock-fs"; +import { vol } from "memfs"; describe("FileNotFoundError", () => { describe("constructor", () => { @@ -24,11 +24,7 @@ describe("FileNotFoundError", () => { describe("throwIfNotFound", () => { beforeEach(() => { - mockFs({ test: "test" }); - }); - - afterEach(() => { - mockFs.restore(); + vol.fromJSON({ test: "test" }); }); test("throws error if file does not exist", () => { diff --git a/tests/unit/utils/io/file-info.spec.ts b/tests/unit/utils/io/file-info.spec.ts index 4554a26..54b1b06 100644 --- a/tests/unit/utils/io/file-info.spec.ts +++ b/tests/unit/utils/io/file-info.spec.ts @@ -1,5 +1,4 @@ -import { statSync } from "node:fs"; -import mockFs from "mock-fs"; +import { fs as memfs, vol } from "memfs"; import { zipContent } from "../../../utils/zip-utils"; import { FileInfo, @@ -14,20 +13,16 @@ import { readZippedFile, } from "@/utils/io/file-info"; -beforeEach(async () => { - mockFs({ +beforeEach(() => { + vol.fromNestedJSON({ "path/to": { "test.txt": "test", "test.json": JSON.stringify({ foo: 42 }), - "test.zip": await zipContent("test", "test.txt"), + "test.zip": zipContent("test", "test.txt"), }, }); }); -afterEach(() => { - mockFs.restore(); -}); - describe("FileInfo", () => { describe("constructor", () => { test("constructs a new instance with the given path", () => { @@ -95,7 +90,7 @@ describe("FileInfo", () => { test("returns the file size", () => { const info = new FileInfo("path/to/test.txt"); - expect(info.size).toBe(statSync("path/to/test.txt").size); + expect(info.size).toBe(memfs.statSync("path/to/test.txt").size); }); test("throws if the file does not exist", () => { diff --git a/tests/unit/utils/net/blob.spec.ts b/tests/unit/utils/net/blob.spec.ts index eef278a..1a8299d 100644 --- a/tests/unit/utils/net/blob.spec.ts +++ b/tests/unit/utils/net/blob.spec.ts @@ -1,16 +1,12 @@ -import mockFs from "mock-fs"; +import { vol } from "memfs"; import { Blob, isBlob, readBlob, readBlobSync } from "@/utils/net/blob"; beforeEach(() => { - mockFs({ + vol.fromJSON({ "test.txt": "test", }); }); -afterEach(() => { - mockFs.restore(); -}); - describe("isBlob", () => { test("returns true for Blob instances", () => { expect(isBlob(new Blob([]))).toBe(true); diff --git a/tests/unit/utils/net/form-data.spec.ts b/tests/unit/utils/net/form-data.spec.ts index a4d97db..806398c 100644 --- a/tests/unit/utils/net/form-data.spec.ts +++ b/tests/unit/utils/net/form-data.spec.ts @@ -1,18 +1,14 @@ -import mockFs from "mock-fs"; +import { vol } from "memfs"; import { FileInfo } from "@/utils/io/file-info"; import { FILE_PATH, FormData, isFormData, toFormData } from "@/utils/net/form-data"; import { isBlob } from "@/utils/net/blob"; beforeEach(() => { - mockFs({ + vol.fromJSON({ "file.json": "{}", }); }); -afterEach(() => { - mockFs.restore(); -}); - describe("FormData", () => { describe("constructor", () => { test("creates a new FormData instance", () => { diff --git a/tests/unit/utils/net/headers.spec.ts b/tests/unit/utils/net/headers.spec.ts index 1cb546e..ad7a18d 100644 --- a/tests/unit/utils/net/headers.spec.ts +++ b/tests/unit/utils/net/headers.spec.ts @@ -1,19 +1,14 @@ -import { createReadStream, statSync } from "node:fs"; -import mockFs from "mock-fs"; +import { fs as memfs, vol } from "memfs"; import { ArrayMap, MultiMap } from "@/utils/collections/map"; import { Blob } from "@/utils/net/blob"; import { appendHeader, appendHeaders, cloneHeaders, deleteHeader, deleteHeaders, getHeader, hasHeader, inferHttpRequestBodyHeaders, setDefaultHeader, setDefaultHeaders, setHeader, setHeaders } from "@/utils/net"; beforeEach(() => { - mockFs({ + vol.fromJSON({ "file.json": "{}", }); }); -afterEach(() => { - mockFs.restore(); -}); - describe("hasHeader", () => { test("returns true when header exists in a Record", () => { const headers = { "Content-Type": "application/json" }; @@ -575,11 +570,11 @@ describe("inferHttpRequestBodyHeaders", () => { }); test("returns correct headers when body is a ReadableStream created from a file path", () => { - const body = createReadStream("file.json"); + const body = memfs.createReadStream("file.json"); const headers = inferHttpRequestBodyHeaders(body); expect(headers["Content-Type"]).toBe("application/octet-stream"); - expect(headers["Content-Length"]).toBe(String(statSync("file.json").size)); + expect(headers["Content-Length"]).toBe(String(memfs.statSync("file.json").size)); }); }); diff --git a/tests/utils/actual-fs.ts b/tests/utils/actual-fs.ts new file mode 100644 index 0000000..05f5fcc --- /dev/null +++ b/tests/utils/actual-fs.ts @@ -0,0 +1,2 @@ +export const actualFs = jest.requireActual("node:fs"); +export const actualFsPromises = jest.requireActual("node:fs/promises"); diff --git a/tests/utils/fetch-utils.ts b/tests/utils/fetch-utils.ts index 3fbe08f..724d481 100644 --- a/tests/utils/fetch-utils.ts +++ b/tests/utils/fetch-utils.ts @@ -1,5 +1,4 @@ -import { readFile } from "node:fs/promises"; -import { existsSync } from "node:fs"; +import { actualFs, actualFsPromises } from "./actual-fs"; import { resolve } from "node:path"; import { Fetch, HttpMethod, HttpRequest, HttpResponse, createFetch } from "@/utils/net"; @@ -32,8 +31,8 @@ async function normalizeResponse(response: FetchInterceptorResponse): Promise typeof x === "string")) { const path = resolve(...response); - if (existsSync(path)) { - const content = await readFile(path, "utf8"); + if (actualFs.existsSync(path)) { + const content = await actualFsPromises.readFile(path, "utf8"); return HttpResponse.text(content); } } diff --git a/tests/utils/zip-utils.ts b/tests/utils/zip-utils.ts index 417214c..2c20c9d 100644 --- a/tests/utils/zip-utils.ts +++ b/tests/utils/zip-utils.ts @@ -1,31 +1,18 @@ import { basename, resolve as resolvePath } from "node:path"; -import { ZipFile } from "yazl"; +import Zip from "adm-zip"; -export async function zipFile(path: string | string[], zipPath?: string): Promise { +export function zipFile(path: string | string[], zipPath?: string): Buffer { + const fs = jest.requireActual("node:fs"); const realPath = typeof path === "string" ? path : resolvePath(...path); zipPath ||= basename(realPath); - const zip = new ZipFile(); - zip.addFile(realPath, zipPath); - zip.end(); - - const chunks = [] as Buffer[]; - for await (const chunk of zip.outputStream) { - chunks.push(Buffer.from(chunk)); - } - - return Buffer.concat(chunks); + const zip = new Zip(); + zip.addFile(zipPath, fs.readFileSync(realPath)); + return zip.toBuffer(); } -export async function zipContent(content: string | Buffer, zipPath: string): Promise { - const zip = new ZipFile(); - zip.addBuffer(Buffer.from(content), zipPath); - zip.end(); - - const chunks = [] as Buffer[]; - for await (const chunk of zip.outputStream) { - chunks.push(Buffer.from(chunk)); - } - - return Buffer.concat(chunks); +export function zipContent(content: string | Buffer, zipPath: string): Buffer { + const zip = new Zip(); + zip.addFile(zipPath, typeof content === "string" ? Buffer.from(content) : content); + return zip.toBuffer(); }