Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@ jobs:
- name: Lint types
run: pnpm lint:types

- name: Build and lint exports
run: pnpm build && pnpm lint:exports
- name: Build, lint exports, and lint publish
run: pnpm build && pnpm lint:exports && pnpm lint:publish
3 changes: 3 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ jobs:
- name: Lint publish (publint)
run: pnpm lint:publish

- name: Run tests
run: pnpm test

build:
runs-on: ubuntu-latest
permissions:
Expand Down
39 changes: 39 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Test

on:
push:
branches: [v5]
pull_request:

permissions: {}

jobs:
test:
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
node-version: [22, 24]

steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- name: Install pnpm
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: ${{ matrix.node-version }}
cache: pnpm

- name: Install Dependencies
run: pnpm install

- name: Run tests
run: pnpm test
33 changes: 28 additions & 5 deletions .lintstagedrc.mjs
Original file line number Diff line number Diff line change
@@ -1,11 +1,34 @@
// lint-staged config — moved here from package.json so we can use a
// function to filter file lists before invoking oxlint. The default glob
// picks up files under src/tests/, but oxlint excludes that directory via
// ignorePatterns in .oxlintrc.json; passing it nothing-but-ignored files
// makes oxlint exit non-zero with "No files found to lint", which breaks
// the pre-commit hook for test-only changes. The filter drops src/tests/
// paths before invoking oxlint; oxfmt still formats them.

import path from "node:path";

const IGNORED = ["src/tests/"];

const filterLintable = (files) =>
files.filter((file) => {
const rel = path.relative(import.meta.dirname, file);
return !IGNORED.some((prefix) => rel.startsWith(prefix));
});

const config = {
"demo/**/*.{js,jsx,ts,tsx}":
"oxlint -c demo/.oxlintrc.json --disable-nested-config --fix",
"!(demo|codemod)/**/*.{js,jsx,ts,tsx}":
"oxlint -c .oxlintrc.json --disable-nested-config --fix",
// Exclude codemod test fixtures from oxfmt — they must exactly match the
// transform output, which jscodeshift formats independently of oxfmt.
"!(codemod/tests/fixtures/**)": "oxfmt",
"!(demo|codemod)/**/*.{js,jsx,ts,tsx}": (files) => {
const lintable = filterLintable(files);
if (lintable.length === 0) {
return [];
}
return `oxlint -c .oxlintrc.json --disable-nested-config --fix ${lintable
.map((f) => JSON.stringify(f))
.join(" ")}`;
},
"*": "oxfmt",
};

