From 4371ab362b42744388bb8154a14a07524577c590 Mon Sep 17 00:00:00 2001 From: Ethan Arrowood Date: Mon, 2 Dec 2024 16:03:11 -0700 Subject: [PATCH] prepare for review --- .gitignore | 4 +- CONTRIBUTING.md | 2 +- fixtures/next-13/.npmrc | 1 + fixtures/next-13/app/layout.js | 2 +- fixtures/next-13/app/page.js | 2 +- fixtures/next-13/package.json | 9 +- fixtures/next-14/.npmrc | 1 + fixtures/next-14/app/layout.js | 2 +- fixtures/next-14/app/page.js | 2 +- fixtures/next-14/package.json | 7 +- fixtures/next-15/.npmrc | 1 + fixtures/next-15/package-lock.json | 901 ------------------ fixtures/next-15/package.json | 7 +- package-lock.json | 64 ++ package.json | 5 +- playwright.config.js | 22 + test/next-13.test.js | 13 + test/next-14.test.js | 13 + test/next-15-node-18.test.js | 26 - test/next-15-node-20.test.js | 19 - test/next-15-node-22.test.js | 19 - test/next-15.test.js | 13 + util/cache-bust.js | 34 +- util/constants-and-names.js | 23 + ...ontainer-engine.js => container-engine.js} | 6 +- util/{ => docker}/base.dockerfile | 0 util/{ => docker}/next.dockerfile | 6 +- util/fixture.js | 48 +- util/get-next-image-name.js | 3 - util/{ => scripts}/pretest.js | 32 +- util/test-fixture.js | 29 + util/tests.js | 32 - 32 files changed, 275 insertions(+), 1073 deletions(-) create mode 100644 fixtures/next-13/.npmrc create mode 100644 fixtures/next-14/.npmrc create mode 100644 fixtures/next-15/.npmrc delete mode 100644 fixtures/next-15/package-lock.json create mode 100644 playwright.config.js create mode 100644 test/next-13.test.js create mode 100644 test/next-14.test.js delete mode 100644 test/next-15-node-18.test.js delete mode 100644 test/next-15-node-20.test.js delete mode 100644 test/next-15-node-22.test.js create mode 100644 test/next-15.test.js create mode 100644 util/constants-and-names.js rename util/{get-container-engine.js => container-engine.js} (64%) rename util/{ => docker}/base.dockerfile (100%) rename util/{ => docker}/next.dockerfile (52%) delete mode 100644 util/get-next-image-name.js rename util/{ => scripts}/pretest.js (67%) create mode 100644 util/test-fixture.js delete mode 100644 util/tests.js diff --git a/.gitignore b/.gitignore index 40b878d..289e347 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -node_modules/ \ No newline at end of file +node_modules/ +.next/ +test-results/ \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 39a0fff..729fe31 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,3 @@ ## How publishing this module works -HarperDB Components require the `config.yaml` to be in the root of the project; however, in order for the Docker \ No newline at end of file +HarperDB Components require the `config.yaml` to be in the root of the project; however, in order for the Docker diff --git a/fixtures/next-13/.npmrc b/fixtures/next-13/.npmrc new file mode 100644 index 0000000..9cf9495 --- /dev/null +++ b/fixtures/next-13/.npmrc @@ -0,0 +1 @@ +package-lock=false \ No newline at end of file diff --git a/fixtures/next-13/app/layout.js b/fixtures/next-13/app/layout.js index ee00d88..4ace4d7 100644 --- a/fixtures/next-13/app/layout.js +++ b/fixtures/next-13/app/layout.js @@ -1,5 +1,5 @@ export const metadata = { - title: 'HarperDB - Next.js v15 App', + title: 'HarperDB - Next.js v13 App', }; export default function RootLayout({ children }) { diff --git a/fixtures/next-13/app/page.js b/fixtures/next-13/app/page.js index 4a48cf9..b3b670a 100644 --- a/fixtures/next-13/app/page.js +++ b/fixtures/next-13/app/page.js @@ -1,7 +1,7 @@ export default async function Page() { return (
-

Next.js v15

+

