diff --git a/jest.config.js b/jest.config.js index 5bf7d3fe..2d4d388f 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,11 +1,13 @@ -/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ -module.exports = { +/** @type {import('ts-jest').JestConfigWithTsJest} */ + +export default { preset: 'ts-jest', testEnvironment: 'jsdom', testEnvironmentOptions: { customExportConditions: ['node', 'node-addons'], }, transform: { + '^.+\\.(js|jsx|ts|tsx)$': '@swc/jest', '^.+\\.vue$': '@vue/vue3-jest', }, moduleNameMapper: { diff --git a/package-lock.json b/package-lock.json index 96bc7cf1..505e2621 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@eslint/eslintrc": "^3.2.0", "@eslint/js": "^9.20.0", "@ffflorian/jszip-cli": "^3.8.2", + "@swc/jest": "^0.2.37", "@types/firefox-webext-browser": "^120.0.4", "@types/fs-extra": "^11.0.4", "@types/jest": "^29.5.14", @@ -2965,6 +2966,18 @@ "node": ">=8" } }, + "node_modules/@jest/create-cache-key-function": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz", + "integrity": "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/@jest/environment": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", @@ -3990,6 +4003,248 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@swc/core": { + "version": "1.10.16", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.10.16.tgz", + "integrity": "sha512-nOINg/OUcZazCW7B55QV2/UB8QAqz9FYe4+z229+4RYboBTZ102K7ebOEjY5sKn59JgAkhjZTz+5BKmXpDFopw==", + "dev": true, + "hasInstallScript": true, + "peer": true, + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.17" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.10.16", + "@swc/core-darwin-x64": "1.10.16", + "@swc/core-linux-arm-gnueabihf": "1.10.16", + "@swc/core-linux-arm64-gnu": "1.10.16", + "@swc/core-linux-arm64-musl": "1.10.16", + "@swc/core-linux-x64-gnu": "1.10.16", + "@swc/core-linux-x64-musl": "1.10.16", + "@swc/core-win32-arm64-msvc": "1.10.16", + "@swc/core-win32-ia32-msvc": "1.10.16", + "@swc/core-win32-x64-msvc": "1.10.16" + }, + "peerDependencies": { + "@swc/helpers": "*" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.10.16", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.10.16.tgz", + "integrity": "sha512-iikIxwqCQ4Bvz79vJ4ELh26efPf1u5D9TFdmXSJUBs7C3mmMHvk5zyWD9A9cTowXiW6WHs2gE58U1R9HOTTIcg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.10.16", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.10.16.tgz", + "integrity": "sha512-R2Eb9aktWd62vPfW9H/c/OaQ0e94iURibBo4uzUUcgxNNmB4+wb6piKbHxGdr/5bEsT+vJ1lwZFSRzfb45E7DA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.10.16", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.10.16.tgz", + "integrity": "sha512-mkqN3HBAMnuiSGZ/k2utScuH8rAPshvNj0T1LjBWon+X9DkMNHSA+aMLdWsy0yZKF1zjOPc4L3Uq2l2wzhUlzA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.10.16", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.10.16.tgz", + "integrity": "sha512-PH/+q/L5nVZJ91CU07CL6Q9Whs6iR6nneMZMAgtVF9Ix8ST0cWVItdUhs6D38kFklCFhaOrpHhS01HlMJ72vWw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.10.16", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.10.16.tgz", + "integrity": "sha512-1169+C9XbydKKc6Ec1XZxTGKtHjZHDIFn0r+Nqp/QSVwkORrOY1Vz2Hdu7tn/lWMg36ZkGePS+LnnyV67s/7yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.10.16", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.10.16.tgz", + "integrity": "sha512-n2rV0XwkjoHn4MDJmpYp5RBrnyi94/6GsJVpbn6f+/eqSrZn3mh3dT7pdZc9zCN1Qp9eDHo+uI6e/wgvbL22uA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.10.16", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.10.16.tgz", + "integrity": "sha512-EevCpwreBrkPrJjQVIbiM81lK42ukNNSlBmrSRxxbx2V9VGmOd5qxX0cJBn0TRRSLIPi62BuMS76F9iYjqsjgg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.10.16", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.10.16.tgz", + "integrity": "sha512-BvE7RWAnKJeELVQWLok6env5I4GUVBTZSvaSN/VPgxnTjF+4PsTeQptYx0xCYhp5QCv68wWYsBnZKuPDS+SBsw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.10.16", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.10.16.tgz", + "integrity": "sha512-7Jf/7AeCgbLR/JsQgMJuacHIq4Jeie3knf6+mXxn8aCvRypsOTIEu0eh7j24SolOboxK1ijqJ86GyN1VA2Rebg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.10.16", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.10.16.tgz", + "integrity": "sha512-p0blVm0R8bjaTtmW+FoPmLxLSQdRNbqhuWcR/8g80OzMSkka9mk5/J3kn/5JRVWh+MaR9LHRHZc1Q1L8zan13g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true + }, + "node_modules/@swc/jest": { + "version": "0.2.37", + "resolved": "https://registry.npmjs.org/@swc/jest/-/jest-0.2.37.tgz", + "integrity": "sha512-CR2BHhmXKGxTiFr21DYPRHQunLkX3mNIFGFkxBGji6r9uyIR5zftTOVYj1e0sFNMV2H7mf/+vpaglqaryBtqfQ==", + "dev": true, + "dependencies": { + "@jest/create-cache-key-function": "^29.7.0", + "@swc/counter": "^0.1.3", + "jsonc-parser": "^3.2.0" + }, + "engines": { + "npm": ">= 7.0.0" + }, + "peerDependencies": { + "@swc/core": "*" + } + }, + "node_modules/@swc/types": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.17.tgz", + "integrity": "sha512-V5gRru+aD8YVyCOMAjMpWR1Ui577DD5KSJsHP8RAxopAH22jFz6GZd/qxqjO6MJHQhcsjvjOFXyDhyLQUnMveQ==", + "dev": true, + "peer": true, + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, "node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -13358,6 +13613,12 @@ "node": ">=6" } }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true + }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", diff --git a/package.json b/package.json index 239aac48..6339cb7d 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "version": "0.9.5", "description": "Improve your Mullvad VPN experience, in your browser.", "private": true, + "type": "module", "engines": { "node": ">=18.14.2", "npm": ">=9.5.0" @@ -43,6 +44,7 @@ "@eslint/eslintrc": "^3.2.0", "@eslint/js": "^9.20.0", "@ffflorian/jszip-cli": "^3.8.2", + "@swc/jest": "^0.2.37", "@types/firefox-webext-browser": "^120.0.4", "@types/fs-extra": "^11.0.4", "@types/jest": "^29.5.14", diff --git a/scripts/utils.ts b/scripts/utils.ts index c461fb21..c8a8ba2d 100644 --- a/scripts/utils.ts +++ b/scripts/utils.ts @@ -1,10 +1,15 @@ -import { resolve } from 'path'; import { bgCyan, black } from 'kolorist'; - -export const port = parseInt(process.env.PORT || '') || 3303; -export const r = (...args: string[]) => resolve(__dirname, '..', ...args); -export const isDev = process.env.NODE_ENV !== 'production'; +import { resolve, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; export function log(name: string, message: string) { console.log(black(bgCyan(` ${name} `)), message); } + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +export const port = parseInt(process.env.PORT || '') || 3303; +export const isDev = process.env.NODE_ENV !== 'production'; + +export const r = (...args: string[]) => resolve(__dirname, '..', ...args); diff --git a/src/components/Location.test.ts b/src/components/Location.test.ts index 9fb2db0a..358ee5b7 100644 --- a/src/components/Location.test.ts +++ b/src/components/Location.test.ts @@ -10,7 +10,7 @@ jest.mock('@/composables/useActiveTab', () => ({ })), })); -jest.mock('@/composables/useSocksProxies/useSocksProxies', () => ({ +jest.mock('@/composables/useSocksProxies', () => ({ __esModule: true, default: jest.fn(() => ({ filteredProxies: [ diff --git a/src/components/Location.vue b/src/components/Location.vue index 1203f9c2..139f9eef 100644 --- a/src/components/Location.vue +++ b/src/components/Location.vue @@ -6,10 +6,10 @@ import LocationTabs from '@/components/LocationTabs.vue'; import SearchLocation from '@/components/SearchLocation.vue'; import IconLabel from '@/components/IconLabel.vue'; -import getRandomSocksProxy from '@/helpers/getRandomSocksProxy'; +import getCityCountrySocksProxy from '@/helpers/socksProxy/getCityCountrySocksProxy'; import { updateCurrentTabProxyBadge } from '@/helpers/proxyBadge'; -import useSocksProxies from '@/composables/useSocksProxies/useSocksProxies'; +import useSocksProxies from '@/composables/useSocksProxies'; import useSocksProxy from '@/composables/useSocksProxy'; import useLocations from '@/composables/useLocations'; import useProxyHistory from '@/composables/useProxyHistory/useProxyHistory'; @@ -61,7 +61,7 @@ const clickServer = ( }; const clickCountryOrCity = (selectedCountry: string, selectedCity?: string) => { - const { country, countryCode, city, hostname, ipv4_address, port } = getRandomSocksProxy({ + const { country, countryCode, city, hostname, ipv4_address, port } = getCityCountrySocksProxy({ socksProxies: filteredProxies.value, country: selectedCountry, city: selectedCity, diff --git a/src/components/OptionsTabs/ProxyTab.vue b/src/components/OptionsTabs/ProxyTab.vue index 05e43d32..6bf356a5 100644 --- a/src/components/OptionsTabs/ProxyTab.vue +++ b/src/components/OptionsTabs/ProxyTab.vue @@ -6,6 +6,7 @@ import CustomProxies from '@/components/Proxy/CustomProxies.vue'; import IconLabel from '@/components/IconLabel.vue'; import LocationDrawer from '@/components/ConnectionDetails/LocationDrawer.vue'; import ProxyAutoReload from '@/components/Proxy/ProxyAutoReload.vue'; +import RandomProxyMode from '@/components/Proxy/RandomProxyMode.vue'; import TitleCategory from '@/components/TitleCategory.vue'; import useProxyPermissions from '@/composables/useProxyPermissions'; @@ -16,6 +17,7 @@ const { isGranted, requestPermissions } = useProxyPermissions(); diff --git a/src/components/Proxy/HomeProxyStatus.vue b/src/components/Proxy/HomeProxyStatus.vue index d97d50ed..1007a751 100644 --- a/src/components/Proxy/HomeProxyStatus.vue +++ b/src/components/Proxy/HomeProxyStatus.vue @@ -11,7 +11,7 @@ import useActiveTab from '@/composables/useActiveTab'; import useConnection, { ConnectionKey, defaultConnection } from '@/composables/useConnection'; import useLocations from '@/composables/useLocations'; import useProxyPermissions from '@/composables/useProxyPermissions'; -import useSocksProxies from '@/composables/useSocksProxies/useSocksProxies'; +import useSocksProxies from '@/composables/useSocksProxies'; import useSocksProxy from '@/composables/useSocksProxy'; import { checkDomain } from '@/helpers/domain'; @@ -128,6 +128,13 @@ const handleRemoveProxy = (host: string) => { watch([currentHostProxyEnabled, subDomainProxyEnabled, domainProxyDetails, excludedHosts], () => { lastClickedTab.value = null; }); + +watch(isGranted, () => { + // This is to make sure there's always a proxy list when the user starts using the proxy feature + if (isGranted.value) { + getSocksProxies(); + } +});