Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
20a1c18
chore(nvm): add .nvmrc with Node 12
Nov 23, 2025
0ef2c40
chore: add Yarn config (node-modules) and update lockfile
Nov 23, 2025
e1cd3ab
wip: Initial commit
Nov 23, 2025
3a97996
chore: prepare environment for React 17 upgrade (WIP)
Nov 23, 2025
a969a01
chore: add regression-tests package.json
Nov 23, 2025
b0587d2
chore(regression-tests): add devDependencies to package.json
Nov 23, 2025
68f3d60
test: add Jest config for regression tests
Nov 23, 2025
472a4cb
test(regression): add regression test handlers scaffold
Nov 23, 2025
6ece364
test(regression): add MSW server setup for regression tests
Nov 23, 2025
de3cd92
test(regression-tests): add setupTests.js to wire up Jest DOM and MSW…
Nov 23, 2025
a9feec9
test(regression): add regression-tests/simple.test.js with render and…
Nov 23, 2025
bfc5675
chore(tests): add test:regression script to run regression tests
Nov 23, 2025
2455574
chore(regression-tests): downgrade jest to 27.5.1
Nov 23, 2025
50d69ed
chore(regression-tests): add jest-environment-jsdom dependency
Nov 23, 2025
7d431b6
test: switch jest environment to jest-environment-jsdom
Nov 23, 2025
e200756
chore(regression-tests): downgrade test dependencies
Nov 23, 2025
18b7eaf
chore(jest): set transform to {} in regression test config
Nov 23, 2025
ea58379
test: switch to new jest-dom v5 import path in setupTests
Nov 23, 2025
56f6b56
test(setup-tests): use extend-expect for jest-dom in setupTests
Nov 23, 2025
0072129
test: register jest-dom matchers in regression-tests/simple.test.js
Nov 23, 2025
5fd0d36
test: add regression test suite scaffolding for React upgrade (WIP)
Nov 23, 2025
cc13a1e
ci: add regression-tests GitHub Actions workflow
Nov 23, 2025
4341e74
chore(yarn): update yarn.lock
Nov 23, 2025
4588861
feat: add find_react_components script to detect React components
Nov 23, 2025
c635e95
chore: exclude regression-tests from project scan
Nov 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/workflows/regression-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Regression Tests

on:
push:
branches:
- '**'
pull_request:

jobs:
regression:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Use Node via nvm and print version
shell: bash -l {0}
run: |
# Ensure nvm is available in the shell
if [ -s "$NVM_DIR/nvm.sh" ]; then . "$NVM_DIR/nvm.sh"; fi
if [ -f .nvmrc ]; then
nvm use && node -v
else
echo ".nvmrc not found; installing and using default LTS"
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
. "$HOME/.nvm/nvm.sh"
nvm install --lts && nvm use --lts && node -v
fi

- name: Set up Yarn cache
uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: 'yarn'

- name: Install dependencies (Yarn)
run: |
yarn install || yarn install --ignore-engines

- name: Run regression tests
run: |
# Prefer yarn (package manager is Yarn); script exists per context
if yarn run -T test:regression --version >/dev/null 2>&1; then
yarn test:regression
else
npm run test:regression
fi
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
12
Binary file added .yarn/install-state.gz
Binary file not shown.
1 change: 1 addition & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@
"test": "npm run jest -- --runInBand --watch",
"test:ci": "npm run jest -- --forceExit --outputFile test-results.json --json --maxWorkers=2",
"test:e2e": "CYPRESS_RETRIES=2 cypress run",
"test:regression": "node -e \"require('child_process').spawn('npx', ['jest', '--config', 'regression-tests/jest.config.js'], { stdio: 'inherit' }).on('exit', code => process.exit(code))\"",
"prestart:api:test": "node -e \"require('./shared/testing/setup.js')().then(() => process.exit())\"",
"start:api:test": "TEST_DB=true FORCE_DEV=true DEBUG=api*,shared* forever build-api/main.js",
"cypress:open": "cypress open",
Expand Down
5 changes: 5 additions & 0 deletions regression-tests/handlers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const { rest } = require('msw');
const handlers = [
// Add API handlers as needed
];
module.exports = { handlers, rest };
7 changes: 7 additions & 0 deletions regression-tests/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
testEnvironment: 'jest-environment-jsdom',
setupFilesAfterEnv: ['<rootDir>/setupTests.js'],
testMatch: ['**/*.test.js'],
rootDir: '.',
transform: {},
};
22 changes: 22 additions & 0 deletions regression-tests/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "regression-tests",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^12.1.5",
"cross-fetch": "^4.1.0",
"jest": "^26.6.3",
"jest-environment-jsdom": "^26.6.2",
"msw": "^0.49.3",
"react": "^16.14.0",
"react-dom": "^16.14.0"
}
}
4 changes: 4 additions & 0 deletions regression-tests/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const { setupServer } = require('msw/node');
const { handlers } = require('./handlers');
const server = setupServer(...handlers);
module.exports = { server };
7 changes: 7 additions & 0 deletions regression-tests/setupTests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Ensure jest-dom matchers are registered for Jest 26
// Some versions require the explicit extend-expect entrypoint
require('@testing-library/jest-dom/extend-expect');
const { server } = require('./server');
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
31 changes: 31 additions & 0 deletions regression-tests/simple.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const React = require('react');
const { render, screen, fireEvent } = require('@testing-library/react');
// Register jest-dom matchers explicitly in test to ensure availability
require('@testing-library/jest-dom/extend-expect');
require('cross-fetch/polyfill');

