Skip to content

Commit d20254d

Browse files
STRMLclaude
andcommitted
chore(test): modernize test infrastructure from Karma/Jasmine to Vitest
- Replace Karma + Jasmine + PhantomJS with Vitest + jsdom for unit tests - Add Puppeteer-based browser tests for real coordinate calculations - Migrate tests to React Testing Library patterns - Update React dev dependency to v18 - Add GitHub Actions CI workflow - Remove deprecated karma configs and specs directory - Add CLAUDE.md with project documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent eefb704 commit d20254d

21 files changed

+3642
-2241
lines changed

.github/workflows/ci.yml

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [master]
6+
pull_request:
7+
branches: [master]
8+
9+
jobs:
10+
lint:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- name: Setup Node.js
16+
uses: actions/setup-node@v4
17+
with:
18+
node-version: '20'
19+
cache: 'yarn'
20+
21+
- name: Install dependencies
22+
run: yarn install --frozen-lockfile
23+
24+
- name: Lint
25+
run: yarn lint
26+
27+
test:
28+
runs-on: ubuntu-latest
29+
strategy:
30+
matrix:
31+
node-version: [18, 20, 22]
32+
steps:
33+
- uses: actions/checkout@v4
34+
35+
- name: Setup Node.js ${{ matrix.node-version }}
36+
uses: actions/setup-node@v4
37+
with:
38+
node-version: ${{ matrix.node-version }}
39+
cache: 'yarn'
40+
41+
- name: Install dependencies
42+
run: yarn install --frozen-lockfile
43+
44+
- name: Run unit tests
45+
run: yarn test
46+
47+
- name: Build
48+
run: yarn build
49+
50+
test-browser:
51+
runs-on: ubuntu-latest
52+
steps:
53+
- uses: actions/checkout@v4
54+
55+
- name: Setup Node.js
56+
uses: actions/setup-node@v4
57+
with:
58+
node-version: '20'
59+
cache: 'yarn'
60+
61+
- name: Install dependencies
62+
run: yarn install --frozen-lockfile
63+
64+
- name: Build
65+
run: yarn build
66+
67+
- name: Run browser tests
68+
run: yarn test:browser
69+
70+
typecheck:
71+
runs-on: ubuntu-latest
72+
steps:
73+
- uses: actions/checkout@v4
74+
75+
- name: Setup Node.js
76+
uses: actions/setup-node@v4
77+
with:
78+
node-version: '20'
79+
cache: 'yarn'
80+
81+
- name: Install dependencies
82+
run: yarn install --frozen-lockfile
83+
84+
- name: Flow check
85+
run: yarn flow
86+
87+
- name: TypeScript check
88+
run: npx tsc -p typings

