From 2ca16621fc33f0d06d1b8249968231062e62ef3b Mon Sep 17 00:00:00 2001 From: Eric Date: Sun, 27 Sep 2026 23:51:44 -0400 Subject: [PATCH 1/2] set compatibility for React 16-19, add tests to prove it --- .github/workflows/playwright.yml | 61 ++++++++++++++++++++++-- README.md | 19 +++++++- package.json | 14 ++++-- scripts/test-react-version.cjs | 80 ++++++++++++++++++++++++++++++++ 4 files changed, 166 insertions(+), 8 deletions(-) create mode 100644 scripts/test-react-version.cjs diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 7463c2c..0e2749b 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -4,8 +4,34 @@ on: branches: [ main, master ] pull_request: branches: [ main, master ] + +permissions: + contents: read + pull-requests: read + jobs: - test: + detect-push-pr-association: + if: github.event_name == 'push' + runs-on: ubuntu-latest + outputs: + has_pr: ${{ steps.detect.outputs.has_pr }} + steps: + - name: Detect whether pushed commit belongs to a PR + id: detect + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const commitSha = context.sha; + const response = await github.rest.repos.listPullRequestsAssociatedWithCommit({ + owner, + repo, + commit_sha: commitSha, + }); + core.setOutput('has_pr', response.data.length > 0 ? 'true' : 'false'); + + pr-all-browsers: + if: github.event_name == 'pull_request' timeout-minutes: 60 runs-on: ubuntu-latest steps: @@ -17,11 +43,38 @@ jobs: run: npm ci --legacy-peer-deps - name: Install Playwright Browsers run: npx playwright install --with-deps - - name: Run Playwright tests - run: npm run test + - name: Run all browser Playwright tests + run: npm run test:all-browsers + - uses: actions/upload-artifact@v4 + if: always() + with: + name: playwright-report-pr-all-browsers + path: playwright-report/ + retention-days: 30 + + push-react-matrix: + if: github.event_name == 'push' && needs.detect-push-pr-association.outputs.has_pr != 'true' + needs: detect-push-pr-association + strategy: + fail-fast: false + matrix: + react-major: [16, 17, 18, 19] + timeout-minutes: 60 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: lts/* + - name: Install dependencies + run: npm ci --legacy-peer-deps + - name: Install Playwright Chromium + run: npx playwright install --with-deps chromium + - name: Run Playwright tests (React ${{ matrix.react-major }}) + run: npm run test:with-react -- ${{ matrix.react-major }} - uses: actions/upload-artifact@v4 if: always() with: - name: playwright-report + name: playwright-report-react-${{ matrix.react-major }} path: playwright-report/ retention-days: 30 diff --git a/README.md b/README.md index a43e8b4..da88d8d 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,29 @@ Uniquely formats while inputting, including decimal and thousands separators, pr # Changes since the original - Now in TypeScript -- Supports React 17, 18 +- Supports React 16, 17, 18, 19 - Totally new automated testing setup with ~~Cypress~~ Playwright (new in 1.4.2+) - Automated Testing setup much more thorough - Caret selection redone and seems to work everywhere - Uses react-device-detect to workaround issues with Gboard +## Testing Across React Versions + +This package can be tested against React 16 through 19 locally: + +```bash +npm run test:react16 +npm run test:react17 +npm run test:react18 +npm run test:react19 +``` + +Run all of them in sequence: + +```bash +npm run test:matrix +``` + ## Codepen Demonstrations There is a CodePen available which you may use to see the component in action, and play with all of it's various parameters to see how it works. It is written with React and TypeScript. diff --git a/package.json b/package.json index e284a93..a4d6912 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,15 @@ "build:esm": "tsc --module es2015 --target es5 --outDir dist/esm", "build:cjs": "tsc --module commonjs --target es5 --outDir dist/cjs", "build-example": "npm run build && browserify examples/index.js -o examples/bundle.js -t [ babelify --presets [ @babel/preset-env ] ]", - "test": "npm run build-example && npx playwright test", + "test": "npm run test:compat", + "test:compat": "npm run build-example && npx playwright test --project=\"base tests\" --project=chromium --reporter=line", + "test:all-browsers": "npm run build-example && npx playwright test --reporter=line", + "test:with-react": "node scripts/test-react-version.cjs", + "test:react16": "npm run test:with-react -- 16", + "test:react17": "npm run test:with-react -- 17", + "test:react18": "npm run test:with-react -- 18", + "test:react19": "npm run test:with-react -- 19", + "test:matrix": "npm run test:react16 && npm run test:react17 && npm run test:react18 && npm run test:react19", "upgrade-deps": "npx npm-check-updates --doctor -u --peer", "webpack": "webpack", "webpack-dev": "webpack-dev-server" @@ -41,8 +49,8 @@ }, "homepage": "https://github.com/ericblade/react-currency-input#readme", "peerDependencies": { - "react": "^18.2.0", - "react-dom": "^18.2.0" + "react": ">=16.14.0 <20", + "react-dom": ">=16.14.0 <20" }, "devDependencies": { "@babel/preset-env": "^7.24.8", diff --git a/scripts/test-react-version.cjs b/scripts/test-react-version.cjs new file mode 100644 index 0000000..50de1e9 --- /dev/null +++ b/scripts/test-react-version.cjs @@ -0,0 +1,80 @@ +const { spawnSync } = require('node:child_process'); +const fs = require('node:fs'); +const path = require('node:path'); + +const reactMajor = process.argv[2]; +const supportedMajors = new Set(['16', '17', '18', '19']); + +if (!supportedMajors.has(reactMajor)) { + console.error('Usage: npm run test:with-react -- <16|17|18|19>'); + process.exit(1); +} + +function run(command, args) { + const result = spawnSync(command, args, { + stdio: 'inherit', + shell: process.platform === 'win32', + }); + + if (result.status !== 0) { + process.exit(result.status || 1); + } +} + +function ensureReactDomClientShimForLegacy(major) { + if (major !== '16' && major !== '17') { + return; + } + + const shimPath = path.join(process.cwd(), 'node_modules', 'react-dom', 'client.js'); + const shimSource = `const ReactDOM = require('./index.js');\n\nexports.createRoot = function createRoot(container) {\n return {\n render(element) {\n ReactDOM.render(element, container);\n },\n unmount() {\n ReactDOM.unmountComponentAtNode(container);\n },\n };\n};\n`; + + fs.writeFileSync(shimPath, shimSource, 'utf8'); +} + +const versionMatrix = { + '16': { + react: '^16.14.0', + reactDom: '^16.14.0', + typesReact: '^16.14.0', + typesReactDom: '^16.9.0', + }, + '17': { + react: '^17.0.2', + reactDom: '^17.0.2', + typesReact: '^17.0.0', + typesReactDom: '^17.0.0', + }, + '18': { + react: '^18.2.0', + reactDom: '^18.2.0', + typesReact: '^18.0.0', + typesReactDom: '^18.0.0', + }, + '19': { + react: '^19.0.0', + reactDom: '^19.0.0', + typesReact: '^19.0.0', + typesReactDom: '^19.0.0', + }, +}; + +const selected = versionMatrix[reactMajor]; +const packageSpecs = [ + `react@${selected.react}`, + `react-dom@${selected.reactDom}`, + `@types/react@${selected.typesReact}`, + `@types/react-dom@${selected.typesReactDom}`, + '@types/scheduler@^0.16.8', +]; + +console.log(`Installing React ${reactMajor}.x test deps...`); +run('npm', ['install', '--no-save', '--no-package-lock', '--legacy-peer-deps', ...packageSpecs]); + +ensureReactDomClientShimForLegacy(reactMajor); + +console.log('Ensuring Playwright Chromium is installed...'); +run('npx', ['playwright', 'install', 'chromium']); + +console.log(`Running tests with React ${reactMajor}.x...`); +run('npm', ['run', 'test:compat']); From 42a6ca81a0f57433a3ea9da07d890ce17f532afc Mon Sep 17 00:00:00 2001 From: Eric Date: Mon, 28 Sep 2026 00:01:33 -0400 Subject: [PATCH 2/2] include test matrix all browsers --- .github/workflows/playwright.yml | 20 ++++++++++++-------- package.json | 2 ++ scripts/test-react-version.cjs | 25 ++++++++++++++++++++----- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 0e2749b..a90a1f8 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -32,6 +32,10 @@ jobs: pr-all-browsers: if: github.event_name == 'pull_request' + strategy: + fail-fast: false + matrix: + react-major: [16, 17, 18, 19] timeout-minutes: 60 runs-on: ubuntu-latest steps: @@ -43,12 +47,12 @@ jobs: run: npm ci --legacy-peer-deps - name: Install Playwright Browsers run: npx playwright install --with-deps - - name: Run all browser Playwright tests - run: npm run test:all-browsers + - name: Run all browser Playwright tests (React ${{ matrix.react-major }}) + run: npm run test:with-react -- ${{ matrix.react-major }} all-browsers - uses: actions/upload-artifact@v4 if: always() with: - name: playwright-report-pr-all-browsers + name: playwright-report-pr-react-${{ matrix.react-major }}-all-browsers path: playwright-report/ retention-days: 30 @@ -68,13 +72,13 @@ jobs: node-version: lts/* - name: Install dependencies run: npm ci --legacy-peer-deps - - name: Install Playwright Chromium - run: npx playwright install --with-deps chromium - - name: Run Playwright tests (React ${{ matrix.react-major }}) - run: npm run test:with-react -- ${{ matrix.react-major }} + - name: Install Playwright Browsers + run: npx playwright install --with-deps + - name: Run all browser Playwright tests (React ${{ matrix.react-major }}) + run: npm run test:with-react -- ${{ matrix.react-major }} all-browsers - uses: actions/upload-artifact@v4 if: always() with: - name: playwright-report-react-${{ matrix.react-major }} + name: playwright-report-push-react-${{ matrix.react-major }}-all-browsers path: playwright-report/ retention-days: 30 diff --git a/package.json b/package.json index a4d6912..b9e5cf5 100644 --- a/package.json +++ b/package.json @@ -17,11 +17,13 @@ "test:compat": "npm run build-example && npx playwright test --project=\"base tests\" --project=chromium --reporter=line", "test:all-browsers": "npm run build-example && npx playwright test --reporter=line", "test:with-react": "node scripts/test-react-version.cjs", + "test:with-react:all-browsers": "node scripts/test-react-version.cjs", "test:react16": "npm run test:with-react -- 16", "test:react17": "npm run test:with-react -- 17", "test:react18": "npm run test:with-react -- 18", "test:react19": "npm run test:with-react -- 19", "test:matrix": "npm run test:react16 && npm run test:react17 && npm run test:react18 && npm run test:react19", + "test:matrix:all-browsers": "npm run test:with-react -- 16 all-browsers && npm run test:with-react -- 17 all-browsers && npm run test:with-react -- 18 all-browsers && npm run test:with-react -- 19 all-browsers", "upgrade-deps": "npx npm-check-updates --doctor -u --peer", "webpack": "webpack", "webpack-dev": "webpack-dev-server" diff --git a/scripts/test-react-version.cjs b/scripts/test-react-version.cjs index 50de1e9..b36c255 100644 --- a/scripts/test-react-version.cjs +++ b/scripts/test-react-version.cjs @@ -3,10 +3,20 @@ const fs = require('node:fs'); const path = require('node:path'); const reactMajor = process.argv[2]; +const mode = process.argv[3] || 'compat'; const supportedMajors = new Set(['16', '17', '18', '19']); +const modeToTestScript = { + compat: 'test:compat', + 'all-browsers': 'test:all-browsers', +}; if (!supportedMajors.has(reactMajor)) { - console.error('Usage: npm run test:with-react -- <16|17|18|19>'); + console.error('Usage: npm run test:with-react -- <16|17|18|19> [compat|all-browsers]'); + process.exit(1); +} + +if (!modeToTestScript[mode]) { + console.error('Mode must be one of: compat, all-browsers'); process.exit(1); } @@ -73,8 +83,13 @@ run('npm', ['install', '--no-save', '--no-package-lock', '--legacy-peer-deps', . ensureReactDomClientShimForLegacy(reactMajor); -console.log('Ensuring Playwright Chromium is installed...'); -run('npx', ['playwright', 'install', 'chromium']); +if (mode === 'all-browsers') { + console.log('Ensuring all Playwright browsers are installed...'); + run('npx', ['playwright', 'install']); +} else { + console.log('Ensuring Playwright Chromium is installed...'); + run('npx', ['playwright', 'install', 'chromium']); +} -console.log(`Running tests with React ${reactMajor}.x...`); -run('npm', ['run', 'test:compat']); +console.log(`Running ${modeToTestScript[mode]} with React ${reactMajor}.x...`); +run('npm', ['run', modeToTestScript[mode]]);