v1.1.2 fix: close scheduler issues #16/#19/#20 + add tests & demo - #26
Merged
Conversation
#19 — `0 1/4 * * *` was rejected. The `/`-branch in the minute/hour/ day-of-month validators routed a plain `n/m` step into REGEX_EVERY_HYPEN (which requires a hyphen range) and failed. Extract a shared isValidStepPart that branches on the content before the slash: `*` -> REGEX_ALL, `x-y` -> REGEX_EVERY_HYPEN, plain `n` -> REGEX_EVERY. Also set the parsed range start/end for the plain `n/m` form in generate*. #20 — changing the `cron` prop to a broader expression left the period stuck on the previous (narrower) value. The writer only ever bumped the period up; now it derives the period from the highest non-`*` segment and sets it unconditionally, guarded by a round-trip check so a manual period selection on default fields does not snap back down. #16 — single-value autocompletes could stay open after a selection because re-render churn (recomputed range-time option arrays) kept the popup mounted. Add blurOnSelect for single selects in CustomSelect to force them closed; multi-selects still stay open for further picks. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Set up an end-to-end test stack: - Vitest with two projects: `unit` (Node) for pure logic and `browser` (Playwright/Chromium) for rendering the real <Scheduler />. jsdom is not viable — MUI's Autocomplete infinite-loops under it. - 114 tests: utils.test.ts (validators/helpers, incl. the #19 regression), selector.test.ts (derivation atoms + writer), scheduler.browser.test.tsx (end-to-end behaviour incl. the #19/#20/#16 fixes). - V8 coverage report (text/html/json-summary) via `yarn coverage` (~88% statements / 87% branches / 93% functions). - Storybook `.play` regression stories for #19 and #20. - GitHub Actions workflow (.github/workflows/test.yml): lint, typecheck, build, Chromium install, coverage, artifact upload. - Pin vite to 7.1.9 via resolutions to avoid a dual Vite instance pulled by Vitest. Document the test setup in the README. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Remove Storybook entirely (config, stories, build artifacts, deps, scripts) and replace it with a small TanStack Router + Vite SPA in demo/ that imports the library straight from ../src via a Vite alias, so the demo always reflects the working tree with no build step. Vercel builds the demo (vercel.json: install/build in demo/, output demo/dist) so every branch and PR gets a live preview URL via the native Git integration. - delete .storybook/, src/stories/, storybook-static, debug-storybook.log - drop @storybook/* + storybook devDeps; swap dev/storybook/build-storybook scripts for demo/demo:install/demo:build - demo/: TanStack Router SPA (Admin toggle, en/zh_CN locale switch, presets, live cron + cronstrue readout); StrictMode omitted because the Scheduler's unmount-time atom reset wipes the initial cron prop under double-mount - README: document the demo app and one-time Vercel setup Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the two opposing prop<->atom sync effects with one effect that propagates only the side that actually changed, fixing the "Maximum update depth exceeded" ping-pong when the initial `cron` prop differs from the atom default. Use the debounced value in CronExp so debouncing affects the written value, not just timing. Force blurOnSelect on single-value autocompletes so they close after selection despite re-render churn. Add browser regression tests for time-range autocomplete close (#16), disabled-input legibility and multi-select chips (#18), and localized labels.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…urce The demo aliases material-ui-cron to ../src, whose imports (notably cronstrue/i18n) resolve against the repo-root node_modules. The previous installCommand only installed demo/ deps, so Vercel failed with 'Rollup failed to resolve import cronstrue/i18n'. Install root deps first.
The published tarball was shipping src/*.test.*, jest-dom.d.ts and a Playwright screenshot PNG. Exclude them so only the library source + dist ship to consumers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Switching the locale left the selected values (period, at/every, week, month) one language behind: pick Chinese and the period still read "day"; switch back to English and it read "天". The shared Jotai atoms held option objects whose label was localized at write time, and the "reset on unmount" effect — which carried currentLocale + the atom setters in its dependency array — fired its cleanup on every locale change, rewriting the atoms with the *previously captured* locale's defaults. - Make the reset effect truly unmount-only: empty deps, read the latest locale through a ref so cleanup still restores the right defaults. - Add an effect that, when the locale changes, re-maps each selected value onto the matching option in the new locale (option values are locale-stable; only labels translate), preserving the user's selection and refreshing its label. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Renders the scheduler, switches en -> zh_CN -> en, and asserts the selected period translates with the locale instead of lagging a step. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes the open scheduler bugs and adds the testing/demo infrastructure to prove and showcase the fixes.
Bug fixes (Jotai scheduler)
0 1/4 * * *(plainn/mstep) no longer reports "Incorrect syntax". Step validation is consolidated intoisValidStepPart, which branches on what precedes the slash (*,x-y, or plainn). Thegenerate{Minute,Hour,DayOfMonth}parsers now also populate the range-start atom for the plainn/mcase.cronprop now re-renders correctly. The writer derives the period from the highest non-*segment and sets it unconditionally, so broadening (30 9 * * 1→* * * * *) resets a now-stale period instead of staying stuck. A round-trip guard (currentDerived) prevents a manual field/period edit from snapping back.blurOnSelectis forced on single selects (they are rendered asmultipleAutocompletes, whose re-render churn otherwise left the popup open).cronprop differed from the atom default.CronExpnow writes the debounced value so debouncing affects the value, not just timing.Testing infrastructure
src/utils.test.ts,src/selector.test.ts) + browser suite (src/scheduler.browser.test.tsx) via@vitest/browser+ Playwright Chromium.test.yml: lint → typecheck → build → coverage, with coverage artifact upload.Demo migration
demo/, wired for Vercel preview deployments (vercel.json).Test Coverage
All 13 changed code paths have tests (100%). 118 tests passing (78 utils + 25 selector + 15 browser), including regression tests for #16, #18, #19, #20 and a localized-label (#17) case.
Pre-Landing Review
No issues found. Logic surface reviewed (selector.ts, utils.ts, Scheduler.tsx, CronExp.tsx, CustomSelect.tsx); typecheck passes, Biome lint clean, build succeeds. The single-effect two-way binding converges in one render and is robust to an unstable
setCronprop.Design Review
Design review (lite): clean. Changes are behavioral, not visual — no AI slop, no mechanical CSS issues.
Test plan
tsc --noEmitpassesbiome lint .cleanyarn buildsucceeds (esm + cjs + d.ts)🤖 Generated with Claude Code