-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
20 changed files
with
19,838 additions
and
0 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,21 @@ | ||
{ | ||
"parser": "@typescript-eslint/parser", | ||
"extends": ["plugin:@typescript-eslint/recommended"], | ||
"settings": { | ||
"import/resolver": "webpack" | ||
}, | ||
"env": { | ||
"browser": true, | ||
"node": true, | ||
"jest/globals": true | ||
}, | ||
"plugins": ["react", "import", "jest", "@typescript-eslint"], | ||
"rules": { | ||
"max-len": ["error", { "code": 120 }], | ||
"react/jsx-filename-extension": "off", | ||
"react/forbid-prop-types": "off", | ||
"@typescript-eslint/indent": ["error", 2], | ||
"@typescript-eslint/no-explicit-any": "off", | ||
"@typescript-eslint/explicit-function-return-type": "off" | ||
} | ||
} |
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,104 @@ | ||
import {Model} from '../src'; | ||
|
||
const payload = { | ||
'id': '123', | ||
'author': { | ||
'id': '1', | ||
'name': 'Paul' | ||
}, | ||
'title': 'My awesome blog post', | ||
'comments': [ | ||
{ | ||
'id': '324', | ||
'commenter': { | ||
'id': '2', | ||
'name': 'Nicole' | ||
} | ||
} | ||
] | ||
}; | ||
|
||
describe('Model with nested models', () => { | ||
let userModel; | ||
let commentModel; | ||
let articleModel; | ||
|
||
beforeAll(() => { | ||
userModel = new Model({ | ||
namespace: 'users', | ||
scopes: [], | ||
fields: {}, | ||
}); | ||
|
||
commentModel = new Model({ | ||
namespace: 'comments', | ||
scopes: [], | ||
fields: { | ||
commenter: userModel | ||
}, | ||
}); | ||
|
||
articleModel = new Model({ | ||
namespace: 'articles', | ||
scopes: ['byPage'], | ||
fields: { | ||
author: userModel, | ||
comments: [commentModel] | ||
}, | ||
}); | ||
}); | ||
|
||
describe('selectors', () => { | ||
let reducedData; | ||
|
||
beforeAll(() => { | ||
const action = articleModel.actions().set('byPage', 1, [payload]); | ||
reducedData = articleModel.reducers()({}, action); | ||
}); | ||
|
||
it('returns expected article for defaultScope.providedId when using the articleModel', () => { | ||
const byPageArticleSelector = articleModel.selectors(articleModel.defaultScope, payload.id); | ||
expect(byPageArticleSelector(reducedData)).toEqual(payload); | ||
}); | ||
|
||
it('returns expected comment for defaultScope.providedId when using the commentModel', () => { | ||
const byPageCommentSelector = commentModel.selectors(commentModel.defaultScope, payload.comments[0].id); | ||
expect(byPageCommentSelector(reducedData)).toEqual(payload.comments[0]); | ||
}); | ||
|
||
it('returns expected user for defaultScope.providedId when using the userModel', () => { | ||
const byPageUserSelector = userModel.selectors(userModel.defaultScope, payload.comments[0].commenter.id); | ||
expect(byPageUserSelector(reducedData)).toEqual(payload.comments[0].commenter); | ||
}); | ||
}); | ||
|
||
describe('reducers', () => { | ||
it('set action sets the normalized nested data in the respective scopes', () => { | ||
const action = articleModel.actions().set(articleModel.defaultScope, payload.id, [payload]); | ||
const reducedData = articleModel.reducers()({}, action); | ||
expect(reducedData).toEqual({ | ||
[articleModel.namespace]: { | ||
[articleModel.defaultScope]: { | ||
123: { | ||
id: '123', | ||
author: '1', | ||
title: 'My awesome blog post', | ||
comments: ['324'] | ||
} | ||
} | ||
}, | ||
[userModel.namespace]: { | ||
[userModel.defaultScope]: { | ||
1: {'id': '1', 'name': 'Paul'}, | ||
2: {'id': '2', 'name': 'Nicole'} | ||
} | ||
}, | ||
[commentModel.namespace]: { | ||
[commentModel.defaultScope]: { | ||
324: {id: '324', 'commenter': '2'} | ||
} | ||
} | ||
}); | ||
}); | ||
}); | ||
}); |
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,84 @@ | ||
import {Data, Model} from '../src'; | ||
|
||
const page1Payload = { | ||
'id': '123', | ||
'title': 'My awesome blog post', | ||
}; | ||
|
||
const page2Payload = { | ||
'id': '321', | ||
'title': 'My other blog post', | ||
}; | ||
|
||
const customScope = 'byPage'; | ||
|
||
describe('Data', () => { | ||
let articleModel; | ||
let actions; | ||
let reducers; | ||
let dispatch; | ||
let data; | ||
let scopeId; | ||
|
||
beforeAll(() => { | ||
articleModel = new Model({ | ||
namespace: 'articles', | ||
scopes: [customScope], | ||
fields: {}, | ||
views: { | ||
asOption: article => ({ | ||
value: article.id, label: `${article.id}. ${article.title}`, disabled: article.disabled || false, | ||
}), | ||
}, | ||
controllers: { | ||
disable: article => { article.disabled = true }, | ||
}, | ||
}); | ||
actions = articleModel.actions(); | ||
reducers = articleModel.reducers(); | ||
}); | ||
|
||
beforeEach(() => { | ||
dispatch = jest.fn(); | ||
scopeId = page1Payload.id; | ||
const action = actions.set(customScope, scopeId, [page1Payload, page2Payload]); | ||
const reducedData = reducers({}, action); | ||
const byPageArticleSelector = articleModel.selectors(articleModel.defaultScope, page1Payload.id); | ||
data = new Data(dispatch, articleModel, byPageArticleSelector(reducedData), customScope, scopeId); | ||
}); | ||
|
||
describe('data is accessible via proxy', () => { | ||
it('with id value', () => { | ||
expect(data.id).toEqual(page1Payload.id); | ||
}); | ||
|
||
it('with title value', () => { | ||
expect(data.title).toEqual(page1Payload.title); | ||
}); | ||
}); | ||
|
||
describe('views', () => { | ||
it('asOption returns value, label and disabled defaulting as false', () => { | ||
expect(data.asOption()).toEqual({ | ||
disabled: false, | ||
label: "123. My awesome blog post", | ||
value: "123" | ||
}); | ||
}); | ||
}); | ||
|
||
describe('controllers', () => { | ||
it('disable triggered a set action with a disabled flag', () => { | ||
data.disable(); | ||
expect(dispatch).toHaveBeenCalledWith({ | ||
payload: [{ | ||
disabled: true, | ||
...page1Payload, | ||
}], | ||
scope: customScope, | ||
scopeId, | ||
type: articleModel.actionTypes().set | ||
}); | ||
}); | ||
}); | ||
}); |
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,41 @@ | ||
import * as React from 'react'; | ||
import {combineModelReducers, Model, useModel} from '../../src'; | ||
import {createStore} from 'redux'; | ||
import {Provider} from 'react-redux'; | ||
import {mount} from 'enzyme'; | ||
|
||
function TestComponent({model}) { | ||
const articleModel = useModel(model); | ||
const article = articleModel.byId(1); | ||
|
||
return ( | ||
<div> | ||
{article.id}. {article.title} | ||
</div> | ||
); | ||
} | ||
|
||
describe('useModel', () => { | ||
let articleModel; | ||
let component; | ||
let store; | ||
|
||
beforeEach(() => { | ||
articleModel = new Model({ | ||
namespace: 'articles', | ||
scopes: [], | ||
fields: {}, | ||
}); | ||
store = createStore(combineModelReducers([articleModel])); | ||
store.dispatch(articleModel.actions().set(articleModel.defaultScope, 1, [{id: 1, title: 'title'}])); | ||
component = mount( | ||
<Provider store={store}> | ||
<TestComponent model={articleModel} /> | ||
</Provider> | ||
); | ||
}); | ||
|
||
it('allows components to access a model state via its scopes', () => { | ||
expect(component.find('div').text()).toEqual('1. title'); | ||
}); | ||
}); |
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,28 @@ | ||
import {Model, combineModelReducers} from '../src'; | ||
|
||
describe('combineModelReducers', () => { | ||
let articleModel; | ||
let reducersSpy; | ||
let combinedModelReducers; | ||
|
||
beforeEach(() => { | ||
articleModel = new Model({ | ||
namespace: 'articles', | ||
scopes: [], | ||
fields: {}, | ||
}); | ||
reducersSpy = jest.spyOn(articleModel, 'reducers').mockImplementation( | ||
// Implements an identity reducer | ||
() => (data) => data | ||
); | ||
combinedModelReducers = combineModelReducers([articleModel]); | ||
}); | ||
|
||
it('calls reducers in article model', () => { | ||
expect(reducersSpy).toHaveBeenCalled(); | ||
}); | ||
|
||
it('reduces all models with the same state', () => { | ||
expect(combinedModelReducers('what')).toEqual('what'); | ||
}); | ||
}); |
Oops, something went wrong.