diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4c55e6c5..497efe6d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -105,10 +105,6 @@ jobs: db-port: ${{ job.services.postgres.ports['5432'] }} redis-port: ${{ job.services.redis.ports['6379'] }} - - name: Run frontend unit tests - if: matrix.shard == 1 - run: npm run test:unit - - name: Build assets run: npm run build diff --git a/composer.json b/composer.json index f9a4236b..8d3a7946 100644 --- a/composer.json +++ b/composer.json @@ -123,7 +123,6 @@ ], "test:all": [ "@test", - "npm run test:unit", "@php artisan test tests/Browser" ], "post-autoload-dump": [ diff --git a/package-lock.json b/package-lock.json index d198f40f..51f067e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,7 +63,6 @@ "typescript": "^5.2.2", "typescript-eslint": "^8.23.0", "vite": "^8.0.16", - "vitest": "^4.1.9", "vue-tsc": "^2.2.4" }, "optionalDependencies": { @@ -1671,13 +1670,6 @@ "license": "MIT", "peer": true }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "dev": true, - "license": "MIT" - }, "node_modules/@swc/helpers": { "version": "0.5.18", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.18.tgz", @@ -2044,17 +2036,6 @@ "tslib": "^2.4.0" } }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" - } - }, "node_modules/@types/d3": { "version": "7.4.3", "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", @@ -2380,13 +2361,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -3213,136 +3187,6 @@ "vue": "^3.2.25" } }, - "node_modules/@vitest/expect": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.9.tgz", - "integrity": "sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.1.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.9", - "@vitest/utils": "4.1.9", - "chai": "^6.2.2", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/mocker": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.9.tgz", - "integrity": "sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "4.1.9", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/@vitest/mocker/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/@vitest/pretty-format": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.9.tgz", - "integrity": "sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.9.tgz", - "integrity": "sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "4.1.9", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.9.tgz", - "integrity": "sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.9", - "@vitest/utils": "4.1.9", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.9.tgz", - "integrity": "sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.9.tgz", - "integrity": "sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.9", - "convert-source-map": "^2.0.0", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, "node_modules/@volar/language-core": { "version": "2.4.15", "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.15.tgz", @@ -3943,16 +3787,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, "node_modules/async-function": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", @@ -4109,16 +3943,6 @@ "node": ">=6" } }, - "node_modules/chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -5292,13 +5116,6 @@ "node": ">= 0.4" } }, - "node_modules/es-module-lexer": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.0.tgz", - "integrity": "sha512-KLdwQm2NvGLDkQDCGvmiQrhkd0JbMzXthwQAUgWjQuQdBLFa3eiBP5arXZyA+f8x+x7OXgud6bq2rxjGtHV2tw==", - "dev": true, - "license": "MIT" - }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -5903,16 +5720,6 @@ "node": ">=0.10.0" } }, - "node_modules/expect-type": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", - "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -7831,20 +7638,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/obug": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.3.tgz", - "integrity": "sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==", - "dev": true, - "funding": [ - "https://github.com/sponsors/sxzz", - "https://opencollective.com/debug" - ], - "license": "MIT", - "engines": { - "node": ">=12.20.0" - } - }, "node_modules/ohash": { "version": "2.0.11", "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", @@ -7994,13 +7787,6 @@ "node": ">=8" } }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, "node_modules/pbf": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.3.0.tgz", @@ -8904,13 +8690,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, - "license": "ISC" - }, "node_modules/socket.io-client": { "version": "4.8.3", "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.3.tgz", @@ -8972,20 +8751,6 @@ "node": ">=12.0.0" } }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true, - "license": "MIT" - }, - "node_modules/std-env": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", - "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", - "dev": true, - "license": "MIT" - }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", @@ -9219,23 +8984,6 @@ "node": ">=12.22" } }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", - "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/tinyglobby": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", @@ -9288,16 +9036,6 @@ "dev": true, "license": "ISC" }, - "node_modules/tinyrainbow": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", - "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -9816,109 +9554,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/vitest": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.9.tgz", - "integrity": "sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/expect": "4.1.9", - "@vitest/mocker": "4.1.9", - "@vitest/pretty-format": "4.1.9", - "@vitest/runner": "4.1.9", - "@vitest/snapshot": "4.1.9", - "@vitest/spy": "4.1.9", - "@vitest/utils": "4.1.9", - "es-module-lexer": "^2.0.0", - "expect-type": "^1.3.0", - "magic-string": "^0.30.21", - "obug": "^2.1.1", - "pathe": "^2.0.3", - "picomatch": "^4.0.3", - "std-env": "^4.0.0-rc.1", - "tinybench": "^2.9.0", - "tinyexec": "^1.0.2", - "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.1.0", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@opentelemetry/api": "^1.9.0", - "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.9", - "@vitest/browser-preview": "4.1.9", - "@vitest/browser-webdriverio": "4.1.9", - "@vitest/coverage-istanbul": "4.1.9", - "@vitest/coverage-v8": "4.1.9", - "@vitest/ui": "4.1.9", - "happy-dom": "*", - "jsdom": "*", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@opentelemetry/api": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser-playwright": { - "optional": true - }, - "@vitest/browser-preview": { - "optional": true - }, - "@vitest/browser-webdriverio": { - "optional": true - }, - "@vitest/coverage-istanbul": { - "optional": true - }, - "@vitest/coverage-v8": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - }, - "vite": { - "optional": false - } - } - }, - "node_modules/vitest/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/vscode-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", @@ -10164,23 +9799,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", diff --git a/package.json b/package.json index 4e3792d6..5920e3a0 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,7 @@ "dev": "vite", "format": "prettier --write resources/", "format:check": "prettier --check resources/", - "lint": "eslint . --fix", - "test:unit": "vitest run" + "lint": "eslint . --fix" }, "devDependencies": { "@eslint/js": "^9.19.0", @@ -37,7 +36,6 @@ "typescript": "^5.2.2", "typescript-eslint": "^8.23.0", "vite": "^8.0.16", - "vitest": "^4.1.9", "vue-tsc": "^2.2.4" }, "dependencies": { diff --git a/resources/js/lib/imageCrop.test.ts b/resources/js/lib/imageCrop.test.ts deleted file mode 100644 index ce35943b..00000000 --- a/resources/js/lib/imageCrop.test.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { describe, expect, it } from 'vitest'; - -import { - clampSelection, - containScale, - defaultSelection, - resizeSelection, - resolveOutputFileName, - resolveOutputMime, -} from '@/lib/imageCrop'; - -const VIEWPORT = 512; - -describe('containScale', () => { - it('fits a landscape image by its width', () => { - expect(containScale(1000, 500, VIEWPORT)).toBeCloseTo(VIEWPORT / 1000, 6); - }); - - it('fits a portrait image by its height', () => { - expect(containScale(500, 1000, VIEWPORT)).toBeCloseTo(VIEWPORT / 1000, 6); - }); - - it('returns 1:1 when the image already matches the viewport', () => { - expect(containScale(VIEWPORT, VIEWPORT, VIEWPORT)).toBe(1); - }); - - it('falls back to 1 for degenerate dimensions', () => { - expect(containScale(0, 500, VIEWPORT)).toBe(1); - expect(containScale(500, 0, VIEWPORT)).toBe(1); - expect(containScale(-10, 500, VIEWPORT)).toBe(1); - }); -}); - -describe('defaultSelection', () => { - it('is a centered square inset from the edges of a landscape image', () => { - expect(defaultSelection(1000, 500)).toEqual({ sx: 300, sy: 50, sw: 400, sh: 400 }); - }); - - it('is a centered square inset from the edges of a portrait image', () => { - expect(defaultSelection(500, 1000)).toEqual({ sx: 50, sy: 300, sw: 400, sh: 400 }); - }); - - it('stays inset even when the image is already square, so the crop box is always visible', () => { - expect(defaultSelection(800, 800)).toEqual({ sx: 80, sy: 80, sw: 640, sh: 640 }); - }); -}); - -describe('clampSelection', () => { - it('caps the size at the shorter image side', () => { - expect(clampSelection({ sx: 0, sy: 0, sw: 9999, sh: 9999 }, 1000, 500, 50)).toEqual({ - sx: 0, - sy: 0, - sw: 500, - sh: 500, - }); - }); - - it('never shrinks below the minimum size', () => { - expect(clampSelection({ sx: 0, sy: 0, sw: 10, sh: 10 }, 1000, 500, 50).sw).toBe(50); - }); - - it('pulls a selection that ran off the right edge back inside', () => { - const clamped = clampSelection({ sx: 900, sy: 0, sw: 500, sh: 500 }, 1000, 500, 50); - - expect(clamped.sx).toBe(500); - expect(clamped.sx + clamped.sw).toBe(1000); - }); - - it('pulls negative offsets back to the origin', () => { - expect(clampSelection({ sx: -100, sy: -100, sw: 300, sh: 300 }, 1000, 500, 50)).toEqual({ - sx: 0, - sy: 0, - sw: 300, - sh: 300, - }); - }); - - it('pulls a selection that ran off the bottom edge back inside', () => { - const clamped = clampSelection({ sx: 0, sy: 900, sw: 400, sh: 400 }, 500, 1000, 50); - - expect(clamped.sy).toBe(600); - expect(clamped.sy + clamped.sh).toBe(1000); - }); -}); - -describe('resizeSelection', () => { - const base = { sx: 200, sy: 100, sw: 200, sh: 200 }; - - it('grows from the anchored top-left corner when the vertical drag dominates (se)', () => { - const resized = resizeSelection(base, 'se', 500, 500, 1000, 600, 50); - - expect(resized).toEqual({ sx: 200, sy: 100, sw: 400, sh: 400 }); - }); - - it('sizes from the horizontal drag when it dominates (se)', () => { - const resized = resizeSelection(base, 'se', 700, 150, 1000, 600, 50); - - expect(resized).toEqual({ sx: 200, sy: 100, sw: 500, sh: 500 }); - }); - - it('anchors the top-right corner when dragging the bottom-left (sw)', () => { - const resized = resizeSelection(base, 'sw', 50, 120, 1000, 600, 50); - - expect(resized).toEqual({ sx: 50, sy: 100, sw: 350, sh: 350 }); - }); - - it('anchors the bottom-left corner when dragging the top-right (ne)', () => { - const resized = resizeSelection(base, 'ne', 450, 50, 1000, 600, 50); - - expect(resized).toEqual({ sx: 200, sy: 50, sw: 250, sh: 250 }); - }); - - it('anchors the bottom-right corner when dragging the top-left (nw)', () => { - const resized = resizeSelection(base, 'nw', 100, 50, 1000, 600, 50); - - expect(resized).toEqual({ sx: 100, sy: 0, sw: 300, sh: 300 }); - }); - - it('stays square whichever axis the pointer favours', () => { - const resized = resizeSelection(base, 'se', 260, 900, 1000, 600, 50); - - expect(resized.sw).toBe(resized.sh); - }); - - it('honours the minimum size when collapsed', () => { - const resized = resizeSelection(base, 'se', 210, 110, 1000, 600, 50); - - expect(resized).toEqual({ sx: 200, sy: 100, sw: 50, sh: 50 }); - }); - - it('never escapes the image bounds under an extreme drag', () => { - const resized = resizeSelection(base, 'ne', 5000, -5000, 1000, 600, 50); - - expect(resized.sx).toBeGreaterThanOrEqual(0); - expect(resized.sy).toBeGreaterThanOrEqual(0); - expect(resized.sx + resized.sw).toBeLessThanOrEqual(1000); - expect(resized.sy + resized.sh).toBeLessThanOrEqual(600); - }); -}); - -describe('resolveOutputMime', () => { - it('passes through mimes the canvas can encode', () => { - expect(resolveOutputMime('image/jpeg')).toBe('image/jpeg'); - expect(resolveOutputMime('image/png')).toBe('image/png'); - expect(resolveOutputMime('image/webp')).toBe('image/webp'); - }); - - it('coerces mimes the canvas cannot encode to png', () => { - expect(resolveOutputMime('image/gif')).toBe('image/png'); - expect(resolveOutputMime('image/svg+xml')).toBe('image/png'); - expect(resolveOutputMime('image/avif')).toBe('image/png'); - expect(resolveOutputMime('')).toBe('image/png'); - }); -}); - -describe('resolveOutputFileName', () => { - it('swaps the extension to match the output mime', () => { - expect(resolveOutputFileName('logo.gif', 'image/png')).toBe('logo.png'); - expect(resolveOutputFileName('photo.jpeg', 'image/jpeg')).toBe('photo.jpg'); - expect(resolveOutputFileName('shot.PNG', 'image/webp')).toBe('shot.webp'); - }); - - it('handles names without a usable extension', () => { - expect(resolveOutputFileName('photo', 'image/png')).toBe('photo.png'); - expect(resolveOutputFileName('photo.', 'image/png')).toBe('photo.png'); - expect(resolveOutputFileName('', 'image/png')).toBe('image.png'); - }); -}); diff --git a/vitest.config.ts b/vitest.config.ts deleted file mode 100644 index 6742ea73..00000000 --- a/vitest.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { fileURLToPath } from 'node:url'; - -import { defineConfig } from 'vitest/config'; - -export default defineConfig({ - resolve: { - alias: { - '@': fileURLToPath(new URL('./resources/js', import.meta.url)), - }, - }, - test: { - environment: 'node', - include: ['resources/js/**/*.{test,spec}.ts'], - }, -});