From 4c1a0b0a0691912c39c2e7841d90d02512f39cba Mon Sep 17 00:00:00 2001 From: Vyachesalv Date: Wed, 6 Mar 2024 23:53:25 +0300 Subject: [PATCH] feat(feat(core): create services && adapter + tests): --- books-ui/src/App.vue | 1 + books-ui/src/adapters/AdapterOfBooks.js | 173 ++++++++++++++++++ books-ui/src/helpers/apiHelpers.js | 39 ++++ books-ui/src/services/ServiceOfBooks.js | 13 ++ .../adapters/_adapter_books.test.js} | 0 .../tests/adapters/adapterOfBooks.test.js | 14 ++ .../1_atoms/ImageBackground.test.js | 0 .../2_molecules/VCardsContainer.test.js | 0 .../components/3_organisms/BookEditor.test.js | 0 .../3_organisms/BooksViewer.test.js | 0 .../components/4_frames/SideMenu.test.js | 0 .../tests/components/5_pages/Authors.test.js | 0 .../tests/components/5_pages/Book.test.js | 0 .../5_pages/BooksCompendium.test.js | 0 .../tests/components/5_pages/Ladning.test.js | 0 .../tests/components/5_pages/Tests.test.js | 0 .../components/5_pages/UserBooks.test.js | 0 .../{src => }/tests/components/App.test.js | 0 .../{src => }/tests/helpers/adapter.test.js | 0 books-ui/tests/helpers/apiHelpers.test.js | 17 ++ .../{src => }/tests/helpers/menuFuncs.test.js | 0 .../tests/helpers/objectUtils.test.js | 0 .../tests/services/serviceOfBooks.test.js | 52 ++++++ .../{src => }/tests/store/userBooks.test.js | 0 books-ui/vite.config.js | 23 ++- 25 files changed, 322 insertions(+), 10 deletions(-) create mode 100644 books-ui/src/adapters/AdapterOfBooks.js create mode 100644 books-ui/src/helpers/apiHelpers.js create mode 100644 books-ui/src/services/ServiceOfBooks.js rename books-ui/{src/tests/services/ApiService.test.js => tests/adapters/_adapter_books.test.js} (100%) create mode 100644 books-ui/tests/adapters/adapterOfBooks.test.js rename books-ui/{src => }/tests/components/1_atoms/ImageBackground.test.js (100%) rename books-ui/{src => }/tests/components/2_molecules/VCardsContainer.test.js (100%) rename books-ui/{src => }/tests/components/3_organisms/BookEditor.test.js (100%) rename books-ui/{src => }/tests/components/3_organisms/BooksViewer.test.js (100%) rename books-ui/{src => }/tests/components/4_frames/SideMenu.test.js (100%) rename books-ui/{src => }/tests/components/5_pages/Authors.test.js (100%) rename books-ui/{src => }/tests/components/5_pages/Book.test.js (100%) rename books-ui/{src => }/tests/components/5_pages/BooksCompendium.test.js (100%) rename books-ui/{src => }/tests/components/5_pages/Ladning.test.js (100%) rename books-ui/{src => }/tests/components/5_pages/Tests.test.js (100%) rename books-ui/{src => }/tests/components/5_pages/UserBooks.test.js (100%) rename books-ui/{src => }/tests/components/App.test.js (100%) rename books-ui/{src => }/tests/helpers/adapter.test.js (100%) create mode 100644 books-ui/tests/helpers/apiHelpers.test.js rename books-ui/{src => }/tests/helpers/menuFuncs.test.js (100%) rename books-ui/{src => }/tests/helpers/objectUtils.test.js (100%) create mode 100644 books-ui/tests/services/serviceOfBooks.test.js rename books-ui/{src => }/tests/store/userBooks.test.js (100%) diff --git a/books-ui/src/App.vue b/books-ui/src/App.vue index f6d9c3b..de9c7cc 100644 --- a/books-ui/src/App.vue +++ b/books-ui/src/App.vue @@ -21,6 +21,7 @@ export default { } }, mounted() { + const url = import.meta.env.VITE_API_ADDR this.fetchBooks() this.initScreenSizeRecalc() }, diff --git a/books-ui/src/adapters/AdapterOfBooks.js b/books-ui/src/adapters/AdapterOfBooks.js new file mode 100644 index 0000000..a149745 --- /dev/null +++ b/books-ui/src/adapters/AdapterOfBooks.js @@ -0,0 +1,173 @@ +import {get, post, put, remove} from '@helpers/apiHelpers.js' +import {convertList, convertObject} from '@helpers/adapter/adapter.js' +import {reverseObject} from '@helpers/objectUtils' +import {path} from 'ramda' + + +const adapterConfig = { + "id": "id", + "created_at": "createdAt", + "updated_at": "updatedAt", + "deleted_at": "deletedAt", + "owner": "owner", + "title": "title", + "author": "author", + "description": "description", + "is_public": "isPublic", + "publication": "publication", + "image_link": "imageLink", + "map_link": "mapLink", + "map_params_id": "mapParamsId", + "variables": "variables" +} + + +/** + * + * @param {Object} adapterFromApiConfig + * @param {Object | undefined} params + * @returns {Object | null | undefined} + */ +const adapterToApiFromParams = (adapterFromApiConfig, params) => { + let adapterToApiConfig = path(['adapterToApiConfig'], params) + + if (adapterToApiConfig) { + return adapterToApiConfig + } else if (adapterFromApiConfig) { + adapterToApiConfig = reverseObject(adapterFromApiConfig) + } else { + adapterToApiConfig = {} + } + + return adapterToApiConfig +} + +/** + * @deftypes Book + * @property {String} title "Тестовая книга", + * @property {String} author "Васильев А.В.", + * @property {String} owner "e75aae0d-c1eb-4199-a1d8-2177f57d6a1e", + * @property {String} description "test description", + * @property {Boolean} is_public false, + * @property {Any} publication null + * + */ + +/** + * BooksApi class + * + * @class + */ + +class AdapterOfBooks { + + /** + * @constructor + * @param {Object | undefined } adapterFromApiConfig - конфигурация адаптера для преобразования объектов из API + * @param {Object | undefined | any} params - параметры + * @param {Object} params.adapterToApiConfig - конфигурация адаптера для преобразования объектов в API, по дефолту преобразование происходит в обратном порядке из adapterFromApiConfig + */ + constructor(url) { + this.adapterFromApiConfig = adapterConfig + this.url = url + } + + /** + * + * @returns {Promise} + */ + async getBooks() { + const books = await get(`${this.url}/books`) + // if (this.adapterFromApiConfig) { + // return convertList(books, {config: this.adapterFromApiConfig}) + // } + return books + } + + /** + * + * @param {Object} book + * @returns {Promise<*|void|Object>} + */ + async updateBook(book) { + const bookToApi = convertObject(book, {config: this.adapterToApiConfig}) + const bookFromApi = await put(`${this.url}/books/${book.id}`, bookToApi) + // if (this.adapterFromApiConfig) { + // return convertObject(bookFromApi, {config: this.adapterFromApiConfig}) + // } + return bookFromApi + } + + /** + * + * @param {Object} book + * @returns {Promise<*|void|Object>} + */ + async createBook(book) { + const bookToApi = convertObject(book, {config: this.adapterToApiConfig}) + const bookFromApi = await post(`${this.url}/books`, bookToApi) + if (this.adapterFromApiConfig) { + return convertObject(bookFromApi, {config: this.adapterFromApiConfig}) + } + return bookFromApi + } + + + /** + * + * @param {Number} id + * @returns {Promise} + */ + async getBookById(id) { + const book = await get(`${this.url}/books/${id}`) + if (this.adapterFromApiConfig) { + return convertObject(book, {config: this.adapterFromApiConfig}) + } + return book + } + + /** + * + * @param {Number} id + * @returns {Promise} + */ + async deleteBookById(id) { + const book = await remove(`${this.url}/books/${id}`) + if (this.adapterFromApiConfig) { + return convertObject(book, {config: this.adapterFromApiConfig}) + } + return book + } + + /** + * @param {Function} logFunction + * @returns {Promise} + */ + async integrationTests(logFunction) { + logFunction("Список книг") + const books = await this.getBooks() + logFunction(books) + logFunction("Создание книги") + const newBook = await this.createBook({ + "title": "Тестовая книга", + "author": "Васильев А.В.", + "owner": "e75aae0d-c1eb-4199-a1d8-2177f57d6a1e", + "description": "test description", + "is_public": false, + "publication": null + }) + logFunction(newBook) + logFunction("Получение книги по id(Созданной)") + const bookById = await this.getBookById(newBook.id) + logFunction(bookById) + logFunction("Обновление книги") + const updatedBook = await this.updateBook({...bookById, title: "Обновленная книга"}) + logFunction(updatedBook) + logFunction("Удаление книги") + const deletedBook = await this.deleteBookById(bookById.id) + logFunction(deletedBook) + } +} + +export default AdapterOfBooks +export {adapterToApiFromParams} \ No newline at end of file diff --git a/books-ui/src/helpers/apiHelpers.js b/books-ui/src/helpers/apiHelpers.js new file mode 100644 index 0000000..9ecb12a --- /dev/null +++ b/books-ui/src/helpers/apiHelpers.js @@ -0,0 +1,39 @@ +import axios from "axios"; + +const post = async (path, data, onError) => { + return axios.post(`${path}`, data) + .then(r => r.data) + .catch(error => { + onError && onError(error) + console.error('Error post request:', error) + }) +} + +const get = async (path) => { + return axios.get(`${path}`) + .then(r => r.data) + .catch(error => { + console.error('Error post request:', error) + }) +} + +const put = async (path, data, onError) => { + return axios.put(`${path}`, data) + .then(r => r.data) + .catch(error => { + onError && onError(error) + console.error('Error put request:', error) + }) +} + +const remove = async (path, onError) => { + return axios.delete(`${path}`) + .then(r => r.data) + .catch(error => { + onError && onError(error) + console.error('Error delete request:', error) + }) +} + + +export {get, post, put, remove} diff --git a/books-ui/src/services/ServiceOfBooks.js b/books-ui/src/services/ServiceOfBooks.js new file mode 100644 index 0000000..267afdb --- /dev/null +++ b/books-ui/src/services/ServiceOfBooks.js @@ -0,0 +1,13 @@ +class ServiceOfBooks { + constructor(adapterOfBooks, store) { + this.adapterOfBooks = adapterOfBooks; + this.store = store; + } + + async fetchBooksList() { + const booksList = await this.adapterOfBooks.getBooks(); + this.store.dispatch('books/saveBooks', booksList); + } +} + +export default ServiceOfBooks; \ No newline at end of file diff --git a/books-ui/src/tests/services/ApiService.test.js b/books-ui/tests/adapters/_adapter_books.test.js similarity index 100% rename from books-ui/src/tests/services/ApiService.test.js rename to books-ui/tests/adapters/_adapter_books.test.js diff --git a/books-ui/tests/adapters/adapterOfBooks.test.js b/books-ui/tests/adapters/adapterOfBooks.test.js new file mode 100644 index 0000000..605e361 --- /dev/null +++ b/books-ui/tests/adapters/adapterOfBooks.test.js @@ -0,0 +1,14 @@ +import {expect, test, describe} from 'vitest' +import AdapterOfBooks from '@/adapters/adapterOfBooks.js' + +describe('adapterOfBooks', () => { + const uri = 'https://www.googleapis.com/books/v1/volumes?q=javascript'; + const adapter = new AdapterOfBooks(uri); + + test('adapterOfBooks is an instance of AdapterOfBooks', () => { + expect(adapter).toBeInstanceOf(AdapterOfBooks) + }) + test('adapterOfBooks is exist', () => { + expect(adapter).toBeDefined() + }) +}) \ No newline at end of file diff --git a/books-ui/src/tests/components/1_atoms/ImageBackground.test.js b/books-ui/tests/components/1_atoms/ImageBackground.test.js similarity index 100% rename from books-ui/src/tests/components/1_atoms/ImageBackground.test.js rename to books-ui/tests/components/1_atoms/ImageBackground.test.js diff --git a/books-ui/src/tests/components/2_molecules/VCardsContainer.test.js b/books-ui/tests/components/2_molecules/VCardsContainer.test.js similarity index 100% rename from books-ui/src/tests/components/2_molecules/VCardsContainer.test.js rename to books-ui/tests/components/2_molecules/VCardsContainer.test.js diff --git a/books-ui/src/tests/components/3_organisms/BookEditor.test.js b/books-ui/tests/components/3_organisms/BookEditor.test.js similarity index 100% rename from books-ui/src/tests/components/3_organisms/BookEditor.test.js rename to books-ui/tests/components/3_organisms/BookEditor.test.js diff --git a/books-ui/src/tests/components/3_organisms/BooksViewer.test.js b/books-ui/tests/components/3_organisms/BooksViewer.test.js similarity index 100% rename from books-ui/src/tests/components/3_organisms/BooksViewer.test.js rename to books-ui/tests/components/3_organisms/BooksViewer.test.js diff --git a/books-ui/src/tests/components/4_frames/SideMenu.test.js b/books-ui/tests/components/4_frames/SideMenu.test.js similarity index 100% rename from books-ui/src/tests/components/4_frames/SideMenu.test.js rename to books-ui/tests/components/4_frames/SideMenu.test.js diff --git a/books-ui/src/tests/components/5_pages/Authors.test.js b/books-ui/tests/components/5_pages/Authors.test.js similarity index 100% rename from books-ui/src/tests/components/5_pages/Authors.test.js rename to books-ui/tests/components/5_pages/Authors.test.js diff --git a/books-ui/src/tests/components/5_pages/Book.test.js b/books-ui/tests/components/5_pages/Book.test.js similarity index 100% rename from books-ui/src/tests/components/5_pages/Book.test.js rename to books-ui/tests/components/5_pages/Book.test.js diff --git a/books-ui/src/tests/components/5_pages/BooksCompendium.test.js b/books-ui/tests/components/5_pages/BooksCompendium.test.js similarity index 100% rename from books-ui/src/tests/components/5_pages/BooksCompendium.test.js rename to books-ui/tests/components/5_pages/BooksCompendium.test.js diff --git a/books-ui/src/tests/components/5_pages/Ladning.test.js b/books-ui/tests/components/5_pages/Ladning.test.js similarity index 100% rename from books-ui/src/tests/components/5_pages/Ladning.test.js rename to books-ui/tests/components/5_pages/Ladning.test.js diff --git a/books-ui/src/tests/components/5_pages/Tests.test.js b/books-ui/tests/components/5_pages/Tests.test.js similarity index 100% rename from books-ui/src/tests/components/5_pages/Tests.test.js rename to books-ui/tests/components/5_pages/Tests.test.js diff --git a/books-ui/src/tests/components/5_pages/UserBooks.test.js b/books-ui/tests/components/5_pages/UserBooks.test.js similarity index 100% rename from books-ui/src/tests/components/5_pages/UserBooks.test.js rename to books-ui/tests/components/5_pages/UserBooks.test.js diff --git a/books-ui/src/tests/components/App.test.js b/books-ui/tests/components/App.test.js similarity index 100% rename from books-ui/src/tests/components/App.test.js rename to books-ui/tests/components/App.test.js diff --git a/books-ui/src/tests/helpers/adapter.test.js b/books-ui/tests/helpers/adapter.test.js similarity index 100% rename from books-ui/src/tests/helpers/adapter.test.js rename to books-ui/tests/helpers/adapter.test.js diff --git a/books-ui/tests/helpers/apiHelpers.test.js b/books-ui/tests/helpers/apiHelpers.test.js new file mode 100644 index 0000000..6a5ce8e --- /dev/null +++ b/books-ui/tests/helpers/apiHelpers.test.js @@ -0,0 +1,17 @@ +import {expect, test, describe} from 'vitest' +import {post, get, put, remove} from '@helpers/apiHelpers.js' + +describe('tests of apiHelpers', () => { + test('post is a function', () => { + expect(post).toBeInstanceOf(Function) + }) + test('get is a function', () => { + expect(get).toBeInstanceOf(Function) + }) + test('put is a function', () => { + expect(put).toBeInstanceOf(Function) + }) + test('remove is a function', () => { + expect(remove).toBeInstanceOf(Function) + }) +}) \ No newline at end of file diff --git a/books-ui/src/tests/helpers/menuFuncs.test.js b/books-ui/tests/helpers/menuFuncs.test.js similarity index 100% rename from books-ui/src/tests/helpers/menuFuncs.test.js rename to books-ui/tests/helpers/menuFuncs.test.js diff --git a/books-ui/src/tests/helpers/objectUtils.test.js b/books-ui/tests/helpers/objectUtils.test.js similarity index 100% rename from books-ui/src/tests/helpers/objectUtils.test.js rename to books-ui/tests/helpers/objectUtils.test.js diff --git a/books-ui/tests/services/serviceOfBooks.test.js b/books-ui/tests/services/serviceOfBooks.test.js new file mode 100644 index 0000000..174f1b7 --- /dev/null +++ b/books-ui/tests/services/serviceOfBooks.test.js @@ -0,0 +1,52 @@ +import {expect, test, describe} from 'vitest' +import ServiceOfBooks from '@services/ServiceOfBooks.js' +import {createStore} from "vuex"; + +class AdapterOfBooks { + constructor(uri) { + this.uri = uri + } + + async getBooks() { + return [{id: 1, title: 'test'}] + } +} + +describe('serviceOfBooks', () => { + const store = createStore({ + modules: { + books: { + namespaced: true, + state: { + booksList: [] + }, + mutations: { + setBooksList(state, booksList) { + state.booksList = booksList + } + }, + getters: { + booksList: (state) => state.booksList + }, + actions: { + async saveBooks({commit}, booksList) { + commit('setBooksList', booksList) + } + } + } + } + }) + + const adapterOfBooks = new AdapterOfBooks(''); + const serviceOfBooks = new ServiceOfBooks(adapterOfBooks, store); + + test('serviceOfBooks is exist', () => { + expect(serviceOfBooks).toBeDefined() + }) + + test("fetch booksList", async () => { + await serviceOfBooks.fetchBooksList() + const booksList = store.getters['books/booksList'] + expect(booksList).toEqual([{id: 1, title: 'test'}]) + }) +}) \ No newline at end of file diff --git a/books-ui/src/tests/store/userBooks.test.js b/books-ui/tests/store/userBooks.test.js similarity index 100% rename from books-ui/src/tests/store/userBooks.test.js rename to books-ui/tests/store/userBooks.test.js diff --git a/books-ui/vite.config.js b/books-ui/vite.config.js index 8569ac0..a2e2ae3 100644 --- a/books-ui/vite.config.js +++ b/books-ui/vite.config.js @@ -7,17 +7,20 @@ export default defineConfig({ plugins: [vue()], resolve: { alias: { - '@': fileURLToPath(new URL("./src", import.meta.url)), - '@store': fileURLToPath(new URL("./src/store", import.meta.url)), - '@router': fileURLToPath(new URL('./src/router/index.js', import.meta.url)), + '@': fileURLToPath(new URL("./src", import.meta.url)), + '@store': fileURLToPath(new URL("./src/store", import.meta.url)), + '@router': fileURLToPath(new URL('./src/router/index.js', import.meta.url)), '@apiServices': fileURLToPath(new URL('./src/services/apiServices', import.meta.url)), - '@helpers': fileURLToPath(new URL('./src/helpers', import.meta.url)), - '@cmp': fileURLToPath(new URL('/src/components', import.meta.url)), - '@atoms': fileURLToPath(new URL('./src/components/1_atoms', import.meta.url)), - '@molecules': fileURLToPath(new URL('./src/components/2_molecules', import.meta.url)), - '@organisms': fileURLToPath(new URL('./src/components/3_organisms', import.meta.url)), - '@frames': fileURLToPath(new URL('./src/components/4_frames', import.meta.url)), - '@pages': fileURLToPath(new URL('./src/components/5_pages', import.meta.url)), + '@helpers': fileURLToPath(new URL('./src/helpers', import.meta.url)), + '@cmp': fileURLToPath(new URL('/src/components', import.meta.url)), + '@atoms': fileURLToPath(new URL('./src/components/1_atoms', import.meta.url)), + '@molecules': fileURLToPath(new URL('./src/components/2_molecules', import.meta.url)), + '@organisms': fileURLToPath(new URL('./src/components/3_organisms', import.meta.url)), + '@frames': fileURLToPath(new URL('./src/components/4_frames', import.meta.url)), + '@pages': fileURLToPath(new URL('./src/components/5_pages', import.meta.url)), + '@adapters': fileURLToPath(new URL('./src/adapters', import.meta.url)), + '@services': fileURLToPath(new URL('./src/services', import.meta.url)), + '@useCases': fileURLToPath(new URL('./src/useCases', import.meta.url)), } }, test: {