diff --git a/examples/demo-app.js b/examples/demo-app.js
index 69f8137..ff23de6 100644
--- a/examples/demo-app.js
+++ b/examples/demo-app.js
@@ -1,58 +1,100 @@
var { selectorGraph } = ReselectTools;
var { createSelector } = Reselect;
-ReselectTools.getStateWith(() => STORE);
var STORE = {
data: {
users: {
- '1': {
- id: '1',
+ 'bob': {
+ id: 'bob',
name: 'bob',
- pets: ['a', 'b'],
+ age: 24,
+ pets: ['fluffy', 'paws'],
},
- '2': {
- id: '2',
+ 'alice': {
+ id: 'alice',
name: 'alice',
- pets: ['a'],
+ age: 22,
+ pets: ['fluffy'],
}
},
pets: {
- 'a': {
+ 'fluffy': {
name: 'fluffy',
},
- 'b': {
+ 'paws': {
name: 'paws',
}
}
},
ui: {
- currentUser: '1',
+ currentUser: 'alice',
}
};
-const data$ = (state) => state.data;
const ui$ = (state) => state.ui;
-var users$ = createSelector(data$, (data) => data.users);
-var pets$ = createSelector(data$, ({ pets }) => pets);
-var currentUser$ = createSelector(ui$, users$, (ui, users) => users[ui.currentUser]);
+const users$ = (state) => state.data.users;
+const pets$ = (state) => state.data.pets;
+const currentUser$ = createSelector(ui$, users$, (ui, users) => users[ui.currentUser]);
-var currentUserPets$ = createSelector(currentUser$, pets$, (currentUser, pets) => currentUser.pets.map((petId) => pets[petId]));
+const currentUserPets$ = createSelector(currentUser$, pets$, (currentUser, pets) => currentUser.pets.map((petId) => pets[petId]));
+const currentUserAge$ = createSelector(currentUser$, (currentUser) => currentUser.age);
const random$ = (state) => 1;
const thingy$ = createSelector(random$, (number) => number + 1);
const selectors = {
- data$,
ui$,
users$,
pets$,
currentUser$,
currentUserPets$,
+ currentUserAge$,
random$,
thingy$,
};
ReselectTools.registerSelectors(selectors);
+ReselectTools.getStateWith(() => STORE);
+
+
+drawCytoscapeGraph(selectorGraph());
+update();
+
+function update() {
+ const currentUserDiv = document.getElementById('current-user');
+ selectorGraph();
+ currentUserDiv.innerHTML = `Current User: ${currentUser$(STORE).name}.`;
+}
+
+document.addEventListener('DOMContentLoaded', () => {
+ const updateBobAge = () => {
+ STORE = Object.assign({}, STORE, {
+ data: Object.assign({}, STORE.data, {
+ users: Object.assign({}, STORE.data.users, {
+ bob: Object.assign({}, STORE.data.users.bob, {
+ age: STORE.data.users.bob.age + 1
+ })
+ })
+ })
+ });
+
+ update();
+ };
+
+ const updateAliceAge = () => {
+ STORE = Object.assign({}, STORE, {
+ data: Object.assign({}, STORE.data, {
+ users: Object.assign({}, STORE.data.users, {
+ alice: Object.assign({}, STORE.data.users.alice, {
+ age: STORE.data.users.alice.age + 1
+ })
+ })
+ })
+ });
+ update();
+ };
-drawCytoscapeGraph(selectorGraph());
\ No newline at end of file
+ document.getElementById('incr-bob-age').addEventListener('click', updateBobAge);
+ document.getElementById('incr-alice-age').addEventListener('click', updateAliceAge);
+});
diff --git a/examples/demo.html b/examples/demo.html
index 75df76e..6a7e88f 100644
--- a/examples/demo.html
+++ b/examples/demo.html
@@ -6,6 +6,14 @@
height: 90vh;
}
+ #info {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ background: white;
+ display: inline-block;
+ }
+
@@ -16,8 +24,13 @@
-
-
+
+
+ Note that downstream selectors only recompute when you increment the current user's age.
+
+
+
+
diff --git a/extension/.eslintrc b/extension/.eslintrc
index 51051f7..fb341d4 100644
--- a/extension/.eslintrc
+++ b/extension/.eslintrc
@@ -14,6 +14,7 @@
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
"jsx-a11y/no-static-element-interactions": 0,
"jsx-a11y/label-has-for": 0,
+ "no-param-reassign": 0,
"consistent-return": 0,
"comma-dangle": 0,
"spaced-comment": 0,
diff --git a/extension/app/actions/graph.js b/extension/app/actions/graph.js
index 0127998..de30cf1 100644
--- a/extension/app/actions/graph.js
+++ b/extension/app/actions/graph.js
@@ -25,6 +25,6 @@ export function getSelectorGraphSuccess(graph) {
return { type: types.GET_SELECTOR_GRAPH_SUCCESS, payload: { graph } };
}
-export function getSelectorGraph() {
- return { type: types.GET_SELECTOR_GRAPH };
+export function getSelectorGraph(resetRecomputations = false) {
+ return { type: types.GET_SELECTOR_GRAPH, payload: { resetRecomputations }};
}
diff --git a/extension/app/components/Header.js b/extension/app/components/Header.js
index 993b408..b6f5a89 100644
--- a/extension/app/components/Header.js
+++ b/extension/app/components/Header.js
@@ -2,6 +2,7 @@ import React, { Component, PropTypes } from 'react';
import Button from 'remotedev-app/lib/components/Button';
import MdHelp from 'react-icons/lib/md/help';
import FindReplace from 'react-icons/lib/md/find-replace';
+import Clear from 'react-icons/lib/md/clear';
import RefreshIcon from 'react-icons/lib/md/refresh';
import styles from 'remotedev-app/lib/styles';
@@ -18,6 +19,10 @@ const headerStyles = {
color: 'white',
outline: 'none',
},
+ helpButton: {
+ flexGrow: 0,
+ maxWidth: '40px',
+ },
};
class NumberButton extends Component {
@@ -25,6 +30,7 @@ class NumberButton extends Component {
defaultValue: PropTypes.number,
onClick: PropTypes.func,
numbers: PropTypes.array.isRequired,
+ children: PropTypes.node.isRequired,
}
constructor(props) {
super(props);
@@ -37,12 +43,9 @@ class NumberButton extends Component {
this.setState({ value: e.target.value.toString() });
e.stopPropagation();
}
- onClickWithNumber(e) {
+ onClickWithNumber() {
this.props.onClick(parseInt(this.state.value, 10));
}
- stopPropagation(e) {
- e.stopPropagation();
- }
render() {
const { numbers, children, ...other } = this.props;
const { value } = this.state;
@@ -68,7 +71,13 @@ class NumberButton extends Component {
}
-export default function Header({ onRefresh, onHelp, onPaintWorst }) {
+export default function Header({
+ onRefresh,
+ onResetRecomputations,
+ onHelp,
+ onPaintWorst,
+ supportsRefreshRecomputations,
+}) {
return (
-
+ { supportsRefreshRecomputations ?
+ : null
+ }
Select
Most Recomputed
-
+
);
}
@@ -97,4 +112,6 @@ Header.propTypes = {
onRefresh: PropTypes.func,
onHelp: PropTypes.func,
onPaintWorst: PropTypes.func,
+ onResetRecomputations: PropTypes.func,
+ supportsRefreshRecomputations: PropTypes.bool
};
diff --git a/extension/app/components/StateTree.js b/extension/app/components/StateTree.js
index 87d2c56..0864088 100644
--- a/extension/app/components/StateTree.js
+++ b/extension/app/components/StateTree.js
@@ -1,7 +1,7 @@
import JSONTree from 'react-json-tree';
import React, { PropTypes } from 'react';
-const shouldExpandNode = (keyName, data, level) => false;
+const shouldExpandNode = (keyName, data, level) => level === 0;
const isObject = o => typeof o === 'object';
diff --git a/extension/app/containers/App.js b/extension/app/containers/App.js
index b66561b..ec39452 100644
--- a/extension/app/containers/App.js
+++ b/extension/app/containers/App.js
@@ -13,6 +13,10 @@ import Header from '../components/Header';
import * as SelectorActions from '../actions/graph';
+import {
+ supportsRefreshRecomputations$,
+ checkedSelector$
+} from '../selectors/selectors';
const contentStyles = {
content: {
@@ -48,35 +52,10 @@ function renderMessage(message) {
function openGitRepo() {
- const url = 'https://github.com/skortchmark9/reselect-devtools-extension';
+ const url = 'https://github.com/skortchmark9/reselect-tools';
window.open(url, '_blank');
}
-const checkedSelector$ = (state) => {
- const { checkedSelectorId, nodes, edges } = state.graph;
- const selector = nodes[checkedSelectorId];
- if (!selector) return;
-
- // this is a bit ugly because it relies on edges being in order.
- const dependencies = edges.filter(edge => edge.from === checkedSelectorId);
- const dependencyIds = dependencies.map(edge => edge.to);
-
- if (!selector.inputs) {
- return selector;
- }
-
- const { inputs } = selector;
- if (dependencyIds.length !== inputs.length) {
- console.error(`Uh oh, inputs and edges out of sync on ${checkedSelectorId}`);
- }
-
- const zipped = [];
- for (let i = 0; i < dependencyIds.length; i++) {
- zipped.push([dependencyIds[i], inputs[i]]);
- }
- return { ...selector, zipped };
-};
-
const RecomputationsTotal = ({ nodes }) => {
const nodeArr = Object.keys(nodes).map(k => nodes[k]);
@@ -84,10 +63,12 @@ const RecomputationsTotal = ({ nodes }) => {
return {total} Recomputations
;
};
+
@connect(
state => ({
graph: state.graph,
checkedSelector: checkedSelector$(state),
+ supportsRefreshRecomputations: supportsRefreshRecomputations$(state),
}),
dispatch => ({
actions: bindActionCreators(SelectorActions, dispatch)
@@ -99,6 +80,7 @@ export default class App extends Component {
actions: PropTypes.object.isRequired,
graph: PropTypes.object,
checkedSelector: PropTypes.object,
+ supportsRefreshRecomputations: PropTypes.bool,
};
constructor(props) {
@@ -110,6 +92,7 @@ export default class App extends Component {
this.refreshGraph = this.refreshGraph.bind(this);
this.toggleDock = this.toggleDock.bind(this);
this.paintNWorst = this.paintNWorst.bind(this);
+ this.resetRecomputations = this.resetRecomputations.bind(this);
}
componentDidMount() {
@@ -117,11 +100,17 @@ export default class App extends Component {
}
refreshGraph() {
+ this.baseRefreshGraph(false);
+ }
+ baseRefreshGraph(resetRecomputations) {
this.sg && this.sg.reset();
this.resetSelectorData();
- this.props.actions.getSelectorGraph();
- }
+ this.props.actions.getSelectorGraph(resetRecomputations);
+ }
+ resetRecomputations() {
+ this.baseRefreshGraph(true);
+ }
paintNWorst(n) {
this.resetSelectorData();
this.sg.highlightNMostRecomputed(n);
@@ -172,7 +161,7 @@ export default class App extends Component {
this.sg = sg}
+ ref={(sg) => { this.sg = sg; }}
{...graph}
/>
@@ -194,6 +183,8 @@ export default class App extends Component {
onRefresh={this.refreshGraph}
onHelp={openGitRepo}
onPaintWorst={this.paintNWorst}
+ onResetRecomputations={this.resetRecomputations}
+ supportsRefreshRecomputations={this.props.supportsRefreshRecomputations}
/>
{ this.renderContent() }
diff --git a/extension/app/reducers/index.js b/extension/app/reducers/index.js
index 235a7f5..eff8989 100644
--- a/extension/app/reducers/index.js
+++ b/extension/app/reducers/index.js
@@ -1,6 +1,10 @@
import { combineReducers } from 'redux';
import graph from './graph';
+const identity = (x = null) => x;
+
export default combineReducers({
- graph
+ graph,
+ // we provide this so combineReducers doesnt complain about initial state
+ version: identity,
});
diff --git a/extension/app/selectors/selectors.js b/extension/app/selectors/selectors.js
new file mode 100644
index 0000000..9b4fddb
--- /dev/null
+++ b/extension/app/selectors/selectors.js
@@ -0,0 +1,28 @@
+import { greaterThan007 } from '../utils/version';
+
+export const supportsRefreshRecomputations$ = state => greaterThan007(state.version);
+
+export const checkedSelector$ = (state) => {
+ const { checkedSelectorId, nodes, edges } = state.graph;
+ const selector = nodes[checkedSelectorId];
+ if (!selector) return;
+
+ // this is a bit ugly because it relies on edges being in order.
+ const dependencies = edges.filter(edge => edge.from === checkedSelectorId);
+ const dependencyIds = dependencies.map(edge => edge.to);
+
+ if (!selector.inputs) {
+ return selector;
+ }
+
+ const { inputs } = selector;
+ if (dependencyIds.length !== inputs.length) {
+ console.error(`Uh oh, inputs and edges out of sync on ${checkedSelectorId}`);
+ }
+
+ const zipped = [];
+ for (let i = 0; i < dependencyIds.length; i++) {
+ zipped.push([dependencyIds[i], inputs[i]]);
+ }
+ return { ...selector, zipped };
+};
diff --git a/extension/app/utils/apiMiddleware.js b/extension/app/utils/apiMiddleware.js
index 1dc8071..3800bb2 100644
--- a/extension/app/utils/apiMiddleware.js
+++ b/extension/app/utils/apiMiddleware.js
@@ -22,7 +22,8 @@ export default api => store => next => async (action) => {
if (action.type === types.GET_SELECTOR_GRAPH) {
try {
- const graph = await api.selectorGraph();
+ const { resetRecomputations } = action.payload;
+ const graph = await api.selectorGraph(resetRecomputations);
store.dispatch(getSelectorGraphSuccess(graph));
} catch (e) {
store.dispatch(getSelectorGraphFailed());
diff --git a/extension/app/utils/rpc.js b/extension/app/utils/rpc.js
index 0f855d2..63d1dcb 100644
--- a/extension/app/utils/rpc.js
+++ b/extension/app/utils/rpc.js
@@ -1,11 +1,3 @@
-chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
- const where = sender.tab ? 'a content script' : 'the extension';
- const message = `extension received a message from ${where}`;
- console.log(message);
- sendResponse({ k: true });
-});
-
-
function sendMessage(data) {
console.log(chrome.windows.getCurrent((x) => console.log(x)));
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
diff --git a/extension/app/utils/version.js b/extension/app/utils/version.js
new file mode 100644
index 0000000..43b35e0
--- /dev/null
+++ b/extension/app/utils/version.js
@@ -0,0 +1,28 @@
+
+export function greaterThan(v1, v2) {
+ if (!v1) {
+ v1 = '0.0.7'; // we only started doing this in 0.0.8
+ }
+
+ const v1Parts = v1.split('.').map(x => parseInt(x, 10));
+ const v2Parts = v2.split('.').map(x => parseInt(x, 10));
+
+ for (let i = 0; i < 3; i += 1) {
+ const v1Part = v1Parts[i];
+ const v2Part = v2Parts[i];
+
+ if (v1Part > v2Part) {
+ return true;
+ }
+ if (v1Part < v2Part) {
+ return false;
+ }
+ }
+ // they were the same the whole way.
+ return false;
+}
+
+/* we're looking for recomputations, reset recomputations */
+export function greaterThan007(v1) {
+ return greaterThan(v1, '0.0.7');
+}
diff --git a/extension/chrome/extension/api.js b/extension/chrome/extension/api.js
new file mode 100644
index 0000000..1a98704
--- /dev/null
+++ b/extension/chrome/extension/api.js
@@ -0,0 +1,54 @@
+function evalPromise(str) {
+ return new Promise((resolve, reject) => {
+ chrome.devtools.inspectedWindow.eval(str, (resultStr, err) => {
+ const result = JSON.parse(resultStr);
+ if (err && err.isException) {
+ console.error(err.value);
+ reject(err.value);
+ } else {
+ resolve(result);
+ }
+ });
+ });
+}
+
+async function execute(strings, ...keys) {
+ const lastIndex = strings.length - 1;
+ const vanilla = strings
+ .slice(0, lastIndex)
+ .reduce((p, s, i) => p + s + keys[i], '')
+ + strings[lastIndex];
+
+ return evalPromise(`(function() {${vanilla}})()`);
+}
+
+
+export async function checkSelector(id) {
+ return execute`
+ const __reselect_last_check = window.__RESELECT_TOOLS__.checkSelector('${id}');
+ console.log(__reselect_last_check);
+ return JSON.stringify(__reselect_last_check);
+ `;
+}
+
+export async function selectorGraph(resetRecomputations) {
+ let resetStr = '';
+ if (resetRecomputations) {
+ const expr = `
+ for (const selector of window.__RESELECT_TOOLS__._allSelectors) {
+ selector.resetRecomputations && selector.resetRecomputations();
+ };
+ `;
+ resetStr = expr;
+ }
+ return execute`
+ ${resetStr}
+ return JSON.stringify(window.__RESELECT_TOOLS__.selectorGraph())
+ `;
+}
+
+export async function getLibVersion() {
+ return execute`
+ return JSON.stringify(window.__RESELECT_TOOLS__.version);
+ `;
+}
diff --git a/extension/chrome/extension/background.js b/extension/chrome/extension/background.js
index 0afca4b..9d62731 100644
--- a/extension/chrome/extension/background.js
+++ b/extension/chrome/extension/background.js
@@ -1,3 +1,3 @@
chrome.browserAction.onClicked.addListener(() => {
- window.open('https://github.com/skortchmark9/reselect-devtools-extension');
+ window.open('https://github.com/skortchmark9/reselect-tools');
});
diff --git a/extension/chrome/extension/page-api.js b/extension/chrome/extension/page-api.js
deleted file mode 100644
index 6510dc9..0000000
--- a/extension/chrome/extension/page-api.js
+++ /dev/null
@@ -1,27 +0,0 @@
-function evalPromise(str) {
- return new Promise((resolve, reject) => {
- chrome.devtools.inspectedWindow.eval(str, (resultStr, err) => {
- const result = JSON.parse(resultStr);
- if (err && err.isException) {
- console.error(err.value);
- reject(err.value);
- } else {
- resolve(result);
- }
- });
- });
-}
-
-export function checkSelector(id) {
- const str = `(function() {
- const __reselect_last_check = window.__RESELECT_TOOLS__.checkSelector('${id}');
- console.log(__reselect_last_check);
- return JSON.stringify(__reselect_last_check);
- })()`;
- return evalPromise(str);
-}
-
-export function selectorGraph() {
- const str = 'JSON.stringify(window.__RESELECT_TOOLS__.selectorGraph())';
- return evalPromise(str);
-}
diff --git a/extension/chrome/extension/reselect-tools-app.js b/extension/chrome/extension/reselect-tools-app.js
index 68f148b..0ddaba4 100644
--- a/extension/chrome/extension/reselect-tools-app.js
+++ b/extension/chrome/extension/reselect-tools-app.js
@@ -3,12 +3,12 @@ import ReactDOM from 'react-dom';
import Root from '../../app/containers/Root';
import './reselect-tools-app.css';
-import * as api from './page-api';
+import * as realApi from './api';
import createStore from '../../app/store/configureStore';
import createApiMiddleware from '../../app/utils/apiMiddleware';
-const checkSelector = (id) => {
+const checkSelector = async (id) => {
if (id === 'c') {
return Promise.resolve({ inputs: [1], output: {hey: 'hey'}, id, name: id });
}
@@ -23,25 +23,33 @@ const checkSelector = (id) => {
const mockApi = {
checkSelector,
- selectorGraph: () => {
+ selectorGraph: async () => {
const a = { id: 'a', recomputations: 10, isNamed: true };
const b = { id: 'b', recomputations: 10, isNamed: true };
const c = { id: 'c', recomputations: 10, isNamed: true };
const d = { id: 'd', recomputations: 2, isNamed: true };
const e = { id: 'e', recomputations: 4, isNamed: true };
const f = { id: 'f', recomputations: 6, isNamed: true };
- return Promise.resolve({ nodes: { a, b, c, d, e, f }, edges: [{ from: 'a', to: 'b' }, { from: 'b', to: 'c' }] });
+ return { nodes: { a, b, c, d, e, f }, edges: [{ from: 'a', to: 'b' }, { from: 'b', to: 'c' }] };
},
+ getLibVersion: async () => '0.0.8',
};
+const useMock = false;
+const api = useMock ? mockApi : realApi;
const apiMiddleware = createApiMiddleware(api);
-// const apiMiddleware = createApiMiddleware(window.location.origin === 'http://localhost:8000' ? mockApi : api);
+async function go() {
+ const version = await api.getLibVersion();
+ const initialState = {
+ version,
+ };
-const initialState = {};
+ ReactDOM.render(
+ ,
+ document.querySelector('#root')
+ );
+}
-ReactDOM.render(
- ,
- document.querySelector('#root')
-);
+go();
diff --git a/extension/test/app/actions/graph.spec.js b/extension/test/app/actions/graph.spec.js
new file mode 100644
index 0000000..e7f9e8b
--- /dev/null
+++ b/extension/test/app/actions/graph.spec.js
@@ -0,0 +1,7 @@
+/* eslint-disable no-unused-vars */
+import { expect } from 'chai';
+import * as types from '../../../app/constants/ActionTypes';
+import * as actions from '../../../app/actions/graph';
+
+describe('graph actions', () => {
+});
diff --git a/extension/test/app/actions/todos.spec.js b/extension/test/app/actions/todos.spec.js
deleted file mode 100644
index b1cfb71..0000000
--- a/extension/test/app/actions/todos.spec.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import { expect } from 'chai';
-import * as types from '../../../app/constants/ActionTypes';
-import * as actions from '../../../app/actions/todos';
-
-describe('todoapp todo actions', () => {
- it('addTodo should create ADD_TODO action', () => {
- expect(actions.addTodo('Use Redux')).to.eql({
- type: types.ADD_TODO,
- text: 'Use Redux'
- });
- });
-
- it('deleteTodo should create DELETE_TODO action', () => {
- expect(actions.deleteTodo(1)).to.eql({
- type: types.DELETE_TODO,
- id: 1
- });
- });
-
- it('editTodo should create EDIT_TODO action', () => {
- expect(actions.editTodo(1, 'Use Redux everywhere')).to.eql({
- type: types.EDIT_TODO,
- id: 1,
- text: 'Use Redux everywhere'
- });
- });
-
- it('completeTodo should create COMPLETE_TODO action', () => {
- expect(actions.completeTodo(1)).to.eql({
- type: types.COMPLETE_TODO,
- id: 1
- });
- });
-
- it('completeAll should create COMPLETE_ALL action', () => {
- expect(actions.completeAll()).to.eql({
- type: types.COMPLETE_ALL
- });
- });
-
- it('clearCompleted should create CLEAR_COMPLETED action', () => {
- expect(actions.clearCompleted('Use Redux')).to.eql({
- type: types.CLEAR_COMPLETED
- });
- });
-});
diff --git a/extension/test/app/components/Header.spec.js b/extension/test/app/components/Header.spec.js
deleted file mode 100644
index f61b0b9..0000000
--- a/extension/test/app/components/Header.spec.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import { expect } from 'chai';
-import sinon from 'sinon';
-import React from 'react';
-import TestUtils from 'react-addons-test-utils';
-import Header from '../../../app/components/Header';
-import TodoTextInput from '../../../app/components/TodoTextInput';
-
-function setup() {
- const props = {
- addTodo: sinon.spy()
- };
-
- const renderer = TestUtils.createRenderer();
- renderer.render();
- const output = renderer.getRenderOutput();
-
- return { props, output, renderer };
-}
-
-describe('todoapp Header component', () => {
- it('should render correctly', () => {
- const { output } = setup();
-
- expect(output.type).to.equal('header');
-
- const [h1, input] = output.props.children;
-
- expect(h1.type).to.equal('h1');
- expect(h1.props.children).to.equal('todos');
-
- expect(input.type).to.equal(TodoTextInput);
- expect(input.props.newTodo).to.equal(true);
- expect(input.props.placeholder).to.equal('What needs to be done?');
- });
-
- it('should call addTodo if length of text is greater than 0', () => {
- const { output, props } = setup();
- const input = output.props.children[1];
- input.props.onSave('');
- expect(props.addTodo.callCount).to.equal(0);
- input.props.onSave('Use Redux');
- expect(props.addTodo.callCount).to.equal(1);
- });
-});
diff --git a/extension/test/app/reducers/graph.spec.js b/extension/test/app/reducers/graph.spec.js
new file mode 100644
index 0000000..58ed237
--- /dev/null
+++ b/extension/test/app/reducers/graph.spec.js
@@ -0,0 +1,8 @@
+/* eslint-disable no-unused-vars */
+import { expect } from 'chai';
+import * as types from '../../../app/constants/ActionTypes';
+import graph from '../../../app/reducers/graph';
+
+describe('graph reducer', () => {
+
+});
diff --git a/extension/test/app/reducers/todos.spec.js b/extension/test/app/reducers/todos.spec.js
deleted file mode 100644
index d03f149..0000000
--- a/extension/test/app/reducers/todos.spec.js
+++ /dev/null
@@ -1,243 +0,0 @@
-import { expect } from 'chai';
-import * as types from '../../../app/constants/ActionTypes';
-import todos from '../../../app/reducers/todos';
-
-describe('todoapp todos reducer', () => {
- it('should handle initial state', () => {
- expect(
- todos(undefined, {})
- ).to.eql([{
- text: 'Use Redux',
- completed: false,
- id: 0
- }]);
- });
-
- it('should handle ADD_TODO', () => {
- expect(
- todos([], {
- type: types.ADD_TODO,
- text: 'Run the tests'
- })
- ).to.eql([{
- text: 'Run the tests',
- completed: false,
- id: 0
- }]);
-
- expect(
- todos([{
- text: 'Use Redux',
- completed: false,
- id: 0
- }], {
- type: types.ADD_TODO,
- text: 'Run the tests'
- })
- ).to.eql([{
- text: 'Run the tests',
- completed: false,
- id: 1
- }, {
- text: 'Use Redux',
- completed: false,
- id: 0
- }]);
-
- expect(
- todos([{
- text: 'Run the tests',
- completed: false,
- id: 1
- }, {
- text: 'Use Redux',
- completed: false,
- id: 0
- }], {
- type: types.ADD_TODO,
- text: 'Fix the tests'
- })
- ).to.eql([{
- text: 'Fix the tests',
- completed: false,
- id: 2
- }, {
- text: 'Run the tests',
- completed: false,
- id: 1
- }, {
- text: 'Use Redux',
- completed: false,
- id: 0
- }]);
- });
-
- it('should handle DELETE_TODO', () => {
- expect(
- todos([{
- text: 'Run the tests',
- completed: false,
- id: 1
- }, {
- text: 'Use Redux',
- completed: false,
- id: 0
- }], {
- type: types.DELETE_TODO,
- id: 1
- })
- ).to.eql([{
- text: 'Use Redux',
- completed: false,
- id: 0
- }]);
- });
-
- it('should handle EDIT_TODO', () => {
- expect(
- todos([{
- text: 'Run the tests',
- completed: false,
- id: 1
- }, {
- text: 'Use Redux',
- completed: false,
- id: 0
- }], {
- type: types.EDIT_TODO,
- text: 'Fix the tests',
- id: 1
- })
- ).to.eql([{
- text: 'Fix the tests',
- completed: false,
- id: 1
- }, {
- text: 'Use Redux',
- completed: false,
- id: 0
- }]);
- });
-
- it('should handle COMPLETE_TODO', () => {
- expect(
- todos([{
- text: 'Run the tests',
- completed: false,
- id: 1
- }, {
- text: 'Use Redux',
- completed: false,
- id: 0
- }], {
- type: types.COMPLETE_TODO,
- id: 1
- })
- ).to.eql([{
- text: 'Run the tests',
- completed: true,
- id: 1
- }, {
- text: 'Use Redux',
- completed: false,
- id: 0
- }]);
- });
-
- it('should handle COMPLETE_ALL', () => {
- expect(
- todos([{
- text: 'Run the tests',
- completed: true,
- id: 1
- }, {
- text: 'Use Redux',
- completed: false,
- id: 0
- }], {
- type: types.COMPLETE_ALL
- })
- ).to.eql([{
- text: 'Run the tests',
- completed: true,
- id: 1
- }, {
- text: 'Use Redux',
- completed: true,
- id: 0
- }]);
-
- // Unmark if all todos are currently completed
- expect(
- todos([{
- text: 'Run the tests',
- completed: true,
- id: 1
- }, {
- text: 'Use Redux',
- completed: true,
- id: 0
- }], {
- type: types.COMPLETE_ALL
- })
- ).to.eql([{
- text: 'Run the tests',
- completed: false,
- id: 1
- }, {
- text: 'Use Redux',
- completed: false,
- id: 0
- }]);
- });
-
- it('should handle CLEAR_COMPLETED', () => {
- expect(
- todos([{
- text: 'Run the tests',
- completed: true,
- id: 1
- }, {
- text: 'Use Redux',
- completed: false,
- id: 0
- }], {
- type: types.CLEAR_COMPLETED
- })
- ).to.eql([{
- text: 'Use Redux',
- completed: false,
- id: 0
- }]);
- });
-
- it('should not generate duplicate ids after CLEAR_COMPLETED', () => {
- expect(
- [{
- type: types.COMPLETE_TODO,
- id: 0
- }, {
- type: types.CLEAR_COMPLETED
- }, {
- type: types.ADD_TODO,
- text: 'Write more tests'
- }].reduce(todos, [{
- id: 0,
- completed: false,
- text: 'Use Redux'
- }, {
- id: 1,
- completed: false,
- text: 'Write tests'
- }])
- ).to.eql([{
- text: 'Write more tests',
- completed: false,
- id: 2
- }, {
- text: 'Write tests',
- completed: false,
- id: 1
- }]);
- });
-});
diff --git a/extension/test/app/utils/version.spec.js b/extension/test/app/utils/version.spec.js
new file mode 100644
index 0000000..1f0ca14
--- /dev/null
+++ b/extension/test/app/utils/version.spec.js
@@ -0,0 +1,14 @@
+import { expect } from 'chai';
+import { greaterThan007 } from '../../../app/utils/version';
+
+
+describe('version utils', () => {
+ it('should do greater than 0.0.7 correctly', () => {
+ expect(greaterThan007('0.0.8')).to.be.true;
+ expect(greaterThan007('0.1.0')).to.be.true;
+ expect(greaterThan007('1.0.0')).to.be.true;
+ expect(greaterThan007(undefined)).to.be.false;
+ expect(greaterThan007('0.0.7')).to.be.false;
+ expect(greaterThan007('0.0.6')).to.be.false;
+ });
+});
diff --git a/lib/index.js b/lib/index.js
index 584c5cb..d047b07 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -93,6 +93,7 @@ function checkSelector(selector) {
_selector$selectorNam = _selector.selectorName,
selectorName = _selector$selectorNam === undefined ? null : _selector$selectorNam;
+
var isNamed = typeof selectorName === 'string';
var recomputations = selector.recomputations ? selector.recomputations() : null;
@@ -105,14 +106,14 @@ function checkSelector(selector) {
extra.inputs = dependencies.map(function (parentSelector) {
return parentSelector(state);
});
- } catch (e) {
- extra.error = 'checkSelector: error getting inputs of selector ' + selectorName + '. The error was:\n' + e;
- }
- try {
- extra.output = selector(state);
+ try {
+ extra.output = selector(state);
+ } catch (e) {
+ extra.error = 'checkSelector: error getting output of selector ' + selectorName + '. The error was:\n' + e;
+ }
} catch (e) {
- extra.error = 'checkSelector: error getting output of selector ' + selectorName + '. The error was:\n' + e;
+ extra.error = 'checkSelector: error getting inputs of selector ' + selectorName + '. The error was:\n' + e;
}
Object.assign(ret, extra);
@@ -204,6 +205,8 @@ function selectorGraph() {
if (typeof window !== 'undefined') {
window.__RESELECT_TOOLS__ = {
selectorGraph: selectorGraph,
- checkSelector: checkSelector
+ checkSelector: checkSelector,
+ _allSelectors: _allSelectors,
+ version: '0.0.8'
};
}
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index ad267bf..1a4454f 100644
--- a/src/index.js
+++ b/src/index.js
@@ -138,6 +138,8 @@ export function selectorGraph(selectorKey = defaultSelectorKey) {
if (typeof window !== 'undefined') {
window.__RESELECT_TOOLS__ = {
selectorGraph,
- checkSelector
+ checkSelector,
+ _allSelectors,
+ version: '0.0.8'
}
}