CLAUDE.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Build Commands
6+
7+
**This project uses Yarn, not npm.** Always use `yarn` for package management.
8+
9+
This project uses Make for builds. Key commands:
10+
11+
- `make build` - Full build (cleans, then builds CJS and web bundles)
12+
- `make lint` - Runs Flow type checker, ESLint, and TypeScript type checking on typings
13+
- `make test` - Runs unit tests via Vitest
14+
- `make test-browser` - Runs browser tests via Puppeteer (requires build first)
15+
- `make test-all` - Runs both unit and browser tests
16+
- `make dev` - Starts webpack dev server with example page
17+
18+
Yarn scripts:
19+
- `yarn test` - Run unit tests (jsdom environment)
20+
- `yarn test:watch` - Run unit tests in watch mode
21+
- `yarn test:browser` - Build and run browser tests (Puppeteer)
22+
- `yarn test:all` - Run all tests
23+
- `yarn test:coverage` - Run tests with coverage report
24+
25+
## Test Architecture
26+
27+
Tests are split into two categories:
28+
29+
1. **Unit tests** (`test/*.test.{js,jsx}`) - Run in jsdom via Vitest
30+
- Fast, no browser required
31+
- Test component logic, callbacks, prop handling
32+
- Some coordinate-based tests skipped (require real browser)
33+
34+
2. **Browser tests** (`test/browser/*.test.js`) - Run in headless Chrome via Puppeteer
35+
- Test actual drag behavior with real coordinate calculations
36+
- Test transforms, axis constraints, bounds, scale
37+
38+
## Architecture
39+
40+
### Component Hierarchy
41+
42+
**DraggableCore** (`lib/DraggableCore.js`) - Low-level component that handles raw drag events
43+
- Maintains minimal internal state (just `dragging`, `lastX`, `lastY`)
44+
- Manages mouse/touch event binding and cleanup
45+
- Provides `onStart`, `onDrag`, `onStop` callbacks with position data
46+
- Use this when you need full control over positioning
47+
48+
**Draggable** (`lib/Draggable.js`) - High-level wrapper around DraggableCore
49+
- Manages position state, bounds checking, axis constraints
50+
- Applies CSS transforms or SVG transform attributes
51+
- Supports controlled (`position` prop) and uncontrolled (`defaultPosition`) modes
52+
- Adds dragging-related CSS classes
53+
54+
### Key Utilities
55+
56+
- `lib/utils/domFns.js` - DOM helpers: event binding, CSS transforms, user-select hacks
57+
- `lib/utils/positionFns.js` - Position calculations: bounds checking, grid snapping, delta computations
58+
- `lib/utils/getPrefix.js` - Browser prefix detection for CSS transforms
59+
60+
### Build Outputs
61+
62+
- `build/cjs/` - CommonJS build (Babel)
63+
- `build/web/react-draggable.min.js` - UMD browser bundle (Webpack)
64+
65+
### Type Systems
66+
67+
The codebase uses Flow for internal type checking (`// @flow` annotations) and ships TypeScript definitions in `typings/index.d.ts`. Both must stay in sync.
68+
69+
## Key Patterns
70+
71+
### nodeRef Pattern
72+
To avoid ReactDOM.findDOMNode deprecation warnings in Strict Mode, components accept a `nodeRef` prop:
73+
```jsx
74+
const nodeRef = React.useRef(null);
75+
<Draggable nodeRef={nodeRef}>
76+
<div ref={nodeRef}>Content</div>
77+
</Draggable>
78+
```
79+
80+
### Callback Return Values
81+
Returning `false` from `onStart`, `onDrag`, or `onStop` cancels the drag operation.
82+
83+
### CSS Transform Approach
84+
Dragging uses CSS transforms (`translate`) rather than absolute positioning, allowing draggable elements to work regardless of their CSS position value.

Makefile

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ clean:
1313