test('component renders', () => {
const element = React.createElement(
'button',
{ 'data-testid': 'btn' },
'Click'
);
render(element);
expect(screen.getByTestId('btn')).toBeInTheDocument();
});

test('button click updates text', () => {
function Button() {
const [label, setLabel] = React.useState('Click');
return React.createElement(
'button',
{ 'data-testid': 'btn', onClick: () => setLabel('Clicked') },
label
);
}
render(React.createElement(Button));
const btn = screen.getByTestId('btn');
expect(btn.textContent).toBe('Click');
fireEvent.click(btn);
expect(btn.textContent).toBe('Clicked');
});
67 changes: 67 additions & 0 deletions scripts/find_react_components.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import os
import re
import json

EXTENSIONS = {".js", ".jsx", ".ts", ".tsx"}

# Regex patterns to detect React components
FUNCTION_COMPONENT_RE = re.compile(r"^\s*function\s+([A-Z][A-Za-z0-9_]*)\s*\(", re.MULTILINE)
CLASS_COMPONENT_RE = re.compile(r"^\s*class\s+([A-Z][A-Za-z0-9_]*)\s+extends\s+React\.Component", re.MULTILINE)
CLASS_COMPONENT_RE2 = re.compile(r"^\s*class\s+([A-Z][A-Za-z0-9_]*)\s+extends\s+Component", re.MULTILINE)
ARROW_COMPONENT_RE = re.compile(r"^\s*(?:const|let|var)\s+([A-Z][A-Za-z0-9_]*)\s*=\s*\([^)]*\)\s*=>", re.MULTILINE)
ARROW_COMPONENT_RE2 = re.compile(r"^\s*(?:const|let|var)\s+([A-Z][A-Za-z0-9_]*)\s*=\s*[^=]*=>", re.MULTILINE)

def is_react_file(content: str) -> bool:
# quick heuristic: if file imports react or uses jsx pragma
return "from 'react'" in content or 'from "react"' in content or 'import React' in content or '<' in content and '/>' in content

def find_components_in_file(path: str) -> list:
try:
with open(path, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
except Exception:
return []

if not is_react_file(content):
return []

names = set()
for regex in (
FUNCTION_COMPONENT_RE,
CLASS_COMPONENT_RE,
CLASS_COMPONENT_RE2,
ARROW_COMPONENT_RE,
ARROW_COMPONENT_RE2,
):
for m in regex.finditer(content):
names.add(m.group(1))

# Also detect default exports of named functions/classes
default_func = re.findall(r"export\s+default\s+function\s+([A-Z][A-Za-z0-9_]*)", content)
default_class = re.findall(r"export\s+default\s+class\s+([A-Z][A-Za-z0-9_]*)", content)
names.update(default_func)
names.update(default_class)

return [{"name": n, "path": path} for n in names]

def scan_project(root: str, limit: int = 15) -> list:
results = []
for dirpath, dirnames, filenames in os.walk(root):
# Skip common non-source dirs
rel = os.path.relpath(dirpath, root)
if rel.startswith(('.git', 'node_modules', 'flow-typed', 'cypress', 'docs', 'public', 'docker', '.circleci', '.github', 'regression-tests')):
continue
for fn in filenames:
_, ext = os.path.splitext(fn)
if ext in EXTENSIONS:
full = os.path.join(dirpath, fn)
comps = find_components_in_file(full)
for c in comps:
results.append({"name": c["name"], "path": os.path.relpath(c["path"], root)})
if len(results) >= limit:
return results
return results

if __name__ == '__main__':
components = scan_project(os.getcwd(), limit=15)
print(json.dumps(components))
Loading
Loading