diff --git a/jest/setup-tests.js b/jest/setup-tests.js index 406b4da..e45e5b1 100644 --- a/jest/setup-tests.js +++ b/jest/setup-tests.js @@ -4,5 +4,13 @@ import { } from '@testing-library/jest-dom/matchers'; import 'src/icons/icons'; import 'src/utils/i18n'; +import 'whatwg-fetch'; expect.extend({ toHaveClass, toHaveAttribute }); + +// mock fetch +beforeAll(() => { + jest.spyOn(window, 'fetch'); +}); +afterEach(() => jest.clearAllMocks()); +afterAll(() => window.fetch.mockRestore()); diff --git a/package-lock.json b/package-lock.json index a1f4d09..e482233 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5195,6 +5195,16 @@ "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", "dev": true }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, "bl": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz", @@ -8883,6 +8893,13 @@ } } }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, "filesize": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", @@ -9415,6 +9432,8 @@ "dev": true, "optional": true, "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1", "node-pre-gyp": "*" }, "dependencies": { @@ -14923,6 +14942,13 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "nan": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", + "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", + "dev": true, + "optional": true + }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -21853,6 +21879,8 @@ "dev": true, "optional": true, "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1", "node-pre-gyp": "*" }, "dependencies": { @@ -23205,7 +23233,11 @@ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "dev": true, - "optional": true + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } }, "glob-parent": { "version": "3.1.0", diff --git a/package.json b/package.json index 4737e97..215e946 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,8 @@ "webpack": "^4.43.0", "webpack-bundle-analyzer": "^3.8.0", "webpack-cli": "^3.3.11", - "webpack-dev-server": "^3.11.0" + "webpack-dev-server": "^3.11.0", + "whatwg-fetch": "^3.0.0" }, "dependencies": { "@fortawesome/fontawesome-svg-core": "^1.2.28", diff --git a/src/containers/app/app.js b/src/containers/app/app.js index 4e8623c..d95d024 100644 --- a/src/containers/app/app.js +++ b/src/containers/app/app.js @@ -1,21 +1,17 @@ import { hot } from 'react-hot-loader/root'; import React, { Component } from 'react'; import { HashRouter as Router, Route, Switch } from 'react-router-dom'; +import PropTypes from 'prop-types'; import copy from 'copy-to-clipboard'; import { withTranslation } from 'react-i18next'; import { ToastContainer, Slide } from 'react-toastify'; -import { - CARDS_DICTIONARIES, - CARDS_TYPES, - FIELD_SIZES, - LANGUAGES, - TEAMS, -} from 'src/data/constants'; +import { CARDS_TYPES, FIELD_SIZES, LANGUAGES, TEAMS } from 'src/data/constants'; import * as Location from 'src/utils/location'; import * as FirebaseService from 'src/service'; import { getRemainingCardsCount } from 'src/utils/team-progress'; import { toast } from 'src/utils/toast'; import { Loader } from 'src/components/loader'; +import { getDefaultDictionary } from 'src/utils/data-provider'; import { Lobby } from '../lobby'; import { NotFound } from '../not-found'; import { ProtectedGame } from '../game'; @@ -29,7 +25,7 @@ class App extends Component { settings: { language: LANGUAGES['ru'], fieldSize: FIELD_SIZES['5x5'], - dictionary: CARDS_DICTIONARIES['GAGA'], + dictionaryFileName: '', }, users: [], cards: [], @@ -46,24 +42,46 @@ class App extends Component { isLoading: true, }; this.sessionId = ''; - // eslint-disable-next-line react/prop-types this.t = props.t; + this.i18n = props.i18n; } async componentDidMount() { - await this.initialize(); + await this.setDefaultDictionary(); + await this.initializeSession(); } - async initialize() { + async initializeSession() { try { await this.connectToSession(); this.addListeners(); } catch (error) { - console.log(error.message); - this.setState({ errorMessage: error.message }); + this.setState({ isLoading: false }, () => { + toast.error(error.message); + }); } } + setDefaultDictionary() { + return new Promise((resolve) => { + const dictionary = getDefaultDictionary(this.i18n.language); + if (!dictionary) { + this.setState({ isLoading: false }, () => { + toast.error(this.t('error.common')); + }); + } + this.setState( + { + settings: { + ...this.state.settings, + dictionaryFileName: dictionary.fileName, + }, + }, + resolve, + ); + }); + } + async connectToSession() { let sessionId = Location.getGameSessionId(window.location.href); let userId; @@ -119,10 +137,10 @@ class App extends Component { this.setState({ users, currentUser }); } - saveSettings({ language, dictionary, fieldSize }) { + saveSettings({ language, dictionaryFileName, fieldSize }) { FirebaseService.saveSettings(this.sessionId, { language, - dictionary, + dictionaryFileName, fieldSize, }); } @@ -255,6 +273,11 @@ class App extends Component { } } +App.propTypes = { + t: PropTypes.func.isRequired, + i18n: PropTypes.object.isRequired, +}; + const HotApp = hot(withTranslation()(App)); export { HotApp as App }; diff --git a/src/containers/lobby/lobby.js b/src/containers/lobby/lobby.js index 43ca7a0..5a4bd24 100644 --- a/src/containers/lobby/lobby.js +++ b/src/containers/lobby/lobby.js @@ -28,26 +28,33 @@ function Lobby({ onClickShare, onClickGenerateCards, }) { - const { t } = useTranslation(); + const { t, i18n } = useTranslation(); const history = useHistory(); const onChangeFieldSize = (e) => { onChangeSettings({ ...settings, fieldSize: e.target.value }); }; const onChangeDictionary = (e) => { - onChangeSettings({ ...settings, dictionary: e.target.value }); + onChangeSettings({ ...settings, dictionaryFileName: e.target.value }); }; const fieldSizes = Object.entries(FIELD_SIZES).map(([label, value]) => ( )); - const dictionaries = Object.entries(CARDS_DICTIONARIES).map( - ([label, value]) => ( - - ), + + const dictionaries = CARDS_DICTIONARIES.reduce( + (acc, { name, fileName, language }) => { + if (i18n.language === language) { + acc.push( + , + ); + } + return acc; + }, + [], ); let color = 'default'; @@ -127,7 +134,10 @@ function Lobby({
- {dictionaries} @@ -177,7 +187,7 @@ Lobby.propTypes = { settings: PropTypes.shape({ language: PropTypes.string.isRequired, fieldSize: PropTypes.string.isRequired, - dictionary: PropTypes.string.isRequired, + dictionaryFileName: PropTypes.string.isRequired, }).isRequired, users: PropTypes.arrayOf( PropTypes.shape({ diff --git a/src/containers/lobby/lobby.stories.js b/src/containers/lobby/lobby.stories.js index 87d9c05..8a0ba68 100644 --- a/src/containers/lobby/lobby.stories.js +++ b/src/containers/lobby/lobby.stories.js @@ -32,7 +32,7 @@ export const Common = () => { const settings = { language: LANGUAGES['ru'], fieldSize: FIELD_SIZES['5x5'], - dictionary: CARDS_DICTIONARIES['GAGA'], + dictionaryFileName: CARDS_DICTIONARIES[0], }; const captains = { [TEAMS['blue']]: '2', diff --git a/src/data/constants.js b/src/data/constants.js index adc456c..9ff37b9 100644 --- a/src/data/constants.js +++ b/src/data/constants.js @@ -8,9 +8,28 @@ export const FIELD_SIZES = { '5x6': '5x6', }; -export const CARDS_DICTIONARIES = { - GAGA: 'gaga', -}; +export const CARDS_DICTIONARIES = [ + { + name: 'Стандартный (400+ слов)', + fileName: 'default-ru.json', + language: 'ru', + }, + { + name: 'Расширенный (1000+ слов)', + fileName: 'extended-ru.json', + language: 'ru', + }, + { + name: 'IT: frontend (200+ терминов)', + fileName: 'frontend-ru.json', + language: 'ru', + }, + { + name: 'IT: frontend (200+ words)', + fileName: 'frontend-en.json', + language: 'en', + }, +]; export const CARDS_TYPES = { agent: 'agent', diff --git a/src/data/dictionaries.json b/src/data/dictionaries.json deleted file mode 100644 index b2cd519..0000000 --- a/src/data/dictionaries.json +++ /dev/null @@ -1,404 +0,0 @@ -{ - "gaga": [ - "Австралия", - "автомат", - "агент", - "адвокат", - "Азия", - "акт", - "альбом", - "Альпы", - "Америка", - "амфибия", - "ангел", - "Англия", - "Антарктида", - "аппарат", - "Атлантида", - "Африка", - "ацтек", - "бабочка", - "база", - "Байкал", - "банк", - "баня", - "бар", - "барьер", - "бассейн", - "батарея", - "башня", - "берёза", - "Берлин", - "Бермуды", - "билет", - "биржа", - "блин", - "блок", - "боевик", - "бокс", - "болезнь", - "больница", - "бомба", - "боров", - "борт", - "ботинок", - "бочка", - "брак", - "бревно", - "бумага", - "бутылка", - "бык", - "вагон", - "вал", - "ведьма", - "век", - "венец", - "вертолёт", - "верфь", - "вес", - "ветер", - "взгляд", - "вид", - "вилка", - "вирус", - "вода", - "водолаз", - "вождь", - "воздух", - "война", - "волна", - "вор", - "время", - "высота", - "газ", - "галоп", - "гвоздь", - "гений", - "Германия", - "гигант", - "глаз", - "Голливуд", - "голова", - "горло", - "горн", - "гранат", - "гребень", - "Греция", - "гриф", - "груша", - "дама", - "декрет", - "день", - "десна", - "динозавр", - "диск", - "доктор", - "дракон", - "дробь", - "дума", - "дух", - "дыра", - "дятел", - "Европа", - "Египет", - "единорог", - "ёрш", - "жизнь", - "жила", - "жук", - "журавль", - "залог", - "замок", - "заноза", - "запад", - "запах", - "заяц", - "звезда", - "зебра", - "земля", - "знак", - "золото", - "зона", - "зуб", - "игла", - "игра", - "икра", - "Индия", - "институт", - "кабинет", - "кавалер", - "кадр", - "казино", - "камень", - "камера", - "канал", - "караул", - "карлик", - "карта", - "каша", - "кенгуру", - "кентавр", - "кетчуп", - "киви", - "кисть", - "кит", - "Китай", - "клетка", - "ключ", - "кокетка", - "кол", - "колода", - "колонна", - "кольцо", - "команда", - "конёк", - "контрабандист", - "концерт", - "кора", - "корабль", - "королева", - "король", - "корона", - "коса", - "кость", - "косяк", - "кошка", - "край", - "кран", - "крест", - "кролик", - "крошка", - "круг", - "крыло", - "кулак", - "курс", - "лад", - "лазер", - "лама", - "ласка", - "лев", - "лёд", - "лейка", - "лес", - "лимузин", - "линия", - "липа", - "лист", - "лицо", - "ложе", - "Лондон", - "лошадь", - "лук", - "луна", - "луч", - "масло", - "масса", - "мат", - "машина", - "мёд", - "медведь", - "Мексика", - "мелочь", - "место", - "механизм", - "микроскоп", - "миллионер", - "мир", - "морковь", - "мороженое", - "Москва", - "мост", - "мотив", - "мушка", - "мышь", - "налёт", - "наряд", - "небоскрёб", - "ниндзя", - "нож", - "номер", - "норка", - "нота", - "ночь", - "НьюЙорк", - "няня", - "область", - "облом", - "образ", - "образование", - "обрез", - "овсянка", - "огонь", - "Олимп", - "опера", - "операция", - "орган", - "орёл", - "осьминог", - "отель", - "падение", - "палата", - "палец", - "палочка", - "панель", - "пара", - "парашют", - "парк", - "партия", - "пассаж", - "паук", - "пачка", - "Пекин", - "перевод", - "перемена", - "перо", - "перчатка", - "пилот", - "пингвин", - "пирамида", - "пират", - "пистолет", - "плата", - "платье", - "площадь", - "пляж", - "побег", - "повар", - "подкова", - "подъём", - "покров", - "пол", - "поле", - "полис", - "полиция", - "помёт", - "порода", - "посольство", - "поток", - "почка", - "пояс", - "право", - "предложение", - "предприниматель", - "прибор", - "привод", - "призрак", - "принцесса", - "пришелец", - "пробка", - "проводник", - "проказа", - "прокат", - "проспект", - "профиль", - "путь", - "Пушкин", - "развод", - "разворот", - "рак", - "раковина", - "раствор", - "рейд", - "Рим", - "робот", - "рог", - "род", - "рок", - "рубашка", - "рукав", - "рулетка", - "рыба", - "рысь", - "рыцарь", - "салют", - "сантехник", - "Сатурн", - "свет", - "свидетель", - "секрет", - "секция", - "сердце", - "сеть", - "сила", - "скат", - "смерть", - "снаряд", - "снег", - "снеговик", - "собака", - "совет", - "солдат", - "соль", - "состав", - "спутник", - "среда", - "ссылка", - "стадион", - "стан", - "станок", - "ствол", - "стекло", - "стена", - "стойка", - "стол", - "стопа", - "стрела", - "строй", - "струна", - "стул", - "ступень", - "судьба", - "супергерой", - "такса", - "танец", - "тарелка", - "театр", - "телескоп", - "течение", - "титан", - "Токио", - "точка", - "трава", - "треугольник", - "труба", - "туба", - "тур", - "ударник", - "удел", - "узел", - "урал", - "урна", - "утка", - "утконос", - "учёный", - "учитель", - "факел", - "фаланга", - "фига", - "флейта", - "фокус", - "форма", - "Франция", - "хвост", - "хлопок", - "центр", - "церковь", - "частица", - "червь", - "шар", - "шоколад", - "шпагат", - "шпион", - "штат", - "шуба", - "экран", - "эльф", - "эфир", - "Юпитер", - "яблоко", - "яд", - "язык", - "якорь", - "ясли" - ] -} diff --git a/src/data/dictionaries/default-ru.json b/src/data/dictionaries/default-ru.json new file mode 100644 index 0000000..cb360fb --- /dev/null +++ b/src/data/dictionaries/default-ru.json @@ -0,0 +1,402 @@ +[ + "Австралия", + "автомат", + "агент", + "адвокат", + "Азия", + "акт", + "альбом", + "Альпы", + "Америка", + "амфибия", + "ангел", + "Англия", + "Антарктида", + "аппарат", + "Атлантида", + "Африка", + "ацтек", + "бабочка", + "база", + "Байкал", + "банк", + "баня", + "бар", + "барьер", + "бассейн", + "батарея", + "башня", + "берёза", + "Берлин", + "Бермуды", + "билет", + "биржа", + "блин", + "блок", + "боевик", + "бокс", + "болезнь", + "больница", + "бомба", + "боров", + "борт", + "ботинок", + "бочка", + "брак", + "бревно", + "бумага", + "бутылка", + "бык", + "вагон", + "вал", + "ведьма", + "век", + "венец", + "вертолёт", + "верфь", + "вес", + "ветер", + "взгляд", + "вид", + "вилка", + "вирус", + "вода", + "водолаз", + "вождь", + "воздух", + "война", + "волна", + "вор", + "время", + "высота", + "газ", + "галоп", + "гвоздь", + "гений", + "Германия", + "гигант", + "глаз", + "Голливуд", + "голова", + "горло", + "горн", + "гранат", + "гребень", + "Греция", + "гриф", + "груша", + "дама", + "декрет", + "день", + "десна", + "динозавр", + "диск", + "доктор", + "дракон", + "дробь", + "дума", + "дух", + "дыра", + "дятел", + "Европа", + "Египет", + "единорог", + "ёрш", + "жизнь", + "жила", + "жук", + "журавль", + "залог", + "замок", + "заноза", + "запад", + "запах", + "заяц", + "звезда", + "зебра", + "земля", + "знак", + "золото", + "зона", + "зуб", + "игла", + "игра", + "икра", + "Индия", + "институт", + "кабинет", + "кавалер", + "кадр", + "казино", + "камень", + "камера", + "канал", + "караул", + "карлик", + "карта", + "каша", + "кенгуру", + "кентавр", + "кетчуп", + "киви", + "кисть", + "кит", + "Китай", + "клетка", + "ключ", + "кокетка", + "кол", + "колода", + "колонна", + "кольцо", + "команда", + "конёк", + "контрабандист", + "концерт", + "кора", + "корабль", + "королева", + "король", + "корона", + "коса", + "кость", + "косяк", + "кошка", + "край", + "кран", + "крест", + "кролик", + "крошка", + "круг", + "крыло", + "кулак", + "курс", + "лад", + "лазер", + "лама", + "ласка", + "лев", + "лёд", + "лейка", + "лес", + "лимузин", + "линия", + "липа", + "лист", + "лицо", + "ложе", + "Лондон", + "лошадь", + "лук", + "луна", + "луч", + "масло", + "масса", + "мат", + "машина", + "мёд", + "медведь", + "Мексика", + "мелочь", + "место", + "механизм", + "микроскоп", + "миллионер", + "мир", + "морковь", + "мороженое", + "Москва", + "мост", + "мотив", + "мушка", + "мышь", + "налёт", + "наряд", + "небоскрёб", + "ниндзя", + "нож", + "номер", + "норка", + "нота", + "ночь", + "НьюЙорк", + "няня", + "область", + "облом", + "образ", + "образование", + "обрез", + "овсянка", + "огонь", + "Олимп", + "опера", + "операция", + "орган", + "орёл", + "осьминог", + "отель", + "падение", + "палата", + "палец", + "палочка", + "панель", + "пара", + "парашют", + "парк", + "партия", + "пассаж", + "паук", + "пачка", + "Пекин", + "перевод", + "перемена", + "перо", + "перчатка", + "пилот", + "пингвин", + "пирамида", + "пират", + "пистолет", + "плата", + "платье", + "площадь", + "пляж", + "побег", + "повар", + "подкова", + "подъём", + "покров", + "пол", + "поле", + "полис", + "полиция", + "помёт", + "порода", + "посольство", + "поток", + "почка", + "пояс", + "право", + "предложение", + "предприниматель", + "прибор", + "привод", + "призрак", + "принцесса", + "пришелец", + "пробка", + "проводник", + "проказа", + "прокат", + "проспект", + "профиль", + "путь", + "Пушкин", + "развод", + "разворот", + "рак", + "раковина", + "раствор", + "рейд", + "Рим", + "робот", + "рог", + "род", + "рок", + "рубашка", + "рукав", + "рулетка", + "рыба", + "рысь", + "рыцарь", + "салют", + "сантехник", + "Сатурн", + "свет", + "свидетель", + "секрет", + "секция", + "сердце", + "сеть", + "сила", + "скат", + "смерть", + "снаряд", + "снег", + "снеговик", + "собака", + "совет", + "солдат", + "соль", + "состав", + "спутник", + "среда", + "ссылка", + "стадион", + "стан", + "станок", + "ствол", + "стекло", + "стена", + "стойка", + "стол", + "стопа", + "стрела", + "строй", + "струна", + "стул", + "ступень", + "судьба", + "супергерой", + "такса", + "танец", + "тарелка", + "театр", + "телескоп", + "течение", + "титан", + "Токио", + "точка", + "трава", + "треугольник", + "труба", + "туба", + "тур", + "ударник", + "удел", + "узел", + "урал", + "урна", + "утка", + "утконос", + "учёный", + "учитель", + "факел", + "фаланга", + "фига", + "флейта", + "фокус", + "форма", + "Франция", + "хвост", + "хлопок", + "центр", + "церковь", + "частица", + "червь", + "шар", + "шоколад", + "шпагат", + "шпион", + "штат", + "шуба", + "экран", + "эльф", + "эфир", + "Юпитер", + "яблоко", + "яд", + "язык", + "якорь", + "ясли" +] \ No newline at end of file diff --git a/src/data/dictionaries/extended-ru.json b/src/data/dictionaries/extended-ru.json new file mode 100644 index 0000000..e0ca4d5 --- /dev/null +++ b/src/data/dictionaries/extended-ru.json @@ -0,0 +1,1002 @@ +[ + "август", + "автобус", + "автомат", + "автомобиль", + "автор", + "администрация", + "адрес", + "академия", + "акт", + "актер", + "активность", + "акция", + "американец", + "анализ", + "аппарат", + "апрель", + "армия", + "артист", + "атмосфера", + "баба", + "бабушка", + "база", + "банк", + "беда", + "безопасность", + "берег", + "беседа", + "библиотека", + "бизнес", + "билет", + "блок", + "бог", + "бой", + "бок", + "болезнь", + "боль", + "больница", + "больной", + "большинство", + "борьба", + "брак", + "брат", + "будущее", + "буква", + "бумага", + "бутылка", + "бюджет", + "вагон", + "вариант", + "век", + "величина", + "вера", + "версия", + "вершина", + "вес", + "весна", + "ветер", + "вечер", + "вещество", + "вещь", + "взаимодействие", + "взгляд", + "взрыв", + "вид", + "вина", + "вино", + "вирус", + "вкус", + "владелец", + "власть", + "влияние", + "внимание", + "вода", + "водитель", + "водка", + "возвращение", + "воздействие", + "воздух", + "возможность", + "возраст", + "война", + "войско", + "волна", + "волос", + "воля", + "вопрос", + "ворота", + "воспитание", + "воспоминание", + "восток", + "восторг", + "впечатление", + "враг", + "врач", + "время", + "встреча", + "вход", + "выбор", + "выборы", + "вывод", + "выполнение", + "выпуск", + "выражение", + "высота", + "выставка", + "выступление", + "выход", + "газ", + "газета", + "генерал", + "герой", + "глава", + "главное", + "глаз", + "глубина", + "год", + "голова", + "голос", + "гора", + "горло", + "город", + "господин", + "господь", + "гостиница", + "гость", + "государство", + "гражданин", + "граница", + "грех", + "грудь", + "группа", + "губа", + "губернатор", + "давление", + "дама", + "данные", + "дача", + "дверь", + "двигатель", + "движение", + "двор", + "дворец", + "девочка", + "девушка", + "дед", + "действие", + "действительность", + "декабрь", + "дело", + "день", + "деньги", + "депутат", + "деревня", + "дерево", + "десяток", + "деталь", + "детство", + "деятельность", + "диван", + "директор", + "длина", + "дно", + "добро", + "договор", + "дождь", + "доказательство", + "доклад", + "доктор", + "документ", + "долг", + "должность", + "доллар", + "доля", + "дом", + "дорога", + "доска", + "достижение", + "достоинство", + "доход", + "дочка", + "дочь", + "друг", + "дружба", + "дума", + "дурак", + "дух", + "душа", + "дым", + "дыхание", + "дядя", + "еврей", + "еда", + "единица", + "желание", + "жена", + "женщина", + "жертва", + "живот", + "животное", + "жизнь", + "жилье", + "житель", + "журнал", + "журналист", + "забота", + "зависимость", + "завод", + "задача", + "заказ", + "заключение", + "закон", + "законодательство", + "зал", + "заместитель", + "замок", + "занятие", + "запад", + "запас", + "запах", + "записка", + "запись", + "зарплата", + "заседание", + "затрата", + "защита", + "заявление", + "звезда", + "звонок", + "звук", + "здание", + "здоровье", + "земля", + "зеркало", + "зима", + "зло", + "знак", + "знакомый", + "знание", + "значение", + "золото", + "зона", + "зрение", + "зритель", + "зуб", + "игра", + "идея", + "известие", + "издание", + "изменение", + "изображение", + "изучение", + "имущество", + "имя", + "инженер", + "инициатива", + "институт", + "инструмент", + "интерес", + "информация", + "исключение", + "искусство", + "исполнение", + "использование", + "испытание", + "исследование", + "история", + "источник", + "итог", + "июль", + "июнь", + "кабинет", + "кадр", + "камень", + "камера", + "канал", + "кандидат", + "капитал", + "капитан", + "карман", + "карта", + "картина", + "категория", + "качество", + "квартира", + "километр", + "кино", + "класс", + "клетка", + "клиент", + "клуб", + "ключ", + "книга", + "книжка", + "князь", + "кодекс", + "кожа", + "колено", + "колесо", + "количество", + "коллега", + "коллектив", + "кольцо", + "команда", + "командир", + "комиссия", + "комитет", + "коммунист", + "комната", + "компания", + "комплекс", + "компьютер", + "конец", + "конкурс", + "конструкция", + "контакт", + "контроль", + "конференция", + "конфликт", + "концепция", + "концерт", + "корабль", + "корень", + "коридор", + "король", + "корпус", + "кость", + "костюм", + "кофе", + "край", + "краска", + "красота", + "кредит", + "кресло", + "крест", + "кризис", + "крик", + "кровать", + "кровь", + "круг", + "крыло", + "крыша", + "кулак", + "культура", + "курс", + "кусок", + "куст", + "кухня", + "лагерь", + "ладонь", + "лев", + "лед", + "лейтенант", + "лес", + "лестница", + "лето", + "лидер", + "линия", + "лист", + "литература", + "лицо", + "личность", + "лоб", + "лодка", + "лошадь", + "любовь", + "магазин", + "май", + "майор", + "мальчик", + "мальчишка", + "мама", + "март", + "масло", + "масса", + "мастер", + "масштаб", + "материал", + "мать", + "машина", + "мгновение", + "мера", + "мероприятие", + "место", + "месяц", + "металл", + "метод", + "метр", + "механизм", + "мечта", + "мешок", + "миг", + "милиция", + "миллион", + "министерство", + "министр", + "минута", + "мир", + "мнение", + "множество", + "модель", + "мозг", + "молодежь", + "молоко", + "момент", + "монастырь", + "море", + "москвич", + "мост", + "мощность", + "муж", + "мужик", + "мужчина", + "музей", + "музыка", + "мысль", + "мясо", + "наблюдение", + "набор", + "надежда", + "название", + "назначение", + "наличие", + "налог", + "направление", + "народ", + "нарушение", + "население", + "настроение", + "наука", + "начало", + "начальник", + "начальство", + "небо", + "неделя", + "недостаток", + "немец", + "необходимость", + "нефть", + "новость", + "нога", + "нож", + "номер", + "норма", + "нос", + "ночь", + "ноябрь", + "обед", + "обеспечение", + "область", + "оборона", + "оборудование", + "образ", + "образец", + "образование", + "обращение", + "обстановка", + "обстоятельство", + "обучение", + "общение", + "общество", + "объединение", + "объект", + "объем", + "объяснение", + "обязанность", + "обязательство", + "огонь", + "одежда", + "ожидание", + "озеро", + "окно", + "окончание", + "округ", + "октябрь", + "опасность", + "операция", + "описание", + "оплата", + "определение", + "опыт", + "орган", + "организация", + "организм", + "оружие", + "осень", + "основа", + "основание", + "основное", + "особенность", + "остаток", + "остров", + "ответ", + "ответственность", + "отдел", + "отделение", + "отдых", + "отец", + "отказ", + "открытие", + "отличие", + "отношение", + "отрасль", + "отсутствие", + "офицер", + "охрана", + "оценка", + "очередь", + "очки", + "ошибка", + "ощущение", + "пакет", + "палата", + "палец", + "памятник", + "память", + "папа", + "пара", + "параметр", + "парень", + "парк", + "партия", + "партнер", + "пенсия", + "перевод", + "переговоры", + "передача", + "переход", + "период", + "перспектива", + "песня", + "песок", + "печать", + "пиво", + "писатель", + "пистолет", + "письмо", + "план", + "плата", + "платье", + "плечо", + "площадка", + "площадь", + "победа", + "поведение", + "поверхность", + "повод", + "поворот", + "повышение", + "подарок", + "подготовка", + "поддержка", + "подразделение", + "подруга", + "подход", + "подъезд", + "поезд", + "поездка", + "позиция", + "поиск", + "показатель", + "покой", + "поколение", + "покупатель", + "пол", + "поле", + "полет", + "политика", + "полковник", + "половина", + "положение", + "полоса", + "получение", + "польза", + "помещение", + "помощник", + "помощь", + "понимание", + "понятие", + "попытка", + "пора", + "порог", + "портрет", + "порядок", + "поселок", + "последствие", + "пост", + "постановление", + "постель", + "потеря", + "поток", + "потолок", + "потребность", + "почва", + "поэзия", + "поэт", + "появление", + "правда", + "правило", + "правительство", + "право", + "праздник", + "практика", + "предел", + "предложение", + "предмет", + "предприятие", + "председатель", + "представитель", + "представление", + "президент", + "премия", + "препарат", + "преступление", + "прием", + "признак", + "признание", + "приказ", + "применение", + "пример", + "принцип", + "принятие", + "природа", + "присутствие", + "причина", + "приятель", + "проблема", + "проведение", + "проверка", + "программа", + "продажа", + "продукт", + "продукция", + "проект", + "произведение", + "производитель", + "производство", + "прокурор", + "промышленность", + "пространство", + "просьба", + "противник", + "профессия", + "профессор", + "процедура", + "процент", + "процесс", + "прошлое", + "психология", + "птица", + "публика", + "пункт", + "путь", + "пыль", + "пьеса", + "работа", + "работник", + "рабочий", + "радость", + "раз", + "развитие", + "разговор", + "размер", + "разница", + "разработка", + "разрешение", + "район", + "ракета", + "рамка", + "рассказ", + "рассмотрение", + "расстояние", + "растение", + "расход", + "расчет", + "реакция", + "реализация", + "реальность", + "ребенок", + "ребята", + "революция", + "регион", + "редактор", + "редакция", + "режим", + "режиссер", + "результат", + "река", + "реклама", + "ремонт", + "республика", + "ресторан", + "ресурс", + "реформа", + "речь", + "решение", + "риск", + "рисунок", + "род", + "родина", + "родитель", + "родственник", + "рождение", + "роль", + "роман", + "рост", + "рот", + "рубеж", + "рубль", + "рука", + "руководитель", + "руководство", + "русский", + "ручка", + "рыба", + "рынок", + "ряд", + "сад", + "самолет", + "сапог", + "сбор", + "сведение", + "свет", + "свидетель", + "свобода", + "свойство", + "связь", + "сделка", + "сезон", + "секретарь", + "секунда", + "село", + "семья", + "сентябрь", + "сердце", + "середина", + "серия", + "сестра", + "сеть", + "сигарета", + "сигнал", + "сила", + "система", + "ситуация", + "сказка", + "скорость", + "слава", + "след", + "следователь", + "следствие", + "слеза", + "СЛОВО", + "слово", + "слой", + "служба", + "слух", + "случай", + "смена", + "смерть", + "смех", + "смысл", + "снег", + "снижение", + "собака", + "собрание", + "собственность", + "событие", + "совесть", + "совет", + "соглашение", + "содержание", + "соединение", + "сожаление", + "создание", + "сознание", + "солдат", + "солнце", + "сомнение", + "сон", + "сообщение", + "соответствие", + "сосед", + "состав", + "состояние", + "сотня", + "сотрудник", + "сотрудничество", + "сочинение", + "союз", + "спектакль", + "специалист", + "спина", + "список", + "спор", + "спорт", + "способ", + "способность", + "сравнение", + "среда", + "средство", + "срок", + "ставка", + "стакан", + "станция", + "старик", + "старуха", + "статус", + "статья", + "стекло", + "стена", + "степень", + "стиль", + "стихи", + "стоимость", + "стол", + "столик", + "столица", + "сторона", + "страна", + "страница", + "страсть", + "страх", + "строительство", + "строй", + "строка", + "структура", + "студент", + "стул", + "субъект", + "суд", + "судьба", + "судья", + "сумка", + "сумма", + "сутки", + "суть", + "существо", + "существование", + "сущность", + "сфера", + "схема", + "сцена", + "счастье", + "счет", + "сын", + "сюжет", + "таблица", + "тайна", + "талант", + "танец", + "танк", + "творчество", + "театр", + "текст", + "телевизор", + "телефон", + "тело", + "тема", + "темнота", + "температура", + "тенденция", + "тень", + "теория", + "территория", + "тетя", + "техника", + "технология", + "течение", + "тип", + "тишина", + "товар", + "товарищ", + "толпа", + "том", + "тон", + "торговля", + "точка", + "трава", + "традиция", + "транспорт", + "требование", + "труба", + "трубка", + "труд", + "тысяча", + "тюрьма", + "убийство", + "увеличение", + "угол", + "угроза", + "удар", + "удивление", + "удовольствие", + "ужас", + "указание", + "улица", + "улыбка", + "ум", + "университет", + "управление", + "уровень", + "урок", + "усилие", + "условие", + "услуга", + "успех", + "установка", + "устройство", + "утро", + "ухо", + "уход", + "участие", + "участник", + "участок", + "ученик", + "ученый", + "учет", + "учитель", + "учреждение", + "факт", + "фактор", + "фамилия", + "февраль", + "федерация", + "фигура", + "философия", + "фильм", + "фирма", + "фон", + "фонд", + "форма", + "формирование", + "формула", + "фотография", + "фраза", + "фронт", + "функция", + "характер", + "характеристика", + "хвост", + "хлеб", + "ход", + "хозяин", + "хозяйка", + "хозяйство", + "храм", + "художник", + "царь", + "цвет", + "цветок", + "целое", + "цель", + "цена", + "ценность", + "центр", + "церковь", + "цифра", + "чай", + "час", + "частность", + "часть", + "часы", + "человек", + "человечество", + "черт", + "черта", + "честь", + "чиновник", + "число", + "читатель", + "член", + "чтение", + "чувство", + "чудо", + "шаг", + "шанс", + "шея", + "школа", + "штаб", + "штат", + "штука", + "шум", + "шутка", + "щека", + "экономика", + "экран", + "эксперимент", + "эксперт", + "эксплуатация", + "элемент", + "энергия", + "эпоха", + "этаж", + "этап", + "эффект", + "эффективность", + "яблоко", + "явление", + "язык", + "январь", + "ящик" +] \ No newline at end of file diff --git a/src/data/dictionaries/frontend-en.json b/src/data/dictionaries/frontend-en.json new file mode 100644 index 0000000..5088fff --- /dev/null +++ b/src/data/dictionaries/frontend-en.json @@ -0,0 +1,214 @@ +[ + "script", + "primitive", + "double", + "integer", + "number", + "string", + "null", + "undefined", + "Symbol", + "Boolean", + "object", + "array", + "RegExp", + "Date", + "Math", + "array", + "function", + "ECMAScript", + "console", + "const", + "let", + "var", + "window", + "globalThis", + "context", + "this", + ".call", + ".apply", + ".bind", + "prototype", + "class", + "constructor", + "arrow function", + "spread", + "rest", + "yield", + "generator", + "promise", + "setTimeout", + "setInterval", + "JSON", + "instanceof", + "typeof", + "new", + "arguments", + "use strict", + "Map", + "WeakMap", + "Set", + "WeakSet", + "Proxy", + "Infinity", + "NaN", + "closure", + "scope", + "hoisting", + "async/await", + "lifecycle", + "hooks", + "virtual dom", + "callback", + "interpolation", + "ref", + "shadow dom", + "web component", + ".prototype", + "__proto__", + "writable", + "configurable", + "enumerable", + "frozen", + "bootstrap", + "polyfill", + "history", + "hash", + "canvas", + "document", + "DOM", + "EventListener", + "EventTarget", + "node", + "element", + "WebRTC", + "WebStorage", + "WebWorkers", + "IndexedDB", + "lighthouse", + "debugger", + "devtools", + "BFF", + "SSR", + "CSR", + "Hydration", + "Webpack", + "Babel", + "css-modules", + "styled components", + "scoped css", + "Rollup", + "RequireJS", + "JQuery", + "React", + "Vue.js", + "Backbone.js", + "Ember.js", + "Parcel", + "CoffeScript", + "Postcss", + "Mocha", + "LiveScript", + "TypeScript", + "Flow", + "Hegel", + "Angular", + "Nuxt.js", + "Next.js", + "Nest.js", + "Gatsby", + "Express", + "Storybook", + "JSX", + "SpiderMonkey", + "V8", + "Firefox", + "Opera", + "Safari", + "Chrome", + "Node.js", + "Deno", + "GraalVM", + "XMLHttpRequest", + "ajax", + "fetch", + "HTTP", + "IE", + "WebSocket", + "Apollo", + "graphql", + "axios", + "superagent", + "POST", + "GET", + "url", + "Firebase", + "import", + "export", + "require", + "AMD", + "IIFE", + "UMD", + "Redux", + "Vuex", + "NgRx", + "state", + "flux", + "Jest", + "Sinon", + "Mocha", + "Chai", + "Cypress", + "Puppeteer", + "Selenium", + "Hermione", + "cookies", + "sessions", + "npm", + "yarn", + "node_modules", + "float", + "grid", + "flex", + "table", + "id", + "eslint", + "prettier", + "stylelint", + "husky", + "lint-staged", + "editorconfig", + "markup", + "link", + "site", + "image", + "text", + "tag", + "adaptivity", + "form", + "validation", + "browser", + "attribute", + "focus", + "environment", + "error", + "exception", + "comment", + "typing", + "component", + "server", + "interface", + "application", + "plugin", + "compilation", + "building", + "prop", + "template", + "page", + "api", + "update", + "model", + "view", + "controller", + "client" +] diff --git a/src/data/dictionaries/frontend-ru.json b/src/data/dictionaries/frontend-ru.json new file mode 100644 index 0000000..4b9ae42 --- /dev/null +++ b/src/data/dictionaries/frontend-ru.json @@ -0,0 +1,213 @@ +[ + "script", + "primitive", + "double", + "integer", + "number", + "string", + "null", + "undefined", + "Symbol", + "Boolean", + "object", + "array", + "RegExp", + "Date", + "Math", + "array", + "function", + "ECMAScript", + "console", + "const", + "let", + "var", + "window", + "globalThis", + "context", + "this", + ".call", + ".apply", + ".bind", + "prototype", + "class", + "constructor", + "arrow function", + "spread", + "rest", + "yield", + "generator", + "promise", + "setTimeout", + "setInterval", + "JSON", + "instanceof", + "typeof", + "new", + "arguments", + "use strict", + "Map", + "WeakMap", + "Set", + "WeakSet", + "Proxy", + "Infinity", + "NaN", + "closure", + "scope", + "hoisting", + "async/await", + "lifecycle", + "hooks", + "virtual dom", + "callback", + "interpolation", + "ref", + "shadow dom", + "web component", + ".prototype", + "__proto__", + "writable", + "configurable", + "enumerable", + "frozen", + "bootstrap", + "polyfill", + "history", + "hash", + "canvas", + "document", + "DOM", + "EventListener", + "EventTarget", + "node", + "element", + "WebRTC", + "WebStorage", + "WebWorkers", + "IndexedDB", + "lighthouse", + "debugger", + "devtools", + "BFF", + "SSR", + "CSR", + "Hydration", + "Webpack", + "Babel", + "css-modules", + "styled components", + "scoped css", + "Rollup", + "RequireJS", + "JQuery", + "React", + "Vue.js", + "Backbone.js", + "Ember.js", + "Parcel", + "CoffeScript", + "Postcss", + "Mocha", + "LiveScript", + "TypeScript", + "Flow", + "Hegel", + "Angular", + "Nuxt.js", + "Next.js", + "Nest.js", + "Gatsby", + "Express", + "Storybook", + "JSX", + "SpiderMonkey", + "V8", + "Firefox", + "Opera", + "Safari", + "Chrome", + "Node.js", + "Deno", + "GraalVM", + "XMLHttpRequest", + "ajax", + "fetch", + "HTTP", + "IE", + "WebSocket", + "Apollo", + "graphql", + "axios", + "superagent", + "POST", + "GET", + "url", + "Firebase", + "import", + "export", + "require", + "AMD", + "IIFE", + "UMD", + "Redux", + "Vuex", + "NgRx", + "state", + "flux", + "Jest", + "Sinon", + "Mocha", + "Chai", + "Cypress", + "Puppeteer", + "Selenium", + "Hermione", + "cookies", + "sessions", + "npm", + "yarn", + "node_modules", + "float", + "grid", + "flex", + "table", + "id", + "eslint", + "prettier", + "stylelint", + "husky", + "lint-staged", + "editorconfig", + "разметка", + "ссылка", + "сайт", + "картинка", + "текст", + "тэг", + "адаптивность", + "форма", + "валидация", + "браузер", + "атрибут", + "фокус", + "окружение", + "ошибка", + "исключение", + "комментарий", + "типизация", + "компонент", + "сервер", + "интерфейс", + "приложение", + "плагин", + "компиляция", + "сборка", + "проп", + "шаблон", + "страница", + "api", + "обновление", + "модель", + "представление", + "контроллер" +] diff --git a/src/data/translation-ru.json b/src/data/translation-ru.json index 040d485..2d0f355 100644 --- a/src/data/translation-ru.json +++ b/src/data/translation-ru.json @@ -14,7 +14,8 @@ "chooseTeam": "Выберите команду", "updateCards": "Обновить карточки", "startGame": "Погнали", - "dictionary": "Словарь" + "dictionary": "Словарь", + "words": "Слов" }, "game": { "leave": "Покинуть игру", @@ -32,6 +33,8 @@ }, "error": { "linkNotCopied": "Ошибка. Не удалось скопировать ссылку", - "cardsNotUpdated": "Ошибка. Не удалось обновить карточки" + "cardsNotUpdated": "Ошибка. Не удалось обновить карточки", + "common": "Произошла ошибка", + "getDictionary": "Не удалось получить словарь" } } diff --git a/src/dictionaries-client.js b/src/dictionaries-client.js new file mode 100644 index 0000000..585ab39 --- /dev/null +++ b/src/dictionaries-client.js @@ -0,0 +1,11 @@ +import i18next from 'i18next'; + +export async function getDictionary(dictionary) { + try { + const response = await window.fetch(`/dictionaries/${dictionary}`); + if (response.ok) return await response.json(); + } catch (e) { + throw new Error(i18next.t('error.getDictionary')); + } + throw new Error(i18next.t('error.getDictionary')); +} diff --git a/src/service.js b/src/service.js index df9d022..fd50c5f 100644 --- a/src/service.js +++ b/src/service.js @@ -25,16 +25,16 @@ const DB_CARDS_REF = 'sessions_cards'; * Инициализация игровой сессии * @param language * @param fieldSize - * @param dictionary + * @param dictionaryFileName * @returns {Promise<{sessionId: string, userId: string}>} */ -export async function initialize({ language, fieldSize, dictionary }) { +export async function initialize({ language, fieldSize, dictionaryFileName }) { const { sessionId, userId } = await createSession({ language, fieldSize, - dictionary, + dictionaryFileName, }); - await setNewCards(sessionId, { dictionary, fieldSize }); + await setNewCards(sessionId, { dictionaryFileName, fieldSize }); return { sessionId, userId }; } @@ -42,10 +42,10 @@ export async function initialize({ language, fieldSize, dictionary }) { * Создание игровой сессии * @param language * @param fieldSize - * @param dictionary + * @param dictionaryFileName * @returns {Promise<{sessionId: string, userId: string}>} */ -async function createSession({ language, fieldSize, dictionary }) { +async function createSession({ language, fieldSize, dictionaryFileName }) { const sessionRef = database.ref(DB_SESSIONS_REF).push(); const sessionId = sessionRef.key; const sessionPath = getSessionPath(sessionId); @@ -54,7 +54,7 @@ async function createSession({ language, fieldSize, dictionary }) { settings: { language, fieldSize, - dictionary, + dictionaryFileName, }, captains: { red: '', @@ -123,13 +123,16 @@ export function setWinnerTeam(sessionId, winnerTeam) { /** * Установка карточек * @param sessionId - * @param dictionary + * @param dictionaryFileName * @param fieldSize * @returns {Promise} */ -export async function setNewCards(sessionId, { dictionary, fieldSize }) { +export async function setNewCards( + sessionId, + { dictionaryFileName, fieldSize }, +) { const cardsRef = getCardsRef(sessionId); - const cards = getGamingCards(dictionary, fieldSize); + const cards = await getGamingCards(dictionaryFileName, fieldSize); return cardsRef.set(cards); } @@ -148,22 +151,22 @@ export async function updateCard(sessionId, cardId) { * Сохранение настроек * @param sessionId * @param language - * @param dictionary + * @param dictionaryFileName * @param fieldSize * @returns {Promise} */ export async function saveSettings( sessionId, - { language, dictionary, fieldSize }, + { language, dictionaryFileName, fieldSize }, ) { const settingsPath = getSettingsPath(sessionId); const winnerTeamPath = getWinnerTeamPath(sessionId); const cardsPath = getCardsPath(sessionId); - const cards = getGamingCards(dictionary, fieldSize); + const cards = await getGamingCards(dictionaryFileName, fieldSize); const updates = { [winnerTeamPath]: '', - [settingsPath]: { language, dictionary, fieldSize }, + [settingsPath]: { language, dictionaryFileName, fieldSize }, [cardsPath]: cards, }; return database.ref().update(updates); diff --git a/src/utils/data-provider.js b/src/utils/data-provider.js index 7b33628..ee75cbb 100644 --- a/src/utils/data-provider.js +++ b/src/utils/data-provider.js @@ -1,18 +1,21 @@ import { getRandomInt } from 'src/utils/math'; -import dictionaries from 'src/data/dictionaries'; import { TEAMS, CARDS_DICTIONARIES, CARDS_TYPES, FIELD_SIZES, } from 'src/data/constants'; +import { getDictionary } from 'src/dictionaries-client'; -export function getGamingCards( - dictionaryName = CARDS_DICTIONARIES['GAGA'], - fieldSize = FIELD_SIZES['5x5'], -) { +export function getDefaultDictionary(language) { + return CARDS_DICTIONARIES.find((dict) => dict.language === language); +} + +export async function getGamingCards(dictionaryFileName, fieldSize) { + const dictionary = await getDictionary(dictionaryFileName); const cardsDivision = getCardsDivision(fieldSize); - const wordsGenerator = generateDictionaryWord(dictionaryName); + const wordsGenerator = generateDictionaryWord(dictionary); + const cards = []; // killer cards for (let i = 0; i < cardsDivision['killerCards']; i++) { @@ -55,13 +58,7 @@ export function getGamingCards( return shuffle(cards); } -export function* generateDictionaryWord( - dictionaryName = CARDS_DICTIONARIES['GAGA'], -) { - if (!(dictionaryName in dictionaries)) { - throw new TypeError('Словарь не найден'); - } - const dictionary = dictionaries[dictionaryName]; +export function* generateDictionaryWord(dictionary) { let wordsIndexes = {}; for (let i = 0; i < dictionary.length; i++) { let wordIndex = getRandomInt(dictionary.length); diff --git a/src/utils/data-provider.spec.js b/src/utils/data-provider.spec.js index 151d513..03ce794 100644 --- a/src/utils/data-provider.spec.js +++ b/src/utils/data-provider.spec.js @@ -1,24 +1,82 @@ -import { generateDictionaryWord } from './data-provider'; - -jest.mock('../data/dictionaries.json', () => ({ - test_dictionary: ['alphabet', 'car', 'tiger'], -})); - -describe('generateDictionaryWord', () => { - test('should return unique dictionary words', () => { - let words = []; - const wordsGenerator = generateDictionaryWord('test_dictionary'); - for (let i = 0; i < 3; i++) { - words.push(wordsGenerator.next().value); +import dictionary from 'src/data/dictionaries/default-ru.json'; +import { CARDS_TYPES, FIELD_SIZES } from 'src/data/constants'; +import { i18n } from 'src/utils/i18n'; +import { getGamingCards } from './data-provider'; + +const setup = async ({ dictionaryName, fieldSize }) => { + window.fetch.mockResolvedValueOnce({ + ok: true, + json: async () => dictionary, + }); + + return await getGamingCards(dictionaryName, fieldSize); +}; + +const getCardsOfType = (cards, type) => + cards.filter((card) => card.type === type); + +describe('generateDictionaryWords', () => { + test('should return correct cards distribution for 5x4 field', async () => { + const cards = await setup({ + dictionaryName: 'dictionary_name', + fieldSize: FIELD_SIZES['5x4'], + }); + + expect(getCardsOfType(cards, CARDS_TYPES['killer'])).toHaveLength(1); + expect(getCardsOfType(cards, CARDS_TYPES['agent'])).toHaveLength(15); + expect(getCardsOfType(cards, CARDS_TYPES['citizen'])).toHaveLength(4); + }); + + test('should return correct cards distribution for 5x5 field', async () => { + const cards = await setup({ + dictionaryName: 'dictionary_name', + fieldSize: FIELD_SIZES['5x5'], + }); + + expect(getCardsOfType(cards, CARDS_TYPES['killer'])).toHaveLength(1); + expect(getCardsOfType(cards, CARDS_TYPES['agent'])).toHaveLength(17); + expect(getCardsOfType(cards, CARDS_TYPES['citizen'])).toHaveLength(7); + }); + + test('should return correct cards distribution for 5x6 field', async () => { + const cards = await setup({ + dictionaryName: 'dictionary_name', + fieldSize: FIELD_SIZES['5x6'], + }); + + expect(getCardsOfType(cards, CARDS_TYPES['killer'])).toHaveLength(1); + expect(getCardsOfType(cards, CARDS_TYPES['agent'])).toHaveLength(19); + expect(getCardsOfType(cards, CARDS_TYPES['citizen'])).toHaveLength(10); + }); + + test('should throw error on bad response', async () => { + window.fetch.mockRejectedValueOnce({ + ok: false, + }); + + let error; + try { + await getGamingCards('bad_dictionary_name', FIELD_SIZES['5x6']); + } catch (e) { + error = e.message; } - const uniqueWords = [...new Set([...words])]; - expect(words).toEqual(uniqueWords); + + expect(error).toEqual(i18n.t('error.getDictionary')); }); - test('should throw exception for non-existing dictionary', () => { - expect(() => { - const generator = generateDictionaryWord('unknown'); - generator.next(); - }).toThrowError(TypeError); + test('should throw error on bad dictionary', async () => { + window.fetch.mockRejectedValueOnce({ + ok: true, + json: async () => null, + }); + + let error; + try { + await getGamingCards('dictionary_name', FIELD_SIZES['5x6']); + } catch (e) { + error = e.message; + } + + expect(error).toEqual(i18n.t('error.getDictionary')); }); }); diff --git a/webpack.config.js b/webpack.config.js index 080021c..d9273cf 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -22,6 +22,10 @@ const plugins = [ from: path.resolve(__dirname, 'assets/favicons'), to: path.resolve(__dirname, 'public/favicons'), }, + { + from: path.resolve(__dirname, 'src/data/dictionaries'), + to: path.resolve(__dirname, 'public/dictionaries'), + }, ], }), ];