1414
lint:
1515
@$(BIN)/flow
16-
@$(BIN)/eslint lib/* lib/utils/* specs/*
16+
@$(BIN)/eslint lib/* lib/utils/*
1717
@$(BIN)/tsc -p typings
1818

1919
build: clean build-cjs build-esm build-web
@@ -29,10 +29,12 @@ install link:
2929
@yarn $@
3030

3131
test: $(BIN)
32-
@$(BIN)/karma start
32+
@$(BIN)/vitest run
3333

34-
test-phantom: $(BIN)
35-
@$(BIN)/karma start karma-phantomjs.conf.js
34+
test-browser: build $(BIN)
35+
@$(BIN)/vitest run --config vitest.browser.config.js
36+
37+
test-all: test test-browser
3638

3739
dev: $(BIN) clean
3840
env DRAGGABLE_DEBUG=1 $(BIN)/webpack serve --mode=development

karma-phantomjs.conf.js

Lines changed: 0 additions & 30 deletions
This file was deleted.

karma.conf.js

Lines changed: 0 additions & 72 deletions
This file was deleted.

package.json

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
"main": "build/cjs/cjs.js",
66
"unpkg": "build/web/react-draggable.min.js",
77
"scripts": {
8-
"test": "make test",
9-
"test-phantom": "make test-phantom",
10-
"test-debug": "karma start --browsers=Chrome --single-run=false --auto-watch=true",
11-
"test-firefox": "karma start --browsers=Firefox --single-run=false --auto-watch=true",
12-
"test-ie": "karma start --browsers=IE --single-run=false --auto-watch=true",
8+
"test": "vitest run --reporter=verbose",
9+
"test:watch": "vitest",
10+
"test:coverage": "vitest run --coverage",
11+
"test:ui": "vitest --ui",
12+
"test:browser": "yarn build && vitest run --config vitest.browser.config.js",
13+
"test:all": "yarn test && yarn test:browser",
1314
"dev": "make dev",
1415
"build": "make clean build",
1516
"lint": "make lint",
@@ -42,8 +43,6 @@
4243
},
4344
"homepage": "https://github.com/react-grid-layout/react-draggable",
4445
"devDependencies": {
45-
"@types/react": "^18.2.23",
46-
"@types/react-dom": "^18.2.8",
4746
"@babel/cli": "^7.27.2",
4847
"@babel/core": "^7.27.4",
4948
"@babel/eslint-parser": "^7.27.5",
@@ -54,36 +53,29 @@
5453
"@babel/preset-react": "^7.27.1",
5554
"@eslint/eslintrc": "^3.3.1",
5655
"@eslint/js": "^9.29.0",
56+
"@testing-library/dom": "^10.4.1",
57+
"@testing-library/react": "^16.3.0",
5758
"@types/node": "^24.0.4",
58-
"assert": "^2.1.0",
59+
"@types/react": "^18.2.23",
60+
"@types/react-dom": "^18.2.8",
61+
"@vitejs/plugin-react": "^5.1.2",
5962
"babel-loader": "^10.0.0",
6063
"babel-plugin-transform-inline-environment-variables": "^0.4.4",
6164
"eslint": "^9.29.0",
6265
"eslint-plugin-react": "^7.37.5",
6366
"flow-bin": "^0.217.0",
6467
"globals": "^16.2.0",
65-
"jasmine-core": "^5.8.0",
66-
"karma": "^6.4.4",
67-
"karma-chrome-launcher": "^3.2.0",
68-
"karma-cli": "2.0.0",
69-
"karma-firefox-launcher": "^2.1.3",
70-
"karma-ie-launcher": "^1.0.0",
71-
"karma-jasmine": "^5.1.0",
72-
"karma-phantomjs-launcher": "^1.0.4",
73-
"karma-phantomjs-shim": "^1.5.0",
74-
"karma-webpack": "^5.0.1",
75-
"lodash": "^4.17.4",
76-
"phantomjs-prebuilt": "^2.1.16",
68+
"jsdom": "^27.3.0",
7769
"pre-commit": "^1.2.2",
7870
"process": "^0.11.10",
7971
"puppeteer": "^24.10.2",
80-
"react": "^16.13.1",
81-
"react-dom": "^16.13.1",
72+
"react": "18",
73+
"react-dom": "18",
8274
"react-frame-component": "^5.2.7",
83-
"react-test-renderer": "^16.13.1",
75+
"react-test-renderer": "18",
8476
"semver": "^7.7.2",
85-
"static-server": "^3.0.0",
8677
"typescript": "^5.8.3",
78+
"vitest": "^4.0.15",
8779
"webpack": "^5.99.9",
8880
"webpack-cli": "^6.0.1",
8981
"webpack-dev-server": "^5.2.2"
@@ -103,4 +95,4 @@
10395
"react": ">= 16.3.0",
10496
"react-dom": ">= 16.3.0"
10597
}
106-
}
98+
}

specs/.eslintrc

Lines changed: 0 additions & 5 deletions
This file was deleted.

specs/draggable-phantom.spec.jsx

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)