Next.js v13

); } diff --git a/fixtures/next-13/package.json b/fixtures/next-13/package.json index a12eadb..83fa08e 100644 --- a/fixtures/next-13/package.json +++ b/fixtures/next-13/package.json @@ -5,10 +5,13 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "postinstall": "npm link @harperdb/nextjs" }, "dependencies": { - "@harperdb/nextjs": "file:/@harperdb/nextjs", - "next": "13.5.7" + "@harperdb/nextjs": "*", + "react": "^18", + "react-dom": "^18", + "next": "^13" } } diff --git a/fixtures/next-14/.npmrc b/fixtures/next-14/.npmrc new file mode 100644 index 0000000..9cf9495 --- /dev/null +++ b/fixtures/next-14/.npmrc @@ -0,0 +1 @@ +package-lock=false \ No newline at end of file diff --git a/fixtures/next-14/app/layout.js b/fixtures/next-14/app/layout.js index ee00d88..7fd8992 100644 --- a/fixtures/next-14/app/layout.js +++ b/fixtures/next-14/app/layout.js @@ -1,5 +1,5 @@ export const metadata = { - title: 'HarperDB - Next.js v15 App', + title: 'HarperDB - Next.js v14 App', }; export default function RootLayout({ children }) { diff --git a/fixtures/next-14/app/page.js b/fixtures/next-14/app/page.js index 4a48cf9..9d17389 100644 --- a/fixtures/next-14/app/page.js +++ b/fixtures/next-14/app/page.js @@ -1,7 +1,7 @@ export default async function Page() { return (
-

Next.js v15

+

Next.js v14

); } diff --git a/fixtures/next-14/package.json b/fixtures/next-14/package.json index db6467a..63ac233 100644 --- a/fixtures/next-14/package.json +++ b/fixtures/next-14/package.json @@ -5,12 +5,13 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "postinstall": "npm link @harperdb/nextjs" }, "dependencies": { - "@harperdb/nextjs": "file:/@harperdb/nextjs", + "@harperdb/nextjs": "*", "react": "^18", "react-dom": "^18", - "next": "14.2.18" + "next": "^14" } } diff --git a/fixtures/next-15/.npmrc b/fixtures/next-15/.npmrc new file mode 100644 index 0000000..9cf9495 --- /dev/null +++ b/fixtures/next-15/.npmrc @@ -0,0 +1 @@ +package-lock=false \ No newline at end of file diff --git a/fixtures/next-15/package-lock.json b/fixtures/next-15/package-lock.json deleted file mode 100644 index 0f8978f..0000000 --- a/fixtures/next-15/package-lock.json +++ /dev/null @@ -1,901 +0,0 @@ -{ - "name": "next-15", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "next-15", - "dependencies": { - "@harperdb/nextjs": "^0.0.12", - "next": "15.0.3", - "react": "19.0.0-rc-66855b96-20241106", - "react-dom": "19.0.0-rc-66855b96-20241106" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", - "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@harperdb/nextjs": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/@harperdb/nextjs/-/nextjs-0.0.12.tgz", - "integrity": "sha512-QClIwYACdhv+iVyvyrJiq5/IFbR/GN4P5CvEi7FdCsu2yT3S/dJkUVni03HMKWGEmlE1NfiwcvJtQb3m4Az1sA==", - "license": "MIT", - "dependencies": { - "shell-quote": "^1.8.1" - }, - "bin": { - "harperdb-nextjs": "cli.js" - } - }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", - "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.0.4" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", - "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.0.4" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", - "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", - "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", - "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", - "cpu": [ - "arm" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", - "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", - "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", - "cpu": [ - "s390x" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", - "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", - "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", - "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", - "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", - "cpu": [ - "arm" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.0.5" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", - "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.0.4" - } - }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", - "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", - "cpu": [ - "s390x" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.0.4" - } - }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", - "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.0.4" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", - "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", - "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.0.4" - } - }, - "node_modules/@img/sharp-wasm32": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", - "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", - "cpu": [ - "wasm32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", - "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.2.0" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", - "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", - "cpu": [ - "ia32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", - "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@next/env": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.0.3.tgz", - "integrity": "sha512-t9Xy32pjNOvVn2AS+Utt6VmyrshbpfUMhIjFO60gI58deSo/KgLOp31XZ4O+kY/Is8WAGYwA5gR7kOb1eORDBA==", - "license": "MIT" - }, - "node_modules/@next/swc-darwin-arm64": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.0.3.tgz", - "integrity": "sha512-s3Q/NOorCsLYdCKvQlWU+a+GeAd3C8Rb3L1YnetsgwXzhc3UTWrtQpB/3eCjFOdGUj5QmXfRak12uocd1ZiiQw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-darwin-x64": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.0.3.tgz", - "integrity": "sha512-Zxl/TwyXVZPCFSf0u2BNj5sE0F2uR6iSKxWpq4Wlk/Sv9Ob6YCKByQTkV2y6BCic+fkabp9190hyrDdPA/dNrw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.0.3.tgz", - "integrity": "sha512-T5+gg2EwpsY3OoaLxUIofmMb7ohAUlcNZW0fPQ6YAutaWJaxt1Z1h+8zdl4FRIOr5ABAAhXtBcpkZNwUcKI2fw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.0.3.tgz", - "integrity": "sha512-WkAk6R60mwDjH4lG/JBpb2xHl2/0Vj0ZRu1TIzWuOYfQ9tt9NFsIinI1Epma77JVgy81F32X/AeD+B2cBu/YQA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.0.3.tgz", - "integrity": "sha512-gWL/Cta1aPVqIGgDb6nxkqy06DkwJ9gAnKORdHWX1QBbSZZB+biFYPFti8aKIQL7otCE1pjyPaXpFzGeG2OS2w==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.0.3.tgz", - "integrity": "sha512-QQEMwFd8r7C0GxQS62Zcdy6GKx999I/rTO2ubdXEe+MlZk9ZiinsrjwoiBL5/57tfyjikgh6GOU2WRQVUej3UA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.0.3.tgz", - "integrity": "sha512-9TEp47AAd/ms9fPNgtgnT7F3M1Hf7koIYYWCMQ9neOwjbVWJsHZxrFbI3iEDJ8rf1TDGpmHbKxXf2IFpAvheIQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.0.3.tgz", - "integrity": "sha512-VNAz+HN4OGgvZs6MOoVfnn41kBzT+M+tB+OK4cww6DNyWS6wKaDpaAm/qLeOUbnMh0oVx1+mg0uoYARF69dJyA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "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==", - "license": "Apache-2.0" - }, - "node_modules/@swc/helpers": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.13.tgz", - "integrity": "sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "dependencies": { - "streamsearch": "^1.1.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001684", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001684.tgz", - "integrity": "sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", - "license": "MIT" - }, - "node_modules/color": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", - "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", - "license": "MIT", - "optional": true, - "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" - }, - "engines": { - "node": ">=12.5.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT", - "optional": true - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "license": "MIT", - "optional": true, - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", - "license": "Apache-2.0", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "license": "MIT", - "optional": true - }, - "node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/next": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/next/-/next-15.0.3.tgz", - "integrity": "sha512-ontCbCRKJUIoivAdGB34yCaOcPgYXr9AAkV/IwqFfWWTXEPUgLYkSkqBhIk9KK7gGmgjc64B+RdoeIDM13Irnw==", - "license": "MIT", - "dependencies": { - "@next/env": "15.0.3", - "@swc/counter": "0.1.3", - "@swc/helpers": "0.5.13", - "busboy": "1.6.0", - "caniuse-lite": "^1.0.30001579", - "postcss": "8.4.31", - "styled-jsx": "5.1.6" - }, - "bin": { - "next": "dist/bin/next" - }, - "engines": { - "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" - }, - "optionalDependencies": { - "@next/swc-darwin-arm64": "15.0.3", - "@next/swc-darwin-x64": "15.0.3", - "@next/swc-linux-arm64-gnu": "15.0.3", - "@next/swc-linux-arm64-musl": "15.0.3", - "@next/swc-linux-x64-gnu": "15.0.3", - "@next/swc-linux-x64-musl": "15.0.3", - "@next/swc-win32-arm64-msvc": "15.0.3", - "@next/swc-win32-x64-msvc": "15.0.3", - "sharp": "^0.33.5" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0", - "@playwright/test": "^1.41.2", - "babel-plugin-react-compiler": "*", - "react": "^18.2.0 || 19.0.0-rc-66855b96-20241106", - "react-dom": "^18.2.0 || 19.0.0-rc-66855b96-20241106", - "sass": "^1.3.0" - }, - "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - }, - "@playwright/test": { - "optional": true - }, - "babel-plugin-react-compiler": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/react": { - "version": "19.0.0-rc-66855b96-20241106", - "resolved": "https://registry.npmjs.org/react/-/react-19.0.0-rc-66855b96-20241106.tgz", - "integrity": "sha512-klH7xkT71SxRCx4hb1hly5FJB21Hz0ACyxbXYAECEqssUjtJeFUAaI2U1DgJAzkGEnvEm3DkxuBchMC/9K4ipg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "19.0.0-rc-66855b96-20241106", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0-rc-66855b96-20241106.tgz", - "integrity": "sha512-D25vdaytZ1wFIRiwNU98NPQ/upS2P8Co4/oNoa02PzHbh8deWdepjm5qwZM/46OdSiGv4WSWwxP55RO9obqJEQ==", - "license": "MIT", - "dependencies": { - "scheduler": "0.25.0-rc-66855b96-20241106" - }, - "peerDependencies": { - "react": "19.0.0-rc-66855b96-20241106" - } - }, - "node_modules/scheduler": { - "version": "0.25.0-rc-66855b96-20241106", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0-rc-66855b96-20241106.tgz", - "integrity": "sha512-HQXp/Mnp/MMRSXMQF7urNFla+gmtXW/Gr1KliuR0iboTit4KvZRY8KYaq5ccCTAOJiUqQh2rE2F3wgUekmgdlA==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "license": "ISC", - "optional": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/sharp": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", - "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", - "hasInstallScript": true, - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "color": "^4.2.3", - "detect-libc": "^2.0.3", - "semver": "^7.6.3" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.33.5", - "@img/sharp-darwin-x64": "0.33.5", - "@img/sharp-libvips-darwin-arm64": "1.0.4", - "@img/sharp-libvips-darwin-x64": "1.0.4", - "@img/sharp-libvips-linux-arm": "1.0.5", - "@img/sharp-libvips-linux-arm64": "1.0.4", - "@img/sharp-libvips-linux-s390x": "1.0.4", - "@img/sharp-libvips-linux-x64": "1.0.4", - "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", - "@img/sharp-libvips-linuxmusl-x64": "1.0.4", - "@img/sharp-linux-arm": "0.33.5", - "@img/sharp-linux-arm64": "0.33.5", - "@img/sharp-linux-s390x": "0.33.5", - "@img/sharp-linux-x64": "0.33.5", - "@img/sharp-linuxmusl-arm64": "0.33.5", - "@img/sharp-linuxmusl-x64": "0.33.5", - "@img/sharp-wasm32": "0.33.5", - "@img/sharp-win32-ia32": "0.33.5", - "@img/sharp-win32-x64": "0.33.5" - } - }, - "node_modules/shell-quote": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", - "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "license": "MIT", - "optional": true, - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/styled-jsx": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", - "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", - "license": "MIT", - "dependencies": { - "client-only": "0.0.1" - }, - "engines": { - "node": ">= 12.0.0" - }, - "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - } - } -} diff --git a/fixtures/next-15/package.json b/fixtures/next-15/package.json index ee2e14c..b5e33e1 100644 --- a/fixtures/next-15/package.json +++ b/fixtures/next-15/package.json @@ -5,12 +5,13 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "postinstall": "npm link @harperdb/nextjs" }, "dependencies": { - "@harperdb/nextjs": "file:/@harperdb/nextjs", + "@harperdb/nextjs": "*", "react": "19.0.0-rc-66855b96-20241106", "react-dom": "19.0.0-rc-66855b96-20241106", - "next": "15.0.3" + "next": "^15" } } diff --git a/package-lock.json b/package-lock.json index a749e34..4fbf814 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ }, "devDependencies": { "@harperdb/code-guidelines": "^0.0.2", + "@playwright/test": "^1.49.0", "prettier": "^3.3.3" } }, @@ -29,6 +30,69 @@ "prettier": "3.3.3" } }, + "node_modules/@playwright/test": { + "version": "1.49.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.49.0.tgz", + "integrity": "sha512-DMulbwQURa8rNIQrf94+jPJQ4FmOVdpE5ZppRNvWVjvhC+6sOeo28r8MgIpQRYouXRtt/FCCXU7zn20jnHR4Qw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.49.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/playwright": { + "version": "1.49.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.0.tgz", + "integrity": "sha512-eKpmys0UFDnfNb3vfsf8Vx2LEOtflgRebl0Im2eQQnYMA4Aqd+Zw8bEOB+7ZKvN76901mRnqdsiOGKxzVTbi7A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.49.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.49.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.0.tgz", + "integrity": "sha512-R+3KKTQF3npy5GTiKH/T+kdhoJfJojjHESR1YEWhYuEKRVfVaxH3+4+GvXE5xyCngCxhxnykk0Vlah9v8fs3jA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/prettier": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", diff --git a/package.json b/package.json index 5e3a493..ef40864 100644 --- a/package.json +++ b/package.json @@ -36,14 +36,15 @@ "format": "prettier .", "format:check": "npm run format -- --check", "format:fix": "npm run format -- --write", - "pretest": "node util/pretest.js", - "test": "node --test" + "pretest": "node util/scripts/pretest.js", + "test": "playwright test --workers 3" }, "dependencies": { "shell-quote": "^1.8.1" }, "devDependencies": { "@harperdb/code-guidelines": "^0.0.2", + "@playwright/test": "^1.49.0", "prettier": "^3.3.3" }, "prettier": "@harperdb/code-guidelines/prettier" diff --git a/playwright.config.js b/playwright.config.js new file mode 100644 index 0000000..8a34c7c --- /dev/null +++ b/playwright.config.js @@ -0,0 +1,22 @@ +import { defineConfig, devices } from '@playwright/test'; + +const NEXT_MAJORS = ['13', '14', '15']; +const NODE_MAJORS = ['18', '20', '22']; + +export default defineConfig({ + testDir: 'test', + fullyParallel: true, + forbidOnly: !!process.env.CI, + workers: 3, + retries: 2, + expect: { + timeout: 30000, + }, + projects: NEXT_MAJORS.flatMap((nextMajor) => + NODE_MAJORS.map((nodeMajor) => ({ + name: `Next.js v${nextMajor} - Node.js v${nodeMajor}`, + use: { versions: { nextMajor, nodeMajor }, ...devices['Desktop Chrome'] }, + testMatch: [`test/next-${nextMajor}.test.js`], + })) + ), +}); diff --git a/test/next-13.test.js b/test/next-13.test.js new file mode 100644 index 0000000..ba46df8 --- /dev/null +++ b/test/next-13.test.js @@ -0,0 +1,13 @@ +import { test, expect } from '../util/test-fixture.js'; + +test.describe.configure({ mode: 'serial' }); + +test('home page', async ({ nextApp, page }) => { + await page.goto(nextApp.rest.toString()); + await expect(page.locator('h1')).toHaveText('Next.js v13'); +}); + +test('title', async ({ nextApp, page }) => { + await page.goto(nextApp.rest.toString()); + await expect(page).toHaveTitle('HarperDB - Next.js v13 App'); +}); diff --git a/test/next-14.test.js b/test/next-14.test.js new file mode 100644 index 0000000..25e590e --- /dev/null +++ b/test/next-14.test.js @@ -0,0 +1,13 @@ +import { test, expect } from '../util/test-fixture.js'; + +test.describe.configure({ mode: 'serial' }); + +test('home page', async ({ nextApp, page }) => { + await page.goto(nextApp.rest.toString()); + await expect(page.locator('h1')).toHaveText('Next.js v14'); +}); + +test('title', async ({ nextApp, page }) => { + await page.goto(nextApp.rest.toString()); + await expect(page).toHaveTitle('HarperDB - Next.js v14 App'); +}); diff --git a/test/next-15-node-18.test.js b/test/next-15-node-18.test.js deleted file mode 100644 index 3e67c7b..0000000 --- a/test/next-15-node-18.test.js +++ /dev/null @@ -1,26 +0,0 @@ -import { suite, test, before, after } from 'node:test'; -import { base, next15 } from '../util/tests.js'; -import { Fixture } from '../util/fixture.js'; - -suite('Next.js v15 - Node.js v18', async () => { - const ctx = {}; - - before(async () => { - ctx.fixture = new Fixture({ nextMajor: '15', nodeMajor: '18' }); - await ctx.fixture.ready; - - const restPort = ctx.fixture.portMap.get('9926'); - - if (!restPort) { - throw new Error('Rest port not found'); - } - - ctx.rest = new URL(`http://${restPort}`); - }); - - await Promise.all(base.concat(next15).map(async ({ name, testFunction }) => test(name, (t) => testFunction(t, ctx)))); - - after(async () => { - await ctx.fixture.clear(); - }); -}); diff --git a/test/next-15-node-20.test.js b/test/next-15-node-20.test.js deleted file mode 100644 index 36ee7ac..0000000 --- a/test/next-15-node-20.test.js +++ /dev/null @@ -1,19 +0,0 @@ -import { suite, test, before, after } from 'node:test'; -import { base, next15 } from '../util/tests.js'; -import { Fixture } from '../util/fixture.js'; - -suite('Next.js v15 - Node.js v20', async () => { - const ctx = {}; - - before(async () => { - ctx.fixture = new Fixture({ nextMajor: '15', nodeMajor: '20' }); - await ctx.fixture.ready; - ctx.rest = new URL(`http://${ctx.fixture.portMap.get('9926')}`); - }); - - await Promise.all(base.concat(next15).map(async ({ name, testFunction }) => test(name, (t) => testFunction(t, ctx)))); - - after(async () => { - await ctx.fixture.clear(); - }); -}); diff --git a/test/next-15-node-22.test.js b/test/next-15-node-22.test.js deleted file mode 100644 index 8304ac6..0000000 --- a/test/next-15-node-22.test.js +++ /dev/null @@ -1,19 +0,0 @@ -import { suite, test, before, after } from 'node:test'; -import { base, next15 } from '../util/tests.js'; -import { Fixture } from '../util/fixture.js'; - -suite('Next.js v15 - Node.js v22', async () => { - const ctx = {}; - - before(async () => { - ctx.fixture = new Fixture({ nextMajor: '15', nodeMajor: '22' }); - await ctx.fixture.ready; - ctx.rest = new URL(`http://${ctx.fixture.portMap.get('9926')}`); - }); - - await Promise.all(base.concat(next15).map(async ({ name, testFunction }) => test(name, (t) => testFunction(t, ctx)))); - - after(async () => { - await ctx.fixture.clear(); - }); -}); diff --git a/test/next-15.test.js b/test/next-15.test.js new file mode 100644 index 0000000..bc985e3 --- /dev/null +++ b/test/next-15.test.js @@ -0,0 +1,13 @@ +import { test, expect } from '../util/test-fixture.js'; + +test.describe.configure({ mode: 'serial' }); + +test('home page', async ({ nextApp, page }) => { + await page.goto(nextApp.rest.toString()); + await expect(page.locator('h1')).toHaveText('Next.js v15'); +}); + +test('title', async ({ nextApp, page }) => { + await page.goto(nextApp.rest.toString()); + await expect(page).toHaveTitle('HarperDB - Next.js v15 App'); +}); diff --git a/util/cache-bust.js b/util/cache-bust.js index 3244b50..75c5edd 100644 --- a/util/cache-bust.js +++ b/util/cache-bust.js @@ -1,15 +1,33 @@ -import { spawn } from 'child_process'; -import { createHash } from 'crypto'; -import { join } from 'path'; -import { pipeline } from 'stream/promises'; +import { spawn } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { join } from 'node:path'; +import { pipeline } from 'node:stream/promises'; +import { readdirSync } from 'node:fs'; -export function getCacheBustValue() { +import { ROOT } from './constants-and-names.js'; + +export function getCacheBustValue(files) { return new Promise((resolve, reject) => { - const proc = spawn('git', ['status', '--porcelain'], { cwd: join(import.meta.dirname, '..') }) + const proc = spawn('git', ['status', '--porcelain', ...files], { cwd: ROOT }); + proc.on('error', reject); + const hash = createHash('sha1'); - pipeline(proc.stdout, hash).then(() => resolve(hash.digest('hex'))).catch(reject); + + pipeline(proc.stdout, hash) + .then(() => resolve(hash.digest('hex'))) + .catch(reject); }); } -export const CACHE_BUST = getCacheBustValue(); +export const MODULE_CACHE_BUST = getCacheBustValue([ + 'config.yaml', + 'cli.js', + 'extension.js', + 'schema.graphql', + 'package.json', +]); + +export function getNextFixtureCacheBustValue(nextMajor) { + return getCacheBustValue(readdirSync(join(ROOT, 'fixtures', `next-${nextMajor}`))); +} diff --git a/util/constants-and-names.js b/util/constants-and-names.js new file mode 100644 index 0000000..5d4d00b --- /dev/null +++ b/util/constants-and-names.js @@ -0,0 +1,23 @@ +import { join } from 'node:path'; + +export const ROOT = join(import.meta.dirname, '..'); + +export const NEXT_MAJORS = ['13', '14', '15']; + +export const NODE_MAJORS = ['18', '20', '22']; + +export const PORTS = ['9925', '9926']; + +export const CONTAINER_ENGINE_LIST = ['podman', 'docker']; + +export function getNodeBaseImageName(nodeMajor) { + return `harperdb-nextjs/node-base-${nodeMajor}`; +} + +export function getNextImageName(nextMajor, nodeMajor) { + return `harperdb-nextjs/test-image-next-${nextMajor}-node-${nodeMajor}`; +} + +export function getNextContainerName(nextMajor, nodeMajor) { + return `harperdb-nextjs-test-container-next-${nextMajor}-node-${nodeMajor}`; +} diff --git a/util/get-container-engine.js b/util/container-engine.js similarity index 64% rename from util/get-container-engine.js rename to util/container-engine.js index 0708692..185f5ec 100644 --- a/util/get-container-engine.js +++ b/util/container-engine.js @@ -1,6 +1,6 @@ -import { spawnSync } from 'child_process'; +import { spawnSync } from 'node:child_process'; -const CONTAINER_ENGINE_LIST = ['podman', 'docker']; +import { CONTAINER_ENGINE_LIST } from './constants-and-names.js'; export function getContainerEngine() { for (const engine of CONTAINER_ENGINE_LIST) { @@ -13,4 +13,4 @@ export function getContainerEngine() { throw new Error(`No container engine found in ${CONTAINER_ENGINE_LIST.join(', ')}`); } -export const containerEngine = getContainerEngine(); +export const CONTAINER_ENGINE = getContainerEngine(); diff --git a/util/base.dockerfile b/util/docker/base.dockerfile similarity index 100% rename from util/base.dockerfile rename to util/docker/base.dockerfile diff --git a/util/next.dockerfile b/util/docker/next.dockerfile similarity index 52% rename from util/next.dockerfile rename to util/docker/next.dockerfile index 0e41386..188d49b 100644 --- a/util/next.dockerfile +++ b/util/docker/next.dockerfile @@ -7,9 +7,11 @@ FROM ${BASE_IMAGE} ARG NEXT_MAJOR -COPY fixtures/next-${NEXT_MAJOR} /hdb/components/next-${NEXT_MAJOR} +ARG CACHE_BUST +RUN echo "${CACHE_BUST}" +COPY --exclude=node_modules --exclude=.next fixtures/next-${NEXT_MAJOR} /hdb/components/next-${NEXT_MAJOR} -RUN npm install -C hdb/components/next-${NEXT_MAJOR} +RUN cd hdb/components/next-${NEXT_MAJOR} && npm install EXPOSE 9925 9926 diff --git a/util/fixture.js b/util/fixture.js index 414da2e..87ecf5a 100644 --- a/util/fixture.js +++ b/util/fixture.js @@ -1,17 +1,26 @@ -import child_process from 'node:child_process'; +import { spawn, spawnSync } from 'node:child_process'; import { Transform } from 'node:stream'; -import { getNextImageName } from './get-next-image-name.js'; -import { containerEngine } from './get-container-engine.js'; + +import { getNextImageName, getNextContainerName, NEXT_MAJORS, NODE_MAJORS, PORTS } from './constants-and-names.js'; +import { CONTAINER_ENGINE } from './container-engine.js'; +import { CollectedTransform } from './collected-transform.js'; export class Fixture { constructor({ autoSetup = true, debug = false, nextMajor, nodeMajor }) { + if (!NEXT_MAJORS.includes(nextMajor)) { + throw new Error(`nextMajor must be one of ${NEXT_MAJORS.join(', ')}`); + } this.nextMajor = nextMajor; + + if (!NODE_MAJORS.includes(nodeMajor)) { + throw new Error(`nodeMajor must be one of ${NODE_MAJORS.join(', ')}`); + } this.nodeMajor = nodeMajor; this.debug = debug || process.env.DEBUG === '1'; this.imageName = getNextImageName(nextMajor, nodeMajor); - this.containerName = `hdb-next-integration-test-container-next-${nextMajor}-node-${nodeMajor}`; + this.containerName = getNextContainerName(nextMajor, nodeMajor); if (autoSetup) { this.ready = this.clear().then(() => this.run()); @@ -24,7 +33,7 @@ export class Fixture { #runCommand(args = [], options = {}) { return new Promise((resolve, reject) => { - const childProcess = child_process.spawn(containerEngine, args, { + const childProcess = spawn(CONTAINER_ENGINE, args, { stdio: this.#stdio, ...options, }); @@ -44,22 +53,11 @@ export class Fixture { clear() { return new Promise((resolve, reject) => { - const psProcess = child_process.spawn(containerEngine, ['ps', '-aq', '-f', `name=${this.containerName}`]); + const psProcess = spawn(CONTAINER_ENGINE, ['ps', '-aq', '-f', `name=${this.containerName}`]); psProcess.on('error', reject); - const collectedStdout = psProcess.stdout.pipe( - new Transform({ - construct(callback) { - this.chunks = []; - callback(null); - }, - transform(chunk, encoding, callback) { - this.chunks.push(chunk); - callback(null, chunk); - }, - }) - ); + const collectedStdout = psProcess.stdout.pipe(new CollectedTransform()); if (this.debug) { collectedStdout.pipe(process.stdout); @@ -67,7 +65,7 @@ export class Fixture { } psProcess.on('exit', (code) => { - if (code === 0 && collectedStdout.chunks.length !== 0) { + if (code === 0 && collectedStdout.output !== '') { return this.stop() .then(() => this.rm()) .then(resolve, reject); @@ -79,11 +77,9 @@ export class Fixture { run() { return new Promise((resolve, reject) => { - const runProcess = child_process.spawn( - containerEngine, - ['run', '-P', '--name', this.containerName, this.imageName], - { stdio: ['ignore', 'pipe', this.debug ? 'inherit' : 'ignore'] } - ); + const runProcess = spawn(CONTAINER_ENGINE, ['run', '-P', '--name', this.containerName, this.imageName], { + stdio: ['ignore', 'pipe', this.debug ? 'inherit' : 'ignore'], + }); runProcess.on('error', reject); runProcess.on('exit', resolve); @@ -107,8 +103,8 @@ export class Fixture { get portMap() { const portMap = new Map(); - for (const port of ['9925', '9926']) { - const { stdout } = child_process.spawnSync(containerEngine, ['port', this.containerName, port]); + for (const port of PORTS) { + const { stdout } = spawnSync(CONTAINER_ENGINE, ['port', this.containerName, port]); portMap.set(port, stdout.toString().trim()); } return portMap; diff --git a/util/get-next-image-name.js b/util/get-next-image-name.js deleted file mode 100644 index 0845860..0000000 --- a/util/get-next-image-name.js +++ /dev/null @@ -1,3 +0,0 @@ -export function getNextImageName(nextMajor, nodeMajor) { - return `harperdb-nextjs/test-image-next-${nextMajor}-node-${nodeMajor}`; -} diff --git a/util/pretest.js b/util/scripts/pretest.js similarity index 67% rename from util/pretest.js rename to util/scripts/pretest.js index 38db212..07d0139 100644 --- a/util/pretest.js +++ b/util/scripts/pretest.js @@ -1,16 +1,12 @@ import { spawn } from 'node:child_process'; import { join } from 'node:path'; -import { containerEngine } from './get-container-engine.js'; -import { getNextImageName } from './get-next-image-name.js'; -import { CollectedTransform } from './collected-transform.js'; -import { CACHE_BUST } from './cache-bust.js'; -const DEBUG = process.env.DEBUG === '1'; - -const NODE_MAJORS = ['18', '20', '22']; -const NEXT_MAJORS = ['13', '14', '15']; +import { CONTAINER_ENGINE } from '../container-engine.js'; +import { CollectedTransform } from '../collected-transform.js'; +import { MODULE_CACHE_BUST, getNextFixtureCacheBustValue } from '../cache-bust.js'; +import { NODE_MAJORS, NEXT_MAJORS, ROOT, getNodeBaseImageName, getNextImageName } from '../constants-and-names.js'; -const getNodeBaseImageName = (nodeMajor) => `harperdb-nextjs/node-base-${nodeMajor}`; +const DEBUG = process.env.DEBUG === '1'; function validateResult(result) { const success = result.code === 0; @@ -28,12 +24,12 @@ function validateResult(result) { function build(name, args, options = {}) { return new Promise((resolve, reject) => { - const buildProcess = spawn(containerEngine, args, { stdio: ['ignore', 'pipe', 'pipe'], ...options }); + const buildProcess = spawn(CONTAINER_ENGINE, args, { cwd: ROOT, stdio: ['ignore', 'pipe', 'pipe'], ...options }); const collectedStdout = buildProcess.stdout.pipe(new CollectedTransform()); const collectedStderr = buildProcess.stderr.pipe(new CollectedTransform()); - buildProcess.on('error', (error) => reject(error)); + buildProcess.on('error', reject); buildProcess.on('close', (code) => resolve({ name, @@ -45,19 +41,19 @@ function build(name, args, options = {}) { }); } -// Build Node Base Images +// Build Node.js Base Images for (const nodeMajor of NODE_MAJORS) { const buildResult = await build(getNodeBaseImageName(nodeMajor), [ 'build', '--build-arg', `NODE_MAJOR=${nodeMajor}`, '--build-arg', - `CACHE_BUST=${CACHE_BUST}`, + `CACHE_BUST=${MODULE_CACHE_BUST}`, '-t', getNodeBaseImageName(nodeMajor), '-f', - join(import.meta.dirname, 'base.dockerfile'), - join(import.meta.dirname, '..'), + join(ROOT, 'util', 'docker', 'base.dockerfile'), + ROOT, ]); validateResult(buildResult); @@ -73,11 +69,13 @@ for (const nextMajor of NEXT_MAJORS) { `BASE_IMAGE=${getNodeBaseImageName(nodeMajor)}`, '--build-arg', `NEXT_MAJOR=${nextMajor}`, + '--build-arg', + `CACHE_BUST=${getNextFixtureCacheBustValue(nextMajor)}`, '-t', getNextImageName(nextMajor, nodeMajor), '-f', - join(import.meta.dirname, 'next.dockerfile'), - join(import.meta.dirname, '..'), + join(ROOT, 'util', 'docker', 'next.dockerfile'), + ROOT, ]); validateResult(buildResult); diff --git a/util/test-fixture.js b/util/test-fixture.js new file mode 100644 index 0000000..e95765b --- /dev/null +++ b/util/test-fixture.js @@ -0,0 +1,29 @@ +import { test as base } from '@playwright/test'; + +import { Fixture } from './fixture'; + +export const test = base.extend({ + versions: [ + { nextMajor: '', nodeMajor: '' }, + { option: true, scope: 'worker' }, + ], + nextApp: [ + async ({ versions: { nextMajor, nodeMajor } }, use) => { + const fixture = new Fixture({ nextMajor, nodeMajor }); + await fixture.ready; + + const rest = fixture.portMap.get('9926'); + + if (!rest) { + throw new Error('Rest port not found'); + } + + await use({ rest: `http://${rest}` }); + + await fixture.clear(); + }, + { scope: 'worker', timeout: 60000 }, + ], +}); + +export { expect } from '@playwright/test'; diff --git a/util/tests.js b/util/tests.js deleted file mode 100644 index 7335be1..0000000 --- a/util/tests.js +++ /dev/null @@ -1,32 +0,0 @@ -export const base = [ - { - name: 'should enable /Dog rest endpoint', - testFunction: async (t, ctx) => { - const response = await fetch(`${ctx.rest}/Dog/0`, { - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Basic aGRiX2FkbWluOnBhc3N3b3Jk', - }, - }); - const json = await response.json(); - - t.assert.deepStrictEqual(json, { id: '0', name: 'Lincoln', breed: 'Shepherd' }); - }, - }, -]; - -export const next15 = [ - { - name: 'should render home page', - testFunction: async (t, ctx) => { - const response = await fetch(`${ctx.rest}/`, { - headers: { - 'Content-Type': 'text/html', - }, - }); - - const text = await response.text(); - t.assert.match(text, /Next\.js v15/); - }, - }, -];