forked from b00tc4mp/isdi-bootcamp-202405
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
create logic and spec of createProduct in cor/logic b00tc4mp#101
- Loading branch information
1 parent
86c85d9
commit 09d87d0
Showing
16 changed files
with
285 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
|
||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>Home</title> | ||
|
||
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon"> | ||
</head> | ||
|
||
<body> | ||
<div id="root"></div> | ||
|
||
<script src="./index.jsx" type="module"></script> | ||
</body> | ||
|
||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import ReactDOM from 'react-dom/client' | ||
import { BrowserRouter as Router } from 'react-router-dom' | ||
|
||
import App from './view/App' | ||
|
||
import './index.css' | ||
|
||
const root = ReactDOM.createRoot(document.getElementById('root')) | ||
root.render(<Router><App /></Router>) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export default () => !!sessionStorage.token |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { useState, useEffect } from 'react' | ||
import { Routes, Route, useNavigate, Navigate } from 'react-router-dom' | ||
|
||
import Login from './login' | ||
import Register from './register' | ||
import Home from './home' | ||
import Alert from './common/Alert' | ||
|
||
import { Context } from './context' | ||
|
||
import logic from '../logic' | ||
|
||
const App = () => { | ||
const navigate = useNavigate() | ||
|
||
const [theme, setTheme] = useState(localStorage.theme) | ||
const [alertMessage, setAlertMessage] = useState(null) | ||
|
||
useEffect(() => { | ||
document.documentElement.className = theme | ||
localStorage.theme = theme | ||
}, [theme]) | ||
|
||
const handleLogin = () => { | ||
navigate('/') | ||
} | ||
|
||
const handleRegisterClick = () => { | ||
navigate('/register') | ||
} | ||
|
||
const handleRegister = () => { | ||
navigate('/login') | ||
} | ||
|
||
const handleLoginClick = () => { | ||
navigate('/login') | ||
} | ||
|
||
const handleLogout = () => { | ||
navigate('/login') | ||
} | ||
|
||
const handleAlertAccept = () => setAlertMessage(null) | ||
|
||
return <Context.Provider value={{ theme, setTheme, alert: setAlertMessage }}> | ||
<Routes> | ||
<Route path="/login"><Login onLogin={handleLogin} onRegisterClick={handleRegisterClick} /></Route> | ||
<Route path="/register"> <Register onRegister={handleRegister} onLoginClick={handleLoginClick} /></Route> | ||
<Route path="/*"><Home onLogout={handleLogout} /></Route> | ||
</Routes> | ||
|
||
{alertMessage && <Alert message={alertMessage} onAccept={handleAlertAccept} />} | ||
</Context.Provider> | ||
} | ||
|
||
export default App |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { User, Product } from '../data/models.js' | ||
|
||
import { validate, errors } from 'com' | ||
|
||
const { NotFoundError, SystemError } = errors | ||
|
||
export default (userId, name, type, minprize, maxprize, image) => { | ||
validate.string(userId, 'userId') | ||
validate.string(name, 'name') | ||
validate.string(type, 'type') | ||
validate.number(minprize, 'minprize') | ||
validate.number(maxprize, 'maxprize') | ||
validate.url(image, 'image') | ||
return User.findById(userId).lean() | ||
.catch(error => { throw new SystemError(error.message) }) | ||
.then(user => { | ||
if (!user) throw new NotFoundError('user not found') | ||
|
||
return Product.create({ | ||
farmer: userId, | ||
name, | ||
type, | ||
minprize, | ||
maxprize, | ||
image | ||
}) | ||
.catch(error => { throw new SystemError(error.message) }) | ||
}) | ||
.then(() => { }) | ||
} |
141 changes: 141 additions & 0 deletions
141
staff/lucas-orts/project/cor/logic/createProduct.spec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
import 'dotenv/config' | ||
import mongoose, { Types } from 'mongoose' | ||
import { expect } from 'chai' | ||
|
||
const { ObjectId } = Types | ||
|
||
import createProduct from './createProduct.js' | ||
import { User, Product } from '../data/models.js' | ||
|
||
import errors from '../../com/errors.js' | ||
const { ValidationError, NotFoundError } = errors | ||
|
||
describe('createProduct', () => { | ||
before(() => mongoose.connect(process.env.MONGODB_URI)) | ||
|
||
beforeEach(() => Promise.all([User.deleteMany(), Product.deleteMany()])) | ||
|
||
it('succeeds on new product', () => | ||
User.create({ name: 'Ester', surname: 'Colero', email: 'ester@colero', phone: '966234731', address: 'calle Tertulia 3, Cuenca', password: '123123123' }) | ||
.then(user => | ||
createProduct(user.id, 'lemon', '', 5.3, 6.1, 'https://media.giphy.com/media/ji6zzUZwNIuLS/giphy.gif?cid=790b7611qml3yetzjkqcp26cvoxayvif8j713kmqj2yp06oi&ep=v1_gifs_trending&rid=giphy.gif&ct=g') | ||
.then(() => Product.findOne({ farmer: user.id }) | ||
.then(product => { | ||
expect(product.farmer.toString()).to.equal(user.id) | ||
expect(product.name).to.equal('lemon') | ||
expect(product.type).to.equal('') | ||
expect(product.minprize).to.equal(5.3) | ||
expect(product.maxprize).to.equal(6.1) | ||
expect(product.image).to.equal('https://media.giphy.com/media/ji6zzUZwNIuLS/giphy.gif?cid=790b7611qml3yetzjkqcp26cvoxayvif8j713kmqj2yp06oi&ep=v1_gifs_trending&rid=giphy.gif&ct=g') | ||
}) | ||
) | ||
) | ||
) | ||
|
||
|
||
it('fails on non-existing user', () => { | ||
let _error | ||
|
||
return createProduct(new ObjectId().toString(), 'lemon', '', 5.3, 6.1, 'https://media.giphy.com/media/ji6zzUZwNIuLS/giphy.gif?cid=790b7611qml3yetzjkqcp26cvoxayvif8j713kmqj2yp06oi&ep=v1_gifs_trending&rid=giphy.gif&ct=g') | ||
.catch(error => _error = error) | ||
.finally(() => { | ||
expect(_error).to.be.instanceOf(NotFoundError) | ||
expect(_error.message).to.equal('user not found') | ||
}) | ||
}) | ||
|
||
it('fails on non-string userId', () => { | ||
let error | ||
|
||
try { | ||
createProduct(123, 'lemon', '', 5.3, 6.1, 'https://media.giphy.com/media/ji6zzUZwNIuLS/giphy.gif?cid=790b7611qml3yetzjkqcp26cvoxayvif8j713kmqj2yp06oi&ep=v1_gifs_trending&rid=giphy.gif&ct=g') | ||
} catch (_error) { | ||
error = _error | ||
} finally { | ||
expect(error).to.be.instanceOf(ValidationError) | ||
expect(error.message).to.equal('userId is not a string') | ||
} | ||
}) | ||
|
||
it('fails on non-string name', () => { | ||
let error | ||
|
||
try { | ||
createProduct(new ObjectId().toString(), 123, '', 5.3, 6.1, 'https://media.giphy.com/media/ji6zzUZwNIuLS/giphy.gif?cid=790b7611qml3yetzjkqcp26cvoxayvif8j713kmqj2yp06oi&ep=v1_gifs_trending&rid=giphy.gif&ct=g') | ||
} catch (_error) { | ||
error = _error | ||
} finally { | ||
expect(error).to.be.instanceOf(ValidationError) | ||
expect(error.message).to.equal('name is not a string') | ||
} | ||
}) | ||
|
||
it('fails on non-string type', () => { | ||
let error | ||
|
||
try { | ||
createProduct(new ObjectId().toString(), 'lemon', 123, 5.3, 6.1, 'https://media.giphy.com/media/ji6zzUZwNIuLS/giphy.gif?cid=790b7611qml3yetzjkqcp26cvoxayvif8j713kmqj2yp06oi&ep=v1_gifs_trending&rid=giphy.gif&ct=g') | ||
} catch (_error) { | ||
error = _error | ||
} finally { | ||
expect(error).to.be.instanceOf(ValidationError) | ||
expect(error.message).to.equal('type is not a string') | ||
} | ||
}) | ||
|
||
it('fails on non-number minprize', () => { | ||
let error | ||
|
||
try { | ||
createProduct(new ObjectId().toString(), 'lemon', '', '5.3', 6.1, 'https://media.giphy.com/media/ji6zzUZwNIuLS/giphy.gif?cid=790b7611qml3yetzjkqcp26cvoxayvif8j713kmqj2yp06oi&ep=v1_gifs_trending&rid=giphy.gif&ct=g') | ||
} catch (_error) { | ||
error = _error | ||
} finally { | ||
expect(error).to.be.instanceOf(ValidationError) | ||
expect(error.message).to.equal('minprize is not a number') | ||
} | ||
}) | ||
|
||
it('fails on non-number maxprize', () => { | ||
let error | ||
|
||
try { | ||
createProduct(new ObjectId().toString(), 'lemon', '', 5.3, '6.1', 'https://media.giphy.com/media/ji6zzUZwNIuLS/giphy.gif?cid=790b7611qml3yetzjkqcp26cvoxayvif8j713kmqj2yp06oi&ep=v1_gifs_trending&rid=giphy.gif&ct=g') | ||
} catch (_error) { | ||
error = _error | ||
} finally { | ||
expect(error).to.be.instanceOf(ValidationError) | ||
expect(error.message).to.equal('maxprize is not a number') | ||
} | ||
}) | ||
|
||
it('fails on non-string image', () => { | ||
let error | ||
|
||
try { | ||
createProduct(new ObjectId().toString(), 'lemon', '', 5.3, 6.1, 321) | ||
} catch (_error) { | ||
error = _error | ||
} finally { | ||
expect(error).to.be.instanceOf(ValidationError) | ||
expect(error.message).to.equal('image is not a string') | ||
} | ||
}) | ||
|
||
it('fails on invalid image', () => { | ||
let error | ||
|
||
try { | ||
createProduct(new ObjectId().toString(), 'lemon', '', 5.3, 6.1, 'htpp:') | ||
} catch (_error) { | ||
error = _error | ||
} finally { | ||
expect(error).to.be.instanceOf(ValidationError) | ||
expect(error.message).to.equal('invalid image') | ||
} | ||
}) | ||
|
||
afterEach(() => Promise.all([User.deleteMany, Product.deleteMany()])) | ||
|
||
after(() => mongoose.disconnect()) | ||
}) |