mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-01-27 09:33:08 +00:00
Compare commits
27 Commits
dependabot
...
add-remove
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22e09b0879 | ||
|
|
af477c56b1 | ||
|
|
4aacb36b3f | ||
|
|
dd63370d20 | ||
|
|
9d72796a67 | ||
|
|
6473ea571c | ||
|
|
2bcd317a4c | ||
|
|
0ddca82c86 | ||
|
|
d5645083f3 | ||
|
|
e0bba53df1 | ||
|
|
223fc0a514 | ||
|
|
625d30f3a8 | ||
|
|
6388cc7032 | ||
|
|
066de435d3 | ||
|
|
4ec6ea0f84 | ||
|
|
a7f8ff5212 | ||
|
|
215abbf2f7 | ||
|
|
c005d4d387 | ||
|
|
fd38371eeb | ||
|
|
3c46312929 | ||
|
|
55850f6d3c | ||
|
|
790bb5d1b7 | ||
|
|
c51e8fd9d1 | ||
|
|
60714fbf58 | ||
|
|
f040805d09 | ||
|
|
c35138e7e3 | ||
|
|
91f7d86fd4 |
@@ -47,6 +47,7 @@ const MetadataEditor = createClass({
|
|||||||
|
|
||||||
getInitialState : function(){
|
getInitialState : function(){
|
||||||
return {
|
return {
|
||||||
|
isOwner : global.account?.username && global.account?.username === this.props.metadata?.authors[0],
|
||||||
showThumbnail : true
|
showThumbnail : true
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -156,6 +157,15 @@ const MetadataEditor = createClass({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleDeleteAuthor : function(author){
|
||||||
|
if(!confirm('Are you sure you want to remove this author? They will lose all edit access to this brew, and it will dissapear from their userpage.')) return;
|
||||||
|
if(!this.props.metadata.authors.includes(author)) return;
|
||||||
|
this.props.onChange({
|
||||||
|
...this.props.metadata,
|
||||||
|
authors : this.props.metadata.authors.filter((a)=>a !== author)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
renderSystems : function(){
|
renderSystems : function(){
|
||||||
return _.map(SYSTEMS, (val)=>{
|
return _.map(SYSTEMS, (val)=>{
|
||||||
return <label key={val}>
|
return <label key={val}>
|
||||||
@@ -194,16 +204,54 @@ const MetadataEditor = createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
renderAuthors : function(){
|
renderAuthors : function(){
|
||||||
let text = 'None.';
|
const authors = this.props.metadata.authors;
|
||||||
if(this.props.metadata.authors && this.props.metadata.authors.length){
|
if(!this.state.isOwner || authors.length < 2) return (
|
||||||
text = this.props.metadata.authors.join(', ');
|
<div className='field authors'>
|
||||||
}
|
<label>authors</label>
|
||||||
return <div className='field authors'>
|
<div className='value'>
|
||||||
<label>authors</label>
|
{authors.length > 0 && (
|
||||||
<div className='value'>
|
<a href={`/user/${authors[0]}`} className='author-link' title={`Owner - Click to open ${authors[0]}'s profile in a new tab`}>
|
||||||
{text}
|
{authors[0]}{authors.length > 1 && ', '}
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
{authors.length > 1 && authors.slice(1).map((author, i)=>(
|
||||||
|
<a href={`/user/${author}`} className='author-link' title={`Author - Click to open ${author}'s profile in a new tab`}>
|
||||||
|
{author}{i+2 < authors.length && ', '}
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
);
|
||||||
|
return (
|
||||||
|
<div className='field authors'>
|
||||||
|
<label>Authors</label>
|
||||||
|
<ul className='list'>
|
||||||
|
{authors.length > 0 && (
|
||||||
|
<li className='tag owner' title='Owner'>
|
||||||
|
<a href={`/user/${authors[0]}`} className='author-link' title={`Owner - Click to open ${authors[0]}'s profile in a new tab`}>
|
||||||
|
{authors[0]}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{authors.length > 1 && authors.slice(1).map((author, i)=>(
|
||||||
|
<li className='tag author' key={i + 1} title='Author'>
|
||||||
|
<a href={`/user/${author}`} className='author-link' title={`Author - Click to open ${authors[0]}'s profile in a new tab`}>
|
||||||
|
{author}
|
||||||
|
</a>
|
||||||
|
<button
|
||||||
|
onClick={()=>this.handleDeleteAuthor(author)}
|
||||||
|
className='delete'
|
||||||
|
title={`Remove ${author} as an author`}
|
||||||
|
>
|
||||||
|
<i className='fa fa-times fa-fw' />
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
renderThemeDropdown : function(){
|
renderThemeDropdown : function(){
|
||||||
|
|||||||
@@ -44,8 +44,6 @@
|
|||||||
gap : 10px;
|
gap : 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.field {
|
.field {
|
||||||
position : relative;
|
position : relative;
|
||||||
display : flex;
|
display : flex;
|
||||||
@@ -116,7 +114,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.thumbnail-preview {
|
.thumbnail-preview {
|
||||||
position : relative;
|
position : relative;
|
||||||
flex : 1 1;
|
flex : 1 1;
|
||||||
@@ -164,7 +161,47 @@
|
|||||||
.colorButton(@red);
|
.colorButton(@red);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.authors.field .value { line-height : 1.5em; }
|
.authors.field {
|
||||||
|
.tag {
|
||||||
|
font-weight:300;
|
||||||
|
transition:background-color 0.2s;
|
||||||
|
|
||||||
|
&.owner {
|
||||||
|
position: relative;
|
||||||
|
background-color:@silverLight;
|
||||||
|
min-width:25px;
|
||||||
|
display:grid;
|
||||||
|
place-items:center;
|
||||||
|
font-weight: 900;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: "\f521";
|
||||||
|
font-family: "Font Awesome 6 Free";
|
||||||
|
color:gold;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width:15px;
|
||||||
|
height:15px;
|
||||||
|
rotate:-45deg;
|
||||||
|
translate:-50% -50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:has(button:hover) {
|
||||||
|
background:#d97d7d;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
color:@red;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color:black;
|
||||||
|
text-decoration:unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.themes.field {
|
.themes.field {
|
||||||
& .dropdown-container {
|
& .dropdown-container {
|
||||||
@@ -266,13 +303,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tag {
|
.tag {
|
||||||
padding : 0.3em;
|
padding : 0.35em;
|
||||||
margin : 2px;
|
margin : 2px;
|
||||||
font-size : 0.9em;
|
font-size : 0.95em;
|
||||||
background-color : #DDDDDD;
|
background-color : #DDDDDD;
|
||||||
border-radius : 0.5em;
|
border-radius : 0.5em;
|
||||||
|
|
||||||
.icon { #groupedIcon; }
|
.icon { #groupedIcon; }
|
||||||
|
|
||||||
|
button {
|
||||||
|
cursor : pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-group {
|
.input-group {
|
||||||
|
|||||||
@@ -171,7 +171,6 @@ const api = {
|
|||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
getCSS : async (req, res)=>{
|
getCSS : async (req, res)=>{
|
||||||
const { brew } = req;
|
const { brew } = req;
|
||||||
if(!brew) return res.status(404).send('');
|
if(!brew) return res.status(404).send('');
|
||||||
@@ -184,7 +183,6 @@ const api = {
|
|||||||
});
|
});
|
||||||
return res.status(200).send(brew.style);
|
return res.status(200).send(brew.style);
|
||||||
},
|
},
|
||||||
|
|
||||||
mergeBrewText : (brew)=>{
|
mergeBrewText : (brew)=>{
|
||||||
let text = brew.text;
|
let text = brew.text;
|
||||||
if(brew.style !== undefined) {
|
if(brew.style !== undefined) {
|
||||||
@@ -202,7 +200,6 @@ const api = {
|
|||||||
`${text}`;
|
`${text}`;
|
||||||
return text;
|
return text;
|
||||||
},
|
},
|
||||||
|
|
||||||
getGoodBrewTitle : (text)=>{
|
getGoodBrewTitle : (text)=>{
|
||||||
const tokens = Markdown.marked.lexer(text);
|
const tokens = Markdown.marked.lexer(text);
|
||||||
return (tokens.find((token)=>token.type === 'heading' || token.type === 'paragraph')?.text || 'No Title')
|
return (tokens.find((token)=>token.type === 'heading' || token.type === 'paragraph')?.text || 'No Title')
|
||||||
|
|||||||
@@ -204,7 +204,6 @@ describe('Tests for api', ()=>{
|
|||||||
expect(id).toEqual('abcdefghij');
|
expect(id).toEqual('abcdefghij');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getBrew', ()=>{
|
describe('getBrew', ()=>{
|
||||||
const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew }));
|
const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew }));
|
||||||
const notFoundError = { HBErrorCode: '05', message: 'Brew not found', name: 'BrewLoad Error', status: 404, accessType: 'share', brewId: '1' };
|
const notFoundError = { HBErrorCode: '05', message: 'Brew not found', name: 'BrewLoad Error', status: 404, accessType: 'share', brewId: '1' };
|
||||||
@@ -382,7 +381,68 @@ describe('Tests for api', ()=>{
|
|||||||
await expect(fn(req, null, next)).rejects.toEqual({ 'HBErrorCode': '51', 'brewId': '1', 'brewTitle': 'test brew', 'code': 404, 'message': 'brew locked' });
|
await expect(fn(req, null, next)).rejects.toEqual({ 'HBErrorCode': '51', 'brewId': '1', 'brewTitle': 'test brew', 'code': 404, 'message': 'brew locked' });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe('Get CSS', ()=>{
|
||||||
|
it('should return brew style content as CSS text', async ()=>{
|
||||||
|
const testBrew = { title: 'test brew', text: '```css\n\nI Have a style!\n```\n\n' };
|
||||||
|
|
||||||
|
const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew }));
|
||||||
|
api.getId = jest.fn(()=>({ id: '1', googleId: undefined }));
|
||||||
|
model.get = jest.fn(()=>toBrewPromise(testBrew));
|
||||||
|
|
||||||
|
const fn = api.getBrew('share', true);
|
||||||
|
const req = { brew: {} };
|
||||||
|
const next = jest.fn();
|
||||||
|
await fn(req, null, next);
|
||||||
|
await api.getCSS(req, res);
|
||||||
|
|
||||||
|
expect(req.brew).toEqual(testBrew);
|
||||||
|
expect(req.brew).toHaveProperty('style', '\nI Have a style!\n');
|
||||||
|
expect(res.status).toHaveBeenCalledWith(200);
|
||||||
|
expect(res.send).toHaveBeenCalledWith('\nI Have a style!\n');
|
||||||
|
expect(res.set).toHaveBeenCalledWith({
|
||||||
|
'Cache-Control' : 'no-cache',
|
||||||
|
'Content-Type' : 'text/css'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return 404 when brew has no style content', async ()=>{
|
||||||
|
const testBrew = { title: 'test brew', text: 'I don\'t have a style!' };
|
||||||
|
|
||||||
|
const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew }));
|
||||||
|
api.getId = jest.fn(()=>({ id: '1', googleId: undefined }));
|
||||||
|
model.get = jest.fn(()=>toBrewPromise(testBrew));
|
||||||
|
|
||||||
|
const fn = api.getBrew('share', true);
|
||||||
|
const req = { brew: {} };
|
||||||
|
const next = jest.fn();
|
||||||
|
await fn(req, null, next);
|
||||||
|
await api.getCSS(req, res);
|
||||||
|
|
||||||
|
expect(req.brew).toEqual(testBrew);
|
||||||
|
expect(req.brew).toHaveProperty('style');
|
||||||
|
expect(res.status).toHaveBeenCalledWith(404);
|
||||||
|
expect(res.send).toHaveBeenCalledWith('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return 404 when brew does not exist', async ()=>{
|
||||||
|
const testBrew = { };
|
||||||
|
|
||||||
|
const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew }));
|
||||||
|
api.getId = jest.fn(()=>({ id: '1', googleId: undefined }));
|
||||||
|
model.get = jest.fn(()=>toBrewPromise(testBrew));
|
||||||
|
|
||||||
|
const fn = api.getBrew('share', true);
|
||||||
|
const req = { brew: {} };
|
||||||
|
const next = jest.fn();
|
||||||
|
await fn(req, null, next);
|
||||||
|
await api.getCSS(req, res);
|
||||||
|
|
||||||
|
expect(req.brew).toEqual(testBrew);
|
||||||
|
expect(req.brew).toHaveProperty('style');
|
||||||
|
expect(res.status).toHaveBeenCalledWith(404);
|
||||||
|
expect(res.send).toHaveBeenCalledWith('');
|
||||||
|
});
|
||||||
|
});
|
||||||
describe('mergeBrewText', ()=>{
|
describe('mergeBrewText', ()=>{
|
||||||
it('should set metadata and no style if it is not present', ()=>{
|
it('should set metadata and no style if it is not present', ()=>{
|
||||||
const result = api.mergeBrewText({
|
const result = api.mergeBrewText({
|
||||||
@@ -445,7 +505,6 @@ hello yes i am css
|
|||||||
brew`);
|
brew`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('exclusion methods', ()=>{
|
describe('exclusion methods', ()=>{
|
||||||
it('excludePropsFromUpdate removes the correct keys', ()=>{
|
it('excludePropsFromUpdate removes the correct keys', ()=>{
|
||||||
const sent = Object.assign({}, googleBrew);
|
const sent = Object.assign({}, googleBrew);
|
||||||
@@ -483,7 +542,6 @@ brew`);
|
|||||||
expect(result.pageCount).toBe(1);
|
expect(result.pageCount).toBe(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('beforeNewSave', ()=>{
|
describe('beforeNewSave', ()=>{
|
||||||
it('sets the title if none', ()=>{
|
it('sets the title if none', ()=>{
|
||||||
const brew = {
|
const brew = {
|
||||||
@@ -525,7 +583,6 @@ brew`);
|
|||||||
expect(hbBrew.text).toEqual('merged');
|
expect(hbBrew.text).toEqual('merged');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('newGoogleBrew', ()=>{
|
describe('newGoogleBrew', ()=>{
|
||||||
it('should call the correct methods', ()=>{
|
it('should call the correct methods', ()=>{
|
||||||
api.excludeGoogleProps = jest.fn(()=>'newBrew');
|
api.excludeGoogleProps = jest.fn(()=>'newBrew');
|
||||||
@@ -539,7 +596,6 @@ brew`);
|
|||||||
expect(google.newGoogleBrew).toHaveBeenCalledWith('client', 'newBrew');
|
expect(google.newGoogleBrew).toHaveBeenCalledWith('client', 'newBrew');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('newBrew', ()=>{
|
describe('newBrew', ()=>{
|
||||||
it('should set up a default brew via Homebrew model', async ()=>{
|
it('should set up a default brew via Homebrew model', async ()=>{
|
||||||
await api.newBrew({ body: { text: 'asdf' }, query: {}, account: { username: 'test user' } }, res);
|
await api.newBrew({ body: { text: 'asdf' }, query: {}, account: { username: 'test user' } }, res);
|
||||||
@@ -631,17 +687,6 @@ brew`);
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('deleteGoogleBrew', ()=>{
|
|
||||||
it('should check auth and delete brew', async ()=>{
|
|
||||||
const result = await api.deleteGoogleBrew({ username: 'test user' }, 'id', 'editId', res);
|
|
||||||
|
|
||||||
expect(result).toBe(true);
|
|
||||||
expect(google.authCheck).toHaveBeenCalledWith({ username: 'test user' }, expect.objectContaining({}));
|
|
||||||
expect(google.deleteGoogleBrew).toHaveBeenCalledWith('client', 'id', 'editId');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Theme bundle', ()=>{
|
describe('Theme bundle', ()=>{
|
||||||
it('should return Theme Bundle for a User Theme', async ()=>{
|
it('should return Theme Bundle for a User Theme', async ()=>{
|
||||||
const brews = {
|
const brews = {
|
||||||
@@ -785,7 +830,94 @@ brew`);
|
|||||||
status : 422 });
|
status : 422 });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe('updateBrew', ()=>{
|
||||||
|
it('should return error on version mismatch', async ()=>{
|
||||||
|
const brewFromClient = { version: 1 };
|
||||||
|
const brewFromServer = { version: 1000, text: '' };
|
||||||
|
|
||||||
|
const req = {
|
||||||
|
brew : brewFromServer,
|
||||||
|
body : brewFromClient
|
||||||
|
};
|
||||||
|
|
||||||
|
await api.updateBrew(req, res);
|
||||||
|
|
||||||
|
expect(res.status).toHaveBeenCalledWith(409);
|
||||||
|
expect(res.send).toHaveBeenCalledWith('{\"message\":\"The server version is out of sync with the saved brew. Please save your changes elsewhere, refresh, and try again.\"}');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return error on hash mismatch', async ()=>{
|
||||||
|
const brewFromClient = { version: 1, hash: '1234' };
|
||||||
|
const brewFromServer = { version: 1, text: 'test' };
|
||||||
|
|
||||||
|
const req = {
|
||||||
|
brew : brewFromServer,
|
||||||
|
body : brewFromClient
|
||||||
|
};
|
||||||
|
|
||||||
|
await api.updateBrew(req, res);
|
||||||
|
|
||||||
|
expect(req.brew.hash).toBe('098f6bcd4621d373cade4e832627b4f6');
|
||||||
|
expect(res.status).toHaveBeenCalledWith(409);
|
||||||
|
expect(res.send).toHaveBeenCalledWith('{\"message\":\"The server copy is out of sync with the saved brew. Please save your changes elsewhere, refresh, and try again.\"}');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Commenting this one out for now, since we are no longer throwing this error while we monitor
|
||||||
|
// it('should return error on applying patches', async ()=>{
|
||||||
|
// const brewFromClient = { version: 1, hash: '098f6bcd4621d373cade4e832627b4f6', patches: 'not a valid patch string' };
|
||||||
|
// const brewFromServer = { version: 1, text: 'test', title: 'Test Title', description: 'Test Description' };
|
||||||
|
|
||||||
|
// const req = {
|
||||||
|
// brew : brewFromServer,
|
||||||
|
// body : brewFromClient,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// let err;
|
||||||
|
// try {
|
||||||
|
// await api.updateBrew(req, res);
|
||||||
|
// } catch (e) {
|
||||||
|
// err = e;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// expect(err).toEqual(Error('Invalid patch string: not a valid patch string'));
|
||||||
|
// });
|
||||||
|
|
||||||
|
it('should save brew, no ID', async ()=>{
|
||||||
|
const brewFromClient = { version: 1, hash: '098f6bcd4621d373cade4e832627b4f6', patches: '' };
|
||||||
|
const brewFromServer = { version: 1, text: 'test', title: 'Test Title', description: 'Test Description' };
|
||||||
|
|
||||||
|
model.save = jest.fn((brew)=>{return brew;});
|
||||||
|
|
||||||
|
const req = {
|
||||||
|
brew : brewFromServer,
|
||||||
|
body : brewFromClient,
|
||||||
|
query : { saveToGoogle: false, removeFromGoogle: false }
|
||||||
|
};
|
||||||
|
|
||||||
|
await api.updateBrew(req, res);
|
||||||
|
|
||||||
|
expect(res.status).toHaveBeenCalledWith(200);
|
||||||
|
expect(res.send).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
_id : '1',
|
||||||
|
description : 'Test Description',
|
||||||
|
hash : '098f6bcd4621d373cade4e832627b4f6',
|
||||||
|
title : 'Test Title',
|
||||||
|
version : 2
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('deleteGoogleBrew', ()=>{
|
||||||
|
it('should check auth and delete brew', async ()=>{
|
||||||
|
const result = await api.deleteGoogleBrew({ username: 'test user' }, 'id', 'editId', res);
|
||||||
|
|
||||||
|
expect(result).toBe(true);
|
||||||
|
expect(google.authCheck).toHaveBeenCalledWith({ username: 'test user' }, expect.objectContaining({}));
|
||||||
|
expect(google.deleteGoogleBrew).toHaveBeenCalledWith('client', 'id', 'editId');
|
||||||
|
});
|
||||||
|
});
|
||||||
describe('deleteBrew', ()=>{
|
describe('deleteBrew', ()=>{
|
||||||
it('should handle case where fetching the brew returns an error', async ()=>{
|
it('should handle case where fetching the brew returns an error', async ()=>{
|
||||||
api.getBrew = jest.fn(()=>async ()=>{ throw { message: 'err', HBErrorCode: '02' }; });
|
api.getBrew = jest.fn(()=>async ()=>{ throw { message: 'err', HBErrorCode: '02' }; });
|
||||||
@@ -1006,68 +1138,7 @@ brew`);
|
|||||||
expect(saved.googleId).toEqual(brew.googleId);
|
expect(saved.googleId).toEqual(brew.googleId);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('Get CSS', ()=>{
|
|
||||||
it('should return brew style content as CSS text', async ()=>{
|
|
||||||
const testBrew = { title: 'test brew', text: '```css\n\nI Have a style!\n```\n\n' };
|
|
||||||
|
|
||||||
const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew }));
|
|
||||||
api.getId = jest.fn(()=>({ id: '1', googleId: undefined }));
|
|
||||||
model.get = jest.fn(()=>toBrewPromise(testBrew));
|
|
||||||
|
|
||||||
const fn = api.getBrew('share', true);
|
|
||||||
const req = { brew: {} };
|
|
||||||
const next = jest.fn();
|
|
||||||
await fn(req, null, next);
|
|
||||||
await api.getCSS(req, res);
|
|
||||||
|
|
||||||
expect(req.brew).toEqual(testBrew);
|
|
||||||
expect(req.brew).toHaveProperty('style', '\nI Have a style!\n');
|
|
||||||
expect(res.status).toHaveBeenCalledWith(200);
|
|
||||||
expect(res.send).toHaveBeenCalledWith('\nI Have a style!\n');
|
|
||||||
expect(res.set).toHaveBeenCalledWith({
|
|
||||||
'Cache-Control' : 'no-cache',
|
|
||||||
'Content-Type' : 'text/css'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return 404 when brew has no style content', async ()=>{
|
|
||||||
const testBrew = { title: 'test brew', text: 'I don\'t have a style!' };
|
|
||||||
|
|
||||||
const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew }));
|
|
||||||
api.getId = jest.fn(()=>({ id: '1', googleId: undefined }));
|
|
||||||
model.get = jest.fn(()=>toBrewPromise(testBrew));
|
|
||||||
|
|
||||||
const fn = api.getBrew('share', true);
|
|
||||||
const req = { brew: {} };
|
|
||||||
const next = jest.fn();
|
|
||||||
await fn(req, null, next);
|
|
||||||
await api.getCSS(req, res);
|
|
||||||
|
|
||||||
expect(req.brew).toEqual(testBrew);
|
|
||||||
expect(req.brew).toHaveProperty('style');
|
|
||||||
expect(res.status).toHaveBeenCalledWith(404);
|
|
||||||
expect(res.send).toHaveBeenCalledWith('');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return 404 when brew does not exist', async ()=>{
|
|
||||||
const testBrew = { };
|
|
||||||
|
|
||||||
const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew }));
|
|
||||||
api.getId = jest.fn(()=>({ id: '1', googleId: undefined }));
|
|
||||||
model.get = jest.fn(()=>toBrewPromise(testBrew));
|
|
||||||
|
|
||||||
const fn = api.getBrew('share', true);
|
|
||||||
const req = { brew: {} };
|
|
||||||
const next = jest.fn();
|
|
||||||
await fn(req, null, next);
|
|
||||||
await api.getCSS(req, res);
|
|
||||||
|
|
||||||
expect(req.brew).toEqual(testBrew);
|
|
||||||
expect(req.brew).toHaveProperty('style');
|
|
||||||
expect(res.status).toHaveBeenCalledWith(404);
|
|
||||||
expect(res.send).toHaveBeenCalledWith('');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe('Split Text, Style, and Metadata', ()=>{
|
describe('Split Text, Style, and Metadata', ()=>{
|
||||||
|
|
||||||
it('basic splitting', async ()=>{
|
it('basic splitting', async ()=>{
|
||||||
@@ -1122,82 +1193,4 @@ brew`);
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('updateBrew', ()=>{
|
|
||||||
it('should return error on version mismatch', async ()=>{
|
|
||||||
const brewFromClient = { version: 1 };
|
|
||||||
const brewFromServer = { version: 1000, text: '' };
|
|
||||||
|
|
||||||
const req = {
|
|
||||||
brew : brewFromServer,
|
|
||||||
body : brewFromClient
|
|
||||||
};
|
|
||||||
|
|
||||||
await api.updateBrew(req, res);
|
|
||||||
|
|
||||||
expect(res.status).toHaveBeenCalledWith(409);
|
|
||||||
expect(res.send).toHaveBeenCalledWith('{\"message\":\"The server version is out of sync with the saved brew. Please save your changes elsewhere, refresh, and try again.\"}');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return error on hash mismatch', async ()=>{
|
|
||||||
const brewFromClient = { version: 1, hash: '1234' };
|
|
||||||
const brewFromServer = { version: 1, text: 'test' };
|
|
||||||
|
|
||||||
const req = {
|
|
||||||
brew : brewFromServer,
|
|
||||||
body : brewFromClient
|
|
||||||
};
|
|
||||||
|
|
||||||
await api.updateBrew(req, res);
|
|
||||||
|
|
||||||
expect(req.brew.hash).toBe('098f6bcd4621d373cade4e832627b4f6');
|
|
||||||
expect(res.status).toHaveBeenCalledWith(409);
|
|
||||||
expect(res.send).toHaveBeenCalledWith('{\"message\":\"The server copy is out of sync with the saved brew. Please save your changes elsewhere, refresh, and try again.\"}');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Commenting this one out for now, since we are no longer throwing this error while we monitor
|
|
||||||
// it('should return error on applying patches', async ()=>{
|
|
||||||
// const brewFromClient = { version: 1, hash: '098f6bcd4621d373cade4e832627b4f6', patches: 'not a valid patch string' };
|
|
||||||
// const brewFromServer = { version: 1, text: 'test', title: 'Test Title', description: 'Test Description' };
|
|
||||||
|
|
||||||
// const req = {
|
|
||||||
// brew : brewFromServer,
|
|
||||||
// body : brewFromClient,
|
|
||||||
// };
|
|
||||||
|
|
||||||
// let err;
|
|
||||||
// try {
|
|
||||||
// await api.updateBrew(req, res);
|
|
||||||
// } catch (e) {
|
|
||||||
// err = e;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// expect(err).toEqual(Error('Invalid patch string: not a valid patch string'));
|
|
||||||
// });
|
|
||||||
|
|
||||||
it('should save brew, no ID', async ()=>{
|
|
||||||
const brewFromClient = { version: 1, hash: '098f6bcd4621d373cade4e832627b4f6', patches: '' };
|
|
||||||
const brewFromServer = { version: 1, text: 'test', title: 'Test Title', description: 'Test Description' };
|
|
||||||
|
|
||||||
model.save = jest.fn((brew)=>{return brew;});
|
|
||||||
|
|
||||||
const req = {
|
|
||||||
brew : brewFromServer,
|
|
||||||
body : brewFromClient,
|
|
||||||
query : { saveToGoogle: false, removeFromGoogle: false }
|
|
||||||
};
|
|
||||||
|
|
||||||
await api.updateBrew(req, res);
|
|
||||||
|
|
||||||
expect(res.status).toHaveBeenCalledWith(200);
|
|
||||||
expect(res.send).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
_id : '1',
|
|
||||||
description : 'Test Description',
|
|
||||||
hash : '098f6bcd4621d373cade4e832627b4f6',
|
|
||||||
title : 'Test Title',
|
|
||||||
version : 2
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user