-
Notifications
You must be signed in to change notification settings - Fork 67
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
Christopher Turner
committed
Jul 5, 2016
1 parent
64e8f28
commit 5b2897a
Showing
4 changed files
with
319 additions
and
15 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
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,15 @@ | ||
<!doctype html> | ||
<html> | ||
<head> | ||
<title>Polymer Redux Test Suite</title> | ||
<meta charset="utf-8"> | ||
<script src="../../web-component-tester/browser.js"></script> | ||
</head> | ||
<body> | ||
<script> | ||
WCT.loadSuites([ | ||
'polymer-redux.unit-spec.html' | ||
]); | ||
</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,263 @@ | ||
<!doctype html> | ||
<html> | ||
<head> | ||
<title>Polymer Redux Unit Specs</title> | ||
<meta charset="utf-8"> | ||
<script src="../../webcomponentsjs/webcomponents-lite.js"></script> | ||
<script src="../../web-component-tester/browser.js"></script> | ||
<link rel="import" href="../polymer-redux.html"> | ||
<link rel="import" href="./support/redux-stub.html"> | ||
</head> | ||
<body> | ||
<script> | ||
describe('PolymerRedux', function() { | ||
it('should throw TypeError when no store given', function() { | ||
assert.throws(function() { | ||
PolymerRedux( /* no store */ ); | ||
}, /missing redux store/); | ||
}); | ||
|
||
describe('Behavior instance', function() { | ||
before(function() { | ||
this.state = {}; | ||
this.element = { | ||
is: 'fake-element', | ||
actions: { | ||
test: this.testAction | ||
} | ||
}; | ||
this.store = ReduxStub.createStore(); | ||
this.behavior = PolymerRedux(this.store); | ||
}); | ||
|
||
it('should have ready method', function() { | ||
assert.typeOf(this.behavior.ready, 'function'); | ||
}); | ||
|
||
it('should have attached method', function() { | ||
assert.typeOf(this.behavior.attached, 'function'); | ||
}); | ||
|
||
it('should have detached method', function() { | ||
assert.typeOf(this.behavior.detached, 'function'); | ||
}); | ||
|
||
it('should have getState method', function() { | ||
assert.typeOf(this.behavior.getState, 'function'); | ||
}); | ||
|
||
describe('#ready', function() { | ||
before(function() { | ||
this.readyUnsubscribe = function() {}; | ||
this.fireReadyStub = sinon.stub(); | ||
this.elementReady = { | ||
_reduxUnsubscribe: null, | ||
fire: this.fireReadyStub | ||
}; | ||
this.store.resetStub(); | ||
this.store.subscribe.returns(this.readyUnsubscribe); | ||
this.store.getState.returns(this.state); | ||
this.behavior.ready.apply(this.elementReady); | ||
}); | ||
|
||
it('should call redux subscribe with listener', function() { | ||
sinon.assert.calledWithMatch( | ||
this.store.subscribe, | ||
sinon.match.func | ||
); | ||
}); | ||
|
||
it('should have unsubscribe function on element', function() { | ||
assert.strictEqual(this.elementReady._reduxUnsubscribe, this.readyUnsubscribe); | ||
}); | ||
}); | ||
|
||
describe('#attached', function() { | ||
before(function() { | ||
this.attachedUnsubscribe = function() {}; | ||
this.fireAttachedStub = sinon.stub(); | ||
this.elementAttached = { | ||
_reduxUnsubscribe: null, | ||
fire: this.fireAttachedStub | ||
}; | ||
this.store.resetStub(); | ||
this.store.subscribe.returns(this.attachedUnsubscribe); | ||
this.store.getState.returns(this.state); | ||
this.behavior.attached.apply(this.elementAttached); | ||
}); | ||
|
||
it('should call redux subscribe with listener', function() { | ||
sinon.assert.calledWithMatch( | ||
this.store.subscribe, | ||
sinon.match.func | ||
); | ||
}); | ||
|
||
it('should have unsubscribe function on element', function() { | ||
assert.strictEqual(this.elementAttached._reduxUnsubscribe, this.attachedUnsubscribe); | ||
}); | ||
|
||
it('should not subscribe if redux listener already added', function() { | ||
this.store.subscribe.reset(); | ||
this.behavior.attached.apply(this.elementAttached); | ||
|
||
sinon.assert.notCalled(this.store.subscribe); | ||
}); | ||
}); | ||
|
||
describe('#detached', function() { | ||
before(function() { | ||
this.detachedUnsubscribe = sinon.stub(); | ||
this.elementDetached = { | ||
_reduxUnsubscribe: this.detachedUnsubscribe | ||
}; | ||
this.behavior.detached.apply(this.elementDetached); | ||
}); | ||
|
||
it('should call unsubscribe whenever detached', function() { | ||
sinon.assert.calledOnce(this.detachedUnsubscribe); | ||
}); | ||
|
||
it('should remove unsubscribe from element', function() { | ||
assert.notProperty(this.elementDetached, '_reduxUnsubscribe'); | ||
}); | ||
|
||
it('should not throw when detached without listener', function() { | ||
var detached = this.behavior.detached; | ||
var element = this.elementDetached; | ||
|
||
delete this.elementDetached._reduxUnsubscribe; | ||
assert.doesNotThrow(function() { | ||
detached.apply(element); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('#dispatch', function() { | ||
it('should return store\'s dispatch', function() { | ||
var returnAction = {}; | ||
|
||
this.store.resetStub(); | ||
this.store.dispatch.returns(returnAction); | ||
|
||
assert.strictEqual(this.behavior.dispatch(), returnAction); | ||
}); | ||
|
||
describe('action name', function() { | ||
before(function() { | ||
var returnAction = this.nameAction = {}; | ||
this.testAction = sinon.spy(function() { | ||
return returnAction; | ||
}); | ||
this.actionElement = { | ||
is: 'fake-element', | ||
actions: { | ||
test: this.testAction | ||
} | ||
}; | ||
this.store.resetStub(); | ||
}); | ||
|
||
describe('action method', function() { | ||
before(function() { | ||
this.behavior.dispatch.apply(this.actionElement, ['test', 'foo']); | ||
}); | ||
|
||
it('should call action method', function() { | ||
sinon.assert.calledOnce(this.testAction); | ||
}); | ||
|
||
it('should be called with element context', function() { | ||
sinon.assert.calledOn(this.testAction, this.actionElement); | ||
}); | ||
|
||
it('should be pass args to action method', function() { | ||
sinon.assert.calledWithExactly(this.testAction, 'foo'); | ||
}); | ||
|
||
it('should pass returned action to redux', function() { | ||
sinon.assert.calledWithMatch( | ||
this.store.dispatch, | ||
sinon.match.same(this.nameAction) | ||
); | ||
}); | ||
}); | ||
|
||
it('should throw TypeError if no action available', function() { | ||
var dispatch = this.behavior.dispatch; | ||
var element = this.actionElement; | ||
|
||
assert.throws(function() { | ||
dispatch.apply(element, ['nothing']); | ||
}, /<fake-element> has no action "nothing"/) | ||
}); | ||
}); | ||
|
||
describe('action creator', function() { | ||
before(function() { | ||
var returnAction = {}; | ||
this.creatorAction = returnAction; | ||
this.store.resetStub(); | ||
this.creatorSpy = sinon.spy(function() { | ||
return returnAction; | ||
}); | ||
this.behavior.dispatch(this.creatorSpy); | ||
}); | ||
|
||
it('should pass redux given returning action creator', function() { | ||
sinon.assert.calledWithMatch( | ||
this.store.dispatch, | ||
sinon.match.same(this.creatorAction) | ||
); | ||
}); | ||
|
||
it('should call action creator', function() { | ||
sinon.assert.calledOnce(this.creatorSpy); | ||
}); | ||
}); | ||
|
||
describe('action', function() { | ||
it('should pass redux given action', function() { | ||
var reduxAction = {}; | ||
|
||
this.store.resetStub(); | ||
this.behavior.dispatch(reduxAction); | ||
|
||
sinon.assert.calledWithMatch( | ||
this.store.dispatch, | ||
sinon.match.same(reduxAction) | ||
); | ||
}); | ||
|
||
it('should not call middleware within behavior', function() { | ||
var middleware = sinon.spy(function(dispatch) {}); | ||
|
||
this.store.resetStub(); | ||
this.behavior.dispatch(middleware); | ||
|
||
sinon.assert.notCalled(middleware); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('#getState', function() { | ||
before(function() { | ||
this.store.resetStub(); | ||
this.store.getState.returns(this.state); | ||
|
||
this.returnedState = this.behavior.getState(); | ||
}); | ||
|
||
it('should called store getState', function() { | ||
sinon.assert.calledOnce(this.store.getState); | ||
}); | ||
|
||
it('should return store\'s state', function() { | ||
assert.strictEqual(this.returnedState, this.state); | ||
}); | ||
}); | ||
}); | ||
}); | ||
</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,24 @@ | ||
<!doctype html> | ||
<html> | ||
<head> | ||
<title>Redux Stub</title> | ||
<meta charset="utf-8"> | ||
</head> | ||
<body> | ||
<script> | ||
ReduxStub = { | ||
createStore: function() { | ||
var sandbox = sinon.sandbox.create(); | ||
return { | ||
getState: sandbox.stub(), | ||
dispatch: sandbox.stub(), | ||
subscribe: sandbox.stub(), | ||
resetStub: function() { | ||
sandbox.reset(); | ||
} | ||
}; | ||
} | ||
}; | ||
</script> | ||
</body> | ||
</html> |