scrabble-solver 2.13.12 → 2.14.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/.eslintrc.js +13 -4
- package/.github/workflows/build.yml +6 -14
- package/.github/workflows/cypress.yml +28 -0
- package/.github/workflows/eslint.yml +9 -16
- package/.github/workflows/jest.yml +21 -0
- package/.nx/cache/nx_files.nxt +0 -0
- package/.nx/workspace-data/file-map.json +639 -543
- package/.nx/workspace-data/lockfile.hash +1 -1
- package/.nx/workspace-data/parsed-lock-file.json +6131 -5552
- package/.nx/workspace-data/project-graph.json +4276 -2896
- package/README.md +5 -3
- package/bin/scrabble-solver.js +0 -0
- package/cypress/e2e/app.spec.cy.ts +118 -0
- package/cypress/e2e/bugs/112-character-bonus.ts +40 -0
- package/cypress/e2e/bugs/129-esc-sidebar.ts +23 -0
- package/cypress/e2e/bugs/2-q-tile-in-english.ts +33 -0
- package/cypress/e2e/bugs/3-x-tile-in-polish.ts +33 -0
- package/cypress/e2e/bugs/30-click-inside-radio-icon.ts +26 -0
- package/cypress/e2e/bugs/333-disabled-radio-cursor.ts +24 -0
- package/cypress/e2e/bugs/342-results-sorting.ts +48 -0
- package/cypress/e2e/bugs/348-results-word-padding.ts +74 -0
- package/cypress/e2e/bugs.spec.cy.ts +8 -0
- package/cypress/support/commands.ts +4 -0
- package/cypress/support/e2e.ts +1 -0
- package/cypress/support/index.ts +1 -0
- package/cypress/support/lib/actions.ts +57 -0
- package/cypress/support/lib/index.ts +2 -0
- package/cypress/support/lib/selectors.ts +70 -0
- package/cypress/tsconfig.json +9 -0
- package/cypress.config.ts +9 -0
- package/jest.config.js +2 -3
- package/lerna.json +1 -1
- package/package.json +29 -22
- package/packages/configs/package.json +3 -3
- package/packages/constants/package.json +1 -1
- package/packages/dictionaries/package-lock.json +2 -2
- package/packages/dictionaries/package.json +4 -4
- package/packages/logger/package-lock.json +3 -3
- package/packages/logger/package.json +2 -2
- package/packages/scrabble-solver/.next/BUILD_ID +1 -1
- package/packages/scrabble-solver/.next/build-manifest.json +14 -14
- package/packages/scrabble-solver/.next/cache/.tsbuildinfo +1 -1
- package/packages/scrabble-solver/.next/cache/eslint/.cache_8dgz12 +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/0.pack +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/prerender-manifest.js +1 -1
- package/packages/scrabble-solver/.next/prerender-manifest.json +1 -1
- package/packages/scrabble-solver/.next/routes-manifest.json +1 -1
- package/packages/scrabble-solver/.next/server/chunks/807.js +1 -1
- package/packages/scrabble-solver/.next/server/middleware-build-manifest.js +1 -1
- package/packages/scrabble-solver/.next/server/pages/404.html +1 -1
- package/packages/scrabble-solver/.next/server/pages/500.html +1 -1
- package/packages/scrabble-solver/.next/server/pages/api/solve.js +1 -1
- package/packages/scrabble-solver/.next/server/pages/index.html +1 -1
- package/packages/scrabble-solver/.next/server/pages/index.js +1 -1
- package/packages/scrabble-solver/.next/server/pages/index.json +1 -1
- package/packages/scrabble-solver/.next/server/pages-manifest.json +1 -1
- package/packages/scrabble-solver/.next/static/{N8hSsS6Ppzlj3ebHMSZvI → TxfjxrH5h31sPQxPhrJzG}/_buildManifest.js +1 -1
- package/packages/scrabble-solver/.next/static/chunks/{main-b5b360c6afb66b05.js → main-8b0b4e610892a916.js} +1 -1
- package/packages/scrabble-solver/.next/static/chunks/pages/{404-0c9f3e0f8b15f487.js → 404-b0c2ccded2455be0.js} +1 -1
- package/packages/scrabble-solver/.next/static/chunks/pages/_app-2912876c7b6e698e.js +17 -0
- package/packages/scrabble-solver/.next/static/chunks/pages/index-86d9ad372c48c8b7.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/webpack-c4acd79e87956a0e.js +1 -0
- package/packages/scrabble-solver/.next/static/css/14625ff7b4d265d0.css +2 -0
- package/packages/scrabble-solver/.next/trace +45 -45
- package/packages/scrabble-solver/package-lock.json +6 -6
- package/packages/scrabble-solver/package.json +13 -13
- package/packages/scrabble-solver/public/service-worker.js +1 -1
- package/packages/scrabble-solver/src/components/Alert/Alert.tsx +1 -1
- package/packages/scrabble-solver/src/components/Board/Board.module.scss +3 -9
- package/packages/scrabble-solver/src/components/Board/Board.tsx +2 -2
- package/packages/scrabble-solver/src/components/Board/BoardPure.tsx +4 -3
- package/packages/scrabble-solver/src/components/Board/components/ToggleDirectionButton/ToggleDirectionButton.tsx +2 -0
- package/packages/scrabble-solver/src/components/Board/hooks/useBackgroundImage.tsx +2 -6
- package/packages/scrabble-solver/src/components/Board/hooks/useBoardStyle.ts +10 -4
- package/packages/scrabble-solver/src/components/Button/Button.tsx +1 -1
- package/packages/scrabble-solver/src/components/Dictionary/Dictionary.module.scss +10 -7
- package/packages/scrabble-solver/src/components/Dictionary/Dictionary.tsx +38 -36
- package/packages/scrabble-solver/src/components/IconButton/IconButton.tsx +1 -1
- package/packages/scrabble-solver/src/components/IconButton/Link.tsx +1 -1
- package/packages/scrabble-solver/src/components/Keys/Arrows/Arrows.tsx +4 -4
- package/packages/scrabble-solver/src/components/Loading/Loading.module.scss +1 -0
- package/packages/scrabble-solver/src/components/Loading/Loading.tsx +1 -1
- package/packages/scrabble-solver/src/components/Modal/components/Section/Section.tsx +3 -2
- package/packages/scrabble-solver/src/components/NavButtons/NavButtons.tsx +1 -0
- package/packages/scrabble-solver/src/components/NotFound/NotFound.tsx +1 -1
- package/packages/scrabble-solver/src/components/Rack/Rack.tsx +1 -0
- package/packages/scrabble-solver/src/components/Radio/Radio.tsx +1 -1
- package/packages/scrabble-solver/src/components/Results/Cell.tsx +7 -3
- package/packages/scrabble-solver/src/components/Results/Header.tsx +99 -0
- package/packages/scrabble-solver/src/components/Results/HeaderButton.tsx +18 -13
- package/packages/scrabble-solver/src/components/Results/Result.tsx +23 -16
- package/packages/scrabble-solver/src/components/Results/Results.module.scss +27 -18
- package/packages/scrabble-solver/src/components/Results/Results.tsx +3 -9
- package/packages/scrabble-solver/src/components/Results/types.ts +0 -8
- package/packages/scrabble-solver/src/components/Solver/Solver.tsx +1 -1
- package/packages/scrabble-solver/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.tsx +1 -1
- package/packages/scrabble-solver/src/components/Tile/TilePure.tsx +2 -1
- package/packages/scrabble-solver/src/hooks/index.ts +1 -0
- package/packages/scrabble-solver/src/hooks/useAppLayout.ts +12 -1
- package/packages/scrabble-solver/src/hooks/useColumns.ts +47 -0
- package/packages/scrabble-solver/src/icons/GeoAlt.svg +5 -0
- package/packages/scrabble-solver/src/icons/OneTwoThree.svg +4 -0
- package/packages/scrabble-solver/src/icons/SquareA.svg +6 -0
- package/packages/scrabble-solver/src/icons/SquareB.svg +6 -0
- package/packages/scrabble-solver/src/icons/Squares.svg +34 -0
- package/packages/scrabble-solver/src/icons/Words.svg +22 -0
- package/packages/scrabble-solver/src/icons/index.ts +6 -0
- package/packages/scrabble-solver/src/lib/groupResults.ts +1 -1
- package/packages/scrabble-solver/src/lib/index.ts +0 -1
- package/packages/scrabble-solver/src/lib/sortResults.ts +10 -10
- package/packages/scrabble-solver/src/modals/KeyMapModal/KeyMapModal.tsx +8 -9
- package/packages/scrabble-solver/src/modals/MenuModal/MenuModal.tsx +1 -1
- package/packages/scrabble-solver/src/modals/RemainingTilesModal/RemainingTilesModal.tsx +1 -0
- package/packages/scrabble-solver/src/modals/SettingsModal/SettingsModal.tsx +5 -5
- package/packages/scrabble-solver/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.tsx +1 -1
- package/packages/scrabble-solver/src/modals/WordsModal/WordsModal.tsx +4 -2
- package/packages/scrabble-solver/src/parameters/index.ts +12 -0
- package/packages/scrabble-solver/src/state/selectors.ts +26 -1
- package/packages/scrabble-solver/src/state/slices/resultsInitialState.ts +2 -2
- package/packages/scrabble-solver/src/state/slices/resultsSlice.ts +2 -2
- package/packages/scrabble-solver/src/state/useTranslate.ts +5 -1
- package/packages/scrabble-solver/src/styles/variables.scss +1 -0
- package/packages/scrabble-solver/src/types/index.ts +11 -2
- package/packages/solver/package-lock.json +2 -2
- package/packages/solver/package.json +5 -5
- package/packages/types/package.json +2 -2
- package/packages/word-definitions/build/lib/request.d.ts +0 -1
- package/packages/word-definitions/package-lock.json +2 -2
- package/packages/word-definitions/package.json +2 -2
- package/packages/word-lists/package-lock.json +3 -3
- package/packages/word-lists/package.json +3 -3
- package/tsconfig.jest.json +2 -1
- package/.github/workflows/test.yml +0 -28
- package/packages/scrabble-solver/.next/static/chunks/pages/_app-8246f5b39b6a5e59.js +0 -17
- package/packages/scrabble-solver/.next/static/chunks/pages/index-65bfe83d121535ab.js +0 -1
- package/packages/scrabble-solver/.next/static/chunks/webpack-6ef43a8d4a395f49.js +0 -1
- package/packages/scrabble-solver/.next/static/css/2f727b21d1331ea5.css +0 -2
- package/packages/scrabble-solver/src/components/Results/getCoordinatesColumn.ts +0 -14
- package/packages/scrabble-solver/src/components/Results/getLocaleColumns.ts +0 -58
- package/packages/scrabble-solver/src/components/Results/useColumns.ts +0 -44
- package/packages/scrabble-solver/src/lib/dataUrlToBlob.ts +0 -20
- /package/packages/scrabble-solver/.next/static/{N8hSsS6Ppzlj3ebHMSZvI → TxfjxrH5h31sPQxPhrJzG}/_ssgManifest.js +0 -0
package/README.md
CHANGED
|
@@ -39,9 +39,10 @@
|
|
|
39
39
|
</p>
|
|
40
40
|
|
|
41
41
|
<p>
|
|
42
|
-
<img src="https://github.com/kamilmielnik/scrabble-solver/workflows/
|
|
43
|
-
<img src="https://github.com/kamilmielnik/scrabble-solver/workflows/
|
|
44
|
-
<img src="https://github.com/kamilmielnik/scrabble-solver/workflows/
|
|
42
|
+
<img src="https://github.com/kamilmielnik/scrabble-solver/actions/workflows/build.yml/badge.svg" alt="Build" />
|
|
43
|
+
<img src="https://github.com/kamilmielnik/scrabble-solver/actions/workflows/jest.yml/badge.svg" alt="Jest Tests" />
|
|
44
|
+
<img src="https://github.com/kamilmielnik/scrabble-solver/actions/workflows/cypress.yml/badge.svg" alt="Cypress Tests" />
|
|
45
|
+
<img src="https://github.com/kamilmielnik/scrabble-solver/actions/workflows/eslint.yml/badge.svg" alt="ESLint" />
|
|
45
46
|
</p>
|
|
46
47
|
|
|
47
48
|
<img alt="Screencast GIF showing user interface when solving for oxyphenbutazone, which is a top-scoring word in English version of Scrabble" src="https://raw.githubusercontent.com/kamilmielnik/scrabble-solver/master/screencast.gif" />
|
|
@@ -183,6 +184,7 @@ npm run build -w @scrabble-solver/word-lists
|
|
|
183
184
|
- [CSS Modules](https://github.com/css-modules/css-modules)
|
|
184
185
|
- [include-media](https://eduardoboucas.github.io/include-media/)
|
|
185
186
|
- [Lerna](https://lerna.js.org/)
|
|
187
|
+
- [Cypress](https://www.cypress.io/)
|
|
186
188
|
- [Jest](https://jestjs.io/)
|
|
187
189
|
- [ESLint](https://eslint.org/)
|
|
188
190
|
- [Prettier](https://prettier.io/)
|
package/bin/scrabble-solver.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertResult,
|
|
3
|
+
closeModal,
|
|
4
|
+
getBoardTile,
|
|
5
|
+
getDictionary,
|
|
6
|
+
getDictionaryInput,
|
|
7
|
+
getDictionaryTitles,
|
|
8
|
+
getLoading,
|
|
9
|
+
getRackTile,
|
|
10
|
+
getResult,
|
|
11
|
+
getSettingOption,
|
|
12
|
+
getSettingsButton,
|
|
13
|
+
getTooltip,
|
|
14
|
+
solve,
|
|
15
|
+
typeRack,
|
|
16
|
+
unregisterServiceWorkers,
|
|
17
|
+
visitIndex,
|
|
18
|
+
} from '../support';
|
|
19
|
+
|
|
20
|
+
describe('app', () => {
|
|
21
|
+
beforeEach(async () => {
|
|
22
|
+
await unregisterServiceWorkers();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
cy.clearLocalStorage();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('has title', () => {
|
|
30
|
+
visitIndex();
|
|
31
|
+
|
|
32
|
+
cy.title().should('equal', 'Scrabble Solver 2 by Kamil Mielnik');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('has default setting values', () => {
|
|
36
|
+
visitIndex();
|
|
37
|
+
getSettingsButton().realClick();
|
|
38
|
+
|
|
39
|
+
getSettingOption('Game', 'Scrabble').should('be.checked');
|
|
40
|
+
getSettingOption('Language', 'English (US)').should('be.checked');
|
|
41
|
+
getSettingOption('Coordinates', 'Hidden').should('be.checked');
|
|
42
|
+
getSettingOption('Input mode', 'Keyboard').should('be.checked');
|
|
43
|
+
getSettingOption('Group remaining tiles', 'Do not group').should('be.checked');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe('full app test', () => {
|
|
47
|
+
beforeEach(() => {
|
|
48
|
+
cy.intercept('/api/solve').as('solve');
|
|
49
|
+
cy.intercept('/api/dictionary/**/*').as('dictionary');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('Scrabble - Polish', () => {
|
|
53
|
+
visitIndex();
|
|
54
|
+
getSettingsButton().realClick();
|
|
55
|
+
getSettingOption('Language', 'Polski').check();
|
|
56
|
+
getSettingOption('Współrzędne', 'Oryginalne').check();
|
|
57
|
+
closeModal();
|
|
58
|
+
typeRack('abł');
|
|
59
|
+
solve();
|
|
60
|
+
|
|
61
|
+
assertResult(0, 'bał', 14);
|
|
62
|
+
getResult(0).realHover();
|
|
63
|
+
getLoading().should('be.visible');
|
|
64
|
+
cy.wait('@dictionary');
|
|
65
|
+
getRackTile(0).parent().should('have.attr', 'role', 'mark');
|
|
66
|
+
getRackTile(1).parent().should('have.attr', 'role', 'mark');
|
|
67
|
+
getRackTile(2).parent().should('have.attr', 'role', 'mark');
|
|
68
|
+
getBoardTile(5, 7).should('have.value', 'b');
|
|
69
|
+
getBoardTile(6, 7).should('have.value', 'a');
|
|
70
|
+
getBoardTile(7, 7).should('have.value', 'ł');
|
|
71
|
+
getBoardTile(5, 7).parent().should('have.attr', 'role', 'mark');
|
|
72
|
+
getBoardTile(6, 7).parent().should('have.attr', 'role', 'mark');
|
|
73
|
+
getBoardTile(7, 7).parent().should('have.attr', 'role', 'mark');
|
|
74
|
+
getDictionaryInput().should('have.value', 'bał');
|
|
75
|
+
getLoading().should('not.exist');
|
|
76
|
+
getDictionaryTitles().should('have.length', 1).and('have.text', 'bał');
|
|
77
|
+
getDictionary()
|
|
78
|
+
.should('include.text', 'bać się')
|
|
79
|
+
.and('include.text', 'odczuwać lęk, strach')
|
|
80
|
+
.and('include.text', 'być niespokojnym o kogoś lub o coś')
|
|
81
|
+
.and('include.text', 'nie śmieć, nie odważać się na coś');
|
|
82
|
+
|
|
83
|
+
cy.findByLabelText('Punkty').realClick();
|
|
84
|
+
getTooltip().should('be.visible').and('have.text', 'Punkty');
|
|
85
|
+
assertResult(0, 'ba', 8);
|
|
86
|
+
getResult(0).realHover();
|
|
87
|
+
getRackTile(0).parent().should('have.attr', 'role', 'mark');
|
|
88
|
+
getRackTile(1).parent().should('have.attr', 'role', 'mark');
|
|
89
|
+
getRackTile(2).parent().should('not.have.attr', 'role', 'mark');
|
|
90
|
+
getBoardTile(5, 7).should('not.have.value');
|
|
91
|
+
getBoardTile(6, 7).should('have.value', 'b');
|
|
92
|
+
getBoardTile(7, 7).should('have.value', 'a');
|
|
93
|
+
getBoardTile(5, 7).parent().should('not.have.attr', 'role', 'mark');
|
|
94
|
+
getBoardTile(6, 7).parent().should('have.attr', 'role', 'mark');
|
|
95
|
+
getBoardTile(7, 7).parent().should('have.attr', 'role', 'mark');
|
|
96
|
+
getDictionaryInput().should('have.value', 'ba');
|
|
97
|
+
getLoading().should('be.visible');
|
|
98
|
+
cy.wait('@dictionary');
|
|
99
|
+
getLoading().should('not.exist');
|
|
100
|
+
getDictionaryTitles().should('have.length', 1).and('have.text', 'ba');
|
|
101
|
+
getDictionary()
|
|
102
|
+
.should('include.text', 'wykrzyknik, który wyraża głównie podziw, zdziwienie')
|
|
103
|
+
.and('include.text', 'w wierzeniach staroegipskich: dusza ludzka ginąca wraz z ciałem');
|
|
104
|
+
|
|
105
|
+
getResult(0).realClick();
|
|
106
|
+
getRackTile(0).parent().should('not.have.attr', 'role', 'mark');
|
|
107
|
+
getRackTile(1).parent().should('not.have.attr', 'role', 'mark');
|
|
108
|
+
getRackTile(2).parent().should('not.have.attr', 'role', 'mark');
|
|
109
|
+
getRackTile(0).should('not.have.value');
|
|
110
|
+
getRackTile(1).should('not.have.value');
|
|
111
|
+
getRackTile(2).should('have.value', 'ł');
|
|
112
|
+
getBoardTile(6, 7).should('have.value', 'b');
|
|
113
|
+
getBoardTile(7, 7).should('have.value', 'a');
|
|
114
|
+
|
|
115
|
+
cy.findByLabelText('Rozwiąż').should('be.visible').and('be.enabled');
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertResult,
|
|
3
|
+
closeModal,
|
|
4
|
+
getSettingOption,
|
|
5
|
+
getSettingsButton,
|
|
6
|
+
solve,
|
|
7
|
+
typeRack,
|
|
8
|
+
unregisterServiceWorkers,
|
|
9
|
+
visitIndex,
|
|
10
|
+
} from '../../support';
|
|
11
|
+
|
|
12
|
+
/*
|
|
13
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/112
|
|
14
|
+
*/
|
|
15
|
+
describe('#112 - Scrabble - Character bonus not applied', () => {
|
|
16
|
+
beforeEach(async () => {
|
|
17
|
+
await unregisterServiceWorkers();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
cy.clearLocalStorage();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('correctly shows points for a result which gets a character bonus', () => {
|
|
25
|
+
visitIndex();
|
|
26
|
+
|
|
27
|
+
getSettingsButton().realClick();
|
|
28
|
+
getSettingOption('Language', 'Français').check();
|
|
29
|
+
closeModal();
|
|
30
|
+
typeRack('jours');
|
|
31
|
+
solve();
|
|
32
|
+
|
|
33
|
+
assertResult(0, 'jours', 40);
|
|
34
|
+
assertResult(1, 'jours', 40);
|
|
35
|
+
assertResult(2, 'jours', 26);
|
|
36
|
+
assertResult(3, 'jours', 26);
|
|
37
|
+
assertResult(4, 'jours', 24);
|
|
38
|
+
assertResult(5, 'jours', 24);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { getModal, getSettingsButton, typeRack, unregisterServiceWorkers, visitIndex } from '../../support';
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/129
|
|
5
|
+
*/
|
|
6
|
+
describe('#129 - Esc does not close the sidebar when letters input is focused', () => {
|
|
7
|
+
beforeEach(async () => {
|
|
8
|
+
await unregisterServiceWorkers();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
cy.clearLocalStorage();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('Esc key closes the sidebar when rack is focused', () => {
|
|
16
|
+
visitIndex();
|
|
17
|
+
getSettingsButton().realClick();
|
|
18
|
+
typeRack('a');
|
|
19
|
+
cy.realPress('Escape');
|
|
20
|
+
|
|
21
|
+
getModal().should('not.exist');
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertResult,
|
|
3
|
+
getResults,
|
|
4
|
+
solve,
|
|
5
|
+
typeBoard,
|
|
6
|
+
typeRack,
|
|
7
|
+
unregisterServiceWorkers,
|
|
8
|
+
visitIndex,
|
|
9
|
+
} from '../../support';
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/2
|
|
13
|
+
*/
|
|
14
|
+
describe('#2 - "Q" tile does not work', () => {
|
|
15
|
+
beforeEach(async () => {
|
|
16
|
+
await unregisterServiceWorkers();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
cy.clearLocalStorage();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('accepts "Q" tile in English', () => {
|
|
24
|
+
visitIndex();
|
|
25
|
+
typeBoard('i', 'horizontal', 7, 7);
|
|
26
|
+
typeRack('q');
|
|
27
|
+
solve();
|
|
28
|
+
|
|
29
|
+
getResults().should('have.length', 2);
|
|
30
|
+
assertResult(0, 'qi', 11);
|
|
31
|
+
assertResult(1, 'qi', 11);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
closeModal,
|
|
3
|
+
getSettingOption,
|
|
4
|
+
getSettingsButton,
|
|
5
|
+
typeBoard,
|
|
6
|
+
typeRack,
|
|
7
|
+
unregisterServiceWorkers,
|
|
8
|
+
visitIndex,
|
|
9
|
+
} from '../../support';
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/3
|
|
13
|
+
*/
|
|
14
|
+
describe('#3 - "X" tile is allowed in Polish', () => {
|
|
15
|
+
beforeEach(async () => {
|
|
16
|
+
await unregisterServiceWorkers();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
cy.clearLocalStorage();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('does not accept "X" tile in Polish', () => {
|
|
24
|
+
visitIndex();
|
|
25
|
+
getSettingsButton().realClick();
|
|
26
|
+
getSettingOption('Language', 'Polski').check();
|
|
27
|
+
closeModal();
|
|
28
|
+
typeBoard('x', 'horizontal', 7, 7);
|
|
29
|
+
typeRack('x');
|
|
30
|
+
|
|
31
|
+
cy.findByText('x').should('not.exist');
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { getSettingOption, getSettingsButton, unregisterServiceWorkers, visitIndex } from '../../support';
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/30
|
|
5
|
+
*/
|
|
6
|
+
describe('#30 - Clicking inside an icon of non-first unchecked radio button does not select that option', () => {
|
|
7
|
+
beforeEach(async () => {
|
|
8
|
+
await unregisterServiceWorkers();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
cy.clearLocalStorage();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('Clicking inside an icon of first unchecked radio button selects it', () => {
|
|
16
|
+
visitIndex();
|
|
17
|
+
getSettingsButton().realClick();
|
|
18
|
+
getSettingOption('Language', 'English (GB)').click();
|
|
19
|
+
getSettingOption('Language', 'English (US)') // first unchecked radio button
|
|
20
|
+
.parent('label')
|
|
21
|
+
.findAllByRole('img', { hidden: true })
|
|
22
|
+
.first()
|
|
23
|
+
.realHover({ position: 'center' })
|
|
24
|
+
.realClick({ position: 'center' });
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { getSettingOption, getSettingsButton, unregisterServiceWorkers, visitIndex } from '../../support';
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/333
|
|
5
|
+
*/
|
|
6
|
+
describe('#333 - Disabled radio button has cursor: pointer', () => {
|
|
7
|
+
beforeEach(async () => {
|
|
8
|
+
await unregisterServiceWorkers();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
cy.clearLocalStorage();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('Disabled radio button has cursor: not-allowed', () => {
|
|
16
|
+
visitIndex();
|
|
17
|
+
getSettingsButton().realClick();
|
|
18
|
+
getSettingOption('Language', 'Polski').check();
|
|
19
|
+
getSettingOption('Gra', 'Scrabble').scrollIntoView();
|
|
20
|
+
|
|
21
|
+
getSettingOption('Gra', 'Super Scrabble').should('be.disabled');
|
|
22
|
+
getSettingOption('Gra', 'Super Scrabble').should('have.css', 'cursor', 'not-allowed');
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertResult,
|
|
3
|
+
closeModal,
|
|
4
|
+
getResult,
|
|
5
|
+
getResultsFilterInput,
|
|
6
|
+
getSettingOption,
|
|
7
|
+
getSettingsButton,
|
|
8
|
+
solve,
|
|
9
|
+
typeBoard,
|
|
10
|
+
typeRack,
|
|
11
|
+
unregisterServiceWorkers,
|
|
12
|
+
visitIndex,
|
|
13
|
+
} from '../../support';
|
|
14
|
+
|
|
15
|
+
/*
|
|
16
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/342
|
|
17
|
+
*/
|
|
18
|
+
describe('#342 - Incorrect sorting when filtering', () => {
|
|
19
|
+
beforeEach(async () => {
|
|
20
|
+
await unregisterServiceWorkers();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
cy.clearLocalStorage();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('correctly sorts valid results first when text filter is active', () => {
|
|
28
|
+
visitIndex();
|
|
29
|
+
getSettingsButton().realClick();
|
|
30
|
+
getSettingOption('Language', 'Polski').check();
|
|
31
|
+
closeModal();
|
|
32
|
+
typeBoard('bopie', 'horizontal', 6, 3);
|
|
33
|
+
typeBoard('apu', 'vertical', 8, 4);
|
|
34
|
+
typeBoard('o', 'vertical', 10, 4);
|
|
35
|
+
typeRack('oe');
|
|
36
|
+
solve();
|
|
37
|
+
getResultsFilterInput().type('p');
|
|
38
|
+
|
|
39
|
+
assertResult(0, 'po', 5);
|
|
40
|
+
assertResult(1, 'pe', 5);
|
|
41
|
+
assertResult(2, 'op', 3);
|
|
42
|
+
assertResult(3, 'eo', 6);
|
|
43
|
+
getResult(0).should('not.have.attr', 'aria-hidden');
|
|
44
|
+
getResult(1).should('not.have.attr', 'aria-hidden');
|
|
45
|
+
getResult(2).should('not.have.attr', 'aria-hidden');
|
|
46
|
+
getResult(3).should('have.attr', 'aria-hidden', 'true');
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {
|
|
2
|
+
closeModal,
|
|
3
|
+
getResult,
|
|
4
|
+
getSettingOption,
|
|
5
|
+
getSettingsButton,
|
|
6
|
+
solve,
|
|
7
|
+
typeRack,
|
|
8
|
+
unregisterServiceWorkers,
|
|
9
|
+
visitIndex,
|
|
10
|
+
} from '../../support';
|
|
11
|
+
|
|
12
|
+
/*
|
|
13
|
+
* @see https://github.com/kamilmielnik/scrabble-solver/issues/348
|
|
14
|
+
*/
|
|
15
|
+
describe('#348 - Missing result word padding when coordinates are not shown', () => {
|
|
16
|
+
beforeEach(async () => {
|
|
17
|
+
await unregisterServiceWorkers();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
cy.clearLocalStorage();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('sets proper padding on result cells depending on coordinates setting (LTR language)', () => {
|
|
25
|
+
visitIndex();
|
|
26
|
+
typeRack('ab');
|
|
27
|
+
solve();
|
|
28
|
+
|
|
29
|
+
getResult(0).then(([$result]) => {
|
|
30
|
+
const $span = $result.children[0];
|
|
31
|
+
const wordCell = $span.children[0];
|
|
32
|
+
|
|
33
|
+
expect(window.getComputedStyle(wordCell).paddingLeft).to.equal('15px');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
getSettingsButton().realClick();
|
|
37
|
+
getSettingOption('Coordinates', 'Original').check();
|
|
38
|
+
closeModal();
|
|
39
|
+
|
|
40
|
+
getResult(0).then(([$result]) => {
|
|
41
|
+
const $span = $result.children[0];
|
|
42
|
+
const wordCell = $span.children[1];
|
|
43
|
+
|
|
44
|
+
expect(window.getComputedStyle(wordCell).paddingLeft).to.equal('15px');
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('sets proper padding on result cells depending on coordinates setting (RTL language)', () => {
|
|
49
|
+
visitIndex();
|
|
50
|
+
getSettingsButton().realClick();
|
|
51
|
+
getSettingOption('Language', 'فارسی').check();
|
|
52
|
+
closeModal();
|
|
53
|
+
typeRack('فا');
|
|
54
|
+
solve();
|
|
55
|
+
|
|
56
|
+
getResult(0).then(([$result]) => {
|
|
57
|
+
const $span = $result.children[0];
|
|
58
|
+
const wordCell = $span.children[0];
|
|
59
|
+
|
|
60
|
+
expect(window.getComputedStyle(wordCell).paddingRight).to.equal('15px');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
getSettingsButton().realClick();
|
|
64
|
+
getSettingOption('مختصات', 'إبداعي').check();
|
|
65
|
+
closeModal();
|
|
66
|
+
|
|
67
|
+
getResult(0).then(([$result]) => {
|
|
68
|
+
const $span = $result.children[0];
|
|
69
|
+
const wordCell = $span.children[1];
|
|
70
|
+
|
|
71
|
+
expect(window.getComputedStyle(wordCell).paddingRight).to.equal('15px');
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import './bugs/2-q-tile-in-english';
|
|
2
|
+
import './bugs/3-x-tile-in-polish';
|
|
3
|
+
import './bugs/112-character-bonus';
|
|
4
|
+
import './bugs/129-esc-sidebar';
|
|
5
|
+
import './bugs/30-click-inside-radio-icon';
|
|
6
|
+
import './bugs/333-disabled-radio-cursor';
|
|
7
|
+
import './bugs/342-results-sorting';
|
|
8
|
+
import './bugs/348-results-word-padding';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import './commands';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './lib';
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { getBoardTile, getLoading, getModal, getRackTile, getResult } from './selectors';
|
|
2
|
+
|
|
3
|
+
const getRandomId = () => {
|
|
4
|
+
return String(Math.random()).replace(/^\d\./, '');
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const visitIndex = () => {
|
|
8
|
+
cy.visit('/');
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const closeModal = () => {
|
|
12
|
+
getModal().should('be.visible');
|
|
13
|
+
cy.realPress('Escape');
|
|
14
|
+
getModal().should('not.exist');
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const typeRack = (tiles: string, index = 0) => {
|
|
18
|
+
getRackTile(index).focus().type(tiles);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const typeBoard = (tiles: string, direction: 'horizontal' | 'vertical', x = 0, y = 0) => {
|
|
22
|
+
getBoardTile(x, y).focus();
|
|
23
|
+
|
|
24
|
+
cy.findByTestId('toggle-direction-button').then(([$button]) => {
|
|
25
|
+
if ($button.dataset.direction !== direction) {
|
|
26
|
+
cy.wrap($button).click();
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
for (let index = 0; index < tiles.length; ++index) {
|
|
31
|
+
const xOffset = direction === 'horizontal' ? index : 0;
|
|
32
|
+
const yOffset = direction === 'vertical' ? index : 0;
|
|
33
|
+
|
|
34
|
+
getBoardTile(x + xOffset, y + yOffset)
|
|
35
|
+
.focus()
|
|
36
|
+
.type(tiles[index]);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const solve = () => {
|
|
41
|
+
const id = `solve-${getRandomId()}`;
|
|
42
|
+
|
|
43
|
+
cy.intercept('/api/solve').as(id);
|
|
44
|
+
getRackTile().focus().parents('form').submit();
|
|
45
|
+
cy.wait(`@${id}`);
|
|
46
|
+
getLoading().should('not.exist');
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const assertResult = (index: number, word: string, points: number) => {
|
|
50
|
+
getResult(index).should('have.attr', 'aria-label', word).and('include.text', word);
|
|
51
|
+
getResult(index).findByTestId('points').should('have.text', String(points));
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const unregisterServiceWorkers = async () => {
|
|
55
|
+
const registrations = await navigator.serviceWorker.getRegistrations();
|
|
56
|
+
return Promise.all(registrations.map((registration) => registration.unregister()));
|
|
57
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export const getModal = () => {
|
|
2
|
+
return cy.findByRole('dialog');
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
export const getBoardContainer = () => {
|
|
6
|
+
return cy.findByTestId('board');
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const getBoardTile = (x = 0, y = 0) => {
|
|
10
|
+
return getBoardContainer()
|
|
11
|
+
.findAllByRole('textbox')
|
|
12
|
+
.then((tiles) => {
|
|
13
|
+
const boardSize = Math.sqrt(tiles.length);
|
|
14
|
+
const index = y * boardSize + x;
|
|
15
|
+
return cy.findByTestId('board').findAllByRole('textbox').eq(index);
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const getDictionary = () => {
|
|
20
|
+
return cy.findByTestId('dictionary');
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const getDictionaryInput = () => {
|
|
24
|
+
return getDictionary().findByRole('textbox');
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const getDictionaryTitles = () => {
|
|
28
|
+
return getDictionary().get('h2');
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const getLoading = () => {
|
|
32
|
+
return cy.findByTestId('loading');
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const getRackContainer = () => {
|
|
36
|
+
return cy.findByTestId('rack');
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const getRackTile = (index = 0) => {
|
|
40
|
+
// use hidden: true so that rack can be interacted with while modal is opened
|
|
41
|
+
return getRackContainer().findAllByRole('textbox', { hidden: true }).eq(index);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const getResultsContainer = () => {
|
|
45
|
+
return cy.findByTestId('results');
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const getResults = () => {
|
|
49
|
+
return getResultsContainer().findAllByTestId('result');
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const getResultsFilterInput = () => {
|
|
53
|
+
return getResultsContainer().findByRole('textbox');
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const getResult = (index = 0) => {
|
|
57
|
+
return getResults().eq(index);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const getSettingsButton = () => {
|
|
61
|
+
return cy.findByTestId('settings-button');
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const getSettingOption = (section: string, option: string) => {
|
|
65
|
+
return getModal().findByLabelText(section).findByLabelText(option);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const getTooltip = () => {
|
|
69
|
+
return cy.findByRole('tooltip');
|
|
70
|
+
};
|
package/jest.config.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
const tsConfig = require('./tsconfig.jest.json');
|
|
2
|
-
|
|
3
1
|
module.exports = {
|
|
4
2
|
coveragePathIgnorePatterns: ['/node_modules/', '/build/'],
|
|
5
3
|
preset: 'ts-jest',
|
|
6
4
|
setupFilesAfterEnv: ['./jest.setup.js'],
|
|
7
5
|
testEnvironment: 'node',
|
|
6
|
+
testPathIgnorePatterns: ['/node_modules/', '/cypress/'],
|
|
8
7
|
transform: {
|
|
9
|
-
'^.+.tsx?$': ['ts-jest',
|
|
8
|
+
'^.+.tsx?$': ['ts-jest', { tsconfig: 'tsconfig.jest.json' }],
|
|
10
9
|
},
|
|
11
10
|
};
|
package/lerna.json
CHANGED