Skip to content

Commit

Permalink
feat(feat(core): create services && adapter + tests):
Browse files Browse the repository at this point in the history
  • Loading branch information
vbuglov committed Mar 6, 2024
1 parent c391135 commit 4c1a0b0
Show file tree
Hide file tree
Showing 25 changed files with 322 additions and 10 deletions.
1 change: 1 addition & 0 deletions books-ui/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export default {
}
},
mounted() {
const url = import.meta.env.VITE_API_ADDR
this.fetchBooks()
this.initScreenSizeRecalc()
},
Expand Down
173 changes: 173 additions & 0 deletions books-ui/src/adapters/AdapterOfBooks.js
Original file line number Diff line number Diff line change
@@ -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<Object[]>}
*/
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<Object>}
*/
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<Object>}
*/
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<null>}
*/
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}
39 changes: 39 additions & 0 deletions books-ui/src/helpers/apiHelpers.js
Original file line number Diff line number Diff line change
@@ -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}
13 changes: 13 additions & 0 deletions books-ui/src/services/ServiceOfBooks.js
Original file line number Diff line number Diff line change
@@ -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;
14 changes: 14 additions & 0 deletions books-ui/tests/adapters/adapterOfBooks.test.js
Original file line number Diff line number Diff line change
@@ -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()
})
})
File renamed without changes.
File renamed without changes.
17 changes: 17 additions & 0 deletions books-ui/tests/helpers/apiHelpers.test.js
Original file line number Diff line number Diff line change
@@ -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)
})
})
File renamed without changes.
File renamed without changes.
52 changes: 52 additions & 0 deletions books-ui/tests/services/serviceOfBooks.test.js
Original file line number Diff line number Diff line change
@@ -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'}])
})
})
File renamed without changes.
23 changes: 13 additions & 10 deletions books-ui/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down

0 comments on commit 4c1a0b0

Please sign in to comment.