export default config;
1 change: 1 addition & 0 deletions .oxfmtrc.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"ignorePatterns": ["codemod/tests/fixtures/"],
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
Expand Down
59 changes: 56 additions & 3 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"jsdoc",
"jsx-a11y",
"node",
"promise"
"promise",
"vitest"
],
"categories": {
"correctness": "error",
Expand Down Expand Up @@ -58,7 +59,15 @@
"no-proto": "error",
"no-regex-spaces": "warn",
"no-sequences": "error",
"no-unused-vars": ["error", { "ignoreRestSiblings": true }],
"no-unused-vars": [
"error",
{
"ignoreRestSiblings": true,
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"caughtErrorsIgnorePattern": "^_"
}
],
"no-var": "error",
"no-void": "warn",
"prefer-const": "error",
Expand Down Expand Up @@ -94,6 +103,7 @@
"@typescript-eslint/strict-boolean-expressions": "off",
"capitalized-comments": "off",
"id-length": "off",
"init-declarations": "off",
"import/exports-last": "off",
"import/group-exports": "off",
"import/no-named-export": "off",
Expand Down Expand Up @@ -122,7 +132,27 @@
"react-perf/jsx-no-new-function-as-prop": "off",
"sort-imports": "off",
"sort-keys": "off",
"unicorn/no-null": "off"
"unicorn/no-null": "off",

"vitest/consistent-test-it": [
"error",
{ "fn": "test", "withinDescribe": "test" }
],
"vitest/max-expects": "off",
"vitest/no-conditional-in-test": "off",
"vitest/no-hooks": "off",
"vitest/no-importing-vitest-globals": "off",
"vitest/no-standalone-expect": "off",
"vitest/prefer-called-times": "off",
"vitest/prefer-called-with": "off",
"vitest/prefer-expect-assertions": "off",
"vitest/prefer-lowercase-title": "off",
"vitest/prefer-strict-boolean-matchers": "off",
"vitest/prefer-to-be": "off",
"vitest/prefer-to-be-falsy": "off",
"vitest/prefer-to-be-truthy": "off",
"vitest/require-hook": "off",
"vitest/require-mock-type-parameters": "off"
},
"overrides": [
{
Expand All @@ -133,6 +163,29 @@
"@typescript-eslint/no-unsafe-call": "off",
"@typescript-eslint/no-unsafe-return": "off"
}
},
{
"files": ["src/tests/**/*.{ts,tsx}"],
"rules": {
// ─── TS strictness relaxed for spy/mock-style test code ───
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-useless-default-assignment": "off",

// ─── General style/correctness rules tests legitimately break ───
"no-console": "off",
"no-param-reassign": "off",
"no-underscore-dangle": "off",

// ─── JSX/a11y/perf rules not applicable to test fixtures ───
"jsx-a11y/no-autofocus": "off",
"react-perf/jsx-no-new-array-as-prop": "off",
"react-perf/jsx-no-new-object-as-prop": "off",

// ─── Unicorn opinions that don't fit test patterns ───
"unicorn/consistent-function-scoping": "off",
"unicorn/prefer-at": "off",
"unicorn/prefer-global-this": "off"
}
}
]
}
49 changes: 47 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ Before you open a PR:
- Run `pnpm dev` to build (and watch) the package source, as well as run the
demo project which can be viewed at http://localhost:5152.
- Please ensure all the examples work correctly after your change.
- Also run `pnpm lint` to ensure that the change meets the projects code
style setup.
- Also run `pnpm lint` to ensure that the change meets the projects code style
setup.
- Run `pnpm test` to verify the test suite still passes. The suite covers both
behavior ported from `react-select` and chakra-specific extensions — see the
[Tests](#tests) section below.
- Make sure there's an issue open for any work you take on and intend to submit
as a pull request - it helps core members review your concept and direction
early and is a good way to discuss what you're planning to do.
Expand All @@ -22,3 +25,45 @@ Before you open a PR:
your hard work.
- All new features and changes need documentation. If you don't have time to
write any, leave a note in your PR.

## Tests

The test suite lives in [`src/tests/`](./src/tests/) and runs with
[Vitest](https://vitest.dev) against a `jsdom` environment plus
`@testing-library/react`:

- `select.test.tsx`, `async-select.test.tsx`, `creatable-select.test.tsx`,
`async-creatable-select.test.tsx`, `state-managed-select.test.tsx` — ported
from `react-select`'s own `__tests__` directory. Each file's header
comment carries a permalink to the upstream source at the pinned version.
- `chakra-specific.test.tsx` — exercises the props this package adds on
top of `react-select` (`size`, `variant`, `isInvalid`, `chakraStyles`,
`tagColorScheme`, `selectedOptionStyle`, etc.).
- `constants.ts` — option fixtures, copied verbatim from upstream.
- `render.tsx`, `setup.ts`, `cases.ts` — local helpers (Chakra-wrapped
render, jsdom polyfills, `jest-in-case` shim).

Useful commands:

- `pnpm test` — run the suite once
- `pnpm test:watch` — re-run on file changes

### When bumping the `react-select` dependency

If a `react-select` bump introduces test changes, port them in as a manual
step rather than rewriting the ported files from scratch:

1. Diff the upstream
[`__tests__/` folder](https://github.com/JedWatson/react-select/tree/master/packages/react-select/src/__tests__)
between the old and new tag — the header comment in each ported file links
to the source at the currently pinned tag.
2. For each upstream test that's new or whose body changed, port it
following the same adaptations already in use:
- imports from `../index` (not `../Select` etc.)
- `render` from `./render` (provides Chakra context)
- `userEvent.setup()` + `await user.click/type` (v14 async API)
- `vi.fn` instead of `jest.fn`
- skip snapshot tests
3. Update each ported file's header permalink to point at the new tag.
4. Leave chakra-specific tests in `chakra-specific.test.tsx` — don't fold
chakra-only assertions into the ported files.
16 changes: 8 additions & 8 deletions demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"chakra-react-select": "workspace:*",
"framer-motion": "^12.38.0",
"react": "^19.2.4",
"react-dom": "^19.2.4"
"framer-motion": "^12.40.0",
"react": "^19.2.6",
"react-dom": "^19.2.6"
},
"devDependencies": {
"@types/react": "^19.2.14",
"@types/react": "^19.2.15",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^6.0.1",
"oxlint": "^1",
"@vitejs/plugin-react": "^6.0.2",
"oxlint": "^1.67.0",
"oxlint-tsgolint": "latest",
"typescript": "^6.0.2",
"vite": "^8.0.12"
"typescript": "^6.0.3",
"vite": "^8.0.14"
}
}
22 changes: 15 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,24 +63,32 @@
"lint:src": "oxlint -c .oxlintrc.json",
"lint:types": "tsc",
"lint-fix": "oxlint -c .oxlintrc.json --fix",
"prepare": "husky"
"prepare": "husky",
"test": "vitest run",
"test:watch": "vitest"
},
"dependencies": {
"react-select": "^5.10.2"
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.18.2",
"@chakra-ui/react": "^2.10.9",
"@types/react": "^19.2.14",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^14.6.1",
"@types/react": "^19.2.15",
"@types/react-dom": "^19.2.3",
"concurrently": "^9.2.1",
"husky": "^9.1.7",
"lint-staged": "^16.4.0",
"oxfmt": "^0.49.0",
"oxlint": "^1.64.0",
"oxlint-tsgolint": "^0.22.1",
"jsdom": "^29.1.1",
"lint-staged": "^17.0.5",
"oxfmt": "^0.52.0",
"oxlint": "^1.67.0",
"oxlint-tsgolint": "^0.23.0",
"publint": "^0.3.21",
"tsup": "^8.5.1",
"typescript": "^6.0.3"
"typescript": "^6.0.3",
"vitest": "^4.1.7"
},
"peerDependencies": {
"@chakra-ui/react": "2.x",
Expand Down
Loading
Loading