scrabble-solver 2.17.0 → 2.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/bunx.yml +13 -10
- package/.github/workflows/e2e.yml +7 -9
- package/.github/workflows/npx.yml +13 -10
- package/.nx/workspace-data/d/server-process.json +2 -2
- package/.nx/workspace-data/file-map.json +591 -587
- package/.nx/workspace-data/lockfile-dependencies.hash +1 -1
- package/.nx/workspace-data/lockfile-nodes.hash +1 -1
- package/.nx/workspace-data/nx_files.nxt +0 -0
- package/.nx/workspace-data/parsed-lock-file.dependencies.json +212 -1317
- package/.nx/workspace-data/parsed-lock-file.nodes.json +758 -2693
- package/.nx/workspace-data/project-graph.json +1015 -4140
- package/.nx/workspace-data/source-maps.json +32 -0
- package/.oxlintrc.json +8 -11
- package/CLAUDE.md +18 -15
- package/README.md +8 -1
- package/bun.lock +230 -499
- package/e2e/app.spec.ts +124 -0
- package/e2e/bugs/112-character-bonus.spec.ts +25 -0
- package/e2e/bugs/129-esc-sidebar.spec.ts +17 -0
- package/e2e/bugs/2-q-tile-in-english.spec.ts +19 -0
- package/e2e/bugs/3-x-tile-in-polish.spec.ts +19 -0
- package/e2e/bugs/30-click-inside-radio-icon.spec.ts +25 -0
- package/e2e/bugs/333-disabled-radio-cursor.spec.ts +18 -0
- package/e2e/bugs/342-results-sorting.spec.ts +30 -0
- package/e2e/bugs/352-dictionary-race-condition.spec.ts +27 -0
- package/e2e/bugs/363-dictionary-input-unique-words.spec.ts +27 -0
- package/e2e/bugs/380-transliteration-when-pasting.spec.ts +55 -0
- package/e2e/bugs/398-digraphs-in-created-words.spec.ts +23 -0
- package/e2e/bugs/401-board-state-on-game-change.spec.ts +24 -0
- package/e2e/features/198-highlight-unreachable-cells.spec.ts +85 -0
- package/e2e/features/91-hover-remaining-tile-highlights.spec.ts +76 -0
- package/e2e/features/hidden-coordinates-migration.spec.ts +27 -0
- package/e2e/features/solver-paths.spec.ts +45 -0
- package/e2e/lib/actions.ts +119 -0
- package/e2e/lib/selectors.ts +71 -0
- package/e2e/tsconfig.json +10 -0
- package/lerna.json +1 -1
- package/package.json +14 -17
- package/packages/configs/package.json +3 -3
- package/packages/constants/package.json +1 -1
- package/packages/dictionaries/package.json +4 -4
- package/packages/logger/package.json +1 -1
- package/packages/scrabble-solver/.next/BUILD_ID +1 -1
- package/packages/scrabble-solver/.next/build-manifest.json +22 -20
- package/packages/scrabble-solver/.next/cache/.previewinfo +1 -1
- package/packages/scrabble-solver/.next/cache/.rscinfo +1 -1
- package/packages/scrabble-solver/.next/cache/.tsbuildinfo +1 -1
- package/packages/scrabble-solver/.next/cache/webpack/client-production/0.pack +0 -0
- package/packages/scrabble-solver/.next/cache/webpack/client-production/index.pack +0 -0
- package/packages/scrabble-solver/.next/cache/webpack/client-production/index.pack.old +0 -0
- package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/index.pack.old +0 -0
- package/packages/scrabble-solver/.next/cache/webpack/server-production/0.pack +0 -0
- package/packages/scrabble-solver/.next/cache/webpack/server-production/index.pack +0 -0
- package/packages/scrabble-solver/.next/cache/webpack/server-production/index.pack.old +0 -0
- package/packages/scrabble-solver/.next/diagnostics/framework.json +1 -1
- package/packages/scrabble-solver/.next/dynamic-css-manifest.json +8 -1
- package/packages/scrabble-solver/.next/next-minimal-server.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/next-server.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/prerender-manifest.json +4 -4
- package/packages/scrabble-solver/.next/react-loadable-manifest.json +176 -1
- package/packages/scrabble-solver/.next/routes-manifest.json +1 -1
- package/packages/scrabble-solver/.next/server/chunks/309.js +1 -0
- package/packages/scrabble-solver/.next/server/chunks/{785.js → 316.js} +1 -1
- package/packages/scrabble-solver/.next/server/chunks/344.js +1 -0
- package/packages/scrabble-solver/.next/server/chunks/371.js +1 -0
- package/packages/scrabble-solver/.next/server/chunks/465.js +1 -0
- package/packages/scrabble-solver/.next/server/chunks/546.js +1 -0
- package/packages/scrabble-solver/.next/server/chunks/623.js +1 -0
- package/packages/scrabble-solver/.next/server/chunks/624.js +1 -0
- package/packages/scrabble-solver/.next/server/chunks/641.js +1 -0
- package/packages/scrabble-solver/.next/server/chunks/671.js +1 -1
- package/packages/scrabble-solver/.next/server/chunks/692.js +1 -0
- package/packages/scrabble-solver/.next/server/chunks/705.js +1 -0
- package/packages/scrabble-solver/.next/server/chunks/712.js +1 -1
- package/packages/scrabble-solver/.next/server/chunks/846.js +1 -0
- package/packages/scrabble-solver/.next/server/chunks/853.js +15 -0
- package/packages/scrabble-solver/.next/server/chunks/886.js +1 -0
- package/packages/scrabble-solver/.next/server/chunks/916.js +1 -0
- package/packages/scrabble-solver/.next/server/chunks/953.js +1 -0
- package/packages/scrabble-solver/.next/server/chunks/961.js +1 -0
- package/packages/scrabble-solver/.next/server/chunks/968.js +1 -0
- package/packages/scrabble-solver/.next/server/dynamic-css-manifest.js +1 -1
- package/packages/scrabble-solver/.next/server/middleware-build-manifest.js +1 -1
- package/packages/scrabble-solver/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/packages/scrabble-solver/.next/server/pages/404.html +28 -1
- package/packages/scrabble-solver/.next/server/pages/500.html +28 -1
- package/packages/scrabble-solver/.next/server/pages/_app.js +1 -1
- package/packages/scrabble-solver/.next/server/pages/_app.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/_document.js +28 -1
- package/packages/scrabble-solver/.next/server/pages/_document.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/_error.js +28 -1
- package/packages/scrabble-solver/.next/server/pages/_error.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale]/[word].js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale].js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/api/solve.js +1 -1
- package/packages/scrabble-solver/.next/server/pages/api/solve.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/api/verify.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/api/visit.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/index.html +28 -1
- package/packages/scrabble-solver/.next/server/pages/index.js +30 -1
- package/packages/scrabble-solver/.next/server/pages/index.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/index.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/not-found.html +28 -1
- package/packages/scrabble-solver/.next/server/pages/not-found.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages-manifest.json +1 -1
- package/packages/scrabble-solver/.next/server/webpack-api-runtime.js +1 -1
- package/packages/scrabble-solver/.next/server/webpack-runtime.js +1 -1
- package/packages/scrabble-solver/.next/static/FL82obwzFHRzvV6z76I-U/_buildManifest.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/101-829ab8a8d310e7a0.js +3 -0
- package/packages/scrabble-solver/.next/static/chunks/106.e414e88694add27f.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/127.125d896a19061d71.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/18.8b91e137d239e15c.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/277.6785dfaf22fdb0b7.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/307.67f52f13e3d60d4e.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/341.79535ba85bf1986f.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/363.01eed3233f92b6a4.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/422.1559ae6756912ca5.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/541.dcd9e8b804f88da5.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/631.98d42abad0a60af6.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/663.d2c9ca36b26695b8.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/711.ba7b8f900dfd40d0.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/744.b06c9a3de4a1d877.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/820.97b82f751ca49579.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/865.a9b563a45848a83c.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/912.ff8037ba9d4db5c8.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/939.19b33a3d3c351d73.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/990.61296e5870b91f11.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/framework-626cbd48ac5aca57.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/main-b92e08f3fc96dd8d.js +5 -0
- package/packages/scrabble-solver/.next/static/chunks/pages/_app-ba5d628e81a15461.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/pages/{_error-afeda7c5231b6c3c.js → _error-f0290a98eb3ed0ec.js} +1 -1
- package/packages/scrabble-solver/.next/static/chunks/pages/index-5f9fa6ac3cd3d97b.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/pages/not-found-23d61fd3ed791cad.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/webpack-e34c3ae12275e978.js +1 -0
- package/packages/scrabble-solver/.next/static/css/2d03f0da2c678dfc.css +1 -0
- package/packages/scrabble-solver/.next/static/css/7b6724d2df70f48f.css +1 -0
- package/packages/scrabble-solver/.next/static/css/abc2425d3ba607bc.css +1 -0
- package/packages/scrabble-solver/.next/static/css/b736be3bd02b5d99.css +1 -0
- package/packages/scrabble-solver/.next/static/css/b74cd7de82dabcdd.css +1 -0
- package/packages/scrabble-solver/.next/static/css/c403ce739a9c0d83.css +1 -0
- package/packages/scrabble-solver/.next/static/css/ca311e6c030663d4.css +1 -0
- package/packages/scrabble-solver/.next/static/css/dee878eb64099d92.css +1 -0
- package/packages/scrabble-solver/.next/static/css/fbfdce70731d0d2b.css +1 -0
- package/packages/scrabble-solver/.next/trace +21 -21
- package/packages/scrabble-solver/.next/trace-build +1 -1
- package/packages/scrabble-solver/empty-module.js +2 -0
- package/packages/scrabble-solver/next.config.js +13 -2
- package/packages/scrabble-solver/package.json +33 -14
- package/packages/scrabble-solver/public/llms.txt +11 -0
- package/packages/scrabble-solver/public/robots.txt +4 -0
- package/packages/scrabble-solver/public/service-worker.js +1 -1
- package/packages/scrabble-solver/scripts/generate-scss-types.ts +112 -0
- package/packages/scrabble-solver/src/@types/scss.d.ts +6 -9
- package/packages/scrabble-solver/src/@types/svg.d.ts +1 -1
- package/packages/scrabble-solver/src/components/Alert/Alert.module.scss.d.ts +13 -0
- package/packages/scrabble-solver/src/components/Alert/Alert.tsx +4 -1
- package/packages/scrabble-solver/src/components/Badge/Badge.module.scss.d.ts +6 -0
- package/packages/scrabble-solver/src/components/Board/Board.module.scss +10 -0
- package/packages/scrabble-solver/src/components/Board/Board.module.scss.d.ts +17 -0
- package/packages/scrabble-solver/src/components/Board/Board.tsx +14 -26
- package/packages/scrabble-solver/src/components/Board/BoardPure.tsx +54 -49
- package/packages/scrabble-solver/src/components/Board/components/Actions/Actions.module.scss +18 -18
- package/packages/scrabble-solver/src/components/Board/components/Actions/Actions.module.scss.d.ts +7 -0
- package/packages/scrabble-solver/src/components/Board/components/Actions/Actions.tsx +6 -3
- package/packages/scrabble-solver/src/components/Board/components/Actions/lib.ts +3 -1
- package/packages/scrabble-solver/src/components/Board/components/Cell/Cell.module.scss.d.ts +13 -0
- package/packages/scrabble-solver/src/components/Board/components/Cell/Cell.tsx +28 -33
- package/packages/scrabble-solver/src/components/Board/components/InputPrompt/InputPrompt.module.scss.d.ts +10 -0
- package/packages/scrabble-solver/src/components/Board/components/InputPrompt/InputPrompt.tsx +1 -1
- package/packages/scrabble-solver/src/components/Board/components/ToggleDirectionButton/ToggleDirectionButton.module.scss.d.ts +8 -0
- package/packages/scrabble-solver/src/components/Board/components/ToggleDirectionButton/ToggleDirectionButton.tsx +2 -2
- package/packages/scrabble-solver/src/components/Board/getBoardBackground.ts +175 -0
- package/packages/scrabble-solver/src/components/Board/hooks/index.ts +0 -1
- package/packages/scrabble-solver/src/components/Board/hooks/useBoardStyle.ts +10 -20
- package/packages/scrabble-solver/src/components/Board/hooks/useFloatingActions.ts +3 -6
- package/packages/scrabble-solver/src/components/Board/hooks/useGrid.ts +6 -3
- package/packages/scrabble-solver/src/components/Board/selectors.ts +1 -1
- package/packages/scrabble-solver/src/components/Button/Button.module.scss.d.ts +12 -0
- package/packages/scrabble-solver/src/components/Dictionary/Dictionary.module.scss +1 -0
- package/packages/scrabble-solver/src/components/Dictionary/Dictionary.module.scss.d.ts +14 -0
- package/packages/scrabble-solver/src/components/Dictionary/Dictionary.tsx +1 -3
- package/packages/scrabble-solver/src/components/DictionaryInput/DictionaryInput.module.scss.d.ts +7 -0
- package/packages/scrabble-solver/src/components/DictionaryInput/DictionaryInput.tsx +1 -1
- package/packages/scrabble-solver/src/components/EmptyState/EmptyState.module.scss.d.ts +7 -0
- package/packages/scrabble-solver/src/components/EmptyState/EmptyState.tsx +1 -1
- package/packages/scrabble-solver/src/components/IconButton/IconButton.module.scss.d.ts +8 -0
- package/packages/scrabble-solver/src/components/Key/Key.module.scss.d.ts +6 -0
- package/packages/scrabble-solver/src/components/Keys/Arrows/Arrows.module.scss.d.ts +11 -0
- package/packages/scrabble-solver/src/components/Keys/Arrows/Arrows.tsx +4 -1
- package/packages/scrabble-solver/src/components/Keys/index.tsx +1 -1
- package/packages/scrabble-solver/src/components/Loading/Loading.module.scss.d.ts +9 -0
- package/packages/scrabble-solver/src/components/Loading/Loading.tsx +1 -1
- package/packages/scrabble-solver/src/components/Logo/Logo.tsx +4 -9
- package/packages/scrabble-solver/src/components/Logo/LogoBlueprint.tsx +1 -0
- package/packages/scrabble-solver/src/components/Modal/Modal.module.scss.d.ts +15 -0
- package/packages/scrabble-solver/src/components/Modal/Modal.tsx +16 -3
- package/packages/scrabble-solver/src/components/Modal/components/Section/Section.module.scss.d.ts +7 -0
- package/packages/scrabble-solver/src/components/NavButtons/NavButtons.module.scss +20 -0
- package/packages/scrabble-solver/src/components/NavButtons/NavButtons.module.scss.d.ts +13 -0
- package/packages/scrabble-solver/src/components/NavButtons/NavButtons.tsx +29 -45
- package/packages/scrabble-solver/src/components/NotFound/NotFound.module.scss.d.ts +9 -0
- package/packages/scrabble-solver/src/components/NotFound/NotFound.tsx +1 -1
- package/packages/scrabble-solver/src/components/PlainTiles/PlainTiles.module.scss.d.ts +11 -0
- package/packages/scrabble-solver/src/components/PlainTiles/PlainTiles.tsx +0 -1
- package/packages/scrabble-solver/src/components/PlainTiles/Tile.tsx +3 -4
- package/packages/scrabble-solver/src/components/PlainTiles/lib.ts +4 -19
- package/packages/scrabble-solver/src/components/PlainTiles/types.ts +0 -1
- package/packages/scrabble-solver/src/components/Progress/Progress.module.scss +7 -0
- package/packages/scrabble-solver/src/components/Progress/Progress.module.scss.d.ts +6 -0
- package/packages/scrabble-solver/src/components/Progress/Progress.tsx +2 -11
- package/packages/scrabble-solver/src/components/Rack/Rack.module.scss +3 -0
- package/packages/scrabble-solver/src/components/Rack/Rack.module.scss.d.ts +10 -0
- package/packages/scrabble-solver/src/components/Rack/Rack.tsx +8 -11
- package/packages/scrabble-solver/src/components/Rack/components/InputPrompt/InputPrompt.module.scss +2 -0
- package/packages/scrabble-solver/src/components/Rack/components/InputPrompt/InputPrompt.module.scss.d.ts +7 -0
- package/packages/scrabble-solver/src/components/Rack/components/InputPrompt/InputPrompt.tsx +1 -13
- package/packages/scrabble-solver/src/components/Rack/components/InputPrompt/lib.ts +1 -1
- package/packages/scrabble-solver/src/components/Rack/components/RackTile/RackTile.module.scss.d.ts +6 -0
- package/packages/scrabble-solver/src/components/Rack/components/RackTile/RackTile.tsx +5 -4
- package/packages/scrabble-solver/src/components/Rack/selectors.ts +1 -1
- package/packages/scrabble-solver/src/components/Radio/Radio.module.scss.d.ts +12 -0
- package/packages/scrabble-solver/src/components/Results/Cell.tsx +3 -12
- package/packages/scrabble-solver/src/components/Results/Header.tsx +9 -18
- package/packages/scrabble-solver/src/components/Results/HeaderButton.tsx +4 -5
- package/packages/scrabble-solver/src/components/Results/Result.tsx +4 -12
- package/packages/scrabble-solver/src/components/Results/Results.module.scss +4 -6
- package/packages/scrabble-solver/src/components/Results/Results.module.scss.d.ts +27 -0
- package/packages/scrabble-solver/src/components/Results/Results.tsx +4 -3
- package/packages/scrabble-solver/src/components/Results/SolveButton.tsx +1 -1
- package/packages/scrabble-solver/src/components/ResultsInput/ResultsInput.module.scss.d.ts +7 -0
- package/packages/scrabble-solver/src/components/ResultsInput/ResultsInput.tsx +1 -1
- package/packages/scrabble-solver/src/components/Solver/Solver.module.scss +6 -5
- package/packages/scrabble-solver/src/components/Solver/Solver.module.scss.d.ts +20 -0
- package/packages/scrabble-solver/src/components/Solver/Solver.tsx +19 -21
- package/packages/scrabble-solver/src/components/Solver/components/InsertButton/InsertButton.module.scss.d.ts +7 -0
- package/packages/scrabble-solver/src/components/Solver/components/InsertButton/InsertButton.tsx +1 -1
- package/packages/scrabble-solver/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.module.scss.d.ts +18 -0
- package/packages/scrabble-solver/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.tsx +3 -1
- package/packages/scrabble-solver/src/components/Spinner/Spinner.module.scss.d.ts +10 -0
- package/packages/scrabble-solver/src/components/Tile/Tile.module.scss +3 -0
- package/packages/scrabble-solver/src/components/Tile/Tile.module.scss.d.ts +19 -0
- package/packages/scrabble-solver/src/components/Tile/Tile.tsx +5 -14
- package/packages/scrabble-solver/src/components/Tile/TilePure.tsx +2 -12
- package/packages/scrabble-solver/src/components/Tooltip/Tooltip.module.scss.d.ts +7 -0
- package/packages/scrabble-solver/src/components/Tooltip/Tooltip.tsx +14 -3
- package/packages/scrabble-solver/src/components/Tooltip/useTooltip.ts +1 -0
- package/packages/scrabble-solver/src/hooks/useColumns.ts +4 -7
- package/packages/scrabble-solver/src/hooks/useDeferredRender.ts +20 -0
- package/packages/scrabble-solver/src/hooks/useDirection.ts +4 -3
- package/packages/scrabble-solver/src/hooks/useLanguage.ts +2 -2
- package/packages/scrabble-solver/src/hooks/useLocalStorage.ts +32 -8
- package/packages/scrabble-solver/src/hooks/useMedia.ts +26 -26
- package/packages/scrabble-solver/src/i18n/constants.ts +2 -15
- package/packages/scrabble-solver/src/i18n/i18n.ts +18 -17
- package/packages/scrabble-solver/src/i18n/languages/english.json +0 -1
- package/packages/scrabble-solver/src/i18n/languages/french.json +0 -1
- package/packages/scrabble-solver/src/i18n/languages/german.json +0 -1
- package/packages/scrabble-solver/src/i18n/languages/persian.json +0 -1
- package/packages/scrabble-solver/src/i18n/languages/polish.json +0 -1
- package/packages/scrabble-solver/src/i18n/languages/romanian.json +0 -1
- package/packages/scrabble-solver/src/i18n/languages/spanish.json +0 -1
- package/packages/scrabble-solver/src/i18n/languages/turkish.json +0 -1
- package/packages/scrabble-solver/src/i18n/localeIcons.ts +24 -0
- package/packages/scrabble-solver/src/lib/localeTransliterate.test.ts +5 -0
- package/packages/scrabble-solver/src/lib/localeTransliterate.ts +26 -6
- package/packages/scrabble-solver/src/lib/waitForIdleOrFirstIntent.ts +33 -0
- package/packages/scrabble-solver/src/modals/DictionaryModal/DictionaryModal.module.scss.d.ts +8 -0
- package/packages/scrabble-solver/src/modals/DictionaryModal/DictionaryModal.tsx +3 -1
- package/packages/scrabble-solver/src/modals/KeyMapModal/KeyMapModal.tsx +3 -1
- package/packages/scrabble-solver/src/modals/KeyMapModal/components/Mapping/Mapping.module.scss.d.ts +11 -0
- package/packages/scrabble-solver/src/modals/MenuModal/MenuModal.module.scss +5 -0
- package/packages/scrabble-solver/src/modals/MenuModal/MenuModal.module.scss.d.ts +10 -0
- package/packages/scrabble-solver/src/modals/MenuModal/MenuModal.tsx +16 -5
- package/packages/scrabble-solver/src/modals/RemainingTilesModal/RemainingTilesModal.module.scss +4 -1
- package/packages/scrabble-solver/src/modals/RemainingTilesModal/RemainingTilesModal.module.scss.d.ts +9 -0
- package/packages/scrabble-solver/src/modals/RemainingTilesModal/RemainingTilesModal.tsx +4 -6
- package/packages/scrabble-solver/src/modals/RemainingTilesModal/components/Character/Character.module.scss +1 -0
- package/packages/scrabble-solver/src/modals/RemainingTilesModal/components/Character/Character.module.scss.d.ts +12 -0
- package/packages/scrabble-solver/src/modals/RemainingTilesModal/components/Character/Character.tsx +5 -12
- package/packages/scrabble-solver/src/modals/ResultsModal/ResultsModal.module.scss.d.ts +8 -0
- package/packages/scrabble-solver/src/modals/ResultsModal/ResultsModal.tsx +8 -4
- package/packages/scrabble-solver/src/modals/SettingsModal/SettingsModal.tsx +2 -2
- package/packages/scrabble-solver/src/modals/SettingsModal/components/AutoGroupTilesSetting/AutoGroupTilesSetting.module.scss.d.ts +7 -0
- package/packages/scrabble-solver/src/modals/SettingsModal/components/AutoGroupTilesSetting/AutoGroupTilesSetting.tsx +1 -1
- package/packages/scrabble-solver/src/modals/SettingsModal/components/ConfigSetting/ConfigSetting.module.scss.d.ts +7 -0
- package/packages/scrabble-solver/src/modals/SettingsModal/components/ConfigSetting/ConfigSetting.tsx +1 -1
- package/packages/scrabble-solver/src/modals/SettingsModal/components/HighlightUnreachableCellsSetting/HighlightUnreachableCellsSetting.module.scss.d.ts +7 -0
- package/packages/scrabble-solver/src/modals/SettingsModal/components/HighlightUnreachableCellsSetting/HighlightUnreachableCellsSetting.tsx +1 -1
- package/packages/scrabble-solver/src/modals/SettingsModal/components/InputModeSetting/InputModeSetting.module.scss.d.ts +7 -0
- package/packages/scrabble-solver/src/modals/SettingsModal/components/InputModeSetting/InputModeSetting.tsx +1 -1
- package/packages/scrabble-solver/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.module.scss.d.ts +8 -0
- package/packages/scrabble-solver/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.tsx +24 -21
- package/packages/scrabble-solver/src/modals/SettingsModal/components/RemoveCellFiltersSetting/RemoveCellFiltersSetting.module.scss.d.ts +7 -0
- package/packages/scrabble-solver/src/modals/SettingsModal/components/RemoveCellFiltersSetting/RemoveCellFiltersSetting.tsx +1 -1
- package/packages/scrabble-solver/src/modals/SettingsModal/components/ShowCoordinatesSetting/ShowCoordinatesSetting.module.scss.d.ts +7 -0
- package/packages/scrabble-solver/src/modals/SettingsModal/components/ShowCoordinatesSetting/ShowCoordinatesSetting.tsx +1 -5
- package/packages/scrabble-solver/src/modals/WordsModal/WordsModal.module.scss.d.ts +11 -0
- package/packages/scrabble-solver/src/modals/WordsModal/WordsModal.tsx +4 -2
- package/packages/scrabble-solver/src/modals/preload.ts +24 -0
- package/packages/scrabble-solver/src/pages/_app.tsx +5 -8
- package/packages/scrabble-solver/src/pages/_document.tsx +91 -5
- package/packages/scrabble-solver/src/pages/api/solve.ts +1 -1
- package/packages/scrabble-solver/src/pages/index.module.scss +1 -0
- package/packages/scrabble-solver/src/pages/index.module.scss.d.ts +11 -0
- package/packages/scrabble-solver/src/pages/index.tsx +98 -38
- package/packages/scrabble-solver/src/pages/not-found.tsx +1 -1
- package/packages/scrabble-solver/src/parameters/index.ts +24 -93
- package/packages/scrabble-solver/src/serviceWorkerManager.ts +5 -2
- package/packages/scrabble-solver/src/state/actions.ts +1 -1
- package/packages/scrabble-solver/src/state/app/index.ts +4 -0
- package/packages/scrabble-solver/src/state/app/initialState.ts +6 -0
- package/packages/scrabble-solver/src/state/app/selectors.ts +5 -0
- package/packages/scrabble-solver/src/state/app/slice.ts +20 -0
- package/packages/scrabble-solver/src/state/app/types.ts +4 -0
- package/packages/scrabble-solver/src/state/board/initialState.ts +1 -2
- package/packages/scrabble-solver/src/state/i18n/index.ts +4 -0
- package/packages/scrabble-solver/src/state/i18n/initialState.ts +5 -0
- package/packages/scrabble-solver/src/state/i18n/selectors.ts +3 -0
- package/packages/scrabble-solver/src/state/i18n/slice.ts +16 -0
- package/packages/scrabble-solver/src/state/i18n/types.ts +7 -0
- package/packages/scrabble-solver/src/state/index.ts +2 -0
- package/packages/scrabble-solver/src/state/lib.ts +1 -1
- package/packages/scrabble-solver/src/state/localStorage.ts +86 -29
- package/packages/scrabble-solver/src/state/rack/initialState.ts +1 -2
- package/packages/scrabble-solver/src/state/rack/slice.ts +4 -1
- package/packages/scrabble-solver/src/state/results/lib.ts +5 -5
- package/packages/scrabble-solver/src/state/results/selectors.ts +1 -1
- package/packages/scrabble-solver/src/state/sagas.ts +125 -9
- package/packages/scrabble-solver/src/state/selectors.ts +1 -1
- package/packages/scrabble-solver/src/state/settings/initialState.ts +7 -10
- package/packages/scrabble-solver/src/state/settings/selectors.ts +7 -2
- package/packages/scrabble-solver/src/state/settings/slice.ts +5 -2
- package/packages/scrabble-solver/src/state/store.ts +4 -0
- package/packages/scrabble-solver/src/state/types.ts +4 -0
- package/packages/scrabble-solver/src/styles/_tokens.scss +1 -0
- package/packages/scrabble-solver/src/styles/global.scss +9 -0
- package/packages/scrabble-solver/src/styles/variables.module.scss +0 -21
- package/packages/scrabble-solver/src/styles/variables.module.scss.d.ts +27 -0
- package/packages/scrabble-solver/src/styles/variables.scss +46 -2
- package/packages/scrabble-solver/src/types/index.ts +1 -2
- package/packages/scrabble-solver/tsconfig.tsbuildinfo +1 -1
- package/packages/solver/package.json +5 -5
- package/packages/types/build/Direction.d.ts +1 -0
- package/packages/types/build/Direction.js +2 -0
- package/packages/types/build/ShowCoordinates.d.ts +1 -2
- package/packages/types/build/TextDirection.d.ts +1 -0
- package/packages/types/build/TextDirection.js +2 -0
- package/packages/types/build/index.d.ts +2 -0
- package/packages/types/package.json +2 -2
- package/packages/types/src/Direction.ts +1 -0
- package/packages/types/src/ShowCoordinates.ts +1 -2
- package/packages/types/src/TextDirection.ts +1 -0
- package/packages/types/src/index.ts +2 -0
- package/packages/word-definitions/package.json +2 -2
- package/packages/word-lists/package.json +2 -2
- package/playwright-report/index.html +49 -0
- package/playwright.config.ts +30 -0
- package/screencast.gif +0 -0
- package/scripts/record-screencast.ts +347 -0
- package/test-results/.last-run.json +4 -0
- package/tsconfig.json +1 -1
- package/babel.config.js +0 -4
- package/cypress/e2e/app.spec.cy.ts +0 -123
- package/cypress/e2e/bugs/112-character-bonus.ts +0 -40
- package/cypress/e2e/bugs/129-esc-sidebar.ts +0 -23
- package/cypress/e2e/bugs/2-q-tile-in-english.ts +0 -33
- package/cypress/e2e/bugs/3-x-tile-in-polish.ts +0 -33
- package/cypress/e2e/bugs/30-click-inside-radio-icon.ts +0 -26
- package/cypress/e2e/bugs/333-disabled-radio-cursor.ts +0 -24
- package/cypress/e2e/bugs/342-results-sorting.ts +0 -48
- package/cypress/e2e/bugs/348-results-word-padding.ts +0 -74
- package/cypress/e2e/bugs/352-dictionary-race-condition.ts +0 -29
- package/cypress/e2e/bugs/363-dictionary-input-unique-words.ts +0 -41
- package/cypress/e2e/bugs/380-transliteration-when-pasting.ts +0 -75
- package/cypress/e2e/bugs/398-digraphs-in-created-words.ts +0 -38
- package/cypress/e2e/bugs/401-board-state-on-game-change.ts +0 -36
- package/cypress/e2e/bugs.spec.cy.ts +0 -13
- package/cypress/e2e/features/198-highlight-unreachable-cells.ts +0 -101
- package/cypress/e2e/features/91-hover-remaining-tile-highlights.ts +0 -90
- package/cypress/e2e/features/solver-paths.ts +0 -66
- package/cypress/e2e/features.spec.cy.ts +0 -3
- package/cypress/support/commands.ts +0 -4
- package/cypress/support/e2e.ts +0 -1
- package/cypress/support/index.ts +0 -1
- package/cypress/support/lib/actions.ts +0 -104
- package/cypress/support/lib/selectors.ts +0 -70
- package/cypress/tsconfig.json +0 -10
- package/cypress.config.ts +0 -17
- package/packages/scrabble-solver/.next/server/chunks/129.js +0 -1
- package/packages/scrabble-solver/.next/server/chunks/318.js +0 -3
- package/packages/scrabble-solver/.next/server/chunks/791.js +0 -15
- package/packages/scrabble-solver/.next/static/OLE8_ZInlGH7ENU0NIOpf/_buildManifest.js +0 -1
- package/packages/scrabble-solver/.next/static/chunks/830.661816bf0de8c2f1.js +0 -1
- package/packages/scrabble-solver/.next/static/chunks/framework-3cf15b8041c59dd3.js +0 -1
- package/packages/scrabble-solver/.next/static/chunks/main-5b999f3f24ebfa84.js +0 -5
- package/packages/scrabble-solver/.next/static/chunks/pages/_app-7024e7a27ffbb2fa.js +0 -7
- package/packages/scrabble-solver/.next/static/chunks/pages/index-8b398b0a5d870773.js +0 -1
- package/packages/scrabble-solver/.next/static/chunks/pages/not-found-9e076427bad69d90.js +0 -1
- package/packages/scrabble-solver/.next/static/chunks/webpack-3943d624bbb47a64.js +0 -1
- package/packages/scrabble-solver/.next/static/css/a78e04fe95452380.css +0 -1
- package/packages/scrabble-solver/.next/static/css/aedeaada218d7280.css +0 -2
- package/packages/scrabble-solver/src/app-layout/AppLayoutContext.tsx +0 -25
- package/packages/scrabble-solver/src/app-layout/index.ts +0 -1
- package/packages/scrabble-solver/src/app-layout/useAppLayoutValue.ts +0 -112
- package/packages/scrabble-solver/src/components/Board/hooks/useBackgroundImage.tsx +0 -279
- package/packages/scrabble-solver/src/components/index.ts +0 -26
- package/packages/scrabble-solver/src/hooks/index.ts +0 -12
- package/packages/scrabble-solver/src/hooks/useOnWindowResize.ts +0 -11
- package/packages/scrabble-solver/src/hooks/useViewportSize.ts +0 -17
- package/packages/scrabble-solver/src/i18n/index.ts +0 -2
- package/packages/scrabble-solver/src/icons/Flag.svg +0 -4
- package/packages/scrabble-solver/src/icons/Star.svg +0 -4
- package/packages/scrabble-solver/src/icons/index.ts +0 -49
- package/packages/scrabble-solver/src/lib/getTileSizes.ts +0 -13
- package/packages/scrabble-solver/src/lib/index.ts +0 -24
- package/packages/scrabble-solver/src/modals/index.ts +0 -7
- /package/{cypress/support → e2e}/lib/index.ts +0 -0
- /package/packages/scrabble-solver/.next/static/{OLE8_ZInlGH7ENU0NIOpf → FL82obwzFHRzvV6z76I-U}/_ssgManifest.js +0 -0
package/e2e/app.spec.ts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { expect, type Page, test } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
assertResult,
|
|
5
|
+
closeModal,
|
|
6
|
+
expectTileHighlighted,
|
|
7
|
+
expectTileNotHighlighted,
|
|
8
|
+
getBoardTile,
|
|
9
|
+
getDictionary,
|
|
10
|
+
getDictionaryInput,
|
|
11
|
+
getDictionaryTitles,
|
|
12
|
+
getLoading,
|
|
13
|
+
getRackTile,
|
|
14
|
+
getResult,
|
|
15
|
+
getSettingOption,
|
|
16
|
+
getSettingsButton,
|
|
17
|
+
getTooltip,
|
|
18
|
+
hoverResult,
|
|
19
|
+
moveMouseAway,
|
|
20
|
+
solve,
|
|
21
|
+
typeRack,
|
|
22
|
+
visitIndex,
|
|
23
|
+
} from './lib';
|
|
24
|
+
|
|
25
|
+
test.describe('app', () => {
|
|
26
|
+
test('has title', async ({ page }) => {
|
|
27
|
+
await visitIndex(page);
|
|
28
|
+
|
|
29
|
+
await expect(page).toHaveTitle('Scrabble Solver 2');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('has default setting values', async ({ page }) => {
|
|
33
|
+
await visitIndex(page);
|
|
34
|
+
await getSettingsButton(page).click();
|
|
35
|
+
|
|
36
|
+
await expect(getSettingOption(page, 'Game', 'Scrabble')).toBeChecked();
|
|
37
|
+
await expect(getSettingOption(page, 'Language', 'English (US)')).toBeChecked();
|
|
38
|
+
await expect(getSettingOption(page, 'Coordinates', 'Original')).toBeChecked();
|
|
39
|
+
await expect(getSettingOption(page, 'Input mode', 'Keyboard')).toBeChecked();
|
|
40
|
+
await expect(getSettingOption(page, 'Group remaining tiles', 'Do not group')).toBeChecked();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test.describe('full app test', () => {
|
|
44
|
+
test('Scrabble - Polish', async ({ page }) => {
|
|
45
|
+
await visitIndex(page);
|
|
46
|
+
await getSettingsButton(page).click();
|
|
47
|
+
await getSettingOption(page, 'Language', 'Polski').check();
|
|
48
|
+
await closeModal(page);
|
|
49
|
+
await typeRack(page, 'abł');
|
|
50
|
+
await solve(page);
|
|
51
|
+
|
|
52
|
+
await assertResult(page, 0, 'bał', 14);
|
|
53
|
+
const definitionsResponse = waitForDictionaryResponse(page);
|
|
54
|
+
await hoverResult(page, 0);
|
|
55
|
+
await expect(getLoading(page)).toBeVisible();
|
|
56
|
+
await definitionsResponse;
|
|
57
|
+
await expectTileHighlighted(getRackTile(page, 0));
|
|
58
|
+
await expectTileHighlighted(getRackTile(page, 1));
|
|
59
|
+
await expectTileHighlighted(getRackTile(page, 2));
|
|
60
|
+
await expect(getBoardTile(page, 5, 7)).toHaveValue('b');
|
|
61
|
+
await expect(getBoardTile(page, 6, 7)).toHaveValue('a');
|
|
62
|
+
await expect(getBoardTile(page, 7, 7)).toHaveValue('ł');
|
|
63
|
+
await expectTileHighlighted(getBoardTile(page, 5, 7));
|
|
64
|
+
await expectTileHighlighted(getBoardTile(page, 6, 7));
|
|
65
|
+
await expectTileHighlighted(getBoardTile(page, 7, 7));
|
|
66
|
+
await expect(getDictionaryInput(page)).toHaveValue('bał');
|
|
67
|
+
await expect(getLoading(page)).toHaveCount(0);
|
|
68
|
+
await expect(getTooltip(page)).toBeVisible();
|
|
69
|
+
await moveMouseAway(page);
|
|
70
|
+
await expect(getTooltip(page)).toHaveCount(0);
|
|
71
|
+
await expectTileNotHighlighted(getRackTile(page, 0));
|
|
72
|
+
await expect(getDictionaryTitles(page)).toHaveCount(1);
|
|
73
|
+
await expect(getDictionaryTitles(page)).toHaveText('bał');
|
|
74
|
+
await expect(getDictionary(page)).toContainText('bać się');
|
|
75
|
+
await expect(getDictionary(page)).toContainText('odczuwać lęk, strach');
|
|
76
|
+
await expect(getDictionary(page)).toContainText('być niespokojnym o kogoś lub o coś');
|
|
77
|
+
await expect(getDictionary(page)).toContainText('nie śmieć, nie odważać się na coś');
|
|
78
|
+
|
|
79
|
+
await page.getByLabel('Punkty', { exact: true }).click();
|
|
80
|
+
await expect(getTooltip(page)).toBeVisible();
|
|
81
|
+
await expect(getTooltip(page)).toHaveText('Punkty');
|
|
82
|
+
await assertResult(page, 0, 'ba', 8);
|
|
83
|
+
const nextDefinitionsResponse = waitForDictionaryResponse(page);
|
|
84
|
+
await hoverResult(page, 0);
|
|
85
|
+
await expectTileHighlighted(getRackTile(page, 0));
|
|
86
|
+
await expectTileHighlighted(getRackTile(page, 1));
|
|
87
|
+
await expectTileNotHighlighted(getRackTile(page, 2));
|
|
88
|
+
await expect(getBoardTile(page, 5, 7)).toHaveValue('');
|
|
89
|
+
await expect(getBoardTile(page, 6, 7)).toHaveValue('b');
|
|
90
|
+
await expect(getBoardTile(page, 7, 7)).toHaveValue('a');
|
|
91
|
+
await expectTileNotHighlighted(getBoardTile(page, 5, 7));
|
|
92
|
+
await expectTileHighlighted(getBoardTile(page, 6, 7));
|
|
93
|
+
await expectTileHighlighted(getBoardTile(page, 7, 7));
|
|
94
|
+
await expect(getDictionaryInput(page)).toHaveValue('ba');
|
|
95
|
+
await expect(getLoading(page)).toBeVisible();
|
|
96
|
+
await nextDefinitionsResponse;
|
|
97
|
+
await expect(getLoading(page)).toHaveCount(0);
|
|
98
|
+
await expect(getDictionaryTitles(page)).toHaveCount(1);
|
|
99
|
+
await expect(getDictionaryTitles(page)).toHaveText('ba');
|
|
100
|
+
await expect(getDictionary(page)).toContainText('wykrzyknik, który wyraża głównie podziw, zdziwienie');
|
|
101
|
+
await expect(getDictionary(page)).toContainText(
|
|
102
|
+
'w wierzeniach staroegipskich: dusza ludzka ginąca wraz z ciałem',
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
await getResult(page, 0).click();
|
|
106
|
+
await expectTileNotHighlighted(getRackTile(page, 0));
|
|
107
|
+
await expectTileNotHighlighted(getRackTile(page, 1));
|
|
108
|
+
await expectTileNotHighlighted(getRackTile(page, 2));
|
|
109
|
+
await expect(getRackTile(page, 0)).toHaveValue('');
|
|
110
|
+
await expect(getRackTile(page, 1)).toHaveValue('');
|
|
111
|
+
await expect(getRackTile(page, 2)).toHaveValue('ł');
|
|
112
|
+
await expect(getBoardTile(page, 6, 7)).toHaveValue('b');
|
|
113
|
+
await expect(getBoardTile(page, 7, 7)).toHaveValue('a');
|
|
114
|
+
|
|
115
|
+
const solveButton = page.getByLabel('Rozwiąż', { exact: true });
|
|
116
|
+
await expect(solveButton).toBeVisible();
|
|
117
|
+
await expect(solveButton).toBeEnabled();
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
function waitForDictionaryResponse(page: Page) {
|
|
123
|
+
return page.waitForResponse('**/api/dictionary/*/*');
|
|
124
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { test } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
import * as Lib from '../lib';
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/112
|
|
7
|
+
*/
|
|
8
|
+
test.describe('#112 - Scrabble - Character bonus not applied', () => {
|
|
9
|
+
test('correctly shows points for a result which gets a character bonus', async ({ page }) => {
|
|
10
|
+
await Lib.visitIndex(page);
|
|
11
|
+
|
|
12
|
+
await Lib.getSettingsButton(page).click();
|
|
13
|
+
await Lib.getSettingOption(page, 'Language', 'Français').check();
|
|
14
|
+
await Lib.closeModal(page);
|
|
15
|
+
await Lib.typeRack(page, 'jours');
|
|
16
|
+
await Lib.solve(page);
|
|
17
|
+
|
|
18
|
+
await Lib.assertResult(page, 0, 'jours', 40);
|
|
19
|
+
await Lib.assertResult(page, 1, 'jours', 40);
|
|
20
|
+
await Lib.assertResult(page, 2, 'jours', 26);
|
|
21
|
+
await Lib.assertResult(page, 3, 'jours', 26);
|
|
22
|
+
await Lib.assertResult(page, 4, 'jours', 24);
|
|
23
|
+
await Lib.assertResult(page, 5, 'jours', 24);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
import * as Lib from '../lib';
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/129
|
|
7
|
+
*/
|
|
8
|
+
test.describe('#129 - Esc does not close the sidebar when letters input is focused', () => {
|
|
9
|
+
test('Esc key closes the sidebar when rack is focused', async ({ page }) => {
|
|
10
|
+
await Lib.visitIndex(page);
|
|
11
|
+
await Lib.getSettingsButton(page).click();
|
|
12
|
+
await Lib.typeRack(page, 'a');
|
|
13
|
+
await page.keyboard.press('Escape');
|
|
14
|
+
|
|
15
|
+
await expect(Lib.getModal(page)).toHaveCount(0);
|
|
16
|
+
});
|
|
17
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
import * as Lib from '../lib';
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/2
|
|
7
|
+
*/
|
|
8
|
+
test.describe('#2 - "Q" tile does not work', () => {
|
|
9
|
+
test('accepts "Q" tile in English', async ({ page }) => {
|
|
10
|
+
await Lib.visitIndex(page);
|
|
11
|
+
await Lib.typeBoard(page, 'i', 'horizontal', { x: 7, y: 7 });
|
|
12
|
+
await Lib.typeRack(page, 'q');
|
|
13
|
+
await Lib.solve(page);
|
|
14
|
+
|
|
15
|
+
await expect(Lib.getResults(page)).toHaveCount(2);
|
|
16
|
+
await Lib.assertResult(page, 0, 'qi', 11);
|
|
17
|
+
await Lib.assertResult(page, 1, 'qi', 11);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
import * as Lib from '../lib';
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/3
|
|
7
|
+
*/
|
|
8
|
+
test.describe('#3 - "X" tile is allowed in Polish', () => {
|
|
9
|
+
test('does not accept "X" tile in Polish', async ({ page }) => {
|
|
10
|
+
await Lib.visitIndex(page);
|
|
11
|
+
await Lib.getSettingsButton(page).click();
|
|
12
|
+
await Lib.getSettingOption(page, 'Language', 'Polski').check();
|
|
13
|
+
await Lib.closeModal(page);
|
|
14
|
+
await Lib.typeBoard(page, 'x', 'horizontal', { x: 7, y: 7 });
|
|
15
|
+
await Lib.typeRack(page, 'x');
|
|
16
|
+
|
|
17
|
+
await expect(page.getByText('x', { exact: true })).toHaveCount(0);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
import * as Lib from '../lib';
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/30
|
|
7
|
+
*/
|
|
8
|
+
test.describe('#30 - Clicking inside an icon of non-first unchecked radio button does not select that option', () => {
|
|
9
|
+
test('Clicking inside an icon of first unchecked radio button selects it', async ({ page }) => {
|
|
10
|
+
await Lib.visitIndex(page);
|
|
11
|
+
await Lib.getSettingsButton(page).click();
|
|
12
|
+
await Lib.getSettingOption(page, 'Language', 'English (GB)').click();
|
|
13
|
+
|
|
14
|
+
const icon = Lib.getSettingOption(page, 'Language', 'English (US)')
|
|
15
|
+
.locator('..')
|
|
16
|
+
.getByRole('img', { includeHidden: true })
|
|
17
|
+
.first();
|
|
18
|
+
|
|
19
|
+
// force - the icon is fully covered by the radio's invisible input overlay,
|
|
20
|
+
// which is exactly what a click at the icon's coordinates is meant to hit
|
|
21
|
+
await icon.click({ force: true });
|
|
22
|
+
|
|
23
|
+
await expect(Lib.getSettingOption(page, 'Language', 'English (US)')).toBeChecked();
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
import * as Lib from '../lib';
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/333
|
|
7
|
+
*/
|
|
8
|
+
test.describe('#333 - Disabled radio button has cursor: pointer', () => {
|
|
9
|
+
test('Disabled radio button has cursor: not-allowed', async ({ page }) => {
|
|
10
|
+
await Lib.visitIndex(page);
|
|
11
|
+
await Lib.getSettingsButton(page).click();
|
|
12
|
+
await Lib.getSettingOption(page, 'Language', 'Polski').check();
|
|
13
|
+
await Lib.getSettingOption(page, 'Gra', 'Scrabble').scrollIntoViewIfNeeded();
|
|
14
|
+
|
|
15
|
+
await expect(Lib.getSettingOption(page, 'Gra', 'Super Scrabble')).toBeDisabled();
|
|
16
|
+
await expect(Lib.getSettingOption(page, 'Gra', 'Super Scrabble')).toHaveCSS('cursor', 'not-allowed');
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
import * as Lib from '../lib';
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/342
|
|
7
|
+
*/
|
|
8
|
+
test.describe('#342 - Incorrect sorting when filtering', () => {
|
|
9
|
+
test('correctly sorts valid results first when text filter is active', async ({ page }) => {
|
|
10
|
+
await Lib.visitIndex(page);
|
|
11
|
+
await Lib.getSettingsButton(page).click();
|
|
12
|
+
await Lib.getSettingOption(page, 'Language', 'Polski').check();
|
|
13
|
+
await Lib.closeModal(page);
|
|
14
|
+
await Lib.typeBoard(page, 'bopie', 'horizontal', { x: 6, y: 3 });
|
|
15
|
+
await Lib.typeBoard(page, 'apu', 'vertical', { x: 8, y: 4 });
|
|
16
|
+
await Lib.typeBoard(page, 'o', 'vertical', { x: 10, y: 4 });
|
|
17
|
+
await Lib.typeRack(page, 'oe');
|
|
18
|
+
await Lib.solve(page);
|
|
19
|
+
await Lib.getResultsFilterInput(page).pressSequentially('p');
|
|
20
|
+
|
|
21
|
+
await Lib.assertResult(page, 0, 'po', 5);
|
|
22
|
+
await Lib.assertResult(page, 1, 'pe', 5);
|
|
23
|
+
await Lib.assertResult(page, 2, 'op', 3);
|
|
24
|
+
await Lib.assertResult(page, 3, 'eo', 6);
|
|
25
|
+
await expect(Lib.getResult(page, 0)).not.toHaveAttribute('aria-hidden');
|
|
26
|
+
await expect(Lib.getResult(page, 1)).not.toHaveAttribute('aria-hidden');
|
|
27
|
+
await expect(Lib.getResult(page, 2)).not.toHaveAttribute('aria-hidden');
|
|
28
|
+
await expect(Lib.getResult(page, 3)).toHaveAttribute('aria-hidden', 'true');
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
import * as Lib from '../lib';
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/352
|
|
7
|
+
*/
|
|
8
|
+
test.describe('#352 - Race condition: dictionary result shows up after clearing the board', () => {
|
|
9
|
+
test('Clearing the board prevents pending dictionary results from showing up', async ({ page }) => {
|
|
10
|
+
await page.route('**/api/dictionary/en-US/123', async (route) => {
|
|
11
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
12
|
+
await route.fulfill({ body: '' });
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
await Lib.visitIndex(page);
|
|
16
|
+
|
|
17
|
+
const dictionaryResponse = page.waitForResponse('**/api/dictionary/en-US/123');
|
|
18
|
+
await Lib.getDictionaryInput(page).pressSequentially('123');
|
|
19
|
+
await Lib.getDictionaryInput(page).press('Enter');
|
|
20
|
+
await page.getByLabel('Clear', { exact: true }).click();
|
|
21
|
+
await dictionaryResponse;
|
|
22
|
+
|
|
23
|
+
await expect(Lib.getDictionary(page)).not.toContainText('This word is not allowed');
|
|
24
|
+
await expect(Lib.getDictionary(page)).not.toContainText('Unexpected end of JSON input');
|
|
25
|
+
await expect(Lib.getDictionary(page)).toContainText('Word definition will be shown here.');
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
import * as Lib from '../lib';
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/363
|
|
7
|
+
*/
|
|
8
|
+
test.describe('#363 - Dictionary input should display unique words', () => {
|
|
9
|
+
test('highlighting a word should cause only unique new words to be looked up in the dictionary', async ({ page }) => {
|
|
10
|
+
await page.route('**/api/dictionary/tr-TR/*', async (route) => {
|
|
11
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
12
|
+
await route.fulfill({ body: '' });
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
await Lib.visitIndex(page);
|
|
16
|
+
await Lib.getSettingsButton(page).click();
|
|
17
|
+
await Lib.getSettingOption(page, 'Language', 'Türkçe').check();
|
|
18
|
+
await Lib.closeModal(page);
|
|
19
|
+
await Lib.typeBoard(page, 'ponje', 'horizontal', { x: 3, y: 7 });
|
|
20
|
+
await Lib.typeRack(page, 'er');
|
|
21
|
+
await Lib.solve(page);
|
|
22
|
+
|
|
23
|
+
await Lib.getResult(page, 0).hover();
|
|
24
|
+
|
|
25
|
+
await expect(Lib.getDictionaryInput(page)).toHaveValue('er, je');
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { expect, type Page, test } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
import * as Lib from '../lib';
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/380
|
|
7
|
+
*/
|
|
8
|
+
test.describe('#380 - No transliteration when pasting', () => {
|
|
9
|
+
test('should transliterate special characters when pasting in Romanian', async ({ page }) => {
|
|
10
|
+
await testTransliterationOnPaste(page, {
|
|
11
|
+
language: 'Română',
|
|
12
|
+
word: 'abordaserăți',
|
|
13
|
+
transliterated: 'abordaserati',
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('should transliterate special characters (except "ñ") when pasting in Spanish', async ({ page }) => {
|
|
18
|
+
await testTransliterationOnPaste(page, {
|
|
19
|
+
language: 'Español',
|
|
20
|
+
word: 'bañó',
|
|
21
|
+
transliterated: 'baño',
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('should transliterate special characters when pasting in French', async ({ page }) => {
|
|
26
|
+
await testTransliterationOnPaste(page, {
|
|
27
|
+
language: 'Français',
|
|
28
|
+
word: 'pâtisserie',
|
|
29
|
+
transliterated: 'patisserie',
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
async function testTransliterationOnPaste(
|
|
35
|
+
page: Page,
|
|
36
|
+
{
|
|
37
|
+
language,
|
|
38
|
+
word,
|
|
39
|
+
transliterated,
|
|
40
|
+
}: {
|
|
41
|
+
language: string;
|
|
42
|
+
word: string;
|
|
43
|
+
transliterated: string;
|
|
44
|
+
},
|
|
45
|
+
) {
|
|
46
|
+
await Lib.visitIndex(page);
|
|
47
|
+
await Lib.getSettingsButton(page).click();
|
|
48
|
+
await Lib.getSettingOption(page, 'Language', language).check();
|
|
49
|
+
await Lib.closeModal(page);
|
|
50
|
+
await Lib.paste(Lib.getBoardTile(page, 0, 0), word);
|
|
51
|
+
|
|
52
|
+
for (const [x, value] of Array.from(transliterated).entries()) {
|
|
53
|
+
await expect(Lib.getBoardTile(page, x, 0)).toHaveValue(value);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
import * as Lib from '../lib';
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/398
|
|
7
|
+
*/
|
|
8
|
+
test.describe('#398 - Solitary digraph tiles are recognised as created words', () => {
|
|
9
|
+
test('should transliterate special characters when pasting in French', async ({ page }) => {
|
|
10
|
+
await Lib.visitIndex(page);
|
|
11
|
+
await Lib.getSettingsButton(page).click();
|
|
12
|
+
await Lib.getSettingOption(page, 'Language', 'Español').check();
|
|
13
|
+
await Lib.closeModal(page);
|
|
14
|
+
await Lib.pasteBoard(page, 'chiclean', 'horizontal', { x: 3, y: 7 });
|
|
15
|
+
await page.getByLabel('Palabras creadas', { exact: true }).click();
|
|
16
|
+
|
|
17
|
+
const modal = Lib.getOpenModal(page);
|
|
18
|
+
await expect(modal.getByText('ch', { exact: true })).toHaveCount(0);
|
|
19
|
+
await expect(modal.getByText('chiclean', { exact: true })).toBeVisible();
|
|
20
|
+
await expect(modal.getByLabel('Incorrecto', { exact: true }).getByText('0', { exact: true })).toBeVisible();
|
|
21
|
+
await expect(modal.getByLabel('Correcto', { exact: true }).getByText('1', { exact: true })).toBeVisible();
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
import * as Lib from '../lib';
|
|
4
|
+
|
|
5
|
+
const SUPER_SCRABBLE_BOARD_WIDTH = 21;
|
|
6
|
+
|
|
7
|
+
/*
|
|
8
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/401
|
|
9
|
+
*/
|
|
10
|
+
test.describe('#401 - Board state not preserved on game type change', () => {
|
|
11
|
+
test('preserves tiles centered on the board when switching to a larger game', async ({ page }) => {
|
|
12
|
+
await Lib.visitIndex(page);
|
|
13
|
+
await Lib.typeBoard(page, 'word', 'horizontal', { x: 7, y: 7 });
|
|
14
|
+
|
|
15
|
+
await Lib.getSettingsButton(page).click();
|
|
16
|
+
await Lib.getSettingOption(page, 'Game', 'Super Scrabble').check();
|
|
17
|
+
await Lib.closeModal(page);
|
|
18
|
+
|
|
19
|
+
await expect(Lib.getBoardTile(page, 10, 10, SUPER_SCRABBLE_BOARD_WIDTH)).toHaveValue('w');
|
|
20
|
+
await expect(Lib.getBoardTile(page, 11, 10, SUPER_SCRABBLE_BOARD_WIDTH)).toHaveValue('o');
|
|
21
|
+
await expect(Lib.getBoardTile(page, 12, 10, SUPER_SCRABBLE_BOARD_WIDTH)).toHaveValue('r');
|
|
22
|
+
await expect(Lib.getBoardTile(page, 13, 10, SUPER_SCRABBLE_BOARD_WIDTH)).toHaveValue('d');
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { expect, type Page, test } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
import * as Lib from '../lib';
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/198
|
|
7
|
+
*/
|
|
8
|
+
test.describe('#198 - Highlight unreachable cells', () => {
|
|
9
|
+
test('has no effect when the rack is empty', async ({ page }) => {
|
|
10
|
+
await Lib.visitIndex(page);
|
|
11
|
+
await Lib.typeBoard(page, 'cat', 'horizontal', { x: 7, y: 7 });
|
|
12
|
+
await setHighlightUnreachableCells(page, 'On');
|
|
13
|
+
|
|
14
|
+
await expectReachable(page, 0, 0);
|
|
15
|
+
await expectReachable(page, 14, 14);
|
|
16
|
+
await expectReachable(page, 7, 7);
|
|
17
|
+
await expectReachable(page, 7, 8);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('has no effect when the setting is off', async ({ page }) => {
|
|
21
|
+
await Lib.visitIndex(page);
|
|
22
|
+
await Lib.typeRack(page, 'abcdefg');
|
|
23
|
+
|
|
24
|
+
await expectReachable(page, 0, 0);
|
|
25
|
+
await expectReachable(page, 14, 14);
|
|
26
|
+
await expectReachable(page, 7, 7);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('dims unreachable cells on an empty board when rack has tiles', async ({ page }) => {
|
|
30
|
+
await Lib.visitIndex(page);
|
|
31
|
+
await Lib.typeRack(page, 'abc');
|
|
32
|
+
await setHighlightUnreachableCells(page, 'On');
|
|
33
|
+
|
|
34
|
+
await expectReachable(page, 7, 7);
|
|
35
|
+
await expectReachable(page, 5, 7);
|
|
36
|
+
await expectReachable(page, 7, 5);
|
|
37
|
+
|
|
38
|
+
await expectUnreachable(page, 0, 0);
|
|
39
|
+
await expectUnreachable(page, 14, 14);
|
|
40
|
+
await expectUnreachable(page, 4, 7);
|
|
41
|
+
await expectUnreachable(page, 6, 6);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('dims cells far from any placed tile or rack reach', async ({ page }) => {
|
|
45
|
+
await Lib.visitIndex(page);
|
|
46
|
+
await Lib.typeBoard(page, 'cat', 'horizontal', { x: 7, y: 7 });
|
|
47
|
+
await Lib.typeRack(page, 'ab');
|
|
48
|
+
await setHighlightUnreachableCells(page, 'On');
|
|
49
|
+
|
|
50
|
+
await expectReachable(page, 7, 7);
|
|
51
|
+
await expectReachable(page, 6, 7);
|
|
52
|
+
await expectReachable(page, 10, 7);
|
|
53
|
+
await expectReachable(page, 8, 6);
|
|
54
|
+
|
|
55
|
+
await expectUnreachable(page, 0, 0);
|
|
56
|
+
await expectUnreachable(page, 14, 14);
|
|
57
|
+
await expectUnreachable(page, 0, 14);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('updates dimming when toggled off after being on', async ({ page }) => {
|
|
61
|
+
await Lib.visitIndex(page);
|
|
62
|
+
await Lib.typeRack(page, 'abc');
|
|
63
|
+
await setHighlightUnreachableCells(page, 'On');
|
|
64
|
+
await expectUnreachable(page, 0, 0);
|
|
65
|
+
|
|
66
|
+
await setHighlightUnreachableCells(page, 'Off');
|
|
67
|
+
await expectReachable(page, 0, 0);
|
|
68
|
+
await expectReachable(page, 14, 14);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
async function setHighlightUnreachableCells(page: Page, value: 'On' | 'Off') {
|
|
73
|
+
await Lib.getSettingsButton(page).click();
|
|
74
|
+
await expect(Lib.getOpenModal(page)).toBeVisible();
|
|
75
|
+
await Lib.getSettingOption(page, 'Highlight unreachable cells', value).check();
|
|
76
|
+
await Lib.closeModal(page);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function expectUnreachable(page: Page, x: number, y: number) {
|
|
80
|
+
await expect(Lib.getBoardTile(page, x, y).locator('..')).toHaveClass(/unreachable/);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function expectReachable(page: Page, x: number, y: number) {
|
|
84
|
+
await expect(Lib.getBoardTile(page, x, y).locator('..')).not.toHaveClass(/unreachable/);
|
|
85
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { expect, type Page, test } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
import * as Lib from '../lib';
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/91
|
|
7
|
+
*/
|
|
8
|
+
test.describe('#91 - Hovering remaining tile highlights all same tiles on the board and rack', () => {
|
|
9
|
+
test('highlights matching letter tiles on the board and rack', async ({ page }) => {
|
|
10
|
+
await Lib.visitIndex(page);
|
|
11
|
+
await Lib.typeBoard(page, 'cat', 'horizontal', { x: 7, y: 7 });
|
|
12
|
+
await Lib.typeRack(page, 'aab ');
|
|
13
|
+
await openRemainingTilesModal(page);
|
|
14
|
+
|
|
15
|
+
await hoverRemainingTile(page, 'a');
|
|
16
|
+
await Lib.expectTileHighlighted(Lib.getRackTile(page, 0));
|
|
17
|
+
await Lib.expectTileHighlighted(Lib.getRackTile(page, 1));
|
|
18
|
+
await Lib.expectTileNotHighlighted(Lib.getRackTile(page, 2));
|
|
19
|
+
await Lib.expectTileNotHighlighted(Lib.getRackTile(page, 3));
|
|
20
|
+
await Lib.expectTileNotHighlighted(Lib.getBoardTile(page, 7, 7));
|
|
21
|
+
await Lib.expectTileHighlighted(Lib.getBoardTile(page, 8, 7));
|
|
22
|
+
await Lib.expectTileNotHighlighted(Lib.getBoardTile(page, 9, 7));
|
|
23
|
+
|
|
24
|
+
await hoverRemainingTile(page, 'b');
|
|
25
|
+
await Lib.expectTileNotHighlighted(Lib.getRackTile(page, 0));
|
|
26
|
+
await Lib.expectTileNotHighlighted(Lib.getRackTile(page, 1));
|
|
27
|
+
await Lib.expectTileHighlighted(Lib.getRackTile(page, 2));
|
|
28
|
+
await Lib.expectTileNotHighlighted(Lib.getRackTile(page, 3));
|
|
29
|
+
await Lib.expectTileNotHighlighted(Lib.getBoardTile(page, 7, 7));
|
|
30
|
+
await Lib.expectTileNotHighlighted(Lib.getBoardTile(page, 8, 7));
|
|
31
|
+
await Lib.expectTileNotHighlighted(Lib.getBoardTile(page, 9, 7));
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('highlights matching blank tiles on the board and rack', async ({ page }) => {
|
|
35
|
+
await Lib.visitIndex(page);
|
|
36
|
+
await Lib.typeBoard(page, 'a', 'horizontal', { x: 7, y: 7 });
|
|
37
|
+
await Lib.getBoardTile(page, 7, 7).focus();
|
|
38
|
+
await Lib.typeBoard(page, ' ', 'horizontal', { x: 7, y: 7 });
|
|
39
|
+
await Lib.typeRack(page, ' a');
|
|
40
|
+
await openRemainingTilesModal(page);
|
|
41
|
+
|
|
42
|
+
await hoverRemainingTile(page, ' ');
|
|
43
|
+
await Lib.expectTileHighlighted(Lib.getRackTile(page, 0));
|
|
44
|
+
await Lib.expectTileNotHighlighted(Lib.getRackTile(page, 1));
|
|
45
|
+
await Lib.expectTileHighlighted(Lib.getBoardTile(page, 7, 7));
|
|
46
|
+
|
|
47
|
+
await hoverRemainingTile(page, 'a');
|
|
48
|
+
await Lib.expectTileNotHighlighted(Lib.getRackTile(page, 0));
|
|
49
|
+
await Lib.expectTileHighlighted(Lib.getRackTile(page, 1));
|
|
50
|
+
await Lib.expectTileNotHighlighted(Lib.getBoardTile(page, 7, 7));
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('does not highlight a remaining tile in the sidebar if it has not been used', async ({ page }) => {
|
|
54
|
+
await Lib.visitIndex(page);
|
|
55
|
+
await Lib.typeRack(page, 'a');
|
|
56
|
+
await openRemainingTilesModal(page);
|
|
57
|
+
|
|
58
|
+
await hoverRemainingTile(page, 'z');
|
|
59
|
+
await expect(page.getByTestId('remaining-tile-z').locator('[role="mark"]')).toHaveCount(0);
|
|
60
|
+
await Lib.expectTileNotHighlighted(Lib.getRackTile(page, 0));
|
|
61
|
+
|
|
62
|
+
await hoverRemainingTile(page, 'a');
|
|
63
|
+
await expect(page.getByTestId('remaining-tile-a').locator('[role="mark"]')).not.toHaveCount(0);
|
|
64
|
+
await Lib.expectTileHighlighted(Lib.getRackTile(page, 0));
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
async function openRemainingTilesModal(page: Page) {
|
|
69
|
+
await page.getByLabel('Remaining tiles', { exact: true }).click();
|
|
70
|
+
await expect(Lib.getOpenModal(page)).toBeVisible();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function hoverRemainingTile(page: Page, character: string) {
|
|
74
|
+
const testId = character === ' ' ? 'remaining-tile-blank' : `remaining-tile-${character}`;
|
|
75
|
+
await page.getByTestId(testId).hover();
|
|
76
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
import * as Lib from '../lib';
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* The 'hidden' showCoordinates option was removed on 2026/08/13.
|
|
7
|
+
* Delete this spec together with migrateHiddenShowCoordinates.
|
|
8
|
+
*/
|
|
9
|
+
test.describe('"hidden" coordinates migration', () => {
|
|
10
|
+
test('falls back to original coordinates when storage holds the removed "hidden" option', async ({ page }) => {
|
|
11
|
+
await page.addInitScript(() => {
|
|
12
|
+
localStorage.setItem('scrabble-solver.settings', JSON.stringify({ showCoordinates: 'hidden' }));
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
await Lib.visitIndex(page);
|
|
16
|
+
|
|
17
|
+
await expect(Lib.getBoardContainer(page).getByText('A', { exact: true })).toBeVisible();
|
|
18
|
+
|
|
19
|
+
await Lib.getSettingsButton(page).click();
|
|
20
|
+
await expect(Lib.getSettingOption(page, 'Coordinates', 'Original')).toBeChecked();
|
|
21
|
+
await Lib.closeModal(page);
|
|
22
|
+
|
|
23
|
+
await expect
|
|
24
|
+
.poll(() => page.evaluate(() => localStorage.getItem('scrabble-solver.settings')))
|
|
25
|
+
.toContain('"showCoordinates":"original"');
|
|
26
|
+
});
|
|
27
|
+
});
|